mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-07 01:00:24 +00:00
Merge 4c16cf9a98
into 00d3aa3780
This commit is contained in:
commit
ec53b752ef
13 changed files with 77 additions and 19 deletions
|
@ -3728,6 +3728,10 @@ pub struct LockArgs {
|
||||||
#[arg(long, conflicts_with = "check_exists", conflicts_with = "check")]
|
#[arg(long, conflicts_with = "check_exists", conflicts_with = "check")]
|
||||||
pub dry_run: bool,
|
pub dry_run: bool,
|
||||||
|
|
||||||
|
/// Force rewrite
|
||||||
|
#[arg(long, conflicts_with = "dry_run")]
|
||||||
|
pub force: bool,
|
||||||
|
|
||||||
/// Lock the specified Python script, rather than the current project.
|
/// Lock the specified Python script, rather than the current project.
|
||||||
///
|
///
|
||||||
/// If provided, uv will lock the script (based on its inline metadata table, in adherence with
|
/// If provided, uv will lock the script (based on its inline metadata table, in adherence with
|
||||||
|
|
|
@ -980,7 +980,7 @@ async fn lock_and_sync(
|
||||||
if locked {
|
if locked {
|
||||||
LockMode::Locked(target.interpreter())
|
LockMode::Locked(target.interpreter())
|
||||||
} else {
|
} else {
|
||||||
LockMode::Write(target.interpreter())
|
LockMode::Write(target.interpreter(), false)
|
||||||
},
|
},
|
||||||
&settings.resolver,
|
&settings.resolver,
|
||||||
client_builder,
|
client_builder,
|
||||||
|
@ -1102,7 +1102,7 @@ async fn lock_and_sync(
|
||||||
if locked {
|
if locked {
|
||||||
LockMode::Locked(target.interpreter())
|
LockMode::Locked(target.interpreter())
|
||||||
} else {
|
} else {
|
||||||
LockMode::Write(target.interpreter())
|
LockMode::Write(target.interpreter(), false)
|
||||||
},
|
},
|
||||||
&settings.resolver,
|
&settings.resolver,
|
||||||
client_builder,
|
client_builder,
|
||||||
|
|
|
@ -180,7 +180,7 @@ pub(crate) async fn export(
|
||||||
// If we're locking a script, avoid creating a lockfile if it doesn't already exist.
|
// If we're locking a script, avoid creating a lockfile if it doesn't already exist.
|
||||||
LockMode::DryRun(interpreter.as_ref().unwrap())
|
LockMode::DryRun(interpreter.as_ref().unwrap())
|
||||||
} else {
|
} else {
|
||||||
LockMode::Write(interpreter.as_ref().unwrap())
|
LockMode::Write(interpreter.as_ref().unwrap(), false)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initialize any shared state.
|
// Initialize any shared state.
|
||||||
|
|
|
@ -85,6 +85,7 @@ pub(crate) async fn lock(
|
||||||
frozen: bool,
|
frozen: bool,
|
||||||
dry_run: DryRun,
|
dry_run: DryRun,
|
||||||
refresh: Refresh,
|
refresh: Refresh,
|
||||||
|
force: bool,
|
||||||
python: Option<String>,
|
python: Option<String>,
|
||||||
install_mirrors: PythonInstallMirrors,
|
install_mirrors: PythonInstallMirrors,
|
||||||
settings: ResolverSettings,
|
settings: ResolverSettings,
|
||||||
|
@ -182,7 +183,7 @@ pub(crate) async fn lock(
|
||||||
} else if dry_run.enabled() {
|
} else if dry_run.enabled() {
|
||||||
LockMode::DryRun(&interpreter)
|
LockMode::DryRun(&interpreter)
|
||||||
} else {
|
} else {
|
||||||
LockMode::Write(&interpreter)
|
LockMode::Write(&interpreter, force)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -253,7 +254,7 @@ pub(crate) async fn lock(
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub(super) enum LockMode<'env> {
|
pub(super) enum LockMode<'env> {
|
||||||
/// Write the lockfile to disk.
|
/// Write the lockfile to disk.
|
||||||
Write(&'env Interpreter),
|
Write(&'env Interpreter, bool),
|
||||||
/// Perform a resolution, but don't write the lockfile to disk.
|
/// Perform a resolution, but don't write the lockfile to disk.
|
||||||
DryRun(&'env Interpreter),
|
DryRun(&'env Interpreter),
|
||||||
/// Error if the lockfile is not up-to-date with the project requirements.
|
/// Error if the lockfile is not up-to-date with the project requirements.
|
||||||
|
@ -359,6 +360,7 @@ impl<'env> LockOperation<'env> {
|
||||||
self.workspace_cache,
|
self.workspace_cache,
|
||||||
self.printer,
|
self.printer,
|
||||||
self.preview,
|
self.preview,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -372,7 +374,7 @@ impl<'env> LockOperation<'env> {
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
LockMode::Write(interpreter) | LockMode::DryRun(interpreter) => {
|
LockMode::Write(interpreter, force) => {
|
||||||
// Read the existing lockfile.
|
// Read the existing lockfile.
|
||||||
let existing = match target.read().await {
|
let existing = match target.read().await {
|
||||||
Ok(Some(existing)) => Some(existing),
|
Ok(Some(existing)) => Some(existing),
|
||||||
|
@ -402,15 +404,49 @@ impl<'env> LockOperation<'env> {
|
||||||
self.workspace_cache,
|
self.workspace_cache,
|
||||||
self.printer,
|
self.printer,
|
||||||
self.preview,
|
self.preview,
|
||||||
|
force,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// If the lockfile changed, write it to disk.
|
|
||||||
if !matches!(self.mode, LockMode::DryRun(_)) {
|
|
||||||
if let LockResult::Changed(_, lock) = &result {
|
if let LockResult::Changed(_, lock) = &result {
|
||||||
target.commit(lock).await?;
|
target.commit(lock).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
LockMode::DryRun(interpreter) => {
|
||||||
|
// Read the existing lockfile.
|
||||||
|
let existing = match target.read().await {
|
||||||
|
Ok(Some(existing)) => Some(existing),
|
||||||
|
Ok(None) => None,
|
||||||
|
Err(ProjectError::Lock(err)) => {
|
||||||
|
warn_user!(
|
||||||
|
"Failed to read existing lockfile; ignoring locked requirements: {err}"
|
||||||
|
);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Perform the lock operation, but don't write the lockfile to disk.
|
||||||
|
let result = do_lock(
|
||||||
|
target,
|
||||||
|
interpreter,
|
||||||
|
existing,
|
||||||
|
self.constraints,
|
||||||
|
self.refresh,
|
||||||
|
self.settings,
|
||||||
|
self.client_builder,
|
||||||
|
self.state,
|
||||||
|
self.logger,
|
||||||
|
self.concurrency,
|
||||||
|
self.cache,
|
||||||
|
self.workspace_cache,
|
||||||
|
self.printer,
|
||||||
|
self.preview,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
@ -434,6 +470,7 @@ async fn do_lock(
|
||||||
workspace_cache: &WorkspaceCache,
|
workspace_cache: &WorkspaceCache,
|
||||||
printer: Printer,
|
printer: Printer,
|
||||||
preview: Preview,
|
preview: Preview,
|
||||||
|
force: bool,
|
||||||
) -> Result<LockResult, ProjectError> {
|
) -> Result<LockResult, ProjectError> {
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
|
|
||||||
|
@ -767,6 +804,7 @@ async fn do_lock(
|
||||||
state.index(),
|
state.index(),
|
||||||
&database,
|
&database,
|
||||||
printer,
|
printer,
|
||||||
|
force,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
|
@ -986,11 +1024,16 @@ impl ValidatedLock {
|
||||||
index: &InMemoryIndex,
|
index: &InMemoryIndex,
|
||||||
database: &DistributionDatabase<'_, Context>,
|
database: &DistributionDatabase<'_, Context>,
|
||||||
printer: Printer,
|
printer: Printer,
|
||||||
|
force: bool,
|
||||||
) -> Result<Self, ProjectError> {
|
) -> Result<Self, ProjectError> {
|
||||||
// Perform checks in a deliberate order, such that the most extreme conditions are tested
|
// Perform checks in a deliberate order, such that the most extreme conditions are tested
|
||||||
// first (i.e., every check that returns `Self::Unusable`, followed by every check that
|
// first (i.e., every check that returns `Self::Unusable`, followed by every check that
|
||||||
// returns `Self::Versions`, followed by every check that returns `Self::Preferable`, and
|
// returns `Self::Versions`, followed by every check that returns `Self::Preferable`, and
|
||||||
// finally `Self::Satisfies`).
|
// finally `Self::Satisfies`).
|
||||||
|
if force {
|
||||||
|
return Ok(Self::Preferable(lock));
|
||||||
|
}
|
||||||
|
// Start with the most severe condition: a fundamental option changed between resolutions.
|
||||||
if lock.resolution_mode() != options.resolution_mode {
|
if lock.resolution_mode() != options.resolution_mode {
|
||||||
let _ = writeln!(
|
let _ = writeln!(
|
||||||
printer.stderr(),
|
printer.stderr(),
|
||||||
|
|
|
@ -294,7 +294,7 @@ pub(crate) async fn remove(
|
||||||
let mode = if locked {
|
let mode = if locked {
|
||||||
LockMode::Locked(target.interpreter())
|
LockMode::Locked(target.interpreter())
|
||||||
} else {
|
} else {
|
||||||
LockMode::Write(target.interpreter())
|
LockMode::Write(target.interpreter(), false)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initialize any shared state.
|
// Initialize any shared state.
|
||||||
|
|
|
@ -266,7 +266,7 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl
|
||||||
} else if locked {
|
} else if locked {
|
||||||
LockMode::Locked(environment.interpreter())
|
LockMode::Locked(environment.interpreter())
|
||||||
} else {
|
} else {
|
||||||
LockMode::Write(environment.interpreter())
|
LockMode::Write(environment.interpreter(), false)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generate a lockfile.
|
// Generate a lockfile.
|
||||||
|
@ -744,7 +744,7 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl
|
||||||
} else if isolated {
|
} else if isolated {
|
||||||
LockMode::DryRun(venv.interpreter())
|
LockMode::DryRun(venv.interpreter())
|
||||||
} else {
|
} else {
|
||||||
LockMode::Write(venv.interpreter())
|
LockMode::Write(venv.interpreter(), false)
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = match project::lock::LockOperation::new(
|
let result = match project::lock::LockOperation::new(
|
||||||
|
|
|
@ -309,7 +309,7 @@ pub(crate) async fn sync(
|
||||||
} else if dry_run.enabled() {
|
} else if dry_run.enabled() {
|
||||||
LockMode::DryRun(environment.interpreter())
|
LockMode::DryRun(environment.interpreter())
|
||||||
} else {
|
} else {
|
||||||
LockMode::Write(environment.interpreter())
|
LockMode::Write(environment.interpreter(), false)
|
||||||
};
|
};
|
||||||
|
|
||||||
let lock_target = match &target {
|
let lock_target = match &target {
|
||||||
|
@ -1272,7 +1272,7 @@ impl From<(&LockTarget<'_>, &LockMode<'_>, &Outcome)> for LockReport {
|
||||||
LockResult::Unchanged(..) => match mode {
|
LockResult::Unchanged(..) => match mode {
|
||||||
// When `--frozen` is used, we don't check the lockfile
|
// When `--frozen` is used, we don't check the lockfile
|
||||||
LockMode::Frozen => LockAction::Use,
|
LockMode::Frozen => LockAction::Use,
|
||||||
LockMode::DryRun(_) | LockMode::Locked(_) | LockMode::Write(_) => {
|
LockMode::DryRun(_) | LockMode::Locked(_) | LockMode::Write(..) => {
|
||||||
LockAction::Check
|
LockAction::Check
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -131,7 +131,7 @@ pub(crate) async fn tree(
|
||||||
// If we're locking a script, avoid creating a lockfile if it doesn't already exist.
|
// If we're locking a script, avoid creating a lockfile if it doesn't already exist.
|
||||||
LockMode::DryRun(interpreter.as_ref().unwrap())
|
LockMode::DryRun(interpreter.as_ref().unwrap())
|
||||||
} else {
|
} else {
|
||||||
LockMode::Write(interpreter.as_ref().unwrap())
|
LockMode::Write(interpreter.as_ref().unwrap(), false)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initialize any shared state.
|
// Initialize any shared state.
|
||||||
|
|
|
@ -582,7 +582,7 @@ async fn lock_and_sync(
|
||||||
let mode = if locked {
|
let mode = if locked {
|
||||||
LockMode::Locked(target.interpreter())
|
LockMode::Locked(target.interpreter())
|
||||||
} else {
|
} else {
|
||||||
LockMode::Write(target.interpreter())
|
LockMode::Write(target.interpreter(), false)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initialize any shared state.
|
// Initialize any shared state.
|
||||||
|
|
|
@ -1940,6 +1940,7 @@ async fn run_project(
|
||||||
args.frozen,
|
args.frozen,
|
||||||
args.dry_run,
|
args.dry_run,
|
||||||
args.refresh,
|
args.refresh,
|
||||||
|
args.force,
|
||||||
args.python,
|
args.python,
|
||||||
args.install_mirrors,
|
args.install_mirrors,
|
||||||
args.settings,
|
args.settings,
|
||||||
|
|
|
@ -1381,6 +1381,7 @@ pub(crate) struct LockSettings {
|
||||||
pub(crate) locked: bool,
|
pub(crate) locked: bool,
|
||||||
pub(crate) frozen: bool,
|
pub(crate) frozen: bool,
|
||||||
pub(crate) dry_run: DryRun,
|
pub(crate) dry_run: DryRun,
|
||||||
|
pub(crate) force: bool,
|
||||||
pub(crate) script: Option<PathBuf>,
|
pub(crate) script: Option<PathBuf>,
|
||||||
pub(crate) python: Option<String>,
|
pub(crate) python: Option<String>,
|
||||||
pub(crate) install_mirrors: PythonInstallMirrors,
|
pub(crate) install_mirrors: PythonInstallMirrors,
|
||||||
|
@ -1400,6 +1401,7 @@ impl LockSettings {
|
||||||
check,
|
check,
|
||||||
check_exists,
|
check_exists,
|
||||||
dry_run,
|
dry_run,
|
||||||
|
force,
|
||||||
script,
|
script,
|
||||||
resolver,
|
resolver,
|
||||||
build,
|
build,
|
||||||
|
@ -1416,6 +1418,7 @@ impl LockSettings {
|
||||||
locked: check,
|
locked: check,
|
||||||
frozen: check_exists,
|
frozen: check_exists,
|
||||||
dry_run: DryRun::from_args(dry_run),
|
dry_run: DryRun::from_args(dry_run),
|
||||||
|
force,
|
||||||
script,
|
script,
|
||||||
python: python.and_then(Maybe::into_option),
|
python: python.and_then(Maybe::into_option),
|
||||||
refresh: Refresh::from(refresh),
|
refresh: Refresh::from(refresh),
|
||||||
|
|
|
@ -9501,6 +9501,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
|
||||||
locked: false,
|
locked: false,
|
||||||
frozen: false,
|
frozen: false,
|
||||||
dry_run: Disabled,
|
dry_run: Disabled,
|
||||||
|
force: false,
|
||||||
script: None,
|
script: None,
|
||||||
python: None,
|
python: None,
|
||||||
install_mirrors: PythonInstallMirrors {
|
install_mirrors: PythonInstallMirrors {
|
||||||
|
@ -9618,6 +9619,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
|
||||||
locked: false,
|
locked: false,
|
||||||
frozen: false,
|
frozen: false,
|
||||||
dry_run: Disabled,
|
dry_run: Disabled,
|
||||||
|
force: false,
|
||||||
script: None,
|
script: None,
|
||||||
python: None,
|
python: None,
|
||||||
install_mirrors: PythonInstallMirrors {
|
install_mirrors: PythonInstallMirrors {
|
||||||
|
@ -9758,6 +9760,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
|
||||||
locked: false,
|
locked: false,
|
||||||
frozen: false,
|
frozen: false,
|
||||||
dry_run: Disabled,
|
dry_run: Disabled,
|
||||||
|
force: false,
|
||||||
script: None,
|
script: None,
|
||||||
python: None,
|
python: None,
|
||||||
install_mirrors: PythonInstallMirrors {
|
install_mirrors: PythonInstallMirrors {
|
||||||
|
@ -9873,6 +9876,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
|
||||||
locked: false,
|
locked: false,
|
||||||
frozen: false,
|
frozen: false,
|
||||||
dry_run: Disabled,
|
dry_run: Disabled,
|
||||||
|
force: false,
|
||||||
script: None,
|
script: None,
|
||||||
python: None,
|
python: None,
|
||||||
install_mirrors: PythonInstallMirrors {
|
install_mirrors: PythonInstallMirrors {
|
||||||
|
@ -9978,6 +9982,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
|
||||||
locked: false,
|
locked: false,
|
||||||
frozen: false,
|
frozen: false,
|
||||||
dry_run: Disabled,
|
dry_run: Disabled,
|
||||||
|
force: false,
|
||||||
script: None,
|
script: None,
|
||||||
python: None,
|
python: None,
|
||||||
install_mirrors: PythonInstallMirrors {
|
install_mirrors: PythonInstallMirrors {
|
||||||
|
@ -10084,6 +10089,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
|
||||||
locked: false,
|
locked: false,
|
||||||
frozen: false,
|
frozen: false,
|
||||||
dry_run: Disabled,
|
dry_run: Disabled,
|
||||||
|
force: false,
|
||||||
script: None,
|
script: None,
|
||||||
python: None,
|
python: None,
|
||||||
install_mirrors: PythonInstallMirrors {
|
install_mirrors: PythonInstallMirrors {
|
||||||
|
|
|
@ -1669,7 +1669,8 @@ uv lock [OPTIONS]
|
||||||
<p>May also be set with the <code>UV_EXTRA_INDEX_URL</code> environment variable.</p></dd><dt id="uv-lock--find-links"><a href="#uv-lock--find-links"><code>--find-links</code></a>, <code>-f</code> <i>find-links</i></dt><dd><p>Locations to search for candidate distributions, in addition to those found in the registry indexes.</p>
|
<p>May also be set with the <code>UV_EXTRA_INDEX_URL</code> environment variable.</p></dd><dt id="uv-lock--find-links"><a href="#uv-lock--find-links"><code>--find-links</code></a>, <code>-f</code> <i>find-links</i></dt><dd><p>Locations to search for candidate distributions, in addition to those found in the registry indexes.</p>
|
||||||
<p>If a path, the target must be a directory that contains packages as wheel files (<code>.whl</code>) or source distributions (e.g., <code>.tar.gz</code> or <code>.zip</code>) at the top level.</p>
|
<p>If a path, the target must be a directory that contains packages as wheel files (<code>.whl</code>) or source distributions (e.g., <code>.tar.gz</code> or <code>.zip</code>) at the top level.</p>
|
||||||
<p>If a URL, the page must contain a flat list of links to package files adhering to the formats described above.</p>
|
<p>If a URL, the page must contain a flat list of links to package files adhering to the formats described above.</p>
|
||||||
<p>May also be set with the <code>UV_FIND_LINKS</code> environment variable.</p></dd><dt id="uv-lock--fork-strategy"><a href="#uv-lock--fork-strategy"><code>--fork-strategy</code></a> <i>fork-strategy</i></dt><dd><p>The strategy to use when selecting multiple versions of a given package across Python versions and platforms.</p>
|
<p>May also be set with the <code>UV_FIND_LINKS</code> environment variable.</p></dd><dt id="uv-lock--force"><a href="#uv-lock--force"><code>--force</code></a></dt><dd><p>Force rewrite</p>
|
||||||
|
</dd><dt id="uv-lock--fork-strategy"><a href="#uv-lock--fork-strategy"><code>--fork-strategy</code></a> <i>fork-strategy</i></dt><dd><p>The strategy to use when selecting multiple versions of a given package across Python versions and platforms.</p>
|
||||||
<p>By default, uv will optimize for selecting the latest version of each package for each supported Python version (<code>requires-python</code>), while minimizing the number of selected versions across platforms.</p>
|
<p>By default, uv will optimize for selecting the latest version of each package for each supported Python version (<code>requires-python</code>), while minimizing the number of selected versions across platforms.</p>
|
||||||
<p>Under <code>fewest</code>, uv will minimize the number of selected versions for each package, preferring older versions that are compatible with a wider range of supported Python versions or platforms.</p>
|
<p>Under <code>fewest</code>, uv will minimize the number of selected versions for each package, preferring older versions that are compatible with a wider range of supported Python versions or platforms.</p>
|
||||||
<p>May also be set with the <code>UV_FORK_STRATEGY</code> environment variable.</p><p>Possible values:</p>
|
<p>May also be set with the <code>UV_FORK_STRATEGY</code> environment variable.</p><p>Possible values:</p>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue