Skip to content

Conversation

@KristofferC
Copy link
Member

alternative to #1095

I am not much of a rust programmer so I kind of wrote pseudo code and had Claude Code translate it for me. Should still do some manual cleanups.

In use:

~/JuliaPkgs/TimerOutputs.jl
❯ julia --project -q
Info: Installing Julia 1.10.10 automatically per juliaup settings...
Checking for new Julia versions
Info: Successfully installed Julia 1.10.10.
julia> VERSION
v"1.10.10"

# Change the manifest file

~/JuliaPkgs/TimerOutputs.jl
❯ julia --project -q
Info: Installing Julia 1.10.8 automatically per juliaup settings...
Checking for new Julia versions
Installing Julia 1.10.8+0.aarch64.apple.darwin14
Info: Successfully installed Julia 1.10.8.
julia> VERSION
v"1.10.8"


// Search for manifest files in priority order
// JuliaManifest.toml takes precedence over Manifest.toml
for manifest_name in ["JuliaManifest.toml", "Manifest.toml"] {
Copy link
Member

@DilumAluthge DilumAluthge Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs support for {Julia,}Manifest-vX.Y.toml

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One idea:

  1. Loop over all files in the directory. Ignore folders.
  2. Collect only the filenames that match the allowed patterns.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would also be reasonable (and in my mind a bit less magical) to say that version selection via the manifest only happens from a JuliaManifest.toml or Manifest.toml file.

The {Julia,}Manifest-vX.Y.toml manifests would then only come into play if one used a higher precedent order override.

@DilumAluthge
Copy link
Member

How should this work if the project directory has multiple versioned manifests, e.g. Manifest-1.10.toml and Manifest-1.12.toml?

@KristofferC
Copy link
Member Author

Probably the highest version?

@KristofferC KristofferC force-pushed the kc/auto_version_select branch from 2510c05 to 842eafa Compare October 31, 2025 18:52
@DilumAluthge
Copy link
Member

DilumAluthge commented Oct 31, 2025

Probably the highest version?

That seems okay.

If the user explicitly provides the desired version (e.g. julia +1.10 --project or julia +1.10.3 --project or julia +lts --project), we'd respect the Julia version specified by julia +ver, right?

@KristofferC
Copy link
Member Author

If the user explicitly provides the desired version (e.g. julia +1.10 --project or julia +1.10.3 --project or julia +lts --project), we'd respect the Julia version specified by julia +ver, right?

Yes, if you look at the priority in the README (which I updated here) it is:

1. A command line Julia version specifier, such as `julia +release`.
2. The `JULIAUP_CHANNEL` environment variable.
3. A directory override, set with the `juliaup override set` command.
3. The default Juliaup channel.
4. Automatic version selection based on the active project.
5. The default Juliaup channel.

So an explicitly provided version has top-priority and will always be used.

@DilumAluthge
Copy link
Member

DilumAluthge commented Oct 31, 2025

BTW I think item 3 should be removed from that list? Redundant with item 5, and IIUC you prefer item 4 over item 5?

EDIT: This was just a confusion over a typo in a GitHub comment. The actual code in the PR was correct.

@KristofferC KristofferC force-pushed the kc/auto_version_select branch 3 times, most recently from 220d16a to 58b6b04 Compare October 31, 2025 22:15
@KristofferC
Copy link
Member Author

I don't fully understand why it is redundant or why this PR makes it more redundant.

@davidanthoff
Copy link
Collaborator

I believe @DilumAluthge was just looking at the list as pasted in the comment here, where there are two 3) items. It is all correct in the PR that modifies the README.

@KristofferC
Copy link
Member Author

Oops, I must have copy pasted from the diff.

@KristofferC
Copy link
Member Author

I realize a better way of testing this is (of course) to call julia itself with the same project flag and env variable and get the truth from that.

@IanButterworth
Copy link
Member

Just had a thought.. how does this handle manifests from julia master, i.e. 1.14, given that there's no "1.14" channel? I guess there isn't a "1.13" either.

@KristofferC
Copy link
Member Author

KristofferC commented Nov 2, 2025

It uses nightly channel if the version is higher than any known version. But maybe it should emit some warning when that happens...

@KristofferC KristofferC force-pushed the kc/auto_version_select branch 3 times, most recently from c846ba4 to 988b305 Compare November 3, 2025 09:36
@tecosaur
Copy link
Member

tecosaur commented Nov 3, 2025

I may be missing something, but why is this ~3x the LOC of #1095? Is this PR larger in scope?

I do notice that #1095 was written before versioned manifests became a thing, but that seems like just a handful of extra lines.

@KristofferC KristofferC marked this pull request as draft November 3, 2025 11:21
@KristofferC
Copy link
Member Author

KristofferC commented Nov 3, 2025

