Skip to content

Commit

Permalink
Add uv build
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Aug 31, 2024
1 parent 83467f0 commit 2ed5720
Show file tree
Hide file tree
Showing 14 changed files with 1,110 additions and 109 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

226 changes: 149 additions & 77 deletions crates/uv-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ static DEFAULT_BACKEND: LazyLock<Pep517Backend> = LazyLock::new(|| Pep517Backend
pub enum Error {
#[error(transparent)]
Io(#[from] io::Error),
#[error("Invalid source distribution: {0}")]
InvalidSourceDist(String),
#[error("{} does not appear to be a Python project, as neither `pyproject.toml` nor `setup.py` is present in the directory", _0.simplified_display())]
InvalidSourceDist(PathBuf),
#[error("Invalid `pyproject.toml`")]
InvalidPyprojectToml(#[from] toml::de::Error),
#[error("Editable installs with setup.py legacy builds are unsupported, please specify a build backend in pyproject.toml")]
Expand Down Expand Up @@ -595,8 +595,7 @@ impl SourceBuild {
// We require either a `pyproject.toml` or a `setup.py` file at the top level.
if !source_tree.join("setup.py").is_file() {
return Err(Box::new(Error::InvalidSourceDist(
"The archive contains neither a `pyproject.toml` nor a `setup.py` file at the top level"
.to_string(),
source_tree.to_path_buf(),
)));
}

Expand Down Expand Up @@ -723,7 +722,7 @@ impl SourceBuild {
#[instrument(skip_all, fields(version_id = self.version_id))]
pub async fn build_wheel(&self, wheel_dir: &Path) -> Result<String, Error> {
// The build scripts run with the extracted root as cwd, so they need the absolute path.
let wheel_dir = fs::canonicalize(wheel_dir)?;
let wheel_dir = std::path::absolute(wheel_dir)?;

// Prevent clashes from two uv processes building wheels in parallel.
let tmp_dir = tempdir_in(&wheel_dir)?;
Expand All @@ -737,86 +736,159 @@ impl SourceBuild {
Ok(filename)
}

/// Perform a PEP 517 build for a wheel or source distribution (sdist).
async fn pep517_build(
&self,
wheel_dir: &Path,
pep517_backend: &Pep517Backend,
) -> Result<String, Error> {
let metadata_directory = self
.metadata_directory
.as_deref()
.map_or("None".to_string(), |path| {
format!(r#""{}""#, path.escape_for_python())
});

// Write the hook output to a file so that we can read it back reliably.
let outfile = self
.temp_dir
.path()
.join(format!("build_{}.txt", self.build_kind));

debug!(
r#"Calling `{}.build_{}("{}", {}, {})`"#,
pep517_backend.backend,
self.build_kind,
wheel_dir.escape_for_python(),
self.config_settings.escape_for_python(),
metadata_directory,
);
let script = formatdoc! {
r#"
{}
match self.build_kind {
BuildKind::Sdist => {
// Write the hook output to a file so that we can read it back reliably.
let outfile = self
.temp_dir
.path()
.join(format!("build_{}.txt", self.build_kind));

debug!(
r#"Calling `{}.build_{}("{}", {})`"#,
pep517_backend.backend,
self.build_kind,
wheel_dir.escape_for_python(),
self.config_settings.escape_for_python(),
);
let script = formatdoc! {
r#"
{}
sdist_filename = backend.build_{}("{}", {})
with open("{}", "w") as fp:
fp.write(sdist_filename)
"#,
pep517_backend.backend_import(),
self.build_kind,
wheel_dir.escape_for_python(),
self.config_settings.escape_for_python(),
outfile.escape_for_python()
};
let span = info_span!(
"run_python_script",
script=format!("build_{}", self.build_kind),
python_version = %self.venv.interpreter().python_version()
);
let output = self
.runner
.run_script(
&self.venv,
&script,
&self.source_tree,
&self.environment_variables,
&self.modified_path,
)
.instrument(span)
.await?;
if !output.status.success() {
return Err(Error::from_command_output(
format!(
"Build backend failed to build sdist through `build_{}()`",
self.build_kind
),
&output,
&self.version_id,
));
}

wheel_filename = backend.build_{}("{}", {}, {})
with open("{}", "w") as fp:
fp.write(wheel_filename)
"#,
pep517_backend.backend_import(),
self.build_kind,
wheel_dir.escape_for_python(),
self.config_settings.escape_for_python(),
metadata_directory,
outfile.escape_for_python()
};
let span = info_span!(
"run_python_script",
script=format!("build_{}", self.build_kind),
python_version = %self.venv.interpreter().python_version()
);
let output = self
.runner
.run_script(
&self.venv,
&script,
&self.source_tree,
&self.environment_variables,
&self.modified_path,
)
.instrument(span)
.await?;
if !output.status.success() {
return Err(Error::from_command_output(
format!(
"Build backend failed to build wheel through `build_{}()`",
self.build_kind
),
&output,
&self.version_id,
));
}
let distribution_filename = fs::read_to_string(&outfile)?;
if !wheel_dir.join(&distribution_filename).is_file() {
return Err(Error::from_command_output(
format!(
"Build backend failed to produce sdist through `build_{}()`: `{distribution_filename}` not found",
self.build_kind
),
&output,
&self.version_id,
));
}
Ok(distribution_filename)
}
BuildKind::Wheel | BuildKind::Editable => {
let metadata_directory = self
.metadata_directory
.as_deref()
.map_or("None".to_string(), |path| {
format!(r#""{}""#, path.escape_for_python())
});

// Write the hook output to a file so that we can read it back reliably.
let outfile = self
.temp_dir
.path()
.join(format!("build_{}.txt", self.build_kind));

debug!(
r#"Calling `{}.build_{}("{}", {}, {})`"#,
pep517_backend.backend,
self.build_kind,
wheel_dir.escape_for_python(),
self.config_settings.escape_for_python(),
metadata_directory,
);
let script = formatdoc! {
r#"
{}
wheel_filename = backend.build_{}("{}", {}, {})
with open("{}", "w") as fp:
fp.write(wheel_filename)
"#,
pep517_backend.backend_import(),
self.build_kind,
wheel_dir.escape_for_python(),
self.config_settings.escape_for_python(),
metadata_directory,
outfile.escape_for_python()
};
let span = info_span!(
"run_python_script",
script=format!("build_{}", self.build_kind),
python_version = %self.venv.interpreter().python_version()
);
let output = self
.runner
.run_script(
&self.venv,
&script,
&self.source_tree,
&self.environment_variables,
&self.modified_path,
)
.instrument(span)
.await?;
if !output.status.success() {
return Err(Error::from_command_output(
format!(
"Build backend failed to build wheel through `build_{}()`",
self.build_kind
),
&output,
&self.version_id,
));
}

let distribution_filename = fs::read_to_string(&outfile)?;
if !wheel_dir.join(&distribution_filename).is_file() {
return Err(Error::from_command_output(
format!(
"Build backend failed to produce wheel through `build_{}()`: `{distribution_filename}` not found",
self.build_kind
),
&output,
&self.version_id,
));
let distribution_filename = fs::read_to_string(&outfile)?;
if !wheel_dir.join(&distribution_filename).is_file() {
return Err(Error::from_command_output(
format!(
"Build backend failed to produce through `build_{}()`: `{distribution_filename}` not found",
self.build_kind
),
&output,
&self.version_id,
));
}
Ok(distribution_filename)
}
}
Ok(distribution_filename)
}
}

Expand Down
Loading

0 comments on commit 2ed5720

Please sign in to comment.