Skip to content

Commit

Permalink
Rename build script rather and include it as bytes
Browse files Browse the repository at this point in the history
  • Loading branch information
smoelius committed Oct 24, 2024
1 parent a79192e commit 54ec9f7
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 25 deletions.
27 changes: 13 additions & 14 deletions src/util/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ use anyhow::{anyhow, bail, ensure, Context, Result};
use once_cell::sync::Lazy;
use std::{
env,
fs::{canonicalize, set_permissions, Permissions},
fs::canonicalize,
io::Write,
os::unix::{ffi::OsStrExt, fs::PermissionsExt},
os::unix::ffi::OsStrExt,
path::Path,
process::{Command, Output, Stdio},
str::Utf8Error,
Expand All @@ -29,8 +29,8 @@ const DEFAULT_PROFILE: &str = r#"(version 1)
/// Executes `command`, forwards its output to stdout and stderr, and optionally checks whether
/// `command` succeeded.
///
/// Called by [`unpack_and_exec`]. Since this file is included in the wrapper build script's
/// src/main.rs file, `exec_forwarding_output` should appear here, alongside [`unpack_and_exec`].
/// Called by [`exec_sibling`]. Since this file is included in the wrapper build script's
/// src/main.rs file, `exec_forwarding_output` should appear here, alongside [`exec_sibling`].
///
/// # Errors
///
Expand Down Expand Up @@ -63,15 +63,16 @@ pub fn exec_forwarding_output(mut command: Command, failure_is_error: bool) -> R
/// Essentially the body of the wrapper build script's `main` function. Not called by `build-wrap`
/// itself.
#[allow(dead_code)]
fn unpack_and_exec(bytes: &[u8]) -> Result<()> {
let (mut file, temp_path) =
tempfile::NamedTempFile::new().map(tempfile::NamedTempFile::into_parts)?;
fn exec_sibling(sibling_path_as_str: &str) -> Result<()> {
let current_exe = env::current_exe()?;

file.write_all(bytes)?;
let parent = current_exe
.parent()
.ok_or_else(|| anyhow!("failed to get `current_exe` parent"))?;

drop(file);
let sibling_path = Path::new(sibling_path_as_str);

set_permissions(&temp_path, Permissions::from_mode(0o755))?;
assert!(sibling_path.starts_with(parent));

// smoelius: The `BUILD_WRAP_CMD` used is the one set when set when the wrapper build script is
// compiled, not when it is run. So if the wrapped build script prints the following and the
Expand All @@ -81,7 +82,7 @@ fn unpack_and_exec(bytes: &[u8]) -> Result<()> {
// cargo:rerun-if-env-changed=BUILD_WRAP_CMD
// ```
// They will cause the wrapped build script to be rerun, however.
let expanded_args = split_and_expand(&temp_path)?;
let expanded_args = split_and_expand(sibling_path)?;

let allow_enabled = enabled("BUILD_WRAP_ALLOW");

Expand All @@ -93,12 +94,10 @@ fn unpack_and_exec(bytes: &[u8]) -> Result<()> {
// `BUILD_WRAP_ALLOW` is enabled.
if !output.status.success() {
debug_assert!(allow_enabled);
let command = Command::new(&temp_path);
let command = Command::new(sibling_path);
let _: Output = exec_forwarding_output(command, true)?;
}

drop(temp_path);

Ok(())
}

Expand Down
28 changes: 19 additions & 9 deletions src/wrapper.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
use crate::util::ToUtf8;
use anyhow::Result;
use anyhow::{anyhow, Result};
use std::{
fs::{create_dir, write},
fs::{create_dir, rename, write},
path::Path,
};
use tempfile::{tempdir, TempDir};
use tempfile::{tempdir, NamedTempFile, TempDir};

#[allow(clippy::disallowed_methods)]
pub fn package(build_script_path: &Path) -> Result<TempDir> {
let build_script_path_as_str = build_script_path.to_utf8()?;
let parent = build_script_path
.parent()
.ok_or_else(|| anyhow!("failed to get `build_script_path` parent"))?;

let temp_file = NamedTempFile::new_in(parent)?;

let (_file, sibling_path) = temp_file.keep()?;

rename(build_script_path, &sibling_path)?;

let sibling_path_as_str = sibling_path.to_utf8()?;

let tempdir = tempdir()?;

write(tempdir.path().join("Cargo.toml"), CARGO_TOML)?;
create_dir(tempdir.path().join("src"))?;
write(
tempdir.path().join("src/main.rs"),
main_rs(build_script_path_as_str),
main_rs(sibling_path_as_str),
)?;

Ok(tempdir)
Expand All @@ -39,19 +49,19 @@ tempfile = "3.10"
/// A wrapper build script's src/main.rs consists of the following:
///
/// - the contents of util/common.rs (included verbatim)
/// - the original build script as a byte slice (`BYTES`)
/// - the path of the renamed original build script (`PATH`)
/// - a `main` function
///
/// See [`package`].
fn main_rs(build_script_path_as_str: &str) -> Vec<u8> {
fn main_rs(sibling_path_as_str: &str) -> Vec<u8> {
[
COMMON_RS,
format!(
r#"
const BYTES: &[u8] = include_bytes!("{build_script_path_as_str}");
const PATH: &str = "{sibling_path_as_str}";
fn main() -> Result<()> {{
unpack_and_exec(BYTES)
exec_sibling(PATH)
}}
"#,
)
Expand Down
15 changes: 13 additions & 2 deletions tests/integration/cargo_config.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::util;
use std::{env::temp_dir, path::Path, process::Command};
use std::{path::Path, process::Command};

const DIR: &str = "fixtures/cargo_config";

Expand All @@ -16,8 +16,19 @@ fn cargo_config() {
// smoelius: When `build-wrap` builds the wrapper package, it expects the target directory to be
// `target`. So building the wrapper package in `fixtures/cargo_config` would fail because it
// contains a `.cargo/config.toml` that sets the target directory to `target-custom`.

// smoelius: The build script in `fixtures/cargo_config` prints the path of the current
// executable, i.e., the wrapped, original build script. Previously, this was unpacked into
// `std::env::temp_dir()`. However, `build-wrap` now renames the original build script so that
// it is a sibling of the wrapper build script. Hence, when this test is run, the current
// executable should be in `target-custom` alongside the wrapper build script.
let command = util::build_with_build_wrap();
test_build(command, &temp_dir());
test_build(
command,
&Path::new(env!("CARGO_MANIFEST_DIR"))
.join(DIR)
.join("target-custom/debug"),
);
}

fn test_build(mut command: Command, expected_dir: &Path) {
Expand Down

0 comments on commit 54ec9f7

Please sign in to comment.