Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial features (no cache invalidation support) #1

Merged
merged 21 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 10 additions & 20 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,23 @@ jobs:

steps:
- uses: actions/checkout@v3
- name: Run sccache-cache only on non-release runs
if: github.event_name != 'release' && github.event_name != 'workflow_dispatch'
uses: mozilla-actions/[email protected]
- name: Set Rust caching env vars only on non-release runs
if: github.event_name != 'release' && github.event_name != 'workflow_dispatch'
run: |
echo "SCCACHE_GHA_ENABLED=true" >> $GITHUB_ENV
echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV
- name: Build
run: cargo build --verbose
- name: Format
run: cargo fmt --check
- name: Clippy
run: cargo clippy -- -D warnings
- name: Check
run: rustup show
- name: Run tests
run: cargo test --verbose
- name: Docs
run: RUSTDOCFLAGS="-D warnings" cargo doc --no-deps

# coverage:
#
# runs-on: ubuntu-latest
#
# steps:
# - uses: actions/checkout@v1
# - uses: actions-rs/toolchain@v1
# with:
# toolchain: nightly
# override: true
# - uses: actions-rs/cargo@v1
# with:
# command: test
# args: --all-features --no-fail-fast
# env:
# CARGO_INCREMENTAL: '0'
# RUSTFLAGS: '-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Cpanic=abort -Zpanic_abort_tests'
# RUSTDOCFLAGS: '-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Cpanic=abort -Zpanic_abort_tests'
# - uses: actions-rs/[email protected]
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ anyhow = { version = "1.0.75", features = [] }
glob = "0.3"
project-root = "0.2.2"
build-target = "0.4.0"

[dev-dependencies]
tempfile = "3.8.1"
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Omnicopy_to_output

Provides a generalized implementation for a "post build copy" operation, which isn't well-supported in rust at time of
writing. This crate is a fork of https://github.com/prenwyn/copy_to_output that implements more managed helpers +
writing. This crate is inspired by https://github.com/prenwyn/copy_to_output, but implements more managed helpers +
addresses some of the missing scenarios (again, at time of writing).

If any scenarios are missing, please contribute!
Expand Down
6 changes: 0 additions & 6 deletions build.rs

This file was deleted.

53 changes: 17 additions & 36 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
//! <br>
//!
//! Provides a generalized implementation for a "post build copy" operation, which isn't
//! well-supported in rust at time of writing. This crate is a fork of
//! https://github.com/prenwyn/copy_to_output that implements more managed helpers + addresses some
//! well-supported in rust at time of writing. This crate is inspired by
//! <https://github.com/prenwyn/copy_to_output>, but implements more managed helpers + addresses some
//! of the missing scenarios (again, at time of writing).
//!
//! As the name implies, the goal here is to provide coverage for all possible build scenarios as
Expand All @@ -18,9 +18,6 @@
//! # Examples
//! - Use in `build.rs`
//!
//! ```
//!
//! ```
//!
//! # Scenario Coverage
//!
Expand Down Expand Up @@ -53,44 +50,35 @@

extern crate core;

use anyhow::*;
use anyhow::{anyhow, Result};
use fs_extra::copy_items;
use fs_extra::dir::CopyOptions;
use project_root::get_project_root;
use std::env;
use std::path::Path;

pub fn copy_to_output(path: &str) -> Result<()> {
copy_to_output_for_build_type(path, &env::var("PROFILE").expect("Could not load env:PROFILE"))
copy_to_output_for_build_type(path, &env::var("PROFILE")?)
}

pub fn copy_to_output_for_build_type(path: &str, build_type: &str) -> Result<()> {
let mut cargo_cache_command = format!("cargo:rerun-if-changed={}", path).to_owned();

if std::fs::metadata(path).expect("Could not pull metadata for path").is_dir() {
cargo_cache_command.push_str("/*");
}

// Re-runs script if any files changed
println!("{}", cargo_cache_command);
copy_to_output_no_cargo(path, build_type)
}