I can remove tests if you want to... But as I have said, you are free to reopen your PR and we can try them on a bunch of cases. But based on

I don't think it's realistic that I'll get around to writing the missing tests, let alone resolving the merge conflicts any time soon.

I thought you didn't plan on getting back to that "any time soon" so I started this. I don't know if four days counts as "any time soon" or if just the fact that someone else started working on it made your desire come back.

However, some things that this does that might be different from that branch:

  • Launch +nightly if the version is > than anyone version we know
  • Launch 1.x+nightly if x is > than any version we now for 1.x
  • Expand ~ to homedir
  • LOAD_PATH
  • Logging
  • Versioned manifests
  • Maybe more, didn't look more.

@tecosaur
Copy link
Member

tecosaur commented Nov 3, 2025

I can remove tests if you want to... But as I have said, you are free to reopen your PR and we can try them on a bunch of cases. But based on

Oh, I'm talking about the non-testing code. Taking a slightly closer look, it seems like ~700 LOC compared to ~400 in the original PR, which doesn't seem too bad given the extra functionality you mentioned.

I thought you didn't plan on getting back to that "any time soon" so I started this. I don't know if four days counts as "any time soon" or if just the fact that someone else started working on it made your desire come back.

Yea, I wasn't thinking of getting back to this any time soon when I said that. I also have a track record of getting around to things later than I expected, which I try to account for.

After making that comment, and given you said that functionality seems needed, I then thought I should just "take a peek" at it that evening to see how bad the merge conflicts really are, and then we talked about how the functionality should work over Slack, and all that moved the work from back-of-mind to front-of-mind. I tend to work on what I'm thinking about.

Net result: I've ended up poking at this months earlier than I thought I would. If there is value in me spinning up that branch again, it's much more viable than it was four days ago. However, if Sonnet 4.5 can't take care of the test writing, or for some other reason the work ends up in limbo again, I don't currently have the motivation in this area to keep working on this for a prolonged period.

Looking at how hard adding project/nightly/versioned manifest support is, and doing it if it's easy, I am up for (but not much more).

@KristofferC KristofferC force-pushed the kc/auto_version_select branch 2 times, most recently from 0a18fe8 to f0e8600 Compare November 3, 2025 13:56
@KristofferC
Copy link
Member Author

KristofferC commented Nov 3, 2025

I rewrote a lot of the implementation here because I realized (while being on the treadmill 🏃‍♂️) that it made a lot of sense to just directly "transpile" the julia code itself that does the project and manifest file resolving. That should make it easier to review, easier to update and more likely to be correct.

As a test of one of the functionality I wanted to use this for I did:

(@v1.12) pkg> app add https://github.com/KristofferC/Rot13.jl
...
[ Info: For package: Rot13 installed apps rot13

which installs the rot13 Julia app. I then set the julia command to run apps with to the juliaup julia and we can see how it detects the julia version in the manifest for the app (which requires JULIA_LOAD_PATH handling support) and uses the correct version:

❯ JULIAUP_LOG=Debug JULIA_APPS_JULIA_CMD=~/juliaup/target/debug/julia rot13 foobar
[2025-11-03T13:54:58Z DEBUG julia] VersionDetect::Found valid project in JULIA_LOAD_PATH entry: /home/kc/.julia/environments/apps/Rot13
[2025-11-03T13:54:58Z DEBUG julia] VersionDetect::Using project file: /home/kc/.julia/environments/apps/Rot13/Project.toml
[2025-11-03T13:54:58Z DEBUG julia] VersionDetect::Detected manifest file: /home/kc/.julia/environments/apps/Rot13/Manifest.toml
[2025-11-03T13:54:58Z DEBUG julia] VersionDetect::Read Julia version from manifest: 1.12.1
sbbone

@KristofferC KristofferC marked this pull request as ready for review November 3, 2025 14:00
@KristofferC KristofferC force-pushed the kc/auto_version_select branch 2 times, most recently from b133d52 to e5e59b0 Compare November 3, 2025 14:03
@KristofferC
Copy link
Member Author

KristofferC commented Nov 14, 2025

It is a runtime opt-in.

Oh sorry, I thought we were talking about these type of features https://doc.rust-lang.org/cargo/reference/features.html

Edit: Added it

@MilesCranmer
Copy link
Member

(I did too, oops!)

@KristofferC KristofferC force-pushed the kc/auto_version_select branch from 8b87bc1 to 5e4df44 Compare November 14, 2025 20:06
@KristofferC KristofferC force-pushed the kc/auto_version_select branch from 5e4df44 to f0634f8 Compare November 14, 2025 20:17
@KristofferC KristofferC force-pushed the kc/auto_version_select branch from 6178e7e to 2da70f0 Compare November 14, 2025 20:44
@MilesCranmer
Copy link
Member

Just to check, do u want me to click resolved on comments once you give a thumbs up, or will you click resolved after implementing?

@KristofferC
Copy link
Member Author

Just to check, do u want me to click resolved on comments once you give a thumbs up, or will you click resolved after implementing?

Not sure.


I made the "feature" opt-in for now since that seems to be what people want.

Copy link
Member

@MilesCranmer MilesCranmer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's looking pretty good; most comments are to improve the code. Some questions are on the desired behaviour of errors.

.filter(|version| version.major == major && version.minor == minor)
.max()
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}
pub fn has_channel(&self, version: &str) -> bool {
self.available_channels.contains_key(version)
}
}


