mirror of https://github.com/jdx/mise
fix: support multiple versions in lockfile (#2923)
Conflicts: .mise.lock .mise.toml e2e/cli/test_use
This commit is contained in:
parent
17a1c501cf
commit
c6e795dc07
|
@ -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"
|
|
@ -3,6 +3,7 @@
|
|||
export MISE_LOCKFILE=1
|
||||
export MISE_EXPERIMENTAL=1
|
||||
|
||||
touch .mise.lock
|
||||
mise install tiny@1.0.0
|
||||
mise use tiny@1
|
||||
mise install tiny@1.0.1
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
export MISE_LOCKFILE=1
|
||||
export MISE_EXPERIMENTAL=1
|
||||
|
||||
touch .mise.lock
|
||||
mise use tiny@1
|
||||
cat <<EOF >.mise.lock
|
||||
[tools]
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
export MISE_LOCKFILE=1
|
||||
export MISE_EXPERIMENTAL=1
|
||||
|
||||
touch .mise.lock
|
||||
mise install tiny@1.0.0
|
||||
mise use tiny@1
|
||||
mise install tiny@1.0.1
|
||||
|
@ -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"
|
||||
|
|
|
@ -329,7 +329,7 @@ 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]
|
||||
|
@ -337,9 +337,21 @@ 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]
|
||||
|
|
|
@ -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 {
|
||||
|
@ -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!(
|
||||
|
@ -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()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 python@3.1`
|
||||
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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue