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

Feature/fix cross compilation #698

Merged
merged 11 commits into from
Feb 26, 2021
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
48 changes: 46 additions & 2 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
pull_request:

jobs:
build:
linux:
runs-on: ubuntu-latest
strategy:
matrix:
Expand All @@ -31,7 +31,7 @@ jobs:
- name: clean
run: cargo clean
- name: build
run: cargo build --verbose
run: cargo build
env:
RUST_BACKTRACE: 1
- name: test
Expand All @@ -52,3 +52,47 @@ jobs:
--data '{"build": true}' \
https://registry.hub.docker.com/u/xd009642/tarpaulin/trigger/${{ secrets.DOCKER_TOKEN }}/
if: github.ref == 'ref/heads/master' || github.ref == 'refs/heads/develop'
windows:
runs-on: windows-latest
strategy:
matrix:
version:
- nightly
target:
- x86_64-pc-windows-gnu
- x86_64-pc-windows-msvc
fail-fast: false
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.version }}
override: true
- name: build
run: cargo build
- name: test
run: cargo test -- --test-threads 1 || true
env:
RUST_BACKTRACE: 1
mac:
runs-on: macos-latest
strategy:
matrix:
version:
- nightly
target:
- x86_64-pc-windows-gnu
- x86_64-pc-windows-msvc
fail-fast: false
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.version }}
override: true
- name: build
run: cargo build
- name: test
run: cargo test -- --test-threads 1 || true
env:
RUST_BACKTRACE: 1
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ start of the support work.
### Changed
- Make doctest prefix matching less specific as the naming convention changed again
- Ensure report is always generated if coverage is below failure threshold
- Rearrange crate internals and enable cross compilation for windows and macos.
This doesn't allow tarpaulin to work on these Operating Systems but it will
print an error and exit instead of failing to build

### Removed

Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

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

9 changes: 6 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,10 @@ git2 = "0.13"
humantime-serde = "1"
indexmap = { version = "1.6.1", features = ["serde-1"] }
lazy_static = "1.0"
libc = "0.2.86"
tracing = { version = "0.1", default-features = false }
tracing-subscriber = {version = "0.2.16", default-features = false, features = ["env-filter", "fmt", "chrono", "ansi", "smallvec", "tracing-log"]}
memmap = "0.7.0"
nix = "0.20.0"
object = "0.23"
procfs = "0.9"
proc-macro2 = { version = "1.0", features = ["span-locations"] }
quick-xml = "0.22"
quote = "1.0"
Expand All @@ -47,6 +44,12 @@ serde_json = "1.0"
syn = { version = "1.0", features = ["full"]}
toml = "0.5"
walkdir = "2.3.1"
cfg-if = "1.0.0"

[target.'cfg(target_os = "linux")'.dependencies]
libc = "0.2.86"
nix = "0.20.0"
procfs = "0.9"

[features]
default = []
Expand Down
4 changes: 4 additions & 0 deletions src/errors/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::report::cobertura;
use std::fmt::{self, Display, Formatter};

