Skip to content

Commit 9fec2e9

Browse files
authored
Complete support for PEX_TOOLS. (#72)
1 parent 97e68ac commit 9fec2e9

15 files changed

Lines changed: 189 additions & 138 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ jobs:
9393
run: |
9494
chmod +x target/release/package
9595
export CARGO="$(command -v cargo)"
96-
target/release/package \
96+
PEXRC_CLIB_FEATURES=tools target/release/package \
9797
--color always --profile release -o dist ${{ matrix.targets }}
9898
- name: Generate Release Hashes Manifest.
9999
run: uv run dev-cmd --color always generate-release-hashes -- -i dist

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ jobs:
6666
run: |
6767
chmod +x target/release/package
6868
export CARGO="$(command -v cargo)"
69-
target/release/package \
69+
PEXRC_CLIB_FEATURES=tools target/release/package \
7070
--color always --profile release -o dist --target ${{ matrix.target }}
7171
- name: Upload pexrc artifacts
7272
uses: actions/upload-artifact@v7

CHANGES.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# Release Notes
22

3+
## 0.7.0
4+
5+
This release adds support for PEX_TOOLS when `pexrc` is built with the `tools` feature; e.g.:
6+
```console
7+
PEXRC_CLIB_FEATURES=tools cargo build ...
8+
```
9+
10+
Releases now ship with this feature enabled.
11+
312
## 0.6.0
413

514
This release adds support for installing venv console scripts.

Cargo.lock

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

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
[package]
55
name = "pexrc"
6-
version = "0.6.0"
6+
version = "0.7.0"
77
edition = "2024"
88
publish = false
99

@@ -236,4 +236,4 @@ tempfile = { workspace = true }
236236
url = { workspace = true }
237237
walkdir = { workspace = true }
238238
zip = { workspace = true }
239-
zstd = { workspace = true }
239+
zstd = { workspace = true }

crates/pex/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ publish = false
88

99
[dependencies]
1010
anyhow = { workspace = true }
11+
chrono = { workspace = true }
1112
csv = { workspace = true }
1213
dashmap = { workspace = true }
1314
fs-err = { workspace = true }

crates/pex/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ pub use pex::{
2222
};
2323
pub use pex_info::{BinPath, InheritPath, InterpreterSelectionStrategy, PexInfo};
2424
pub use pex_path::PexPath;
25-
pub use wheel::{EntryPoint, EntryPoints, WheelMetadata, repackage_wheels};
25+
pub use wheel::{EntryPoint, EntryPoints, WheelMetadata, WheelOptions, repackage_wheels};

crates/pex/src/wheel/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ pub use entry_points::{EntryPoint, EntryPoints};
1313
pub(crate) use file::WheelFile;
1414
pub(crate) use metadata::MetadataReader;
1515
pub use metadata::WheelMetadata;
16-
pub use package::repackage_wheels;
16+
pub use package::{WheelOptions, repackage_wheels};

crates/pex/src/wheel/original_wheel_info.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use std::io::Read;
55
use std::path::Path;
66

7+
use chrono::Utc;
78
use fs_err::File;
89
use ouroboros::self_referencing;
910
use serde::Deserialize;
@@ -67,17 +68,23 @@ impl OriginalWheelInfo {
6768
pub(crate) fn iter_file_options(
6869
&self,
6970
base_options: SimpleFileOptions,
71+
timestamp: Option<chrono::DateTime<Utc>>,
7072
) -> anyhow::Result<Vec<(&str, FileOptions<'static, ()>)>> {
7173
self.borrow_info()
7274
.entries
7375
.iter()
7476
.map(|(name, last_modified, external_attr)| {
75-
last_modified.as_zip_date_time().map(|date_time| {
76-
let options = base_options
77-
.last_modified_time(date_time)
78-
.unix_permissions(external_attr >> 16);
79-
(*name, options)
80-
})
77+
let mtime = if let Some(timestamp) = timestamp {
78+
zip::DateTime::try_from(timestamp.naive_utc())?
79+
} else {
80+
last_modified.as_zip_date_time()?
81+
};
82+
Ok((
83+
*name,
84+
base_options
85+
.last_modified_time(mtime)
86+
.unix_permissions(external_attr >> 16),
87+
))
8188
})
8289
.collect::<anyhow::Result<_>>()
8390
}

crates/pex/src/wheel/package.rs

Lines changed: 66 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::path::{Component, Path};
99
use std::sync::Arc;
1010

1111
use anyhow::bail;
12+
use chrono::{DateTime, Utc};
1213
use fs_err as fs;
1314
use fs_err::File;
1415
use logging_timer::time;
@@ -31,11 +32,46 @@ enum DirPexDepType {
3132
ZippedChroot,
3233
}
3334

35+
pub struct WheelOptions {
36+
compression_method: CompressionMethod,
37+
compression_level: Option<i64>,
38+
timestamp: Option<DateTime<Utc>>,
39+
}
40+
41+
impl WheelOptions {
42+
pub fn new(
43+
compression_method: CompressionMethod,
44+
compression_level: Option<i64>,
45+
timestamp: Option<DateTime<Utc>>,
46+
) -> Self {
47+
Self {
48+
compression_method,
49+
compression_level,
50+
timestamp,
51+
}
52+
}
53+
54+
pub fn file_options(&self) -> anyhow::Result<SimpleFileOptions> {
55+
self.add_timestamp(
56+
SimpleFileOptions::default()
57+
.compression_method(self.compression_method)
58+
.compression_level(self.compression_level),
59+
)
60+
}
61+
62+
fn add_timestamp(&self, options: SimpleFileOptions) -> anyhow::Result<SimpleFileOptions> {
63+
Ok(if let Some(timestamp) = self.timestamp {
64+
options.last_modified_time(zip::DateTime::try_from(timestamp.naive_utc())?)
65+
} else {
66+
options
67+
})
68+
}
69+
}
70+
3471
#[time("debug", "{}")]
3572
pub fn repackage_wheels(
3673
pex: &Pex,
37-
compression_method: CompressionMethod,
38-
compression_level: Option<i64>,
74+
options: &WheelOptions,
3975
dest_dir: &Path,
4076
) -> anyhow::Result<Vec<File>> {
4177
let wheel_files = pex
@@ -58,8 +94,7 @@ pub fn repackage_wheels(
5894
pex.path,
5995
&wheel_file,
6096
dep_type,
61-
compression_method,
62-
compression_level,
97+
options,
6398
dest_dir,
6499
)
65100
})
@@ -76,8 +111,7 @@ pub fn repackage_wheels(
76111
zip_metadata.clone(),
77112
&wheel_file,
78113
pex.info.deps_are_wheel_files,
79-
compression_method,
80-
compression_level,
114+
options,
81115
dest_dir,
82116
)
83117
})
@@ -91,8 +125,7 @@ fn repackage_zipapp_pex_wheel(
91125
zip_metadata: Arc<ZipArchiveMetadata>,
92126
wheel_file: &WheelFile,
93127
is_whl_zip: bool,
94-
compression_method: CompressionMethod,
95-
compression_level: Option<i64>,
128+
options: &WheelOptions,
96129
dest_dir: &Path,
97130
) -> anyhow::Result<File> {
98131
let mut pex_zip_fp =
@@ -105,51 +138,34 @@ fn repackage_zipapp_pex_wheel(
105138
recompress_zipped_whl(
106139
ZipArchive::new(pex_zip_fp.by_name_seek(&wheel_prefix)?)?,
107140
wheel_file,
108-
compression_method,
109-
compression_level,
141+
options,
110142
dest_dir,
111143
)
112144
} else {
113-
recompress_zipped_whl_chroot(
114-
pex_zip_fp,
115-
wheel_file,
116-
compression_method,
117-
compression_level,
118-
dest_dir,
119-
true,
120-
)
145+
recompress_zipped_whl_chroot(pex_zip_fp, wheel_file, options, dest_dir, true)
121146
}
122147
}
123148

124149
fn repackage_directory_pex_wheel(
125150
pex_dir: &Path,
126151
wheel_file: &WheelFile,
127152
dep_type: DirPexDepType,
128-
compression_method: CompressionMethod,
129-
compression_level: Option<i64>,
153+
options: &WheelOptions,
130154
dest_dir: &Path,
131155
) -> anyhow::Result<File> {
132156
let wheel_path = pex_dir.join(".deps").join(wheel_file.file_name);
133157
match dep_type {
134-
DirPexDepType::Chroot => compress_whl_chroot(
135-
&wheel_path,
136-
wheel_file,
137-
compression_method,
138-
compression_level,
139-
dest_dir,
140-
),
158+
DirPexDepType::Chroot => compress_whl_chroot(&wheel_path, wheel_file, options, dest_dir),
141159
DirPexDepType::OriginalWhl => recompress_zipped_whl(
142160
ZipArchive::new(File::open(wheel_path)?)?,
143161
wheel_file,
144-
compression_method,
145-
compression_level,
162+
options,
146163
dest_dir,
147164
),
148165
DirPexDepType::ZippedChroot => recompress_zipped_whl_chroot(
149166
ZipArchive::new(File::open(wheel_path)?)?,
150167
wheel_file,
151-
compression_method,
152-
compression_level,
168+
options,
153169
dest_dir,
154170
false,
155171
),
@@ -159,8 +175,7 @@ fn repackage_directory_pex_wheel(
159175
fn recompress_zipped_whl(
160176
mut wheel: ZipArchive<impl Read + Seek>,
161177
wheel_file: &WheelFile,
162-
compression_method: CompressionMethod,
163-
compression_level: Option<i64>,
178+
options: &WheelOptions,
164179
dest_dir: &Path,
165180
) -> anyhow::Result<File> {
166181
fs::create_dir_all(dest_dir)?;
@@ -172,10 +187,10 @@ fn recompress_zipped_whl(
172187
if entry.name().ends_with(".pyc") {
173188
continue;
174189
}
175-
if entry.compression() == compression_method {
190+
if entry.compression() == options.compression_method && options.timestamp.is_none() {
176191
compressed_whl.raw_copy_file(entry)?;
177192
} else if entry.is_dir() {
178-
compressed_whl.add_directory(entry.name(), entry.options())?;
193+
compressed_whl.add_directory(entry.name(), options.add_timestamp(entry.options())?)?;
179194
} else {
180195
drop(entry);
181196
let mut entry = wheel.by_index(index)?;
@@ -187,10 +202,12 @@ fn recompress_zipped_whl(
187202
// See: https://github.com/zip-rs/zip2/issues/433
188203
compressed_whl.start_file(
189204
entry.name(),
190-
entry
191-
.options()
192-
.compression_method(compression_method)
193-
.compression_level(compression_level),
205+
options.add_timestamp(
206+
entry
207+
.options()
208+
.compression_method(options.compression_method)
209+
.compression_level(options.compression_level),
210+
)?,
194211
)?;
195212

196213
io::copy(&mut entry, &mut compressed_whl)?;
@@ -203,16 +220,12 @@ fn recompress_zipped_whl(
203220
fn recompress_zipped_whl_chroot(
204221
mut zipped_wheel_chroot: ZipArchive<impl Read + Seek>,
205222
wheel_file: &WheelFile,
206-
compression_method: CompressionMethod,
207-
compression_level: Option<i64>,
223+
options: &WheelOptions,
208224
dest_dir: &Path,
209225
prefixed: bool,
210226
) -> anyhow::Result<File> {
211227
fs::create_dir_all(dest_dir)?;
212-
let file_options = SimpleFileOptions::default()
213-
.compression_method(compression_method)
214-
.compression_level(compression_level);
215-
228+
let file_options = options.file_options()?;
216229
let prefix = if prefixed {
217230
format_args!(
218231
".deps/{wheel_file_name}/",
@@ -278,7 +291,9 @@ fn recompress_zipped_whl_chroot(
278291
let (dest_wheel, compressed_whl) = if let Some(wheel_info) = wheel_info {
279292
let dest_wheel = dest_dir.join(wheel_info.filename());
280293
let mut compressed_whl = ZipWriter::new(File::create(&dest_wheel)?);
281-
for (dst_rel_path, options) in wheel_info.iter_file_options(file_options)? {
294+
for (dst_rel_path, options) in
295+
wheel_info.iter_file_options(file_options, options.timestamp)?
296+
{
282297
if dst_rel_path.ends_with(".pyc") {
283298
continue;
284299
}
@@ -381,14 +396,11 @@ fn recompress_zipped_whl_chroot(
381396
fn compress_whl_chroot(
382397
wheel_dir: &Path,
383398
wheel_file: &WheelFile,
384-
compression_method: CompressionMethod,
385-
compression_level: Option<i64>,
399+
options: &WheelOptions,
386400
dest_dir: &Path,
387401
) -> anyhow::Result<File> {
388402
fs::create_dir_all(dest_dir)?;
389-
let file_options = SimpleFileOptions::default()
390-
.compression_method(compression_method)
391-
.compression_level(compression_level);
403+
let file_options = options.file_options()?;
392404

393405
let (record, record_rel_path) = Record::parse(wheel_dir, wheel_file)?;
394406

@@ -413,7 +425,9 @@ fn compress_whl_chroot(
413425
{
414426
let dest_wheel = dest_dir.join(wheel_info.filename());
415427
let mut compressed_whl = ZipWriter::new(File::create(&dest_wheel)?);
416-
for (dst_rel_path, options) in wheel_info.iter_file_options(file_options)? {
428+
for (dst_rel_path, options) in
429+
wheel_info.iter_file_options(file_options, options.timestamp)?
430+
{
417431
if dst_rel_path.ends_with(".pyc") {
418432
continue;
419433
}

0 commit comments

Comments
 (0)