Files
uv/Cargo.toml
konsti 39021263dd Windows launchers using posy trampolines (#1092)
## Background

In virtual environments, we want to install python programs as console
commands, e.g. `black .` over `python -m black .`. They may be called
[entrypoints](https://packaging.python.org/en/latest/specifications/entry-points/)
or scripts. For entrypoints, we're given a module name and function to
call in that module.

On Unix, we generate a minimal python script launcher. Text files are
runnable on unix by adding a shebang at their top, e.g.

```python
#!/usr/bin/env python
```

will make the operating system run the file with the current python
interpreter. A venv launcher for black in `/home/ferris/colorize/.venv`
(module name: `black`, function to call: `patched_main`) would look like
this:

```python
#!/home/ferris/colorize/.venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
from black import patched_main
if __name__ == "__main__":
    sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0])
    sys.exit(patched_main())
```

On windows, this doesn't work, we can only rely on launching `.exe`
files.

## Summary

We use posy's rust implementation of a trampoline, which is based on
distlib's c++ implementation. We pre-build a minimal exe and append the
launcher script as stored zip archive behind it. The exe will look for
the venv python interpreter next to it and use it to execute the
appended script.

The changes in this PR make the `black` entrypoint work:

```powershell
cargo run -- venv .venv
cargo run -q -- pip install black
.\.venv\Scripts\black --version
```

Integration with our existing tests will be done in follow-up PRs.

## Implementation and Details

I've vendored the posy trampoline crate. It is a formatted, renamed and
slightly changed for embedding version of
https://github.com/njsmith/posy/pull/28.

The posy launchers are smaller than the distlib launchers, 16K vs 106K
for black. Currently only `x86_64-pc-windows-msvc` is supported. The
crate requires a nightly compiler for its no-std binary size tricks.

On windows, an application can be launched with a console or without (to
create windows instead), which needs two different launchers. The gui
launcher will subsequently use `pythonw.exe` while the console launcher
uses `python.exe`.
2024-01-26 13:54:11 +00:00

181 lines
6.5 KiB
TOML

[workspace]
members = ["crates/*"]
exclude = [
"scripts",
# Needs nightly
"crates/puffin-trampoline"
]
resolver = "2"
[workspace.package]
edition = "2021"
rust-version = "1.74"
homepage = "https://pypi.org/project/puffin-alpha/"
documentation = "https://pypi.org/project/puffin-alpha/"
repository = "https://github.com/astral-sh/puffin"
authors = ["Puffin"]
license = "MIT OR Apache-2.0"
[workspace.dependencies]
anstream = { version = "0.6.5" }
anyhow = { version = "1.0.79" }
async_http_range_reader = { git = "https://github.com/baszalmstra/async_http_range_reader", rev = "8dab2c08ac864fec1df014465264f9a7c8eae905" }
async_zip = { version = "0.0.16", features = ["tokio", "deflate"] }
base64 = { version = "0.21.7" }
cachedir = { version = "0.3.1" }
camino = { version = "1.1.6", features = ["serde1"] }
cargo-util = { version = "0.2.8" }
chrono = { version = "0.4.31" }
clap = { version = "4.4.13" }
configparser = { version = "3.0.4" }
csv = { version = "1.3.0" }
dashmap = { version = "5.5.3" }
data-encoding = { version = "2.5.0" }
derivative = { version = "2.2.0" }
directories = { version = "5.0.1" }
dirs = { version = "5.0.1" }
dunce = { version = "1.0.4" }
flate2 = { version = "1.0.28", default-features = false }
fs-err = { version = "2.11.0" }
fs2 = { version = "0.4.3" }
futures = { version = "0.3.30" }
git2 = { version = "0.18.1" }
glob = { version = "0.3.1" }
goblin = { version = "0.8.0" }
hex = { version = "0.4.3" }
hmac = { version = "0.12.1" }
home = { version = "0.5.9" }
html-escape = { version = "0.2.13" }
http = { version = "0.2.11" }
http-cache-semantics = { version = "1.0.2" }
indexmap = { version = "2.1.0" }
indicatif = { version = "0.17.7" }
indoc = { version = "2.0.4" }
itertools = { version = "0.12.0" }
junction = { version = "1.0.0" }
mailparse = { version = "0.14.0" }
# For additional textwrap options: https://github.com/zkat/miette/pull/321, https://github.com/zkat/miette/pull/328
miette = { git = "https://github.com/zkat/miette.git", rev = "b0744462adbbfbb6d845f382db36be883c7f3c45" }
nanoid = { version = "0.4.0" }
once_cell = { version = "1.19.0" }
owo-colors = { version = "3.5.0" }
petgraph = { version = "0.6.4" }
platform-info = { version = "2.0.2" }
plist = { version = "1.6.0" }
pubgrub = { git = "https://github.com/zanieb/pubgrub", rev = "86447f2a391c0aa25c56acb3a8b6ce10aac305b6" }
pyo3 = { version = "0.20.2" }
pyo3-log = { version = "0.9.0"}
pyproject-toml = { version = "0.8.1" }
rand = { version = "0.8.5" }
rayon = { version = "1.8.0" }
reflink-copy = { version = "0.1.14" }
regex = { version = "1.10.2" }
reqwest = { version = "0.11.23", default-features = false, features = ["json", "gzip", "brotli", "stream", "rustls-tls"] }
reqwest-middleware = { version = "0.2.4" }
reqwest-retry = { version = "0.3.0" }
rmp-serde = { version = "1.1.2" }
rustc-hash = { version = "1.1.0" }
same-file = { version = "1.0.6" }
seahash = { version = "4.1.0" }
serde = { version = "1.0.194" }
serde_json = { version = "1.0.111" }
sha1 = { version = "0.10.6" }
sha2 = { version = "0.10.8" }
tar = { version = "0.4.40" }
target-lexicon = { version = "0.12.13" }
tempfile = { version = "3.9.0" }
textwrap = { version = "0.15.2" }
thiserror = { version = "1.0.56" }
tl = { version = "0.7.7" }
tokio = { version = "1.35.1", features = ["rt-multi-thread"] }
tokio-util = { version = "0.7.10", features = ["compat"] }
toml = { version = "0.8.8" }
toml_edit = { version = "0.21.0" }
tracing = { version = "0.1.40" }
tracing-durations-export = { version = "0.1.0", features = ["plot"] }
tracing-indicatif = { version = "0.3.6" }
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
tracing-tree = { version = "0.3.0" }
unicode-width = { version = "0.1.11" }
unscanny = { version = "0.1.0" }
url = { version = "2.5.0" }
uuid = { version = "1.7.0", default-features = false }
waitmap = { version = "1.1.0" }
walkdir = { version = "2.4.0" }
which = { version = "5.0.0" }
zip = { version = "0.6.6", default-features = false, features = ["deflate"] }
[patch.crates-io]
# For pyproject-toml
pep508_rs = { path = "crates/pep508-rs" }
[workspace.lints.rust]
unsafe_code = "warn"
unreachable_pub = "warn"
[workspace.lints.clippy]
pedantic = { level = "warn", priority = -2 }
# Allowed pedantic lints
char_lit_as_u8 = "allow"
collapsible_else_if = "allow"
collapsible_if = "allow"
implicit_hasher = "allow"
match_same_arms = "allow"
missing_errors_doc = "allow"
missing_panics_doc = "allow"
module_name_repetitions = "allow"
must_use_candidate = "allow"
similar_names = "allow"
too_many_lines = "allow"
# Disallowed restriction lints
print_stdout = "warn"
print_stderr = "warn"
dbg_macro = "warn"
empty_drop = "warn"
empty_structs_with_brackets = "warn"
exit = "warn"
get_unwrap = "warn"
rc_buffer = "warn"
rc_mutex = "warn"
rest_pat_in_fully_bound_structs = "warn"
[profile.profiling]
inherits = "release"
debug = true
# The profile that 'cargo dist' will build with.
[profile.dist]
inherits = "release"
lto = "thin"
# Config for 'cargo dist'
[workspace.metadata.dist]
# The preferred cargo-dist version to use in CI (Cargo.toml SemVer syntax)
cargo-dist-version = "0.8.0"
# CI backends to support
ci = ["github"]
# The installers to generate for each app
installers = ["shell", "powershell"]
# The archive format to use for windows builds (defaults .zip)
windows-archive = ".zip"
# The archive format to use for non-windows builds (defaults .tar.xz)
unix-archive = ".tar.gz"
# Target platforms to build apps for (Rust target-triple syntax)
targets = ["aarch64-unknown-linux-gnu", "x86_64-unknown-linux-gnu", "i686-unknown-linux-gnu", "aarch64-apple-darwin", "x86_64-apple-darwin", "aarch64-unknown-linux-musl", "x86_64-unknown-linux-musl", "i686-unknown-linux-musl", "aarch64-pc-windows-msvc", "x86_64-pc-windows-msvc", "i686-pc-windows-msvc", "armv7-unknown-linux-gnueabihf", "powerpc64-unknown-linux-gnu", "powerpc64le-unknown-linux-gnu", "s390x-unknown-linux-gnu"]
# Whether to auto-include files like READMEs and CHANGELOGs (default true)
auto-includes = false
# Whether cargo-dist should create a Github Release or use an existing draft
create-release = true
# Publish jobs to run in CI
pr-run-mode = "skip"
# Whether CI should trigger releases with dispatches instead of tag pushes
dispatch-releases = true
# Whether CI should include auto-generated code to build local artifacts
build-local-artifacts = false
# Local artifacts jobs to run in CI
local-artifacts-jobs = ["./build-binaries", "./build-docker"]
# Publish jobs to run in CI
publish-jobs = ["./publish-pypi"]
# For: `permissions: packages: write`.
allow-dirty = ["ci"]