/// Advanced usage, leaves cargo commands up to you.
pub fn copy_to_output_no_cargo(path: &str, build_type: &str) -> Result<()> {
let mut options = CopyOptions::new();
let mut out_path = get_project_root()?;
out_path.push("target");

// TODO: This is a hack, ideally we would plug into https://docs.rs/cargo/latest/cargo/core/compiler/enum.CompileKind.html
let triple = build_target::target_triple().unwrap();
if env::var_os("OUT_DIR").unwrap().to_str().unwrap().contains(&triple) {
out_path.push(triple)
// This is a hack, ideally we would plug into https://docs.rs/cargo/latest/cargo/core/compiler/enum.CompileKind.html
// However, since the path follows predictable rules https://doc.rust-lang.org/cargo/guide/build-cache.html
// we can just check our parent path for the pattern target/{triple}/{profile}.
// If it is present, we know CompileKind::Target was used, otherwise CompileKind::Host was used.
let triple = build_target::target_triple()?;

if env::var("OUT_DIR")?.contains(&format!("target{}{}", std::path::MAIN_SEPARATOR, triple)) {
out_path.push(triple);
}

out_path.push(build_type);

// Overwrite existing files with same name
let mut options = CopyOptions::new();
options.overwrite = true;
options.copy_inside = true;

Expand All @@ -101,21 +89,14 @@ pub fn copy_to_output_no_cargo(path: &str, build_type: &str) -> Result<()> {

/// Copies files to output
pub fn copy_to_output_by_path(path: &Path) -> Result<()> {
copy_to_output(path_to_str(path))
copy_to_output(path_to_str(path)?)
}

fn path_to_str(path: &Path) -> &str {
fn path_to_str(path: &Path) -> Result<&str> {
path.to_str()
.expect("Could not convert file path to string")
.ok_or(anyhow!("Could not convert file path to string"))
}

pub fn copy_to_output_by_path_for_build_type(path: &Path, build_type: &str) -> Result<()> {
copy_to_output_for_build_type(path_to_str(path), build_type)
}

/// Advanced usage, leaves cargo commands up to you.
pub fn copy_to_output_by_path_no_cargo(path: &Path, build_type: &str) -> Result<()> {
copy_to_output_no_cargo(path_to_str(path), build_type)
copy_to_output_for_build_type(path_to_str(path)?, build_type)
}


34 changes: 34 additions & 0 deletions tests/build_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use crate::common::{
build_environment, build_environment_with_target, custom_test_target, fake_crate_in_tempdir,
fake_workspace_in_tempdir, validate,
};

mod common;

#[test]
fn build_crate() {
let environment = fake_crate_in_tempdir();
build_environment(&environment);
validate(&environment, None);
}

#[test]
fn build_crate_target_specified() {
let environment = fake_crate_in_tempdir();
build_environment_with_target(&environment, custom_test_target());
validate(&environment, Some(custom_test_target()));
}

#[test]
fn build_workspace() {
let environment = fake_workspace_in_tempdir();
build_environment(&environment);
validate(&environment, None);
}

#[test]
fn build_workspace_target_specified() {
let environment = fake_workspace_in_tempdir();
build_environment_with_target(&environment, custom_test_target());
validate(&environment, Some(custom_test_target()));
}
1 change: 0 additions & 1 deletion tests/cargo_cache_tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

// Verify cache clears occur by:
// 1. Clone to temp dir and build
// 2. Edit a resource file
Expand Down
122 changes: 122 additions & 0 deletions tests/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use fs_extra::copy_items;
use fs_extra::dir::CopyOptions;
use std::fs;
use std::path::{Path, PathBuf};
use tempfile::TempDir;

pub struct TestEnvironment {
_handle: TempDir,
pub path: PathBuf,
}

// Creates a copy of the fake crate in a temp dir and returns handle
pub fn fake_crate_in_tempdir() -> TestEnvironment {
let mut environment = fake_workspace_in_tempdir();

// In order for the fake crate to work as expected, kill the workspace file that owns it.
fs::remove_file(environment.path.join("Cargo.toml")).expect("Failed to delete workspace toml");

// We just reused the workspace builder, fake crate is nested just append to the path.
environment.path = environment.path.join("fake_crate");

environment
}

pub fn fake_workspace_in_tempdir() -> TestEnvironment {
let dir = TempDir::new().expect("Failed to create temp dir");

let mut options = CopyOptions::new();
options.overwrite = true;
options.copy_inside = true;

copy_items(&[Path::new("./")], &dir.path(), &options).expect("Failed to copy");

let path = dir.path().join("tests").join("fake_workspace");

TestEnvironment { _handle: dir, path }
}

pub fn build_environment(environment: &TestEnvironment) {
let result = std::process::Command::new("cargo")
.current_dir(
environment
.path
.to_str()
.expect("Couldn't to_string environment path"),
)
.arg("build")
.output()
.expect("failed to execute process");

println!("{:?}", result.status);
println!("{:?}", std::str::from_utf8(&result.stdout).unwrap());
println!("{:?}", std::str::from_utf8(&result.stderr).unwrap());
}

pub fn build_environment_with_target(environment: &TestEnvironment, target: String) {
let result = std::process::Command::new("cargo")
.current_dir(
environment
.path
.to_str()
.expect("Couldn't to_string environment path"),
)
.arg("build")
.arg("--target")
.arg(target)
.output()
.expect("failed to execute process");

println!("{:?}", result.status);
println!("{:?}", std::str::from_utf8(&result.stdout).unwrap());
println!("{:?}", std::str::from_utf8(&result.stderr).unwrap());
}

pub fn validate(environment: &TestEnvironment, target: Option<String>) {
let base_path = environment.path.join("target");

let base_path = if let Some(target) = target {
base_path.join(target)
} else {
base_path
};

let base_path = base_path.join("debug");

assert!(base_path.join("empty").exists());
assert!(base_path.join("nested").exists());

assert!(base_path.join("nested").join("doublenested").exists());
assert!(base_path
.join("nested")
.join("doublenested")
.join("emptiest")
.exists());
assert!(base_path
.join("nested")
.join("doublenested")
.join("seconddoublenested.txt")
.exists());
assert!(base_path
.join("nested")
.join("doublenested")
.join("test3.txt")
.exists());

assert!(base_path.join("nested").join("emptier").exists());
assert!(base_path.join("nested").join("secondnested.txt").exists());
assert!(base_path.join("nested").join("test2.txt").exists());

assert!(base_path.join("second.txt").exists());
assert!(base_path.join("test.dat").exists());
assert!(base_path.join("test.txt").exists());
}

// Just makes running the tests on a windows machine easier
pub fn custom_test_target() -> String {
if cfg!(target_os = "windows") {
"x86_64-pc-windows-msvc".to_string()
} else {
"x86_64-unknown-linux-gnu".to_string()
}
}
9 changes: 0 additions & 9 deletions tests/fake_crate/build.rs

This file was deleted.

6 changes: 6 additions & 0 deletions tests/fake_workspace/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[workspace]
resolver = "2"

members = [
"fake_crate"
]
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ version = "1.0.0"
edition = "2021"

[build-dependencies]
build_copy_to_output = { path = "../Omnicopy-To-Outputbuild" }
omnicopy_to_output = { path = "../../../" }
25 changes: 25 additions & 0 deletions tests/fake_workspace/fake_crate/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use omnicopy_to_output::copy_to_output;
use std::fs;
use std::path::Path;

fn main() -> Result<(), Box<dyn std::error::Error>> {
// Can't commit empty directories to git, dynamically create to ensure copying them works properly.
fs::create_dir_all(Path::new("res").join("empty")).unwrap();
fs::create_dir_all(Path::new("res").join("nested").join("emptier")).unwrap();
fs::create_dir_all(
Path::new("res")
.join("nested")
.join("doublenested")
.join("emptiest"),
)
.unwrap();

// Bin-place resource files
copy_to_output("res/nested").unwrap();
copy_to_output("res/empty").unwrap();
copy_to_output("res/test.dat").unwrap();
copy_to_output("res/test.txt").unwrap();
copy_to_output("res/second.txt").unwrap();

Ok(())
}
Empty file.
3 changes: 3 additions & 0 deletions tests/fake_workspace/fake_crate/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub fn hello_world() {
println!("Hello world!")
}
Loading