1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
//! Atomic operations on a cargo workspace
//!
//! This module contains operations that can be executed on a
//! workspace.  They take some set of inputs, modelled as fields, and
//! produce a shared output which is represented by `Result`

mod publish;
pub(self) use publish::{versions, Publish, PublishMod, PublishType};

mod error;
mod executor;
mod parser;

use crate::models::{CrateId, DepGraph};
pub use error::{OpError, Result};
use std::path::PathBuf;

trait RenderHelp {
    fn render_help(c: i32) -> !;
}

/// Render the help-page for a particular command
pub(crate) fn render_help(cmd: String) -> ! {
    match cmd.as_str() {
        "print" => Print::render_help(0),
        "publish" => Publish::render_help(0),
        c => {
            eprintln!("Unknown command `{}`", c);
            std::process::exit(2);
        }
    }
}

pub(crate) fn list_commands() {
    eprintln!("Available commands:\n");
    eprintln!(" - print: echo the selected crate set");
    eprintln!(" - publish: release new crates on crates.io");
}

/// Differentiating operation enum
pub enum Op {
    /// Publish a new version, according to some rules
    Publish(Publish),
    /// Print the query selection
    Print(Print),
}

impl Op {
    /// Parse an arg line into an operation to execute
    pub fn parse(line: Vec<String>) -> Self {
        match parser::run(line) {
            Some(op) => op,
            None => std::process::exit(2),
        }
    }

    pub(crate) fn execute(self, set: Vec<CrateId>, root: PathBuf, g: &mut DepGraph) {
        match self {
            Self::Publish(p) => publish::run(p, set, g),
            Self::Print(p) => executor::print(p, set, root, g),
        }
    }
}

/// Ask the user to be sure
pub(self) fn verify_user() {
    eprintln!("------");
    use std::io::{stdin, stdout, Write};
    let mut s = String::new();
    print!("Execute operations? [N|y]: ");
    let _ = stdout().flush();
    stdin().read_line(&mut s).expect("Failed to read term!");

    match s.trim() {
        "Y" | "y" => {}
        _ => std::process::exit(0),
    }
}

/// Selection of which type to print
pub enum Print {
    /// Default: just the package name
    Name,
    /// The path inside the repo
    Path { abs: bool },
    /// Both the name and path
    Both { abs: bool },
}

impl Default for Print {
    fn default() -> Self {
        Self::Name
    }
}

impl RenderHelp for Print {
    fn render_help(code: i32) -> ! {
        eprintln!("Print the selected set of crates");
        eprintln!("Usage: cargo ws2 <...> print [OPTIONS]\n");
        eprintln!("Available options:\n");
        eprintln!(" - path: print the path of the crate, instead of the name");
        eprintln!(" - both: print the both the path and the name");
        eprintln!(" - abs: (If `path` or `both`) Use an absolute path, instead of relative");
        std::process::exit(code)
    }
}