5f1f207628
Previously, when installing a package we would delete the target directory before copying (or linking) the contents of the package. However, this means that we do not properly support namespace packages which can share a target directory. Instead the last package to be installed would be override existing packages. Since we install packages in parallel, this could result in a race condition where the target directory already exists which is not allowed when using `clonefile`. See example error in #515. https://github.com/astral-sh/puffin/pull/516/commits/c7e63d2dcebab6aa37427c58a9db7603db546a4f provides a regression test for this — it fails on `main`. Here, we implement a recursive merge when the target directory already exists. Both packages will be installed into the same directory. We no longer delete the target directory, which seems okay since we uninstall packages before installing now. When files conflict, we will likely throw an error still. The correct behavior to implement in this case is unclear, as if we just take "first write wins" or "last write wins" we could end up with some files from one package and some from another resulting in two broken packages. A possible solution here is to lock the target directories while copying.
828 lines
26 KiB
Rust
828 lines
26 KiB
Rust
#![cfg(all(feature = "python", feature = "pypi"))]
|
|
|
|
use std::path::Path;
|
|
use std::process::Command;
|
|
|
|
use anyhow::{Context, Result};
|
|
use assert_cmd::prelude::*;
|
|
use assert_fs::prelude::*;
|
|
use insta_cmd::_macro_support::insta;
|
|
use insta_cmd::{assert_cmd_snapshot, get_cargo_bin};
|
|
|
|
use common::{create_venv_py312, BIN_NAME, INSTA_FILTERS};
|
|
|
|
mod common;
|
|
|
|
fn check_command(venv: &Path, command: &str, temp_dir: &Path) {
|
|
Command::new(venv.join("bin").join("python"))
|
|
.arg("-c")
|
|
.arg(command)
|
|
.current_dir(temp_dir)
|
|
.assert()
|
|
.success();
|
|
}
|
|
|
|
#[test]
|
|
fn missing_requirements_txt() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.current_dir(&temp_dir));
|
|
|
|
requirements_txt.assert(predicates::path::missing());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn missing_venv() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv = temp_dir.child(".venv");
|
|
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
|
|
venv.assert(predicates::path::missing());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Install a package into a virtual environment using the default link semantics. (On macOS,
|
|
/// this using `clone` semantics.)
|
|
#[test]
|
|
fn install() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv = create_venv_py312(&temp_dir, &cache_dir);
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("MarkupSafe==2.1.3")?;
|
|
|
|
insta::with_settings!({
|
|
filters => INSTA_FILTERS.to_vec()
|
|
}, {
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
});
|
|
|
|
check_command(&venv, "import markupsafe", &temp_dir);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Install a package into a virtual environment using copy semantics.
|
|
#[test]
|
|
fn install_copy() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv = create_venv_py312(&temp_dir, &cache_dir);
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("MarkupSafe==2.1.3")?;
|
|
|
|
insta::with_settings!({
|
|
filters => INSTA_FILTERS.to_vec()
|
|
}, {
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--link-mode")
|
|
.arg("copy")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
});
|
|
|
|
check_command(&venv, "import markupsafe", &temp_dir);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Install a package into a virtual environment using hardlink semantics.
|
|
#[test]
|
|
fn install_hardlink() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv = create_venv_py312(&temp_dir, &cache_dir);
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("MarkupSafe==2.1.3")?;
|
|
|
|
insta::with_settings!({
|
|
filters => INSTA_FILTERS.to_vec()
|
|
}, {
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--link-mode")
|
|
.arg("hardlink")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
});
|
|
|
|
check_command(&venv, "import markupsafe", &temp_dir);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Install multiple packages into a virtual environment.
|
|
#[test]
|
|
fn install_many() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv = create_venv_py312(&temp_dir, &cache_dir);
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("MarkupSafe==2.1.3\ntomli==2.0.1")?;
|
|
|
|
insta::with_settings!({
|
|
filters => INSTA_FILTERS.to_vec()
|
|
}, {
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
});
|
|
|
|
check_command(&venv, "import markupsafe; import tomli", &cache_dir);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Attempt to install an already-installed package into a virtual environment.
|
|
#[test]
|
|
fn noop() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv = create_venv_py312(&temp_dir, &cache_dir);
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("MarkupSafe==2.1.3")?;
|
|
|
|
Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir)
|
|
.assert()
|
|
.success();
|
|
|
|
insta::with_settings!({
|
|
filters => INSTA_FILTERS.to_vec()
|
|
}, {
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
});
|
|
|
|
check_command(&venv, "import markupsafe", &temp_dir);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Install a package into a virtual environment, then install the same package into a different
|
|
/// virtual environment.
|
|
#[test]
|
|
fn link() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv1 = create_venv_py312(&temp_dir, &cache_dir);
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("MarkupSafe==2.1.3")?;
|
|
|
|
Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv1.as_os_str())
|
|
.current_dir(&temp_dir)
|
|
.assert()
|
|
.success();
|
|
|
|
let venv2 = temp_dir.child(".venv2");
|
|
Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("venv")
|
|
.arg(venv2.as_os_str())
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.arg("--python")
|
|
.arg("python3.12")
|
|
.current_dir(&temp_dir)
|
|
.assert()
|
|
.success();
|
|
venv2.assert(predicates::path::is_dir());
|
|
|
|
insta::with_settings!({
|
|
filters => INSTA_FILTERS.to_vec()
|
|
}, {
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv2.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
});
|
|
|
|
check_command(&venv2, "import markupsafe", &temp_dir);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Install a package into a virtual environment, then sync the virtual environment with a
|
|
/// different requirements file.
|
|
#[test]
|
|
fn add_remove() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv = create_venv_py312(&temp_dir, &cache_dir);
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("MarkupSafe==2.1.3")?;
|
|
|
|
Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir)
|
|
.assert()
|
|
.success();
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("tomli==2.0.1")?;
|
|
|
|
insta::with_settings!({
|
|
filters => INSTA_FILTERS.to_vec()
|
|
}, {
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
});
|
|
|
|
check_command(&venv, "import tomli", &temp_dir);
|
|
|
|
Command::new(venv.join("bin").join("python"))
|
|
.arg("-c")
|
|
.arg("import markupsafe")
|
|
.current_dir(&temp_dir)
|
|
.assert()
|
|
.failure();
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Install a package into a virtual environment, then install a second package into the same
|
|
/// virtual environment.
|
|
#[test]
|
|
fn install_sequential() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv = create_venv_py312(&temp_dir, &cache_dir);
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("MarkupSafe==2.1.3")?;
|
|
|
|
Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir)
|
|
.assert()
|
|
.success();
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("MarkupSafe==2.1.3\ntomli==2.0.1")?;
|
|
|
|
insta::with_settings!({
|
|
filters => INSTA_FILTERS.to_vec()
|
|
}, {
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
});
|
|
|
|
check_command(&venv, "import markupsafe; import tomli", &cache_dir);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Install a package into a virtual environment, then install a second package into the same
|
|
/// virtual environment.
|
|
#[test]
|
|
fn upgrade() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv = create_venv_py312(&temp_dir, &cache_dir);
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("tomli==2.0.0")?;
|
|
|
|
Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir)
|
|
.assert()
|
|
.success();
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("tomli==2.0.1")?;
|
|
|
|
insta::with_settings!({
|
|
filters => INSTA_FILTERS.to_vec()
|
|
}, {
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
});
|
|
|
|
check_command(&venv, "import tomli", &temp_dir);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Install a package into a virtual environment from a URL.
|
|
#[test]
|
|
fn install_url() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv = create_venv_py312(&temp_dir, &cache_dir);
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("werkzeug @ https://files.pythonhosted.org/packages/ff/1d/960bb4017c68674a1cb099534840f18d3def3ce44aed12b5ed8b78e0153e/Werkzeug-2.0.0-py3-none-any.whl")?;
|
|
|
|
insta::with_settings!({
|
|
filters => vec![
|
|
(r"(\d|\.)+(ms|s)", "[TIME]"),
|
|
]
|
|
}, {
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
});
|
|
|
|
check_command(&venv, "import werkzeug", &temp_dir);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Install a package into a virtual environment from a Git repository.
|
|
#[test]
|
|
#[cfg(feature = "git")]
|
|
fn install_git_commit() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv = create_venv_py312(&temp_dir, &cache_dir);
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("werkzeug @ git+https://github.com/pallets/werkzeug.git@af160e0b6b7ddd81c22f1652c728ff5ac72d5c74")?;
|
|
|
|
insta::with_settings!({
|
|
filters => vec![
|
|
(r"(\d|\.)+(ms|s)", "[TIME]"),
|
|
]
|
|
}, {
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
});
|
|
|
|
check_command(&venv, "import werkzeug", &temp_dir);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Install a package into a virtual environment from a Git repository.
|
|
#[test]
|
|
#[cfg(feature = "git")]
|
|
fn install_git_tag() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv = create_venv_py312(&temp_dir, &cache_dir);
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("werkzeug @ git+https://github.com/pallets/werkzeug.git@2.0.0")?;
|
|
|
|
insta::with_settings!({
|
|
filters => vec![
|
|
(r"(\d|\.)+(ms|s)", "[TIME]"),
|
|
]
|
|
}, {
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
});
|
|
|
|
check_command(&venv, "import werkzeug", &temp_dir);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Install two packages from the same Git repository.
|
|
#[test]
|
|
#[cfg(feature = "git")]
|
|
fn install_git_subdirectories() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv = create_venv_py312(&temp_dir, &cache_dir);
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("example-pkg-a @ git+https://github.com/pypa/sample-namespace-packages.git@df7530eeb8fa0cb7dbb8ecb28363e8e36bfa2f45#subdirectory=pkg_resources/pkg_a\nexample-pkg-b @ git+https://github.com/pypa/sample-namespace-packages.git@df7530eeb8fa0cb7dbb8ecb28363e8e36bfa2f45#subdirectory=pkg_resources/pkg_b")?;
|
|
|
|
insta::with_settings!({
|
|
filters => vec![
|
|
(r"(\d|\.)+(ms|s)", "[TIME]"),
|
|
]
|
|
}, {
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
});
|
|
|
|
check_command(&venv, "import example_pkg", &temp_dir);
|
|
check_command(&venv, "import example_pkg.a", &temp_dir);
|
|
check_command(&venv, "import example_pkg.b", &temp_dir);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Install a source distribution into a virtual environment.
|
|
#[test]
|
|
fn install_sdist() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv = create_venv_py312(&temp_dir, &cache_dir);
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("Werkzeug==0.9.6")?;
|
|
|
|
insta::with_settings!({
|
|
filters => vec![
|
|
(r"(\d|\.)+(ms|s)", "[TIME]"),
|
|
]
|
|
}, {
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
});
|
|
|
|
check_command(&venv, "import werkzeug", &temp_dir);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Attempt to re-install a package into a virtual environment from a URL. The second install
|
|
/// should be a no-op.
|
|
#[test]
|
|
fn install_url_then_install_url() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv = create_venv_py312(&temp_dir, &cache_dir);
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("werkzeug @ https://files.pythonhosted.org/packages/ff/1d/960bb4017c68674a1cb099534840f18d3def3ce44aed12b5ed8b78e0153e/Werkzeug-2.0.0-py3-none-any.whl")?;
|
|
|
|
Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir)
|
|
.assert()
|
|
.success();
|
|
|
|
insta::with_settings!({
|
|
filters => vec![
|
|
(r"(\d|\.)+(ms|s)", "[TIME]"),
|
|
]
|
|
}, {
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
});
|
|
|
|
check_command(&venv, "import werkzeug", &temp_dir);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Install a package via a URL, then via a registry version. The second install _should_ remove the
|
|
/// URL-based version, but doesn't right now.
|
|
#[test]
|
|
fn install_url_then_install_version() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv = create_venv_py312(&temp_dir, &cache_dir);
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("werkzeug @ https://files.pythonhosted.org/packages/ff/1d/960bb4017c68674a1cb099534840f18d3def3ce44aed12b5ed8b78e0153e/Werkzeug-2.0.0-py3-none-any.whl")?;
|
|
|
|
Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir)
|
|
.assert()
|
|
.success();
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("werkzeug==2.0.0")?;
|
|
|
|
insta::with_settings!({
|
|
filters => vec![
|
|
(r"(\d|\.)+(ms|s)", "[TIME]"),
|
|
]
|
|
}, {
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
});
|
|
|
|
check_command(&venv, "import werkzeug", &temp_dir);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Install a package via a registry version, then via a direct URL version. The second install
|
|
/// should remove the registry-based version.
|
|
#[test]
|
|
fn install_version_then_install_url() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv = create_venv_py312(&temp_dir, &cache_dir);
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("werkzeug==2.0.0")?;
|
|
|
|
Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir)
|
|
.assert()
|
|
.success();
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("werkzeug @ https://files.pythonhosted.org/packages/ff/1d/960bb4017c68674a1cb099534840f18d3def3ce44aed12b5ed8b78e0153e/Werkzeug-2.0.0-py3-none-any.whl")?;
|
|
|
|
insta::with_settings!({
|
|
filters => vec![
|
|
(r"(\d|\.)+(ms|s)", "[TIME]"),
|
|
]
|
|
}, {
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
});
|
|
|
|
check_command(&venv, "import werkzeug", &temp_dir);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Test that we select the last 3.8 compatible numpy version instead of trying to compile an
|
|
/// incompatible sdist <https://github.com/astral-sh/puffin/issues/388>
|
|
#[test]
|
|
fn install_numpy_py38() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv = temp_dir.child(".venv");
|
|
|
|
Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("venv")
|
|
.arg(venv.as_os_str())
|
|
.arg("--python")
|
|
// TODO(konstin): Mock the venv in the installer test so we don't need this anymore
|
|
.arg(which::which("python3.8").context("python3.8 must be installed")?)
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.current_dir(&temp_dir)
|
|
.assert()
|
|
.success();
|
|
venv.assert(predicates::path::is_dir());
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.touch()?;
|
|
requirements_txt.write_str("numpy")?;
|
|
|
|
insta::with_settings!({
|
|
filters => INSTA_FILTERS.to_vec()
|
|
}, {
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
});
|
|
|
|
check_command(&venv, "import numpy", &temp_dir);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn warn_on_yanked_version() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv = create_venv_py312(&temp_dir, &cache_dir);
|
|
|
|
let requirements_in = temp_dir.child("requirements.txt");
|
|
requirements_in.touch()?;
|
|
// This version is yanked
|
|
requirements_in.write_str("ipython==8.13.0")?;
|
|
|
|
insta::with_settings!({
|
|
filters => INSTA_FILTERS.to_vec()
|
|
}, {
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
});
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Resolve a local wheel.
|
|
#[test]
|
|
fn install_local_wheel() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv = create_venv_py312(&temp_dir, &cache_dir);
|
|
|
|
// Download a wheel.
|
|
let response = reqwest::blocking::get("https://files.pythonhosted.org/packages/36/42/015c23096649b908c809c69388a805a571a3bea44362fe87e33fc3afa01f/flask-3.0.0-py3-none-any.whl")?;
|
|
let flask_wheel = temp_dir.child("flask-3.0.0-py3-none-any.whl");
|
|
let mut flask_wheel_file = std::fs::File::create(&flask_wheel)?;
|
|
std::io::copy(&mut response.bytes()?.as_ref(), &mut flask_wheel_file)?;
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.write_str(&format!("flask @ file://{}", flask_wheel.path().display()))?;
|
|
|
|
// In addition to the standard filters, remove the temporary directory from the snapshot.
|
|
let mut filters = INSTA_FILTERS.to_vec();
|
|
filters.push((r"file://.*/", "file://[TEMP_DIR]/"));
|
|
|
|
insta::with_settings!({
|
|
filters => filters
|
|
}, {
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
});
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Install a local source distribution.
|
|
#[test]
|
|
fn install_local_source_distribution() -> Result<()> {
|
|
let temp_dir = assert_fs::TempDir::new()?;
|
|
let cache_dir = assert_fs::TempDir::new()?;
|
|
let venv = create_venv_py312(&temp_dir, &cache_dir);
|
|
|
|
// Download a source distribution.
|
|
let response = reqwest::blocking::get("https://files.pythonhosted.org/packages/d8/09/c1a7354d3925a3c6c8cfdebf4245bae67d633ffda1ba415add06ffc839c5/flask-3.0.0.tar.gz")?;
|
|
let flask_wheel = temp_dir.child("flask-3.0.0.tar.gz");
|
|
let mut flask_wheel_file = std::fs::File::create(&flask_wheel)?;
|
|
std::io::copy(&mut response.bytes()?.as_ref(), &mut flask_wheel_file)?;
|
|
|
|
let requirements_txt = temp_dir.child("requirements.txt");
|
|
requirements_txt.write_str(&format!("flask @ file://{}", flask_wheel.path().display()))?;
|
|
|
|
// In addition to the standard filters, remove the temporary directory from the snapshot.
|
|
let mut filters = INSTA_FILTERS.to_vec();
|
|
filters.push((r"file://.*/", "file://[TEMP_DIR]/"));
|
|
|
|
insta::with_settings!({
|
|
filters => filters
|
|
}, {
|
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
|
.arg("pip-sync")
|
|
.arg("requirements.txt")
|
|
.arg("--cache-dir")
|
|
.arg(cache_dir.path())
|
|
.env("VIRTUAL_ENV", venv.as_os_str())
|
|
.current_dir(&temp_dir));
|
|
});
|
|
|
|
Ok(())
|
|
}
|