New way to handle other versions - #1682
Conversation
721c32c to
5f030ce
Compare
|
Oh this is interesting! Thanks for getting this PR in place for discussion too! First impressions: I think I would like to not merge this PR though (...unless we have a use-case where we need Bit of background... my current feeling is that the current way we handle multiple versions is duct tape: good enough to hold us over until we go with a proper solution. I was originally hoping that we could avoid multiple versions entirely until we had the proper solution, but enough conflicts popped up around different dependency versions that we needed something to unblock us. For the final design, I still feel pretty happy overall with the design I outlined here: brioche-dev/brioche#97 (comment) (if you asked me a year ago, I definitely would've hoped to at least have a prototype of this feature by now though!) Also lots of good question:
...we kind of already have this today, kind of! Every time the client resolves a package from the registry, it gets it with a tag name. Today, that's hard-coded as Personally, having a specific "default" name makes a lot of sense to me intuitively, but it's bit hard to describe why. I guess it's harder for me to imagine what things would look like without some kind of default tag. Docker uses
I think this ties in with brioche-dev/brioche#320. Honestly, I would still push for using ...actually I decided to check Cargo, and
Yes, I definitely want this! That's honestly a big part of the motivation to me: letting packages pick the right version of their dependencies. If
Today, https://brioche.dev/packages/ just links to the GitHub repo, but that was mostly done as a placeholder! Eventually, I want a package page that shows everything you'd want about a package: the current version and hash, version history, TypeScript docs, details about what's in the default export, etc. That's a big task on its own though! Shorter term, I think it'd be reasonable to add
Agreed at a high level, but the reason it's under
Also agreed 100%. I do think this should be something that Brioche itself + the registry support though, I'd prefer if packages themselves didn't need to manually do these tag aliases each time, and instead we just handled it automatically (same with |
The only downside of this proposal is that if a recipe depends on another recipe and we need to override its version as in the Today, we have that: export default function awsCli(): std.Recipe<std.Directory> {
const pythonVersion = "3.13";
const managedPython = python({ version: pythonVersion });
let venv = std.recipe(managedPython);
}With the proposal, we'll have: export default function awsCli(): std.Recipe<std.Directory> {
const pythonVersion = "3.13.9";
const managedPython = python({ version: pythonVersion });
let venv = std.recipe(managedPython);
}Which means every time, the path version if Python changes, we need to update all the downstream recipes. I would more see something that is a mix of today and your proposal: export const project = {
name: "postgresql",
version: "16.0.0",
versions: [
"15": "15.0.0",
"14": "14.0.0",
],
};But again with this proposal, it means the tag is export const project = {
name: "postgresql",
version: "16.0.0",
versions: [
"16": "16.0.0",
"15": "15.0.0",
"14": "14.0.0",
],
};
As far as this character is forbidden in the name of a recipe, I guess, it can work. I agree that
I agree for the MVP, we should have a way to request the available versions (and all its hashes ?) from the CLI. The webpage could come later.
Sure, we can experiment in the
Agree, that's why I wasn't feeling comfortable with the current approach of this PR.
Sure, I wasn't expected to be merged anytime soon ! I'll just extract the fix for the go recipe, plus a quick uniformization we could have. |
|
Also, after a second thought, it's maybe just me, but I'm not a big fan of having both 1export const project = {
name: "single",
versions: [
"1": "1.0.0",
],
};export const project = {
name: "multiple",
versions: [
"1": "1.0.0",
"2": "2.0.0",
],
};Cons:
2export const project = {
name: "single",
version: "1.1.0",
};export const project = {
name: "multiple",
versions: [
"1": "1.1.0",
"2": "2.0.0",
],
};Cons:
3export const project = {
name: "single",
versions: "1.1.0",
};export const project = {
name: "multiple",
versions: [
"1.1.0",
"2.0.0",
],
};Cons:
4export const project = {
name: "single",
version: "1.1.0",
};export const project = {
name: "multiple",
versions: [
"1.1.0",
"2.0.0",
],
tags: [
"1": "1.1.0",
"2": "2.0.0",
],
};Cons:
5Any other ideas ? |
|
I kind of like (4), since it's not a breaking change for 98% of current recipes. For recipe with one version, we should only allow For recipe with multiple versions, export const project = {
name: "multiple",
versions: [
"1.1.0",
"2.0.0-rc2",
"3.0.0-2025-11-01"
],
tags: [
"1": "1.1.0",
"beta": "2.0.0-rc2",
"nightly": "3.0.0-2025-11-01"
],
};So it means a such recipe could be installed with these different commands: Edit: Another use case of having name tags would be for the dev environment. It's pretty common to import a tool this way. Based on your comment here, we could have something like that: import * as std from "std";
import rust_analyzer from "rust_analyzer";
import rust from "rust";
export const devTools = std.merge(
rust({ nightly }),
rust_analyzer({ nightly }),
);While still relying on the lock file to have pinned version of packages. I know this example is not that realistic, since most of the time, a user would also want to choose the nightly version, a bit like here where I pinned my Rust nightly toolchain. Another example is the Edit 2: I said earlier that export const project = {
name: "multiple",
versions: [
"1.1.0",
"2.0.0-2025-11-01"
],
tags: [
"1": "1.1.0",
"latest": "1.1.0",
"nightly": "2.0.0-2025-11-01"
],
}; |
863b36a to
f3d6feb
Compare
|
@jaudiger I like the last example you gave, I think that's the one that resonates with me the most, but yeah it gets tricky when you start considering how to handle things like "setting ...oh, and I can't remember if we ever discussed how the import rust from "rust@nightly";...which means you wouldn't need to call it like import rust from "rust" with { version: "nightly" };This gets somewhat more complicated to handle on the runtime side, but I feel like this syntax would make it pretty intuitive to use a specific pinned version of something! |
No we haven't, but I kinda like your first proposition, it seems more natural for people coming from other package managers.
Ok, so let me push this direction with this PR to see what it could do. I'll do that in the coming days |
…t it Signed-off-by: Jérémy Audiger <jeremy.audiger@icloud.com>
Signed-off-by: Jérémy Audiger <jeremy.audiger@icloud.com>
f3d6feb to
0f2465c
Compare


It would have taken time, but here we go. This PR is here to open the discussion on how to handle multiple versions of a recipe. I'm not quite happy with what we were doing, and I'm still not happy with this proposal.
Basic user story
Having a way to choose the version of a
recipewhen we want to install it locally or when we want to use it in an other recipes.How do we do it today ?
Basically, we have
project.versionthat serves as the latest version of a recipe, and we can have an optional keyproject.extra.otherVersionswhich exposes other possible versions that can be used for this recipe. Today, the concept of other versions could be defined as: "X(.Y)?" where X is the major number and Y the optional minor number. Here we don't wantZto be part of the tag.What we really want ?
This is not yet completely decided, but here is a good summary from @kylewlacy.
The CLI interface could be defined as is:
# From the registry brioche install -r sqlx_cli@tagWhere
tagis optional and could take one of these values:latestX(.Y)?Questions
latestwhich is the same thing as just not setting the tag ?@since it's a valid character for a folder name# From a local path brioche install -p ./packages/sqlx_cli@taglatest,X(.Y)?and a hash)