pub fn resolve_auto_channel(required: String, versions_db: &JuliaupVersionDB) -> Result<String> {
// Check if exact version is available
if versions_db.available_channels.contains_key(&required) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if versions_db.available_channels.contains_key(&required) {
if versions_db.has_channel(&required) {

Comment on lines 547 to 550
if versions_db
.available_channels
.contains_key(&versioned_nightly)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if versions_db
.available_channels
.contains_key(&versioned_nightly)
{
if versions_db.has_channel(&versioned_nightly) {

Comment on lines 347 to 368
// Try --project or JULIA_PROJECT first
if let Some(project_file) = init_active_project_impl(
args,
current_dir,
julia_project.as_deref(),
depot_path.as_deref(),
)? {
return extract_version_from_project(project_file);
}

// Fall back to JULIA_LOAD_PATH
if let Some(ref load_path) = julia_load_path {
if let Some(project_file) =
find_project_from_load_path(load_path, current_dir, depot_path.as_deref())?
{
return extract_version_from_project(project_file);
}
}

// No project found
log::debug!("VersionDetect::No project specification found");
Ok(None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Try --project or JULIA_PROJECT first
if let Some(project_file) = init_active_project_impl(
args,
current_dir,
julia_project.as_deref(),
depot_path.as_deref(),
)? {
return extract_version_from_project(project_file);
}
// Fall back to JULIA_LOAD_PATH
if let Some(ref load_path) = julia_load_path {
if let Some(project_file) =
find_project_from_load_path(load_path, current_dir, depot_path.as_deref())?
{
return extract_version_from_project(project_file);
}
}
// No project found
log::debug!("VersionDetect::No project specification found");
Ok(None)
// Resolve project file (in priority order)
let maybe_project_file =
// 1. --project flag or JULIA_PROJECT env
init_active_project_impl(
args,
current_dir,
julia_project.as_deref(),
depot_path.as_deref(),
)?
// 2. Fallback to JULIA_LOAD_PATH
.or_else(|| {
julia_load_path.as_ref().and_then(|load_path| {
find_project_from_load_path(load_path, current_dir, depot_path.as_deref())
.ok() // Result<Option<PathBuf>> → Option<Option<PathBuf>>
.flatten() // Option<Option<PathBuf>> → Option<PathBuf>
})
});
// If no project was found, stop here
let Some(project_file) = maybe_project_file else {
log::debug!("VersionDetect::No project specification found");
return Ok(None);
};
// Extract version from the resolved project
extract_version_from_project(project_file)

Just made it a bit more readable to myself

continue;
}

let Ok(Some(project_file)) = load_path_expand_impl(entry, current_dir, depot_path) else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If load_path_expand_impl returns an Err, it gets skipped. Is that on purpose? Or would we want it to propagate normally?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General question:

If Manifest.toml is invalid, do we want Juliaup to hard error, or should it just log it and fall back?

Copy link
Member Author

@KristofferC KristofferC Nov 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imo, I think you never want it to hard error. It should print the error and fall back to default.

@IanButterworth
Copy link
Member

I made the "feature" opt-in for now since that seems to be what people want.

You could add a prompt to enable the opt-in first time in interactive mode, like the auto channel install thing.

@KristofferC KristofferC force-pushed the kc/auto_version_select branch from 8c48f93 to 8a41d3a Compare November 18, 2025 14:43
@KristofferC
Copy link
Member Author

Since this is now off by default, maybe it is safe to put this in and ask people to try things out?

@KristofferC
Copy link
Member Author

I think this is at the point where it would be good to merge, ask people to try it out and then it can be enabled by default.

Copy link
Member

@IanButterworth IanButterworth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plan to try this out sounds good to me

@KristofferC KristofferC merged commit 37ff9de into JuliaLang:main Dec 30, 2025
29 checks passed
@KristofferC KristofferC deleted the kc/auto_version_select branch December 30, 2025 14:52
visr added a commit to visr/juliaup that referenced this pull request Jan 5, 2026
Right now the readme reads like it is enabled by default.

Would be nice to have a release with JuliaLang#1315.

Or I'm also fine to not merge this and set the default to true, it works well for me and seems preferable.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants