Skip to content

Commit

Permalink
fix: support multiple versions in lockfile (#2923)
Browse files Browse the repository at this point in the history
� Conflicts:
�	.mise.lock
�	.mise.toml
�	e2e/cli/test_use
  • Loading branch information
jdx authored Nov 6, 2024
1 parent 448e205 commit 48a6f7b
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 12 deletions.
18 changes: 18 additions & 0 deletions .mise.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[tools]
actionlint = "1.7.4"
cargo-binstall = "1.10.10"
"cargo:cargo-edit" = "0.13.0"
"cargo:cargo-insta" = "1.41.1"
"cargo:cargo-show" = "0.6.0"
"cargo:git-cliff" = "2.6.1"
"cargo:usage-cli" = "1.1.1"
direnv = "latest"
jq = "1.7.1"
"npm:markdownlint-cli" = "0.42.0"
"npm:prettier" = "3.3.3"
"pipx:toml-sort" = "0.23.1"
python = "3.10.15"
ripgrep = "14.1.1"
shellcheck = "0.10.0"
shfmt = "3.10.0"
tiny = "2.1.0"
1 change: 1 addition & 0 deletions e2e/lockfile/test_lockfile_exec
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
export MISE_LOCKFILE=1
export MISE_EXPERIMENTAL=1

touch .mise.lock
mise install [email protected]
mise use tiny@1
mise install [email protected]
Expand Down
1 change: 1 addition & 0 deletions e2e/lockfile/test_lockfile_install
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
export MISE_LOCKFILE=1
export MISE_EXPERIMENTAL=1

touch .mise.lock
mise use tiny@1
cat <<EOF >.mise.lock
[tools]
Expand Down
14 changes: 14 additions & 0 deletions e2e/lockfile/test_lockfile_use
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
export MISE_LOCKFILE=1
export MISE_EXPERIMENTAL=1

touch .mise.lock
mise install [email protected]
mise use tiny@1
mise install [email protected]
Expand Down Expand Up @@ -30,3 +31,16 @@ assert "cat .mise.lock" '[tools]
tiny = "3.1.0"'
assert "mise ls tiny --json --current | jq -r '.[0].requested_version'" "3"
assert "mise ls tiny --json --current | jq -r '.[0].version'" "3.1.0"

mise use tiny@1 tiny@2
assert "cat .mise.lock" '[tools]
tiny = [
"1.0.0",
"2.1.0",
]'
mise uninstall --all tiny
mise install tiny
assert "mise ls tiny --json --current | jq -r '.[0].requested_version'" "1"
assert "mise ls tiny --json --current | jq -r '.[0].version'" "1.0.0"
assert "mise ls tiny --json --current | jq -r '.[1].requested_version'" "2"
assert "mise ls tiny --json --current | jq -r '.[1].version'" "2.1.0"
20 changes: 16 additions & 4 deletions settings.toml
Original file line number Diff line number Diff line change
Expand Up @@ -329,17 +329,29 @@ type = "Bool"
default = false
description = "Create and read lockfiles for tool versions."
docs = """
Create and read lockfiles for tool versions. This is useful when you'd like to have loose versions in mise.toml like this:
Read/update lockfiles for tool versions. This is useful when you'd like to have loose versions in mise.toml like this:
```toml
[tools]
node = "22"
gh = "latest"
```
But you'd like the versions installed to be consistent within a project. When this is enabled, mise will automatically
create mise.lock files next to mise.toml files containing pinned versions.
When installing tools, mise will reference this lockfile if it exists and this setting is enabled to resolve versions.
But you'd like the versions installed to be consistent within a project. When this is enabled, mise will update mise.lock
files next to mise.toml files containing pinned versions. When installing tools, mise will reference this lockfile if it exists and this setting is enabled to resolve versions.
The lockfiles are not created automatically. To generate them, run the following (assuming the config file is `mise.toml`):
```sh
touch mise.lock && mise install
```
The lockfile is named the same as the config file but with `.lock` instead of `.toml` as the extension, e.g.:
- `mise.toml` -> `mise.lock`
- `.mise.toml` -> `.mise.lock`
- `mise.local.toml` -> `mise.local.lock`
- `.config/mise.toml` -> `.config/mise.lock`
"""

[log_level]
Expand Down
44 changes: 37 additions & 7 deletions src/lockfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::sync::Mutex;
#[derive(Debug, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Lockfile {
tools: BTreeMap<String, String>,
tools: BTreeMap<String, toml::Value>,
}

impl Lockfile {
Expand Down Expand Up @@ -76,6 +76,9 @@ pub fn update_lockfiles(new_versions: &[ToolVersion]) -> Result<()> {
let empty = HashMap::new();
for config_path in lockfiles {
let lockfile_path = config_path.with_extension("lock");
if !lockfile_path.exists() {
continue;
}
let tool_source = ToolSource::MiseToml(config_path.clone());
let tools = tools_by_source.get(&tool_source).unwrap_or(&empty);
trace!(
Expand All @@ -94,10 +97,19 @@ pub fn update_lockfiles(new_versions: &[ToolVersion]) -> Result<()> {
.retain(|k, _| all_tool_names.contains(k) || SETTINGS.disable_tools.contains(k));

for (short, tvl) in tools {
for tv in &tvl.versions {
existing_lockfile
.tools
.insert(short.to_string(), tv.version.to_string());
if tvl.versions.len() > 1 {
let versions = toml::Value::Array(
tvl.versions
.iter()
.map(|tv| tv.version.clone().into())
.collect(),
);
existing_lockfile.tools.insert(short.to_string(), versions);
} else {
existing_lockfile.tools.insert(
short.to_string(),
toml::Value::String(tvl.versions[0].version.clone()),
);
}
}

Expand All @@ -107,7 +119,7 @@ pub fn update_lockfiles(new_versions: &[ToolVersion]) -> Result<()> {
Ok(())
}

pub fn get_locked_version(path: &Path, short: &str) -> Result<Option<String>> {
pub fn get_locked_version(path: &Path, short: &str, prefix: &str) -> Result<Option<String>> {
static CACHE: Lazy<Mutex<HashMap<PathBuf, Lockfile>>> = Lazy::new(Default::default);

if !SETTINGS.lockfile {
Expand All @@ -122,7 +134,25 @@ pub fn get_locked_version(path: &Path, short: &str) -> Result<Option<String>> {
.unwrap_or_else(|err| handle_missing_lockfile(err, &lockfile_path))
});

Ok(lockfile.tools.get(short).cloned())
if let Some(tool) = lockfile.tools.get(short) {
// TODO: handle something like `mise use python@3 [email protected]`
match tool {
toml::Value::String(v) => {
if v.starts_with(prefix) {
Ok(Some(v.clone()))
} else {
Ok(None)
}
}
toml::Value::Array(v) => Ok(v
.iter()
.map(|v| v.as_str().unwrap().to_string())
.find(|v| v.starts_with(prefix))),
_ => unimplemented!("unsupported lockfile format"),
}
} else {
Ok(None)
}
}

fn handle_missing_lockfile(err: Report, lockfile_path: &Path) -> Lockfile {
Expand Down
2 changes: 1 addition & 1 deletion src/toolset/tool_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ impl ToolRequest {

pub fn lockfile_resolve(&self) -> Result<Option<String>> {
if let Some(path) = self.source().path() {
return lockfile::get_locked_version(path, &self.backend().short);
return lockfile::get_locked_version(path, &self.backend().short, &self.version());
}
Ok(None)
}
Expand Down

0 comments on commit 48a6f7b

Please sign in to comment.