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

[WIP] add a command to install man pages #312

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
18 changes: 18 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions cargo-nextest/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ rust-version = "1.59"
camino = "1.0.9"
cfg-if = "1.0.0"
clap = { version = "3.2.6", features = ["derive", "env"] }
clap_mangen = "0.1.9"
# we don't use the tracing support
color-eyre = { version = "0.6.1", default-features = false }
dialoguer = "0.10.1"
Expand All @@ -23,6 +24,7 @@ enable-ansi-support = "0.1.2"
# we don't use the default formatter so we don't need default features
env_logger = { version = "0.9.0", default-features = false }
guppy = "0.14.2"
home = "0.5.3"
log = "0.4.17"
itertools = "0.10.3"
miette = { version = "4.7.1", features = ["fancy"] }
Expand Down
23 changes: 20 additions & 3 deletions cargo-nextest/src/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

use crate::{
cargo_cli::{CargoCli, CargoOptions},
mangen::install_man,
output::{OutputContext, OutputOpts, OutputWriter},
reuse_build::{make_path_mapper, ArchiveFormatOpt, ReuseBuildOpts},
ExpectedError, Result, ReuseBuildKind,
Expand Down Expand Up @@ -55,14 +56,20 @@ impl CargoNextestApp {
}

#[derive(Debug, Subcommand)]
enum NextestSubcommand {
pub(crate) enum NextestSubcommand {
/// A next-generation test runner for Rust. <https://nexte.st>
Nextest(AppOpts),
}

#[derive(Debug, Args)]
/// cargo-nextest is a next-generation test runner for Rust projects.
///
/// Nextest runs tests in parallel and provides a rich set of features, such as partitioning test
/// runs, JUnit output, and archiving and reusing builds.
///
/// For the full documentation, see the nextest site at <https://nexte.st>.
#[derive(Debug, Parser)]
#[clap(version)]
struct AppOpts {
pub(crate) struct AppOpts {
/// Path to Cargo.toml
#[clap(long, global = true, value_name = "PATH")]
manifest_path: Option<Utf8PathBuf>,
Expand Down Expand Up @@ -1018,6 +1025,12 @@ impl App {

#[derive(Debug, Subcommand)]
enum SelfCommand {
/// Install man pages for nextest.
InstallMan {
/// The output directory [default: <current-exe-path>/../man]
output_dir: Option<Utf8PathBuf>,
},

#[cfg_attr(
not(feature = "self-update"),
doc = "This version of nextest does not have self-update enabled\n\
Expand Down Expand Up @@ -1064,6 +1077,10 @@ impl SelfCommand {
let output = output.init();

match self {
Self::InstallMan { output_dir } => {
install_man(output_dir)?;
Ok(0)
}
Self::Update {
version,
check,
Expand Down
33 changes: 33 additions & 0 deletions cargo-nextest/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,11 @@ pub enum ExpectedError {
reason: &'static str,
args: Vec<String>,
},
#[error(transparent)]
InstallManError {
#[from]
error: InstallManError,
},
}

impl ExpectedError {
Expand Down Expand Up @@ -311,6 +316,7 @@ impl ExpectedError {
NextestExitCode::EXPERIMENTAL_FEATURE_NOT_ENABLED
}
Self::FilterExpressionParseError { .. } => NextestExitCode::INVALID_FILTER_EXPRESSION,
Self::InstallManError { .. } => NextestExitCode::INSTALL_MAN_ERROR,
}
}

Expand Down Expand Up @@ -529,6 +535,11 @@ impl ExpectedError {
);
None
}
Self::InstallManError { error } => {
// This is a transparent error.
log::error!("{}", error);
error.source()
}
};

while let Some(err) = next_error {
Expand All @@ -537,3 +548,25 @@ impl ExpectedError {
}
}
}

#[derive(Debug, Error)]
#[doc(hidden)]
pub enum InstallManError {
#[error("could not determine current executable path")]
CurrentExe {
#[source]
error: std::io::Error,
},
#[error("error creating output directory `{path}`")]
CreateOutputDir {
path: Utf8PathBuf,
#[source]
error: std::io::Error,
},
#[error("error writing to `{path}`")]
WriteToFile {
path: Utf8PathBuf,
#[source]
error: std::io::Error,
},
}
1 change: 1 addition & 0 deletions cargo-nextest/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
mod cargo_cli;
mod dispatch;
mod errors;
mod mangen;
mod output;
mod reuse_build;
#[cfg(feature = "self-update")]
Expand Down
58 changes: 58 additions & 0 deletions cargo-nextest/src/mangen.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (c) The nextest Contributors
// SPDX-License-Identifier: MIT OR Apache-2.0

use crate::{AppOpts, InstallManError};
use camino::{Utf8Path, Utf8PathBuf};
use clap::CommandFactory;
use clap_mangen::Man;

pub(crate) fn install_man(output_dir: Option<Utf8PathBuf>) -> Result<(), InstallManError> {
let mut output_dir = match output_dir {
Some(d) => d,
None => {
let mut current_exe = std::env::current_exe()
.and_then(|home| {
Utf8PathBuf::try_from(home).map_err(|error| {
std::io::Error::new(std::io::ErrorKind::InvalidData, error)
})
})
.map_err(|error| InstallManError::CurrentExe { error })?;
// If the current exe is foo/bar/bin/cargo-nextest, the man directory is foo/bar/man.
current_exe.pop();
current_exe.pop();
current_exe.push("man");
current_exe
}
};

// All of nextest's commands go in man1.
output_dir.push("man1");

std::fs::create_dir_all(&output_dir).map_err(|error| InstallManError::CreateOutputDir {
path: output_dir.clone(),
error,
})?;

let command = AppOpts::command();

let man = Man::new(command.clone()).manual("Nextest Manual");
let path = output_dir.join("cargo-nextest.1");
render_to_file(&man, &path).map_err(|error| InstallManError::WriteToFile { path, error })?;

for subcommand in command.get_subcommands() {
let name = subcommand.get_name();
// XXX this line crashes with "Command list: Argument or group 'manifest-path' specified in
// 'conflicts_with*' for 'cargo-metadata' does not exist".
let man = Man::new(subcommand.clone()).manual("Nextest Manual");
let path = output_dir.join(format!("cargo-nextest-{}.1", name));
render_to_file(&man, &path)
.map_err(|error| InstallManError::WriteToFile { path, error })?;
}

Ok(())
}

fn render_to_file(man: &Man, path: &Utf8Path) -> Result<(), std::io::Error> {
let mut writer = std::fs::File::create(&path)?;
man.render(&mut writer)
}
3 changes: 3 additions & 0 deletions nextest-metadata/src/exit_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ impl NextestExitCode {
/// Writing data to stdout or stderr produced an error.
pub const WRITE_OUTPUT_ERROR: i32 = 110;

/// Installing man pages produced an error.
pub const INSTALL_MAN_ERROR: i32 = 120;

/// Downloading an update resulted in an error.
pub const UPDATE_ERROR: i32 = 90;

Expand Down