/// Error states that could be returned from tarpaulin
#[derive(Debug)]
pub enum RunError {
Expand All @@ -23,6 +24,7 @@ pub enum RunError {
OutFormat(String),
IO(std::io::Error),
StateMachine(String),
#[cfg(target_os = "linux")]
NixError(nix::Error),
Html(String),
XML(cobertura::Error),
Expand Down Expand Up @@ -50,6 +52,7 @@ impl Display for RunError {
Self::OutFormat(e) => write!(f, "{}", e),
Self::IO(e) => write!(f, "{}", e),
Self::StateMachine(e) => write!(f, "Error running test: {}", e),
#[cfg(target_os = "linux")]
Self::NixError(e) => write!(f, "{}", e),
Self::Html(e) => write!(f, "Failed to generate HTML report! Error: {}", e),
Self::XML(e) => write!(f, "Failed to generate XML report! Error: {}", e),
Expand All @@ -69,6 +72,7 @@ impl From<std::io::Error> for RunError {
}
}

#[cfg(target_os = "linux")]
impl From<nix::Error> for RunError {
fn from(e: nix::Error) -> Self {
RunError::NixError(e)
Expand Down
25 changes: 16 additions & 9 deletions src/event_log.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
use crate::cargo::TestBinary;
#[cfg(target_os = "linux")]
use crate::ptrace_control::*;
use crate::statemachine::{ProcessInfo, TracerAction};
#[cfg(target_os = "linux")]
use crate::statemachine::ProcessInfo;
use crate::statemachine::TracerAction;
use crate::traces::{Location, TraceMap};
use chrono::offset::Local;
#[cfg(target_os = "linux")]
use nix::libc::*;
#[cfg(target_os = "linux")]
use nix::sys::{signal::Signal, wait::WaitStatus};
use serde::{Deserialize, Serialize};
use std::cell::RefCell;
Expand All @@ -20,8 +25,8 @@ pub enum Event {

#[derive(Clone, Default, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct TraceEvent {
pid: Option<pid_t>,
child: Option<pid_t>,
pid: Option<i64>,
child: Option<i64>,
signal: Option<String>,
addr: Option<u64>,
return_val: Option<i64>,
Expand All @@ -30,27 +35,28 @@ pub struct TraceEvent {
}

impl TraceEvent {
#[cfg(target_os = "linux")]
pub(crate) fn new_from_action(action: &TracerAction<ProcessInfo>) -> Self {
match *action {
TracerAction::TryContinue(t) => TraceEvent {
pid: Some(t.pid.as_raw()),
pid: Some(t.pid.as_raw().into()),
signal: t.signal.map(|x| x.to_string()),
description: "Try continue child".to_string(),
..Default::default()
},
TracerAction::Continue(t) => TraceEvent {
pid: Some(t.pid.as_raw()),
pid: Some(t.pid.as_raw().into()),
signal: t.signal.map(|x| x.to_string()),
description: "Continue child".to_string(),
..Default::default()
},
TracerAction::Step(t) => TraceEvent {
pid: Some(t.pid.as_raw()),
pid: Some(t.pid.as_raw().into()),
description: "Step child".to_string(),
..Default::default()
},
TracerAction::Detach(t) => TraceEvent {
pid: Some(t.pid.as_raw()),
pid: Some(t.pid.as_raw().into()),
description: "Detach child".to_string(),
..Default::default()
},
Expand All @@ -61,8 +67,9 @@ impl TraceEvent {
}
}

#[cfg(target_os = "linux")]
pub(crate) fn new_from_wait(wait: &WaitStatus, offset: u64, traces: &TraceMap) -> Self {
let pid = wait.pid().map(|p| p.as_raw());
let pid = wait.pid().map(|p| p.as_raw().into());
let mut event = TraceEvent {
pid,
..Default::default()
Expand Down Expand Up @@ -94,7 +101,7 @@ impl TraceEvent {
PTRACE_EVENT_CLONE => {
event.description = "Ptrace Clone".to_string();
if *sig == Signal::SIGTRAP {
event.child = get_event_data(*pid).ok().map(|x| x as pid_t);
event.child = get_event_data(*pid).ok();
}
}
PTRACE_EVENT_FORK => {
Expand Down
131 changes: 1 addition & 130 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,13 @@ use crate::path_utils::*;
use crate::process_handling::*;
use crate::report::report_coverage;
use crate::source_analysis::{LineAnalysis, SourceAnalysis};
use crate::statemachine::*;
use crate::test_loader::*;
use crate::traces::*;
use nix::unistd::*;
use std::collections::HashMap;
use std::env;
use std::ffi::CString;
use std::fs::create_dir_all;
use std::path::{Path, PathBuf};
use tracing::{debug, error, info, trace_span, warn};
use tracing::{debug, error, info, warn};
use tracing_subscriber::{filter::LevelFilter, EnvFilter};

pub mod branching;
pub mod breakpoint;
pub mod cargo;
pub mod config;
pub mod errors;
Expand All @@ -32,8 +25,6 @@ mod statemachine;
pub mod test_loader;
pub mod traces;

mod ptrace_control;

const RUST_LOG_ENV: &str = "RUST_LOG";

pub fn setup_logging(color: Color, debug: bool, verbose: bool) {
Expand Down Expand Up @@ -227,123 +218,3 @@ pub fn launch_tarpaulin(
}
Ok((result, return_code))
}

/// Returns the coverage statistics for a test executable in the given workspace
pub fn get_test_coverage(
test: &TestBinary,
analysis: &HashMap<PathBuf, LineAnalysis>,
config: &Config,
ignored: bool,
logger: &Option<EventLog>,
) -> Result<Option<(TraceMap, i32)>, RunError> {
if !test.path().exists() {
return Ok(None);
}
if let Err(e) = limit_affinity() {
warn!("Failed to set processor affinity {}", e);
}
if let Some(log) = logger.as_ref() {
log.push_binary(test.clone());
}
unsafe {
match fork() {
Ok(ForkResult::Parent { child }) => {
match collect_coverage(test.path(), child, analysis, config, logger) {
Ok(t) => Ok(Some(t)),
Err(e) => Err(RunError::TestCoverage(e.to_string())),
}
}
Ok(ForkResult::Child) => {
info!("Launching test");
execute_test(test, ignored, config)?;
Ok(None)
}
Err(err) => Err(RunError::TestCoverage(format!(
"Failed to run test {}, Error: {}",
test.path().display(),
err.to_string()
))),
}
}
}

/// Collects the coverage data from the launched test
fn collect_coverage(
test_path: &Path,
test: Pid,
analysis: &HashMap<PathBuf, LineAnalysis>,
config: &Config,
logger: &Option<EventLog>,
) -> Result<(TraceMap, i32), RunError> {
let mut ret_code = 0;
let mut traces = generate_tracemap(test_path, analysis, config)?;
{
let span = trace_span!("Collect coverage", pid=%test);
let _enter = span.enter();
let (mut state, mut data) =
create_state_machine(test, &mut traces, analysis, config, logger);
loop {
state = state.step(&mut data, config)?;
if state.is_finished() {
if let TestState::End(i) = state {
ret_code = i;
}
break;
}
}
}
Ok((traces, ret_code))
}

/// Launches the test executable
fn execute_test(test: &TestBinary, ignored: bool, config: &Config) -> Result<(), RunError> {
let exec_path = CString::new(test.path().to_str().unwrap()).unwrap();
info!("running {}", test.path().display());
let _ = match test.manifest_dir() {
Some(md) => env::set_current_dir(&md),
None => env::set_current_dir(&config.root()),
};

let mut envars: Vec<CString> = Vec::new();

for (key, value) in env::vars() {
let mut temp = String::new();
temp.push_str(key.as_str());
temp.push('=');
temp.push_str(value.as_str());
envars.push(CString::new(temp).unwrap());
}
let mut argv = if ignored {
vec![exec_path.clone(), CString::new("--ignored").unwrap()]
} else {
vec![exec_path.clone()]
};
if config.verbose {
envars.push(CString::new("RUST_BACKTRACE=1").unwrap());
}
for s in &config.varargs {
argv.push(CString::new(s.as_bytes()).unwrap_or_default());
}
argv.push(CString::new("--color").unwrap_or_default());
argv.push(CString::new(config.color.to_string().to_ascii_lowercase()).unwrap_or_default());

if let Some(s) = test.pkg_name() {
envars.push(CString::new(format!("CARGO_PKG_NAME={}", s)).unwrap_or_default());
}
if let Some(s) = test.pkg_version() {
envars.push(CString::new(format!("CARGO_PKG_VERSION={}", s)).unwrap_or_default());
}
if let Some(s) = test.pkg_authors() {
envars.push(CString::new(format!("CARGO_PKG_AUTHORS={}", s.join(":"))).unwrap_or_default());
}
if let Some(s) = test.manifest_dir() {
envars
.push(CString::new(format!("CARGO_MANIFEST_DIR={}", s.display())).unwrap_or_default());
}
if config.engine == TraceEngine::Llvm || config.engine == TraceEngine::Auto {
// Used for llvm coverage to avoid report naming clashes
envars.push(CString::new("LLVM_PROFILE_FILE=default_%p.profraw").unwrap_or_default());
}

execute(exec_path, &argv, envars.as_slice())
}
File renamed without changes.
Loading