From 7b7a6f64655e283f40d58b54b3b39f56c5d6d8f4 Mon Sep 17 00:00:00 2001 From: Jason Ozias Date: Tue, 9 Feb 2021 18:45:19 -0500 Subject: [PATCH] Attempt #2 to fix code coverage with kcov (#33) * Attempt #2 to fix code coverage with kcov * Fixed scripts issue * testing * typo in travis.yml * using tarpaulin * fixed up scripts a bit * removed unused script * some code coverage * testing * testing * moar testing * worktree testing * worktree testing * debugging worktree test in CI * debugging worktree test in CI * debugging worktree test in CI * testing refactor * more testing * more test coverage * last test for coverage * better detached head test * run against beta, nightly also Co-authored-by: Jason Ozias --- .travis.yml | 41 ++---- README.md | 2 +- build.rs | 2 - src/output/envvar.rs | 185 +++++++++++++++++++++---- src/output/mod.rs | 100 +++++++++++-- testdata/badgit | 1 + testdata/blah/worktrees/vergen-1/HEAD | 1 + testdata/blah2/worktrees/vergen-1/HEAD | 1 + testdata/blahgit | 1 + testdata/blahgit2 | 1 + testdata/gitdir/HEAD | 1 + testdata/gitdir/kcov | 1 + testdata/gitdir2/HEAD | 1 + 13 files changed, 273 insertions(+), 65 deletions(-) create mode 120000 testdata/badgit create mode 100644 testdata/blah/worktrees/vergen-1/HEAD create mode 100644 testdata/blah2/worktrees/vergen-1/HEAD create mode 100644 testdata/blahgit create mode 100644 testdata/blahgit2 create mode 100644 testdata/gitdir/HEAD create mode 100644 testdata/gitdir/kcov create mode 100644 testdata/gitdir2/HEAD diff --git a/.travis.yml b/.travis.yml index 44712359..e763a3da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,37 +1,20 @@ +dist: bionic language: rust - +addons: + apt: + packages: + - libssl-dev +cache: cargo rust: -- stable -- beta -- nightly + - stable + - beta + - nightly os: -- linux + - linux -addons: - apt: - packages: - - libcurl4-openssl-dev - - libelf-dev - - libdw-dev - - cmake - - gcc - - binutils-dev - - libiberty-dev +before_script: cargo install cargo-tarpaulin script: "./scripts/run-tests.sh" -after_success: | - wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz && - tar xzf master.tar.gz && - cd kcov-master && - mkdir build && - cd build && - cmake .. && - make && - make install DESTDIR=../../kcov-build && - cd ../.. && - rm -rf kcov-master && - for file in target/debug/build/vergen-*[^\.d]; do mkdir -p "target/cov/$(basename $file)"; ./kcov-build/usr/local/bin/kcov --exclude-pattern=/.cargo,/usr/lib --verify "target/cov/$(basename $file)" "$file"; done && - bash <(curl -s https://codecov.io/bash) && - echo "Uploaded code coverage" \ No newline at end of file +after_success: cargo tarpaulin --ciserver travis-ci --coveralls $TRAVIS_JOB_ID \ No newline at end of file diff --git a/README.md b/README.md index 0009157f..35714c12 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ | Appveyor | [![Build status](https://ci.appveyor.com/api/projects/status/fjliwvxqayyecl1j?svg=true)](https://ci.appveyor.com/project/CraZySacX/vergen)| ## Code Coverage -[![codecov](https://codecov.io/gh/rustyhorde/vergen/branch/master/graph/badge.svg)](https://codecov.io/gh/rustyhorde/vergen) +[![Coverage Status](https://coveralls.io/repos/github/rustyhorde/vergen/badge.svg?branch=masterv)](https://coveralls.io/github/rustyhorde/vergen?branch=master) ## Documentation [Documentation](https://docs.rs/vergen) diff --git a/build.rs b/build.rs index 9d996a09..f6d824c3 100644 --- a/build.rs +++ b/build.rs @@ -1,5 +1,3 @@ -extern crate chrono; - pub fn main() { let now = chrono::Utc::now(); println!( diff --git a/src/output/envvar.rs b/src/output/envvar.rs index a2c1a859..f05cdc41 100644 --- a/src/output/envvar.rs +++ b/src/output/envvar.rs @@ -9,8 +9,14 @@ //! Build time information. use crate::constants::ConstantsFlags; use crate::output::generate_build_info; -use std::fs::{self, File}; -use std::io::Read; +use std::{ + fs::{self, File}, + io::Write, +}; +use std::{ + io::{self, Read}, + path::Path, +}; use std::{path::PathBuf, process::Command}; use super::Result; @@ -29,8 +35,6 @@ use super::Result; /// # Example `build.rs` /// /// ``` -/// extern crate vergen; -/// /// use vergen::{ConstantsFlags, generate_cargo_keys}; /// /// fn main() { @@ -38,50 +42,69 @@ use super::Result; /// } /// ``` pub fn generate_cargo_keys(flags: ConstantsFlags) -> Result<()> { + let base = super::run_command(Command::new("git").args(&["rev-parse", "--show-toplevel"])); + let mut git_dir_or_file = PathBuf::from(base); + git_dir_or_file.push(".git"); + gen_cargo_keys( + &flags, + git_dir_or_file, + &mut io::stdout(), + &mut io::stderr(), + ) +} + +fn gen_cargo_keys( + flags: &ConstantsFlags, + git_path: P, + stdout: &mut T, + stderr: &mut E, +) -> Result<()> +where + P: AsRef, + T: Write, + E: Write, +{ // Generate the build info map. let build_info = generate_build_info(flags)?; // Generate the 'cargo:' key output for (k, v) in build_info { - println!("cargo:rustc-env={}={}", k.name(), v); + writeln!(stdout, "cargo:rustc-env={}={}", k.name(), v)?; } - let base = super::run_command(Command::new("git").args(&["rev-parse", "--show-toplevel"])); - let mut git_dir_or_file = PathBuf::from(base); - git_dir_or_file.push(".git"); - - if let Ok(metadata) = fs::metadata(&git_dir_or_file) { + if let Ok(metadata) = fs::symlink_metadata(&git_path) { if metadata.is_dir() { // Echo the HEAD path - let git_head_path = git_dir_or_file.join("HEAD"); - println!("cargo:rerun-if-changed={}", git_head_path.display()); + let gp = git_path.as_ref().to_path_buf(); + let git_head_path = gp.join("HEAD"); + writeln!(stdout, "cargo:rerun-if-changed={}", git_head_path.display())?; // Determine where HEAD points and echo that path also. let mut f = File::open(&git_head_path)?; let mut git_head_contents = String::new(); let _ = f.read_to_string(&mut git_head_contents)?; - eprintln!("HEAD contents: {}", git_head_contents); + writeln!(stderr, "HEAD contents: {}", git_head_contents)?; let ref_vec: Vec<&str> = git_head_contents.split(": ").collect(); if ref_vec.len() == 2 { let current_head_file = ref_vec[1].trim(); - let git_refs_path = PathBuf::from(".git").join(current_head_file); - println!("cargo:rerun-if-changed={}", git_refs_path.display()); + let git_refs_path = gp.join(current_head_file); + writeln!(stdout, "cargo:rerun-if-changed={}", git_refs_path.display())?; } else { - eprintln!("You are most likely in a detached HEAD state"); + writeln!(stderr, "You are most likely in a detached HEAD state")?; } } else if metadata.is_file() { // We are in a worktree, so find out where the actual worktrees//HEAD file is. - let mut git_file = File::open(&git_dir_or_file)?; + let mut git_file = File::open(&git_path)?; let mut git_contents = String::new(); let _ = git_file.read_to_string(&mut git_contents)?; let dir_vec: Vec<&str> = git_contents.split(": ").collect(); - eprintln!(".git contents: {}", git_contents); + writeln!(stderr, ".git contents: {}", git_contents)?; let git_path = dir_vec[1].trim(); - // Echo the HEAD psth + // Echo the HEAD path let git_head_path = PathBuf::from(git_path).join("HEAD"); - println!("cargo:rerun-if-changed={}", git_head_path.display()); + writeln!(stdout, "cargo:rerun-if-changed={}", git_head_path.display())?; // Find out what the full path to the .git dir is. let mut actual_git_dir = PathBuf::from(git_path); @@ -92,22 +115,136 @@ pub fn generate_cargo_keys(flags: ConstantsFlags) -> Result<()> { let mut f = File::open(&git_head_path)?; let mut git_head_contents = String::new(); let _ = f.read_to_string(&mut git_head_contents)?; - eprintln!("HEAD contents: {}", git_head_contents); + writeln!(stderr, "HEAD contents: {}", git_head_contents)?; let ref_vec: Vec<&str> = git_head_contents.split(": ").collect(); if ref_vec.len() == 2 { let current_head_file = ref_vec[1].trim(); let git_refs_path = actual_git_dir.join(current_head_file); - println!("cargo:rerun-if-changed={}", git_refs_path.display()); + writeln!(stdout, "cargo:rerun-if-changed={}", git_refs_path.display())?; } else { - eprintln!("You are most likely in a detached HEAD state"); + writeln!(stderr, "You are most likely in a detached HEAD state")?; } } else { return Err("Invalid .git format (Not a directory or a file)".into()); }; } else { - eprintln!("Unable to generate 'cargo:rerun-if-changed'"); + writeln!(stderr, "Unable to generate 'cargo:rerun-if-changed'")?; } Ok(()) } + +#[cfg(test)] +mod test { + use super::{gen_cargo_keys, generate_cargo_keys}; + use crate::constants::ConstantsFlags; + + #[test] + fn pub_api() { + assert!(generate_cargo_keys(ConstantsFlags::all()).is_ok()); + } + + #[test] + fn gitdir() { + let mut buf_stdout = Vec::new(); + let mut buf_stderr = Vec::new(); + + assert!(gen_cargo_keys( + &ConstantsFlags::all(), + "testdata/gitdir", + &mut buf_stdout, + &mut buf_stderr, + ) + .is_ok()); + let stdout = String::from_utf8_lossy(&buf_stdout); + assert!(stdout.contains("cargo:rerun-if-changed=testdata/gitdir/HEAD")); + assert!(stdout.contains("cargo:rerun-if-changed=testdata/gitdir/kcov")); + } + + #[test] + fn detached_gitdir() { + let mut buf_stdout = Vec::new(); + let mut buf_stderr = Vec::new(); + + assert!(gen_cargo_keys( + &ConstantsFlags::all(), + "testdata/gitdir2", + &mut buf_stdout, + &mut buf_stderr, + ) + .is_ok()); + let stdout = String::from_utf8_lossy(&buf_stdout); + let stderr = String::from_utf8_lossy(&buf_stderr); + assert!(stdout.contains("cargo:rerun-if-changed=testdata/gitdir2/HEAD")); + assert!(stderr.contains("You are most likely in a detached HEAD state")); + } + + #[test] + fn worktree() { + let mut buf_stdout = Vec::new(); + let mut buf_stderr = Vec::new(); + + assert!(gen_cargo_keys( + &ConstantsFlags::all(), + "testdata/blahgit", + &mut buf_stdout, + &mut buf_stderr, + ) + .is_ok()); + + let stdout = String::from_utf8_lossy(&buf_stdout); + assert!(stdout.contains("cargo:rerun-if-changed=testdata/blah/worktrees/vergen-1/HEAD")); + assert!(stdout.contains("cargo:rerun-if-changed=testdata/blah/refs/heads/vergen-1")); + } + + #[test] + fn detached_worktree() { + let mut buf_stdout = Vec::new(); + let mut buf_stderr = Vec::new(); + + assert!(gen_cargo_keys( + &ConstantsFlags::all(), + "testdata/blahgit2", + &mut buf_stdout, + &mut buf_stderr, + ) + .is_ok()); + + let stdout = String::from_utf8_lossy(&buf_stdout); + let stderr = String::from_utf8_lossy(&buf_stderr); + assert!(stdout.contains("cargo:rerun-if-changed=testdata/blah2/worktrees/vergen-1/HEAD")); + assert!(stderr.contains("You are most likely in a detached HEAD state")); + } + + #[test] + fn error_on_symlink() { + let mut buf_stdout = Vec::new(); + let mut buf_stderr = Vec::new(); + + assert!(gen_cargo_keys( + &ConstantsFlags::all(), + "testdata/badgit", + &mut buf_stdout, + &mut buf_stderr, + ) + .is_err()); + } + + #[test] + fn invalid_file() { + let mut buf_stdout = Vec::new(); + let mut buf_stderr = Vec::new(); + + assert!(gen_cargo_keys( + &ConstantsFlags::all(), + "xxxxzzzyyy", + &mut buf_stdout, + &mut buf_stderr, + ) + .is_ok()); + + let stderr = String::from_utf8_lossy(&buf_stderr); + assert!(stderr.contains("Unable to generate 'cargo:rerun-if-changed'")); + } +} diff --git a/src/output/mod.rs b/src/output/mod.rs index 2d8a3d8a..f885ef98 100644 --- a/src/output/mod.rs +++ b/src/output/mod.rs @@ -14,13 +14,18 @@ use crate::constants::{ }; use chrono::Utc; use rustc_version::Channel; -use std::{collections::HashMap, env, process::Command}; +use std::{ + collections::HashMap, + env, + io::{Read, Write}, + process::{Command, Stdio}, +}; pub(crate) mod envvar; type Result = std::result::Result>; -pub(crate) fn generate_build_info(flags: ConstantsFlags) -> Result> { +pub(crate) fn generate_build_info(flags: &ConstantsFlags) -> Result> { let mut build_info = HashMap::new(); let now = Utc::now(); @@ -34,13 +39,13 @@ pub(crate) fn generate_build_info(flags: ConstantsFlags) -> Result Result Result<()> { if flags.contains(ConstantsFlags::TAG_DIRTY) { - let diff = run_command(Command::new("git").args(&["diff"])); - if !diff.is_empty() { + let status_proc = Command::new("git") + .args(&["status"]) + .stdout(Stdio::piped()) + .spawn()?; + let mut buf = String::new(); + let _ = status_proc.stdout.unwrap().read_to_string(&mut buf)?; + + let grep = Command::new("grep") + .args(&["Changes not staged\\|Untracked"]) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn()?; + grep.stdin.unwrap().write_all(buf.as_bytes())?; + let mut buf2 = String::new(); + let _ = grep.stdout.unwrap().read_to_string(&mut buf2)?; + + if !buf2.is_empty() { sha.push_str("-dirty"); } } + + Ok(()) } pub(crate) fn run_command(command: &mut Command) -> String { @@ -190,11 +212,71 @@ impl VergenKey { #[cfg(test)] mod test { - use super::run_command; - use std::process::Command; + use super::{ + generate_build_info, run_command, Result, + VergenKey::{ + self, Branch, BuildDate, BuildTimestamp, CommitDate, HostTriple, RustcChannel, + RustcSemver, Semver, SemverLightweight, Sha, ShortSha, TargetTriple, + }, + }; + use crate::constants::ConstantsFlags; + use std::{collections::HashMap, fs::OpenOptions, process::Command}; + + fn check_build_info(build_info: &HashMap) { + assert!(build_info.get(&Branch).is_some()); + assert!(build_info.get(&BuildDate).is_some()); + assert!(build_info.get(&BuildTimestamp).is_some()); + assert!(build_info.get(&CommitDate).is_some()); + assert!(build_info.get(&HostTriple).is_some()); + assert!(build_info.get(&RustcChannel).is_some()); + assert!(build_info.get(&RustcSemver).is_some()); + assert!(build_info.get(&Semver).is_some()); + assert!(build_info.get(&SemverLightweight).is_some()); + assert!(build_info.get(&Sha).is_some()); + assert!(build_info.get(&ShortSha).is_some()); + assert!(build_info.get(&TargetTriple).is_some()); + } #[test] fn bad_command_generates_unknown() { assert_eq!(run_command(&mut Command::new("zzzyyyxxx")), "UNKNOWN"); } + + #[test] + fn build_info_semver() -> Result<()> { + let mut flags = ConstantsFlags::all(); + flags.toggle(ConstantsFlags::SEMVER_FROM_CARGO_PKG); + + let build_info = generate_build_info(&flags)?; + check_build_info(&build_info); + Ok(()) + } + + #[test] + fn build_info_cargo_pkg() -> Result<()> { + let mut flags = ConstantsFlags::all(); + flags.toggle(ConstantsFlags::SEMVER); + + let build_info = generate_build_info(&flags)?; + check_build_info(&build_info); + Ok(()) + } + + #[test] + fn dirty_semver() -> Result<()> { + let _file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open("blah")?; + let mut flags = ConstantsFlags::all(); + flags.toggle(ConstantsFlags::SEMVER_FROM_CARGO_PKG); + let mut build_info = generate_build_info(&flags)?; + + let _ = Command::new("rm").args(&["blah"]).spawn(); + + let sha = build_info.entry(Sha).or_insert_with(String::new); + assert!(sha.ends_with("-dirty")); + Ok(()) + } } diff --git a/testdata/badgit b/testdata/badgit new file mode 120000 index 00000000..5a19b83f --- /dev/null +++ b/testdata/badgit @@ -0,0 +1 @@ +../.gitignore \ No newline at end of file diff --git a/testdata/blah/worktrees/vergen-1/HEAD b/testdata/blah/worktrees/vergen-1/HEAD new file mode 100644 index 00000000..c1e73f19 --- /dev/null +++ b/testdata/blah/worktrees/vergen-1/HEAD @@ -0,0 +1 @@ +ref: refs/heads/vergen-1 \ No newline at end of file diff --git a/testdata/blah2/worktrees/vergen-1/HEAD b/testdata/blah2/worktrees/vergen-1/HEAD new file mode 100644 index 00000000..94e6be03 --- /dev/null +++ b/testdata/blah2/worktrees/vergen-1/HEAD @@ -0,0 +1 @@ +0764a8bcd157dca64ea77af4970b295f785c7a53 \ No newline at end of file diff --git a/testdata/blahgit b/testdata/blahgit new file mode 100644 index 00000000..36b78b0a --- /dev/null +++ b/testdata/blahgit @@ -0,0 +1 @@ +gitdir: testdata/blah/worktrees/vergen-1 \ No newline at end of file diff --git a/testdata/blahgit2 b/testdata/blahgit2 new file mode 100644 index 00000000..7f545f55 --- /dev/null +++ b/testdata/blahgit2 @@ -0,0 +1 @@ +gitdir: testdata/blah2/worktrees/vergen-1 \ No newline at end of file diff --git a/testdata/gitdir/HEAD b/testdata/gitdir/HEAD new file mode 100644 index 00000000..3849abf1 --- /dev/null +++ b/testdata/gitdir/HEAD @@ -0,0 +1 @@ +ref: kcov \ No newline at end of file diff --git a/testdata/gitdir/kcov b/testdata/gitdir/kcov new file mode 100644 index 00000000..94e6be03 --- /dev/null +++ b/testdata/gitdir/kcov @@ -0,0 +1 @@ +0764a8bcd157dca64ea77af4970b295f785c7a53 \ No newline at end of file diff --git a/testdata/gitdir2/HEAD b/testdata/gitdir2/HEAD new file mode 100644 index 00000000..94e6be03 --- /dev/null +++ b/testdata/gitdir2/HEAD @@ -0,0 +1 @@ +0764a8bcd157dca64ea77af4970b295f785c7a53 \ No newline at end of file