julialang 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mohammad Raziei
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,336 @@
1
+ Metadata-Version: 2.4
2
+ Name: julialang
3
+ Version: 0.1.0
4
+ Summary: Install and switch Julia versions from pip: a tiny wheel plus a GitHub-mirrored copy of the official binaries.
5
+ Author-email: Mohammad Raziei <mohammadraziei1375@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 Mohammad Raziei
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Source, https://github.com/mohammadraziei/julialang
29
+ Project-URL: Issues, https://github.com/mohammadraziei/julialang/issues
30
+ Project-URL: Changelog, https://github.com/mohammadraziei/julialang/releases
31
+ Keywords: julia,julialang,julia-lang,binary,installer,wheel,version-manager
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Intended Audience :: Developers
34
+ Classifier: Intended Audience :: Science/Research
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Operating System :: POSIX :: Linux
37
+ Classifier: Operating System :: MacOS
38
+ Classifier: Operating System :: Microsoft :: Windows
39
+ Classifier: Programming Language :: Python :: 3
40
+ Classifier: Programming Language :: Python :: 3.9
41
+ Classifier: Programming Language :: Python :: 3.10
42
+ Classifier: Programming Language :: Python :: 3.11
43
+ Classifier: Programming Language :: Python :: 3.12
44
+ Classifier: Programming Language :: Python :: 3.13
45
+ Classifier: Topic :: Software Development :: Interpreters
46
+ Classifier: Topic :: Scientific/Engineering
47
+ Requires-Python: >=3.9
48
+ Description-Content-Type: text/markdown
49
+ License-File: LICENSE
50
+ Dynamic: license-file
51
+
52
+ <div align="center">
53
+
54
+ # julialang
55
+
56
+ **Install, switch and remove [Julia](https://julialang.org) versions with `pip`: no installer, no `apt`, no `juliaup`.**
57
+
58
+ [![PyPI](https://img.shields.io/pypi/v/julialang.svg)](https://pypi.org/project/julialang/)
59
+ [![Python](https://img.shields.io/pypi/pyversions/julialang.svg)](https://pypi.org/project/julialang/)
60
+ [![Wheel](https://github.com/MohammadRaziei/julialang/actions/workflows/wheel.yml/badge.svg)](https://github.com/MohammadRaziei/julialang/actions/workflows/wheel.yml)
61
+ [![Sync](https://github.com/MohammadRaziei/julialang/actions/workflows/sync.yml/badge.svg)](https://github.com/MohammadRaziei/julialang/actions/workflows/sync.yml)
62
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
63
+
64
+ ```bash
65
+ pip install julialang && julialang install && julia
66
+ ```
67
+
68
+ </div>
69
+
70
+ ---
71
+
72
+ ## Contents
73
+
74
+ - [Why julialang?](#why-julialang)
75
+ - [Quick start](#quick-start)
76
+ - [Everyday use](#everyday-use)
77
+ - [Install Julia](#install-julia) · [Run Julia](#run-julia) · [See what you have](#see-what-you-have) · [Switch version](#switch-version) · [Upgrade and downgrade](#upgrade-and-downgrade) · [Remove versions](#remove-versions) · [Remove everything](#remove-everything)
78
+ - [Version specs](#version-specs)
79
+ - [Command reference](#command-reference)
80
+ - [Environment variables](#environment-variables)
81
+ - [How it works](#how-it-works)
82
+ - [For maintainers](#for-maintainers)
83
+ - [Notes](#notes)
84
+
85
+ ## Why julialang?
86
+
87
+ Like [`ziglang`](https://pypi.org/project/ziglang/) does for Zig, `julialang` makes Julia installable from Python
88
+ tooling.
89
+
90
+ - **Tiny wheel.** `pip install julialang` downloads a pure-Python wheel of a few KB (`py3-none-any`), the same on every platform.
91
+ - **No julialang.org needed.** The official binaries are mirrored on GitHub by CI; `julialang` downloads from there and verifies sha256 and md5.
92
+ - **Many versions side by side.** Install as many as you like, switch with one command, upgrade, downgrade, remove.
93
+ - **pip-style version specs.** `julialang install ">=1.10,<1.13"`, `julialang install 1.12`, `julialang install ~=1.12.2`.
94
+ - **Every stable release.** The mirror covers all stable Julia versions, from 0.x to the latest.
95
+ - **Zero dependencies.** Standard library only. Works on Linux (x86_64, aarch64, i686), macOS (x86_64, arm64) and Windows (x86_64, i686) with Python 3.9+.
96
+
97
+ ## Quick start
98
+
99
+ ```bash
100
+ pip install julialang
101
+ julialang install # latest Julia, becomes the default
102
+ julia -e 'println("hello from Julia ", VERSION)'
103
+ ```
104
+
105
+ Julia itself is **not** inside the wheel: `julialang install` downloads it into `~/.julialang`.
106
+
107
+ ## Everyday use
108
+
109
+ ### Install Julia
110
+
111
+ ```bash
112
+ julialang install # the latest version
113
+ julialang install 1.12 # the newest 1.12.x
114
+ julialang install 1.10.5 # exactly this version
115
+ julialang install ">=1.10,<1.13" # the newest version that satisfies the spec
116
+ julialang install 1.10 1.12 # several at once
117
+ ```
118
+
119
+ `install` only **adds** versions: nothing is removed, and the installed version becomes the default. Pass
120
+ `--no-default` to keep the current default:
121
+
122
+ ```bash
123
+ julialang install 1.10 --no-default
124
+ ```
125
+
126
+ ### Run Julia
127
+
128
+ `julia` is a thin shim that runs the selected Julia with your arguments:
129
+
130
+ ```bash
131
+ julia # REPL
132
+ julia script.jl # run a script
133
+ julia -e 'print(VERSION)'
134
+ JULIALANG_VERSION=1.10 julia -e 'print(VERSION)' # one command with another installed version
135
+ ```
136
+
137
+ Which Julia runs: `JULIALANG_VERSION` (a spec, must be installed), else the default chosen by `julialang`, else the
138
+ newest installed one. The shim never touches the network. If nothing is installed yet it tells you to run
139
+ `julialang install` (set `JULIALANG_AUTO_INSTALL=1` to let `julia` install the latest on first use instead).
140
+
141
+ ### See what you have
142
+
143
+ ```bash
144
+ julialang # status: installed versions, the default, the latest on the mirror
145
+ julialang list # installed versions and the ones the mirror offers
146
+ julialang list --installed # only what is on your machine
147
+ julialang list --all # everything the mirror has
148
+ julialang latest # newest version on the mirror
149
+ julialang which # path of the executable `julia` runs
150
+ julialang fetch # refresh the cached list of mirrored versions now
151
+ ```
152
+
153
+ ### Switch version
154
+
155
+ Switch the default among the versions you have installed:
156
+
157
+ ```bash
158
+ julialang use 1.10
159
+ julia -e 'print(VERSION)' # 1.10.x
160
+ julialang use latest
161
+ ```
162
+
163
+ `use` never downloads: if the version is not installed it tells you to `julialang install` it first.
164
+
165
+ ### Upgrade and downgrade
166
+
167
+ `install` keeps old versions; `upgrade` and `downgrade` **replace** the current default:
168
+
169
+ ```bash
170
+ julialang upgrade # install the latest, make it the default, remove the previous default
171
+ julialang upgrade 1.12 # ... or the newest 1.12.x
172
+ julialang downgrade 1.10 # same, towards an older version (the spec is required)
173
+ ```
174
+
175
+ The previous default is deleted only after the new version is downloaded and its checksum verified. Asking `upgrade`
176
+ for an older version (or `downgrade` for a newer one) is an error that points you to the other command; asking for
177
+ the version you already use just says so.
178
+
179
+ ### Remove versions
180
+
181
+ ```bash
182
+ julialang uninstall 1.12.2 # one version
183
+ julialang uninstall 1.10 1.11 # several
184
+ julialang uninstall "<1.12" --yes # a spec that matches many versions asks first; --yes skips the question
185
+ ```
186
+
187
+ Uninstalling the default promotes the newest remaining version to be the new default.
188
+
189
+ ### Remove everything
190
+
191
+ ```bash
192
+ rm -rf ~/.julialang # all installed Julia versions and the cache (Windows: delete %USERPROFILE%\.julialang)
193
+ pip uninstall julialang
194
+ ```
195
+
196
+ Installed versions live outside your virtual environment, so `pip uninstall julialang` alone leaves them in place.
197
+
198
+ ## Version specs
199
+
200
+ Specs work like pip's, with npm-style handling of partial versions:
201
+
202
+ | Spec | Meaning |
203
+ | --- | --- |
204
+ | `latest` (or nothing) | the newest version |
205
+ | `1`, `1.12`, `1.12.*`, `==1.12` | the newest 1.x / 1.12.x |
206
+ | `1.12.4`, `==1.12.4` | exactly that version |
207
+ | `!=1.12.4` | anything but 1.12.4 |
208
+ | `>=1.10`, `<1.13` | comparison, as in pip |
209
+ | `<=1.12`, `>1.12` | with a partial version the whole line counts: `<=1.12` includes 1.12.x, `>1.12` starts at 1.13 |
210
+ | `~=1.12.2` | compatible release: `>=1.12.2,<1.13` (and `~=1.12` is `>=1.12,<2`) |
211
+ | `>=1.10,<1.13` | comma-joined: every part must hold, the newest match wins |
212
+
213
+ Quote specs that contain `<` or `>` so the shell does not treat them as redirection. Several words are joined with
214
+ commas, so `julialang install ">=1.10" "<1.13"` means the same as `julialang install ">=1.10,<1.13"`.
215
+
216
+ ## Command reference
217
+
218
+ | Command | What it does |
219
+ | --- | --- |
220
+ | `julialang` / `julialang status` | installed versions, the default and the latest available |
221
+ | `julialang list [--all\|--installed]` | installed and mirrored versions |
222
+ | `julialang fetch` | refresh the cached list of mirrored versions |
223
+ | `julialang latest` | print the newest mirrored version |
224
+ | `julialang install [SPEC...] [--no-default]` | download and install (latest if no spec); makes it the default |
225
+ | `julialang uninstall SPEC... [--yes]` | delete versions (aliases: `remove`, `rm`) |
226
+ | `julialang use SPEC` | set the default among installed versions |
227
+ | `julialang upgrade [SPEC]` | install the target (latest by default), make it the default, delete the old default |
228
+ | `julialang downgrade SPEC` | the same towards an older version (spec required) |
229
+ | `julialang which` | path of the executable `julia` runs |
230
+ | `julialang --version` | version of this package |
231
+
232
+ The cached version list is trusted for one hour by `status`, `list` and `latest`; `install`, `upgrade`, `downgrade`
233
+ and `fetch` always try the network first and fall back to the cache when offline.
234
+
235
+ ## Environment variables
236
+
237
+ | Variable | Effect |
238
+ | --- | --- |
239
+ | `JULIALANG_HOME` | where versions, `config.json` and the cache live (default `~/.julialang`) |
240
+ | `JULIALANG_VERSION` | spec of an installed version that `julia` should run, instead of the default |
241
+ | `JULIALANG_AUTO_INSTALL=1` | let `julia` install the latest version on first use |
242
+ | `JULIALANG_REPO` | GitHub repository to read the mirror from (default `MohammadRaziei/julialang`) |
243
+ | `JULIALANG_LIST_URL` | full URL of `julia-list.json`, overriding `JULIALANG_REPO` (useful for your own mirror or tests) |
244
+
245
+ State layout: `~/.julialang/versions/<version>/` holds each Julia, and `~/.julialang/config.json` records the default
246
+ and the installed versions; it is re-synchronised with the folders on every command, so you can also delete a folder by hand.
247
+
248
+ ## How it works
249
+
250
+ Three kinds of GitHub releases act as storage, and two independent workflows do the work:
251
+
252
+ | Tag | Kind | Holds |
253
+ | --- | --- | --- |
254
+ | `__download__`, `__download_2__`, ... | prerelease | mirrored Julia archives (`julia-<version>-<os>-<arch>.<ext>`); `__download__` also holds **`julia-list.json`** (md5 + sha256 and URL of every file). GitHub allows ~1000 assets per release, so the mirror starts the next one after 900 files |
255
+ | `__beta__` | prerelease | the latest tested build of master (wheel + sdist) |
256
+ | `vX.Y.Z` | release | the published wheel and sdist |
257
+
258
+ `julia-list.json` is **not** in git: it is only a release asset, uploaded again after every mirrored version.
259
+
260
+ ```
261
+ julialang.org (crawled) ──▶ sync.yml ──▶ __download__ (+ __download_N__) + julia-list.json asset
262
+
263
+ push to master ──▶ wheel.yml: ruff + pytest → build wheel/sdist → smoke test on 5 OSes
264
+ (pip install, `julialang install` FROM THE MIRROR, run julia) → __beta__
265
+ push of tag vX.Y.Z ──▶ the same, then → GitHub release vX.Y.Z + PyPI
266
+ ```
267
+
268
+ `sync.yml` and `wheel.yml` never call each other.
269
+
270
+ - **`tools/sync.py`** crawls <https://julialang.org/downloads/manual-downloads/> and
271
+ <https://julialang.org/downloads/oldreleases/>, downloads every stable Julia that is not mirrored yet
272
+ (`--min-version` defaults to 0.0.0 = all), verifies it against the upstream sha256 (and md5 when published), uploads
273
+ it and records md5 + sha256 in `julia-list.json`. Only archives with a verifiable hash and a known name are mirrored:
274
+ `.tar.gz` for Linux/macOS, `.zip` for Windows (no installers, musl, FreeBSD, pre-releases). `--source json` uses the
275
+ official `versions.json` feed instead. A full backfill takes many hours, so the job stops itself before the 6 h limit
276
+ (`--max-minutes`); the next run (weekly cron, a push, or a manual start) continues where it stopped.
277
+ - **`sync.yml`** ("Sync Julia binaries") runs on every push, weekly and by hand. It only updates the mirror: it makes no
278
+ package release and starts no other workflow.
279
+ - **`wheel.yml`** ("Wheel") runs on every push to master and on tags `v*`. Its smoke test installs Julia from the mirror
280
+ on every OS, so it doubles as a health check of the mirror.
281
+
282
+ **Integrity.** `julialang install` checks the sha256 and md5 from `julia-list.json`. Both come from the same GitHub
283
+ repository as the archives, so this protects against corrupted downloads, not against someone taking over the repository.
284
+
285
+ ## For maintainers
286
+
287
+ ### Set up your own copy
288
+
289
+ 1. Create the repo (default branch `master`; for a name other than `mohammadraziei/julialang` change `DEFAULT_REPO` in
290
+ `julialang/_state.py` and `tools/sync.py`, and the URLs in `pyproject.toml`) and push.
291
+ 2. Settings → Actions → General → Workflow permissions: **Read and write**.
292
+ 3. Every push starts **Sync Julia binaries**; run it by hand from the Actions tab for a `dry_run` (shows the plan) or to
293
+ mirror in slices with `limit`. The first full backfill needs several runs: start it again by hand (or wait for the
294
+ weekly cron) until nothing is left.
295
+ 4. PyPI (optional): add the repository secret `PYPI_PASS` (an API token; for a new project use a token with the scope of
296
+ the whole account) under Settings → Secrets and variables → Actions. Secrets are per repository, so those of another
297
+ repo do not apply. `PYPI_USER` is only needed for a non-token login and must be `__token__` when `PYPI_PASS` is a
298
+ token.
299
+
300
+ ### Release a new version
301
+
302
+ Versions are bumped by hand: edit `version` in `pyproject.toml`, commit, then tag and push.
303
+
304
+ ```bash
305
+ git tag v0.1.0
306
+ git push origin master v0.1.0
307
+ ```
308
+
309
+ The tag must equal the version in `pyproject.toml` (otherwise `wheel.yml` fails immediately). The tag run publishes the
310
+ GitHub release (with generated notes) and uploads to PyPI. Without the `PYPI_PASS` secret it prints a warning and skips
311
+ the upload: add the secret and re-run the tag's run (`twine upload --skip-existing` and the release step are safe to
312
+ repeat).
313
+
314
+ Without PyPI, the wheel installs straight from a GitHub release:
315
+
316
+ ```bash
317
+ pip install julialang --find-links https://github.com/MohammadRaziei/julialang/releases/expanded_assets/v0.1.0
318
+ ```
319
+
320
+ ### Develop
321
+
322
+ ```bash
323
+ pip install -e . pytest setuptools wheel ruff
324
+ python -m ruff check .
325
+ python -m pytest -q tests # about a minute; the end-to-end test builds a wheel
326
+ python tools/sync.py --dry-run # show what would be mirrored
327
+ ```
328
+
329
+ ## Notes
330
+
331
+ - Julia is MIT-licensed, but its binary distribution bundles third-party libraries under their own licenses (see
332
+ `share/julia/` and `share/licenses` inside each version). The code in this repository is MIT.
333
+ - The `julia` command of this package may shadow another `julia` (or `juliaup`) earlier on your `PATH`; `julialang which`
334
+ shows what is actually run.
335
+ - GitHub pauses scheduled workflows after 60 days without repository activity; if the weekly sync stops, re-enable it in
336
+ the Actions tab.
@@ -0,0 +1,285 @@
1
+ <div align="center">
2
+
3
+ # julialang
4
+
5
+ **Install, switch and remove [Julia](https://julialang.org) versions with `pip`: no installer, no `apt`, no `juliaup`.**
6
+
7
+ [![PyPI](https://img.shields.io/pypi/v/julialang.svg)](https://pypi.org/project/julialang/)
8
+ [![Python](https://img.shields.io/pypi/pyversions/julialang.svg)](https://pypi.org/project/julialang/)
9
+ [![Wheel](https://github.com/MohammadRaziei/julialang/actions/workflows/wheel.yml/badge.svg)](https://github.com/MohammadRaziei/julialang/actions/workflows/wheel.yml)
10
+ [![Sync](https://github.com/MohammadRaziei/julialang/actions/workflows/sync.yml/badge.svg)](https://github.com/MohammadRaziei/julialang/actions/workflows/sync.yml)
11
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
12
+
13
+ ```bash
14
+ pip install julialang && julialang install && julia
15
+ ```
16
+
17
+ </div>
18
+
19
+ ---
20
+
21
+ ## Contents
22
+
23
+ - [Why julialang?](#why-julialang)
24
+ - [Quick start](#quick-start)
25
+ - [Everyday use](#everyday-use)
26
+ - [Install Julia](#install-julia) · [Run Julia](#run-julia) · [See what you have](#see-what-you-have) · [Switch version](#switch-version) · [Upgrade and downgrade](#upgrade-and-downgrade) · [Remove versions](#remove-versions) · [Remove everything](#remove-everything)
27
+ - [Version specs](#version-specs)
28
+ - [Command reference](#command-reference)
29
+ - [Environment variables](#environment-variables)
30
+ - [How it works](#how-it-works)
31
+ - [For maintainers](#for-maintainers)
32
+ - [Notes](#notes)
33
+
34
+ ## Why julialang?
35
+
36
+ Like [`ziglang`](https://pypi.org/project/ziglang/) does for Zig, `julialang` makes Julia installable from Python
37
+ tooling.
38
+
39
+ - **Tiny wheel.** `pip install julialang` downloads a pure-Python wheel of a few KB (`py3-none-any`), the same on every platform.
40
+ - **No julialang.org needed.** The official binaries are mirrored on GitHub by CI; `julialang` downloads from there and verifies sha256 and md5.
41
+ - **Many versions side by side.** Install as many as you like, switch with one command, upgrade, downgrade, remove.
42
+ - **pip-style version specs.** `julialang install ">=1.10,<1.13"`, `julialang install 1.12`, `julialang install ~=1.12.2`.
43
+ - **Every stable release.** The mirror covers all stable Julia versions, from 0.x to the latest.
44
+ - **Zero dependencies.** Standard library only. Works on Linux (x86_64, aarch64, i686), macOS (x86_64, arm64) and Windows (x86_64, i686) with Python 3.9+.
45
+
46
+ ## Quick start
47
+
48
+ ```bash
49
+ pip install julialang
50
+ julialang install # latest Julia, becomes the default
51
+ julia -e 'println("hello from Julia ", VERSION)'
52
+ ```
53
+
54
+ Julia itself is **not** inside the wheel: `julialang install` downloads it into `~/.julialang`.
55
+
56
+ ## Everyday use
57
+
58
+ ### Install Julia
59
+
60
+ ```bash
61
+ julialang install # the latest version
62
+ julialang install 1.12 # the newest 1.12.x
63
+ julialang install 1.10.5 # exactly this version
64
+ julialang install ">=1.10,<1.13" # the newest version that satisfies the spec
65
+ julialang install 1.10 1.12 # several at once
66
+ ```
67
+
68
+ `install` only **adds** versions: nothing is removed, and the installed version becomes the default. Pass
69
+ `--no-default` to keep the current default:
70
+
71
+ ```bash
72
+ julialang install 1.10 --no-default
73
+ ```
74
+
75
+ ### Run Julia
76
+
77
+ `julia` is a thin shim that runs the selected Julia with your arguments:
78
+
79
+ ```bash
80
+ julia # REPL
81
+ julia script.jl # run a script
82
+ julia -e 'print(VERSION)'
83
+ JULIALANG_VERSION=1.10 julia -e 'print(VERSION)' # one command with another installed version
84
+ ```
85
+
86
+ Which Julia runs: `JULIALANG_VERSION` (a spec, must be installed), else the default chosen by `julialang`, else the
87
+ newest installed one. The shim never touches the network. If nothing is installed yet it tells you to run
88
+ `julialang install` (set `JULIALANG_AUTO_INSTALL=1` to let `julia` install the latest on first use instead).
89
+
90
+ ### See what you have
91
+
92
+ ```bash
93
+ julialang # status: installed versions, the default, the latest on the mirror
94
+ julialang list # installed versions and the ones the mirror offers
95
+ julialang list --installed # only what is on your machine
96
+ julialang list --all # everything the mirror has
97
+ julialang latest # newest version on the mirror
98
+ julialang which # path of the executable `julia` runs
99
+ julialang fetch # refresh the cached list of mirrored versions now
100
+ ```
101
+
102
+ ### Switch version
103
+
104
+ Switch the default among the versions you have installed:
105
+
106
+ ```bash
107
+ julialang use 1.10
108
+ julia -e 'print(VERSION)' # 1.10.x
109
+ julialang use latest
110
+ ```
111
+
112
+ `use` never downloads: if the version is not installed it tells you to `julialang install` it first.
113
+
114
+ ### Upgrade and downgrade
115
+
116
+ `install` keeps old versions; `upgrade` and `downgrade` **replace** the current default:
117
+
118
+ ```bash
119
+ julialang upgrade # install the latest, make it the default, remove the previous default
120
+ julialang upgrade 1.12 # ... or the newest 1.12.x
121
+ julialang downgrade 1.10 # same, towards an older version (the spec is required)
122
+ ```
123
+
124
+ The previous default is deleted only after the new version is downloaded and its checksum verified. Asking `upgrade`
125
+ for an older version (or `downgrade` for a newer one) is an error that points you to the other command; asking for
126
+ the version you already use just says so.
127
+
128
+ ### Remove versions
129
+
130
+ ```bash
131
+ julialang uninstall 1.12.2 # one version
132
+ julialang uninstall 1.10 1.11 # several
133
+ julialang uninstall "<1.12" --yes # a spec that matches many versions asks first; --yes skips the question
134
+ ```
135
+
136
+ Uninstalling the default promotes the newest remaining version to be the new default.
137
+
138
+ ### Remove everything
139
+
140
+ ```bash
141
+ rm -rf ~/.julialang # all installed Julia versions and the cache (Windows: delete %USERPROFILE%\.julialang)
142
+ pip uninstall julialang
143
+ ```
144
+
145
+ Installed versions live outside your virtual environment, so `pip uninstall julialang` alone leaves them in place.
146
+
147
+ ## Version specs
148
+
149
+ Specs work like pip's, with npm-style handling of partial versions:
150
+
151
+ | Spec | Meaning |
152
+ | --- | --- |
153
+ | `latest` (or nothing) | the newest version |
154
+ | `1`, `1.12`, `1.12.*`, `==1.12` | the newest 1.x / 1.12.x |
155
+ | `1.12.4`, `==1.12.4` | exactly that version |
156
+ | `!=1.12.4` | anything but 1.12.4 |
157
+ | `>=1.10`, `<1.13` | comparison, as in pip |
158
+ | `<=1.12`, `>1.12` | with a partial version the whole line counts: `<=1.12` includes 1.12.x, `>1.12` starts at 1.13 |
159
+ | `~=1.12.2` | compatible release: `>=1.12.2,<1.13` (and `~=1.12` is `>=1.12,<2`) |
160
+ | `>=1.10,<1.13` | comma-joined: every part must hold, the newest match wins |
161
+
162
+ Quote specs that contain `<` or `>` so the shell does not treat them as redirection. Several words are joined with
163
+ commas, so `julialang install ">=1.10" "<1.13"` means the same as `julialang install ">=1.10,<1.13"`.
164
+
165
+ ## Command reference
166
+
167
+ | Command | What it does |
168
+ | --- | --- |
169
+ | `julialang` / `julialang status` | installed versions, the default and the latest available |
170
+ | `julialang list [--all\|--installed]` | installed and mirrored versions |
171
+ | `julialang fetch` | refresh the cached list of mirrored versions |
172
+ | `julialang latest` | print the newest mirrored version |
173
+ | `julialang install [SPEC...] [--no-default]` | download and install (latest if no spec); makes it the default |
174
+ | `julialang uninstall SPEC... [--yes]` | delete versions (aliases: `remove`, `rm`) |
175
+ | `julialang use SPEC` | set the default among installed versions |
176
+ | `julialang upgrade [SPEC]` | install the target (latest by default), make it the default, delete the old default |
177
+ | `julialang downgrade SPEC` | the same towards an older version (spec required) |
178
+ | `julialang which` | path of the executable `julia` runs |
179
+ | `julialang --version` | version of this package |
180
+
181
+ The cached version list is trusted for one hour by `status`, `list` and `latest`; `install`, `upgrade`, `downgrade`
182
+ and `fetch` always try the network first and fall back to the cache when offline.
183
+
184
+ ## Environment variables
185
+
186
+ | Variable | Effect |
187
+ | --- | --- |
188
+ | `JULIALANG_HOME` | where versions, `config.json` and the cache live (default `~/.julialang`) |
189
+ | `JULIALANG_VERSION` | spec of an installed version that `julia` should run, instead of the default |
190
+ | `JULIALANG_AUTO_INSTALL=1` | let `julia` install the latest version on first use |
191
+ | `JULIALANG_REPO` | GitHub repository to read the mirror from (default `MohammadRaziei/julialang`) |
192
+ | `JULIALANG_LIST_URL` | full URL of `julia-list.json`, overriding `JULIALANG_REPO` (useful for your own mirror or tests) |
193
+
194
+ State layout: `~/.julialang/versions/<version>/` holds each Julia, and `~/.julialang/config.json` records the default
195
+ and the installed versions; it is re-synchronised with the folders on every command, so you can also delete a folder by hand.
196
+
197
+ ## How it works
198
+
199
+ Three kinds of GitHub releases act as storage, and two independent workflows do the work:
200
+
201
+ | Tag | Kind | Holds |
202
+ | --- | --- | --- |
203
+ | `__download__`, `__download_2__`, ... | prerelease | mirrored Julia archives (`julia-<version>-<os>-<arch>.<ext>`); `__download__` also holds **`julia-list.json`** (md5 + sha256 and URL of every file). GitHub allows ~1000 assets per release, so the mirror starts the next one after 900 files |
204
+ | `__beta__` | prerelease | the latest tested build of master (wheel + sdist) |
205
+ | `vX.Y.Z` | release | the published wheel and sdist |
206
+
207
+ `julia-list.json` is **not** in git: it is only a release asset, uploaded again after every mirrored version.
208
+
209
+ ```
210
+ julialang.org (crawled) ──▶ sync.yml ──▶ __download__ (+ __download_N__) + julia-list.json asset
211
+
212
+ push to master ──▶ wheel.yml: ruff + pytest → build wheel/sdist → smoke test on 5 OSes
213
+ (pip install, `julialang install` FROM THE MIRROR, run julia) → __beta__
214
+ push of tag vX.Y.Z ──▶ the same, then → GitHub release vX.Y.Z + PyPI
215
+ ```
216
+
217
+ `sync.yml` and `wheel.yml` never call each other.
218
+
219
+ - **`tools/sync.py`** crawls <https://julialang.org/downloads/manual-downloads/> and
220
+ <https://julialang.org/downloads/oldreleases/>, downloads every stable Julia that is not mirrored yet
221
+ (`--min-version` defaults to 0.0.0 = all), verifies it against the upstream sha256 (and md5 when published), uploads
222
+ it and records md5 + sha256 in `julia-list.json`. Only archives with a verifiable hash and a known name are mirrored:
223
+ `.tar.gz` for Linux/macOS, `.zip` for Windows (no installers, musl, FreeBSD, pre-releases). `--source json` uses the
224
+ official `versions.json` feed instead. A full backfill takes many hours, so the job stops itself before the 6 h limit
225
+ (`--max-minutes`); the next run (weekly cron, a push, or a manual start) continues where it stopped.
226
+ - **`sync.yml`** ("Sync Julia binaries") runs on every push, weekly and by hand. It only updates the mirror: it makes no
227
+ package release and starts no other workflow.
228
+ - **`wheel.yml`** ("Wheel") runs on every push to master and on tags `v*`. Its smoke test installs Julia from the mirror
229
+ on every OS, so it doubles as a health check of the mirror.
230
+
231
+ **Integrity.** `julialang install` checks the sha256 and md5 from `julia-list.json`. Both come from the same GitHub
232
+ repository as the archives, so this protects against corrupted downloads, not against someone taking over the repository.
233
+
234
+ ## For maintainers
235
+
236
+ ### Set up your own copy
237
+
238
+ 1. Create the repo (default branch `master`; for a name other than `mohammadraziei/julialang` change `DEFAULT_REPO` in
239
+ `julialang/_state.py` and `tools/sync.py`, and the URLs in `pyproject.toml`) and push.
240
+ 2. Settings → Actions → General → Workflow permissions: **Read and write**.
241
+ 3. Every push starts **Sync Julia binaries**; run it by hand from the Actions tab for a `dry_run` (shows the plan) or to
242
+ mirror in slices with `limit`. The first full backfill needs several runs: start it again by hand (or wait for the
243
+ weekly cron) until nothing is left.
244
+ 4. PyPI (optional): add the repository secret `PYPI_PASS` (an API token; for a new project use a token with the scope of
245
+ the whole account) under Settings → Secrets and variables → Actions. Secrets are per repository, so those of another
246
+ repo do not apply. `PYPI_USER` is only needed for a non-token login and must be `__token__` when `PYPI_PASS` is a
247
+ token.
248
+
249
+ ### Release a new version
250
+
251
+ Versions are bumped by hand: edit `version` in `pyproject.toml`, commit, then tag and push.
252
+
253
+ ```bash
254
+ git tag v0.1.0
255
+ git push origin master v0.1.0
256
+ ```
257
+
258
+ The tag must equal the version in `pyproject.toml` (otherwise `wheel.yml` fails immediately). The tag run publishes the
259
+ GitHub release (with generated notes) and uploads to PyPI. Without the `PYPI_PASS` secret it prints a warning and skips
260
+ the upload: add the secret and re-run the tag's run (`twine upload --skip-existing` and the release step are safe to
261
+ repeat).
262
+
263
+ Without PyPI, the wheel installs straight from a GitHub release:
264
+
265
+ ```bash
266
+ pip install julialang --find-links https://github.com/MohammadRaziei/julialang/releases/expanded_assets/v0.1.0
267
+ ```
268
+
269
+ ### Develop
270
+
271
+ ```bash
272
+ pip install -e . pytest setuptools wheel ruff
273
+ python -m ruff check .
274
+ python -m pytest -q tests # about a minute; the end-to-end test builds a wheel
275
+ python tools/sync.py --dry-run # show what would be mirrored
276
+ ```
277
+
278
+ ## Notes
279
+
280
+ - Julia is MIT-licensed, but its binary distribution bundles third-party libraries under their own licenses (see
281
+ `share/julia/` and `share/licenses` inside each version). The code in this repository is MIT.
282
+ - The `julia` command of this package may shadow another `julia` (or `juliaup`) earlier on your `PATH`; `julialang which`
283
+ shows what is actually run.
284
+ - GitHub pauses scheduled workflows after 60 days without repository activity; if the weekly sync stops, re-enable it in
285
+ the Actions tab.
@@ -0,0 +1,15 @@
1
+ """julialang: `pip install julialang`, then `julialang install` and run `julia`."""
2
+ from importlib.metadata import PackageNotFoundError
3
+ from importlib.metadata import version as _version
4
+
5
+ try:
6
+ __version__ = _version("julialang")
7
+ except PackageNotFoundError: # running from a source checkout
8
+ __version__ = "0.0.0.dev0"
9
+
10
+
11
+ def julia_executable() -> str:
12
+ """Path of the Julia executable that the `julia` command would run."""
13
+ from . import _state
14
+
15
+ return str(_state.exe_in(_state.resolve_root()))
@@ -0,0 +1,3 @@
1
+ from .cli import main
2
+
3
+ raise SystemExit(main())