mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-22 08:12:44 +00:00
Add uv run --no-sync
(#7192)
## Summary When `--no-sync` is provided, we won't lock or sync, but we will run the command in the project environment. Closes https://github.com/astral-sh/uv/issues/7165.
This commit is contained in:
parent
4b7fed84eb
commit
3f011f3b7b
7 changed files with 142 additions and 56 deletions
|
@ -2434,6 +2434,13 @@ pub struct RunArgs {
|
|||
#[arg(long)]
|
||||
pub isolated: bool,
|
||||
|
||||
/// Avoid syncing the virtual environment.
|
||||
///
|
||||
/// Implies `--frozen`, as the project dependencies will be ignored (i.e., the lockfile will not
|
||||
/// be updated, since the environment will not be synced regardless).
|
||||
#[arg(long, conflicts_with = "frozen")]
|
||||
pub no_sync: bool,
|
||||
|
||||
/// Assert that the `uv.lock` will remain unchanged.
|
||||
///
|
||||
/// Requires that the lockfile is up-to-date. If the lockfile is missing or
|
||||
|
@ -2735,7 +2742,7 @@ pub struct AddArgs {
|
|||
#[arg(long)]
|
||||
pub extra: Option<Vec<ExtraName>>,
|
||||
|
||||
/// Avoid syncing the virtual environment after re-locking the project.
|
||||
/// Avoid syncing the virtual environment.
|
||||
#[arg(long, conflicts_with = "frozen")]
|
||||
pub no_sync: bool,
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ pub(crate) async fn run(
|
|||
show_resolution: bool,
|
||||
locked: bool,
|
||||
frozen: bool,
|
||||
no_sync: bool,
|
||||
isolated: bool,
|
||||
package: Option<PackageName>,
|
||||
no_project: bool,
|
||||
|
@ -258,6 +259,11 @@ pub(crate) async fn run(
|
|||
"`--frozen` is a no-op for Python scripts with inline metadata, which always run in isolation"
|
||||
);
|
||||
}
|
||||
if no_sync {
|
||||
warn_user!(
|
||||
"`--no-sync` is a no-op for Python scripts with inline metadata, which always run in isolation"
|
||||
);
|
||||
}
|
||||
if isolated {
|
||||
warn_user!(
|
||||
"`--isolated` is a no-op for Python scripts with inline metadata, which always run in isolation"
|
||||
|
@ -318,6 +324,9 @@ pub(crate) async fn run(
|
|||
if frozen {
|
||||
warn_user!("`--frozen` has no effect when used alongside `--no-project`");
|
||||
}
|
||||
if no_sync {
|
||||
warn_user!("`--no-sync` has no effect when used alongside `--no-project`");
|
||||
}
|
||||
} else if project.is_none() {
|
||||
// If we can't find a project and the user provided a project-only setting, warn.
|
||||
if !extras.is_empty() {
|
||||
|
@ -329,8 +338,8 @@ pub(crate) async fn run(
|
|||
if locked {
|
||||
warn_user!("`--locked` has no effect when used outside of a project");
|
||||
}
|
||||
if frozen {
|
||||
warn_user!("`--frozen` has no effect when used outside of a project");
|
||||
if no_sync {
|
||||
warn_user!("`--no-sync` has no effect when used outside of a project");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -414,60 +423,64 @@ pub(crate) async fn run(
|
|||
.await?
|
||||
};
|
||||
|
||||
let result = match project::lock::do_safe_lock(
|
||||
locked,
|
||||
frozen,
|
||||
project.workspace(),
|
||||
venv.interpreter(),
|
||||
settings.as_ref().into(),
|
||||
if show_resolution {
|
||||
Box::new(DefaultResolveLogger)
|
||||
} else {
|
||||
Box::new(SummaryResolveLogger)
|
||||
},
|
||||
connectivity,
|
||||
concurrency,
|
||||
native_tls,
|
||||
cache,
|
||||
printer,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(result) => result,
|
||||
Err(ProjectError::Operation(operations::Error::Resolve(
|
||||
uv_resolver::ResolveError::NoSolution(err),
|
||||
))) => {
|
||||
let report = miette::Report::msg(format!("{err}")).context(err.header());
|
||||
eprint!("{report:?}");
|
||||
return Ok(ExitStatus::Failure);
|
||||
}
|
||||
Err(err) => return Err(err.into()),
|
||||
};
|
||||
if no_sync {
|
||||
debug!("Skipping environment synchronization due to `--no-sync`");
|
||||
} else {
|
||||
let result = match project::lock::do_safe_lock(
|
||||
locked,
|
||||
frozen,
|
||||
project.workspace(),
|
||||
venv.interpreter(),
|
||||
settings.as_ref().into(),
|
||||
if show_resolution {
|
||||
Box::new(DefaultResolveLogger)
|
||||
} else {
|
||||
Box::new(SummaryResolveLogger)
|
||||
},
|
||||
connectivity,
|
||||
concurrency,
|
||||
native_tls,
|
||||
cache,
|
||||
printer,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(result) => result,
|
||||
Err(ProjectError::Operation(operations::Error::Resolve(
|
||||
uv_resolver::ResolveError::NoSolution(err),
|
||||
))) => {
|
||||
let report = miette::Report::msg(format!("{err}")).context(err.header());
|
||||
eprint!("{report:?}");
|
||||
return Ok(ExitStatus::Failure);
|
||||
}
|
||||
Err(err) => return Err(err.into()),
|
||||
};
|
||||
|
||||
let install_options = InstallOptions::default();
|
||||
let install_options = InstallOptions::default();
|
||||
|
||||
project::sync::do_sync(
|
||||
InstallTarget::from(&project),
|
||||
&venv,
|
||||
result.lock(),
|
||||
&extras,
|
||||
dev,
|
||||
install_options,
|
||||
Modifications::Sufficient,
|
||||
settings.as_ref().into(),
|
||||
&state,
|
||||
if show_resolution {
|
||||
Box::new(DefaultInstallLogger)
|
||||
} else {
|
||||
Box::new(SummaryInstallLogger)
|
||||
},
|
||||
connectivity,
|
||||
concurrency,
|
||||
native_tls,
|
||||
cache,
|
||||
printer,
|
||||
)
|
||||
.await?;
|
||||
project::sync::do_sync(
|
||||
InstallTarget::from(&project),
|
||||
&venv,
|
||||
result.lock(),
|
||||
&extras,
|
||||
dev,
|
||||
install_options,
|
||||
Modifications::Sufficient,
|
||||
settings.as_ref().into(),
|
||||
&state,
|
||||
if show_resolution {
|
||||
Box::new(DefaultInstallLogger)
|
||||
} else {
|
||||
Box::new(SummaryInstallLogger)
|
||||
},
|
||||
connectivity,
|
||||
concurrency,
|
||||
native_tls,
|
||||
cache,
|
||||
printer,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
venv.into_interpreter()
|
||||
} else {
|
||||
|
|
|
@ -1123,6 +1123,7 @@ async fn run_project(
|
|||
args.show_resolution || globals.verbose > 0,
|
||||
args.locked,
|
||||
args.frozen,
|
||||
args.no_sync,
|
||||
args.isolated,
|
||||
args.package,
|
||||
args.no_project,
|
||||
|
|
|
@ -217,6 +217,7 @@ pub(crate) struct RunSettings {
|
|||
pub(crate) show_resolution: bool,
|
||||
pub(crate) package: Option<PackageName>,
|
||||
pub(crate) no_project: bool,
|
||||
pub(crate) no_sync: bool,
|
||||
pub(crate) python: Option<String>,
|
||||
pub(crate) refresh: Refresh,
|
||||
pub(crate) settings: ResolverInstallerSettings,
|
||||
|
@ -237,6 +238,7 @@ impl RunSettings {
|
|||
with_editable,
|
||||
with_requirements,
|
||||
isolated,
|
||||
no_sync,
|
||||
locked,
|
||||
frozen,
|
||||
installer,
|
||||
|
@ -266,6 +268,7 @@ impl RunSettings {
|
|||
show_resolution,
|
||||
package,
|
||||
no_project,
|
||||
no_sync,
|
||||
python,
|
||||
refresh: Refresh::from(refresh),
|
||||
settings: ResolverInstallerSettings::combine(
|
||||
|
|
|
@ -976,6 +976,62 @@ fn run_frozen() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_no_sync() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["anyio==3.7.0"]
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools>=42"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
"#,
|
||||
)?;
|
||||
|
||||
// Running with `--no-sync` should succeed error, even if the lockfile isn't present.
|
||||
uv_snapshot!(context.filters(), context.run().arg("--no-sync").arg("--").arg("python").arg("--version"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
Python 3.12.[X]
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
|
||||
context.lock().assert().success();
|
||||
|
||||
// Running with `--no-sync` should not install any requirements.
|
||||
uv_snapshot!(context.filters(), context.run().arg("--no-sync").arg("--").arg("python").arg("--version"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
Python 3.12.[X]
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
|
||||
context.sync().assert().success();
|
||||
|
||||
// But it should have access to the installed packages.
|
||||
uv_snapshot!(context.filters(), context.run().arg("--no-sync").arg("--").arg("python").arg("-c").arg("import anyio; print(anyio.__name__)"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
anyio
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_empty_requirements_txt() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue