Skip to content

Commit

Permalink
Allows usage of custom source fork CPython, Pypy and UV.
Browse files Browse the repository at this point in the history
This enables enterprise use-cases.
  • Loading branch information
Coruscant11 committed Jul 30, 2024
1 parent 2980970 commit 8126616
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 5 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ passthrough = [
"PYAPP_SELF_COMMAND",
"PYAPP_SKIP_INSTALL",
"PYAPP_UPGRADE_VIRTUALENV",
"PYAPP_UV_CUSTOM_SOURCE",
"PYAPP_UV_ENABLED",
"PYAPP_UV_ONLY_BOOTSTRAP",
"PYAPP_UV_VERSION",
Expand Down
32 changes: 30 additions & 2 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,14 +310,36 @@ fn get_python_version() -> String {
DEFAULT_PYTHON_VERSION.to_string()
}

fn get_custom_source(name: &str) -> Option<String> {
let name = name.to_uppercase().replace(".", "_");
let variable_name = format!("PYAPP_DISTRIBUTION_SOURCE_{}", name);
if let Ok(value) = env::var(variable_name) {
if !value.is_empty() {
return Some(value);
}
}
None
}

fn get_distribution_source() -> String {
let selected_python_version = get_python_version();

// Return custom source if specified for this version
if let Some(custom_source) = get_custom_source(&selected_python_version) {
dbg!(
"Using custom source for version {}: {}",
&selected_python_version,
&custom_source
);
return custom_source;
}

// Otherwise, check if there is a global custom source
let distribution_source = env::var("PYAPP_DISTRIBUTION_SOURCE").unwrap_or_default();
if !distribution_source.is_empty() {
return distribution_source;
};

let selected_python_version = get_python_version();

// https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts
let selected_platform = match env::var("CARGO_CFG_TARGET_OS").unwrap().as_str() {
"windows" => "windows",
Expand Down Expand Up @@ -922,6 +944,11 @@ fn set_uv_only_bootstrap() {
}
}

fn set_uv_custom_source() {
let variable = "PYAPP_UV_CUSTOM_SOURCE";
set_runtime_variable(variable, env::var(variable).unwrap_or_default());
}

fn set_uv_version() {
let variable = "PYAPP_UV_VERSION";
let version = env::var(variable).unwrap_or("any".to_string());
Expand Down Expand Up @@ -1070,6 +1097,7 @@ fn main() {
set_pip_allow_config();
set_uv_enabled();
set_uv_only_bootstrap();
set_uv_custom_source();
set_uv_version();
set_allow_updates();
set_indicator();
Expand Down
6 changes: 6 additions & 0 deletions docs/config/distribution.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ You may explicitly set the `PYAPP_DISTRIBUTION_SOURCE` option which overrides th

Setting this manually may require you to define extra metadata about the distribution that is required for correct [runtime behavior](../runtime.md).

### Version

For greater granularity, you may set the `PYAPP_DISTRIBUTION_SOURCE_<NAME>` option. The source is also the URL to the distribution's archive.

The placeholder `<NAME>` is the uppercased version of the distribution name with periods replaced by underscores e.g. `pypy3.10` would become `PYPY3_10`.

### Format

The following formats are supported for the `PYAPP_DISTRIBUTION_FORMAT` option, with the default chosen based on the ending of the source URL:
Expand Down
6 changes: 6 additions & 0 deletions docs/config/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ You may use a specific `X.Y.Z` version by setting the `PYAPP_UV_VERSION` option.

By default, a version of UV that has already been downloaded by a PyApp application is used. If UV has not yet been downloaded then the latest version is used.

### Source

You may explicitly set the `PYAPP_UV_SOURCE` option in order to download your own UV release archive.

The value must end with the archive's real file extension, which is used to determine the extraction method.

### Only bootstrap

You may set the `PYAPP_UV_ONLY_BOOTSTRAP` option to `true` or `1` to only use UV for virtual environment creation and continue using pip for project installation.
Expand Down
4 changes: 4 additions & 0 deletions docs/users.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ The following is not intended to be a complete enumeration. Be sure to view the
| [Litestar](https://github.com/litestar-org/litestar-fullstack/blob/dc72eee78173790c3e91b0c095ac9e70ba91bedd/scripts/post-builds.py)
| [Preservation Workbench](https://github.com/Preservation-Workbench/PWCode/blob/e7777806be35bd60ca8c33e677ffd77e38b277d0/build/make.sh)
| [tidal-wave](https://github.com/ebb-earl-co/tidal-wave/blob/6358ede21adb715a053b1e6cc73968933c3bed05/BUILDME.md#pyapp-created-binaries)

## Industry

- [Amadeus](https://amadeus.com) <sup>\[[1](https://github.com/ofek/pyapp/pull/147)|[2](https://github.com/AmadeusITGroup/pyapp)\]</sup>
24 changes: 24 additions & 0 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use anyhow::{Context, Result};
use base64::{engine::general_purpose::STANDARD_NO_PAD, Engine as _};
use directories::ProjectDirs;
use once_cell::sync::OnceCell;
use reqwest::Url;

static PLATFORM_DIRS: OnceCell<ProjectDirs> = OnceCell::new();
static INSTALLATION_DIRECTORY: OnceCell<PathBuf> = OnceCell::new();
Expand Down Expand Up @@ -206,6 +207,29 @@ pub fn uv_as_installer() -> bool {
uv_enabled() && !uv_only_bootstrap()
}

pub fn uv_custom_source() -> String {
env!("PYAPP_UV_CUSTOM_SOURCE").into()
}

pub fn uv_custom_source_artifact_name() -> String {
let custom_source = uv_custom_source();

let parsed =
Url::parse(&custom_source).expect(&format!("unable to parse url: {}", &custom_source));

// Try to find artifact name from URL path
if let Some(segments) = parsed.path_segments() {
if let Some(segment) = segments.last() {
return segment.into();
}
}

panic!(
"unable to determine artifact name from url: {}",
&custom_source
);
}

pub fn is_gui() -> bool {
env!("PYAPP_IS_GUI") == "1"
}
Expand Down
12 changes: 9 additions & 3 deletions src/distribution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -488,13 +488,20 @@ fn ensure_uv_available() -> Result<()> {
.with_context(|| format!("unable to create UV cache {}", &managed_uv_cache.display()))?;

let dir = tempdir().with_context(|| "unable to create temporary directory")?;
let artifact_name = app::uv_artifact_name();

let artifact_name: String = if app::uv_custom_source().is_empty() {
app::uv_artifact_name()
} else {
app::uv_custom_source_artifact_name()
};
let temp_path = dir.path().join(&artifact_name);

let mut f = fs::File::create(&temp_path)
.with_context(|| format!("unable to create temporary file: {}", &temp_path.display()))?;

let url = if uv_version == "any" {
let url = if !app::uv_custom_source().is_empty() {
app::uv_custom_source()
} else if uv_version == "any" {
format!(
"https://github.com/astral-sh/uv/releases/latest/download/{}",
&artifact_name,
Expand All @@ -505,7 +512,6 @@ fn ensure_uv_available() -> Result<()> {
&uv_version, &artifact_name,
)
};

network::download(&url, &mut f, "UV")?;

if artifact_name.ends_with(".zip") {
Expand Down

0 comments on commit 8126616

Please sign in to comment.