Skip to content

Commit 24d28b7

Browse files
adamentamamiya-lenpavelzw
authored
feat: Support scheme 'file' to process local conda files (#166)
Co-authored-by: amamiya-len <yuanhang.zhao@timeplus.io> Co-authored-by: Pavel Zwerschke <pavelzw@gmail.com>
1 parent cd407b5 commit 24d28b7

File tree

10 files changed

+2315
-13
lines changed

10 files changed

+2315
-13
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ $RECYCLE.BIN/
116116
# pixi-pack
117117
activate.*
118118
cache/
119-
channel/
120119
env/
121120
environment.yml
122121
environment

.typos.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
[default.extend-words]
22
intoto = "intoto"
3+
4+
[files]
5+
extend-exclude = ["pixi.lock.template"]

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "pixi-pack"
33
description = "A command line tool to pack and unpack conda environments for easy sharing"
4-
version = "0.6.4"
4+
version = "0.6.5"
55
edition = "2024"
66

77
# See https://doc.rust-lang.org/cargo/reference/profiles.html
Binary file not shown.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"info": {
3+
"subdir": "noarch"
4+
},
5+
"packages": {},
6+
"packages.conda": {
7+
"my-webserver-0.1.0-pyh4616a5c_0.conda": {
8+
"build": "pyh4616a5c_0",
9+
"build_number": 0,
10+
"constrains": ["pydantic >=2,<3"],
11+
"depends": ["python >=3.12", "fastapi", "python"],
12+
"md5": "243def6b96cf556936d075033a2f1ae4",
13+
"name": "my-webserver",
14+
"noarch": "python",
15+
"sha256": "8bc75a2f9baab61004b02b022bb0c6a08fcc57dee5d521a5a61640f861f69da9",
16+
"size": 6581,
17+
"subdir": "noarch",
18+
"timestamp": 1729264746409,
19+
"version": "0.1.0"
20+
}
21+
},
22+
"removed": [],
23+
"repodata_version": 1
24+
}

examples/local-channel/pixi.lock.template

Lines changed: 2206 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[project]
2+
channels = ["<local-channel-url>", "conda-forge"]
3+
name = "no-timestamp"
4+
platforms = ["linux-64", "linux-aarch64", "win-64", "osx-64", "osx-arm64"]
5+
6+
[dependencies]
7+
my-webserver = "*"

src/pack.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -395,17 +395,25 @@ async fn download_package(
395395
}
396396
}
397397

398-
let mut dest = File::create(&output_path).await?;
399-
400-
tracing::debug!("Fetching package {}", package.location);
401-
let url = match &package.location {
402-
UrlOrPath::Url(url) => url,
403-
UrlOrPath::Path(path) => anyhow::bail!("Path not supported: {}", path),
404-
};
398+
let url = package.location.try_into_url()?;
399+
match url.scheme() {
400+
"file" => {
401+
let local_path = url
402+
.to_file_path()
403+
.map_err(|_| anyhow!("could not convert url: {} to file path", url))?;
404+
tracing::debug!("Copying from path: {}", local_path.display());
405+
// Copy file
406+
fs::copy(local_path, &output_path).await?;
407+
}
408+
_ => {
409+
let mut dest = File::create(&output_path).await?;
405410

406-
let mut response = client.get(url.clone()).send().await?.error_for_status()?;
407-
while let Some(chunk) = response.chunk().await? {
408-
dest.write_all(&chunk).await?;
411+
tracing::debug!("Fetching package {}", package.location);
412+
let mut response = client.get(url.clone()).send().await?.error_for_status()?;
413+
while let Some(chunk) = response.chunk().await? {
414+
dest.write_all(&chunk).await?;
415+
}
416+
}
409417
}
410418

411419
// Save to cache if enabled

tests/integration_test.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,3 +770,58 @@ async fn test_pixi_pack_source(
770770
let sha256_digest = sha256_digest_bytes(&output_file);
771771
insta::assert_snapshot!(format!("sha256-{}-executable", platform), &sha256_digest);
772772
}
773+
774+
#[fixture]
775+
fn templated_pixi_toml() -> (PathBuf, TempDir) {
776+
use url::Url;
777+
let temp_pixi_project = tempdir().expect("Couldn't create a temp dir for tests");
778+
let absolute_path_to_local_channel =
779+
std::path::absolute("examples/local-channel/channel").unwrap();
780+
let absolute_path_to_package = absolute_path_to_local_channel
781+
.join("noarch/my-webserver-0.1.0-pyh4616a5c_0.conda")
782+
.to_str()
783+
.unwrap()
784+
.to_owned();
785+
let local_channel_url = Url::from_directory_path(&absolute_path_to_local_channel)
786+
.unwrap()
787+
.to_string();
788+
789+
let pixi_toml = temp_pixi_project.path().join("pixi.toml");
790+
let pixi_lock = temp_pixi_project.path().join("pixi.lock");
791+
let pixi_toml_contents = fs::read_to_string("examples/local-channel/pixi.toml.template")
792+
.unwrap()
793+
.replace("<local-channel-url>", &local_channel_url);
794+
let pixi_lock_contents = fs::read_to_string("examples/local-channel/pixi.lock.template")
795+
.unwrap()
796+
.replace("<local-channel-url>", &local_channel_url)
797+
.replace("<absolute-path-to-package>", &absolute_path_to_package);
798+
799+
fs::write(&pixi_toml, pixi_toml_contents).unwrap();
800+
fs::write(&pixi_lock, pixi_lock_contents).unwrap();
801+
802+
(pixi_toml, temp_pixi_project)
803+
}
804+
805+
#[rstest]
806+
#[tokio::test]
807+
async fn test_local_channel(
808+
#[allow(unused_variables)] templated_pixi_toml: (PathBuf, TempDir),
809+
#[with(templated_pixi_toml.0.clone())] options: Options,
810+
) {
811+
let pack_options = options.pack_options;
812+
let pack_result = pixi_pack::pack(pack_options).await;
813+
assert!(pack_result.is_ok(), "{:?}", pack_result);
814+
815+
let unpack_options = options.unpack_options;
816+
let unpack_result = pixi_pack::unpack(unpack_options.clone()).await;
817+
assert!(unpack_result.is_ok(), "{:?}", unpack_result);
818+
819+
assert!(
820+
unpack_options
821+
.output_directory
822+
.join("env")
823+
.join("conda-meta")
824+
.join("my-webserver-0.1.0-pyh4616a5c_0.json")
825+
.exists()
826+
);
827+
}

0 commit comments

Comments
 (0)