mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-06 08:40: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")]
|
||||
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.
|
||||
///
|
||||
/// 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 {
|
||||
LockMode::Locked(target.interpreter())
|
||||
} else {
|
||||
LockMode::Write(target.interpreter())
|
||||
LockMode::Write(target.interpreter(), false)
|
||||
},
|
||||
&settings.resolver,
|
||||
client_builder,
|
||||
|
@ -1102,7 +1102,7 @@ async fn lock_and_sync(
|
|||
if locked {
|
||||
LockMode::Locked(target.interpreter())
|
||||
} else {
|
||||
LockMode::Write(target.interpreter())
|
||||
LockMode::Write(target.interpreter(), false)
|
||||
},
|
||||
&settings.resolver,
|
||||
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.
|
||||
LockMode::DryRun(interpreter.as_ref().unwrap())
|
||||
} else {
|
||||
LockMode::Write(interpreter.as_ref().unwrap())
|
||||
LockMode::Write(interpreter.as_ref().unwrap(), false)
|
||||
};
|
||||
|
||||
// Initialize any shared state.
|
||||
|
|
|
@ -85,6 +85,7 @@ pub(crate) async fn lock(
|
|||
frozen: bool,
|
||||
dry_run: DryRun,
|
||||
refresh: Refresh,
|
||||
force: bool,
|
||||
python: Option<String>,
|
||||
install_mirrors: PythonInstallMirrors,
|
||||
settings: ResolverSettings,
|
||||
|
@ -182,7 +183,7 @@ pub(crate) async fn lock(
|
|||
} else if dry_run.enabled() {
|
||||
LockMode::DryRun(&interpreter)
|
||||
} else {
|
||||
LockMode::Write(&interpreter)
|
||||
LockMode::Write(&interpreter, force)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -253,7 +254,7 @@ pub(crate) async fn lock(
|
|||
#[derive(Debug, Clone, Copy)]
|
||||
pub(super) enum LockMode<'env> {
|
||||
/// Write the lockfile to disk.
|
||||
Write(&'env Interpreter),
|
||||
Write(&'env Interpreter, bool),
|
||||
/// Perform a resolution, but don't write the lockfile to disk.
|
||||
DryRun(&'env Interpreter),
|
||||
/// 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.printer,
|
||||
self.preview,
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
@ -372,7 +374,7 @@ impl<'env> LockOperation<'env> {
|
|||
|
||||
Ok(result)
|
||||
}
|
||||
LockMode::Write(interpreter) | LockMode::DryRun(interpreter) => {
|
||||
LockMode::Write(interpreter, force) => {
|
||||
// Read the existing lockfile.
|
||||
let existing = match target.read().await {
|
||||
Ok(Some(existing)) => Some(existing),
|
||||
|
@ -402,16 +404,50 @@ impl<'env> LockOperation<'env> {
|
|||
self.workspace_cache,
|
||||
self.printer,
|
||||
self.preview,
|
||||
force,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// If the lockfile changed, write it to disk.
|
||||
if !matches!(self.mode, LockMode::DryRun(_)) {
|
||||
if let LockResult::Changed(_, lock) = &result {
|
||||
target.commit(lock).await?;
|
||||
}
|
||||
if let LockResult::Changed(_, lock) = &result {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -434,6 +470,7 @@ async fn do_lock(
|
|||
workspace_cache: &WorkspaceCache,
|
||||
printer: Printer,
|
||||
preview: Preview,
|
||||
force: bool,
|
||||
) -> Result<LockResult, ProjectError> {
|
||||
let start = std::time::Instant::now();
|
||||
|
||||
|
@ -767,6 +804,7 @@ async fn do_lock(
|
|||
state.index(),
|
||||
&database,
|
||||
printer,
|
||||
force,
|
||||
)
|
||||
.await
|
||||
{
|
||||
|
@ -986,11 +1024,16 @@ impl ValidatedLock {
|
|||
index: &InMemoryIndex,
|
||||
database: &DistributionDatabase<'_, Context>,
|
||||
printer: Printer,
|
||||
force: bool,
|
||||
) -> Result<Self, ProjectError> {
|
||||
// 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
|
||||
// returns `Self::Versions`, followed by every check that returns `Self::Preferable`, and
|
||||
// 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 {
|
||||
let _ = writeln!(
|
||||
printer.stderr(),
|
||||
|
|
|
@ -294,7 +294,7 @@ pub(crate) async fn remove(
|
|||
let mode = if locked {
|
||||
LockMode::Locked(target.interpreter())
|
||||
} else {
|
||||
LockMode::Write(target.interpreter())
|
||||
LockMode::Write(target.interpreter(), false)
|
||||
};
|
||||
|
||||
// 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 {
|
||||
LockMode::Locked(environment.interpreter())
|
||||
} else {
|
||||
LockMode::Write(environment.interpreter())
|
||||
LockMode::Write(environment.interpreter(), false)
|
||||
};
|
||||
|
||||
// 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 {
|
||||
LockMode::DryRun(venv.interpreter())
|
||||
} else {
|
||||
LockMode::Write(venv.interpreter())
|
||||
LockMode::Write(venv.interpreter(), false)
|
||||
};
|
||||
|
||||
let result = match project::lock::LockOperation::new(
|
||||
|
|
|
@ -309,7 +309,7 @@ pub(crate) async fn sync(
|
|||
} else if dry_run.enabled() {
|
||||
LockMode::DryRun(environment.interpreter())
|
||||
} else {
|
||||
LockMode::Write(environment.interpreter())
|
||||
LockMode::Write(environment.interpreter(), false)
|
||||
};
|
||||
|
||||
let lock_target = match &target {
|
||||
|
@ -1272,7 +1272,7 @@ impl From<(&LockTarget<'_>, &LockMode<'_>, &Outcome)> for LockReport {
|
|||
LockResult::Unchanged(..) => match mode {
|
||||
// When `--frozen` is used, we don't check the lockfile
|
||||
LockMode::Frozen => LockAction::Use,
|
||||
LockMode::DryRun(_) | LockMode::Locked(_) | LockMode::Write(_) => {
|
||||
LockMode::DryRun(_) | LockMode::Locked(_) | LockMode::Write(..) => {
|
||||
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.
|
||||
LockMode::DryRun(interpreter.as_ref().unwrap())
|
||||
} else {
|
||||
LockMode::Write(interpreter.as_ref().unwrap())
|
||||
LockMode::Write(interpreter.as_ref().unwrap(), false)
|
||||
};
|
||||
|
||||
// Initialize any shared state.
|
||||
|
|
|
@ -582,7 +582,7 @@ async fn lock_and_sync(
|
|||
let mode = if locked {
|
||||
LockMode::Locked(target.interpreter())
|
||||
} else {
|
||||
LockMode::Write(target.interpreter())
|
||||
LockMode::Write(target.interpreter(), false)
|
||||
};
|
||||
|
||||
// Initialize any shared state.
|
||||
|
|
|
@ -1940,6 +1940,7 @@ async fn run_project(
|
|||
args.frozen,
|
||||
args.dry_run,
|
||||
args.refresh,
|
||||
args.force,
|
||||
args.python,
|
||||
args.install_mirrors,
|
||||
args.settings,
|
||||
|
|
|
@ -1381,6 +1381,7 @@ pub(crate) struct LockSettings {
|
|||
pub(crate) locked: bool,
|
||||
pub(crate) frozen: bool,
|
||||
pub(crate) dry_run: DryRun,
|
||||
pub(crate) force: bool,
|
||||
pub(crate) script: Option<PathBuf>,
|
||||
pub(crate) python: Option<String>,
|
||||
pub(crate) install_mirrors: PythonInstallMirrors,
|
||||
|
@ -1400,6 +1401,7 @@ impl LockSettings {
|
|||
check,
|
||||
check_exists,
|
||||
dry_run,
|
||||
force,
|
||||
script,
|
||||
resolver,
|
||||
build,
|
||||
|
@ -1416,6 +1418,7 @@ impl LockSettings {
|
|||
locked: check,
|
||||
frozen: check_exists,
|
||||
dry_run: DryRun::from_args(dry_run),
|
||||
force,
|
||||
script,
|
||||
python: python.and_then(Maybe::into_option),
|
||||
refresh: Refresh::from(refresh),
|
||||
|
|
|
@ -9501,6 +9501,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
|
|||
locked: false,
|
||||
frozen: false,
|
||||
dry_run: Disabled,
|
||||
force: false,
|
||||
script: None,
|
||||
python: None,
|
||||
install_mirrors: PythonInstallMirrors {
|
||||
|
@ -9618,6 +9619,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
|
|||
locked: false,
|
||||
frozen: false,
|
||||
dry_run: Disabled,
|
||||
force: false,
|
||||
script: None,
|
||||
python: None,
|
||||
install_mirrors: PythonInstallMirrors {
|
||||
|
@ -9758,6 +9760,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
|
|||
locked: false,
|
||||
frozen: false,
|
||||
dry_run: Disabled,
|
||||
force: false,
|
||||
script: None,
|
||||
python: None,
|
||||
install_mirrors: PythonInstallMirrors {
|
||||
|
@ -9873,6 +9876,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
|
|||
locked: false,
|
||||
frozen: false,
|
||||
dry_run: Disabled,
|
||||
force: false,
|
||||
script: None,
|
||||
python: None,
|
||||
install_mirrors: PythonInstallMirrors {
|
||||
|
@ -9978,6 +9982,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
|
|||
locked: false,
|
||||
frozen: false,
|
||||
dry_run: Disabled,
|
||||
force: false,
|
||||
script: None,
|
||||
python: None,
|
||||
install_mirrors: PythonInstallMirrors {
|
||||
|
@ -10084,6 +10089,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
|
|||
locked: false,
|
||||
frozen: false,
|
||||
dry_run: Disabled,
|
||||
force: false,
|
||||
script: None,
|
||||
python: None,
|
||||
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>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>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>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>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue