-
Notifications
You must be signed in to change notification settings - Fork 2.2k
enhancement(dev): Add dedicated dev tool #14990
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
Changes from 10 commits
a1afed9
9ebac12
3b71558
9f44785
fb2163f
ec58410
4de3c12
3d1ffa6
9e3d6f4
fd833a7
a2e000c
f43fb51
b9d8583
9939e81
f12f024
89d1892
25f08a8
953937b
5b68809
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| [package] | ||
| name = "vdev" | ||
| version = "0.1.0" | ||
| edition = "2021" | ||
| authors = ["Vector Contributors <vector@datadoghq.com>"] | ||
| license = "MPL-2.0" | ||
| readme = "README.md" | ||
| publish = false | ||
|
|
||
| [dependencies] | ||
| anyhow = "1.0.66" | ||
| atty = "0.2.14" | ||
| cached = "0.40.0" | ||
| clap = { version = "4.0.18", features = ["derive"] } | ||
| clap-verbosity-flag = "2.0.0" | ||
| confy = "0.5.1" | ||
| directories = "4.0.1" | ||
| # remove this when stabilized https://doc.rust-lang.org/stable/std/path/fn.absolute.html | ||
| dunce = "1.0.3" | ||
| env_logger = "0.9.1" | ||
| globset = "0.4.9" | ||
| hashlink = { version = "0.8.1", features = ["serde_impl"] } | ||
| home = "0.5.4" | ||
| indicatif = { version = "0.17.1", features = ["improved_unicode"] } | ||
| itertools = "0.10.5" | ||
| log = "0.4.17" | ||
| once_cell = "1.16.0" | ||
| os_info = { version = "3.5.1", default-features = false } | ||
| # watch https://github.com/epage/anstyle for official interop with Clap | ||
| owo-colors = { version = "3.5.0", features = ["supports-colors"] } | ||
| serde = { version = "1.0", features = ["derive"] } | ||
| serde_json = "1.0.87" | ||
| toml = "0.5.9" | ||
|
|
||
| # https://github.com/rust-lang/cargo/issues/6745#issuecomment-472667516 | ||
| [workspace] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| # vdev | ||
|
|
||
| ----- | ||
|
|
||
| This is the command line tooling for Vector development. | ||
|
|
||
| Table of Contents: | ||
|
|
||
| - [Installation](#installation) | ||
| - [Configuration](#configuration) | ||
| - [Repository](#repository) | ||
| - [Starship](#starship) | ||
| - [CLI](#cli) | ||
|
|
||
| ## Installation | ||
|
|
||
|
ofek marked this conversation as resolved.
|
||
| Run the following command from the root of the Vector repository: | ||
|
|
||
| ```text | ||
| cargo install -f --path vdev | ||
| ``` | ||
|
|
||
| ## Configuration | ||
|
|
||
| ### Repository | ||
|
|
||
| Setting the path to the repository explicitly allows the application to be used at any time no matter the current working directory. | ||
|
|
||
| ```text | ||
| vdev config set repo . | ||
| ``` | ||
|
|
||
| To test, enter your home directory and then run: | ||
|
|
||
| ```text | ||
| vdev exec ls | ||
| ``` | ||
|
|
||
| ### Starship | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a really nice touch! |
||
|
|
||
| A custom command for the [Starship](https://starship.rs) prompt is available. | ||
|
|
||
| ```toml | ||
| format = """ | ||
| ... | ||
| ${custom.vdev}\ | ||
| ... | ||
| $line_break\ | ||
| ... | ||
| $character""" | ||
|
|
||
| # <clipped> | ||
|
|
||
| [custom.vdev] | ||
| command = "vdev meta starship" | ||
| when = true | ||
| # Windows | ||
| # shell = ["cmd", "/C"] | ||
| # Other | ||
| # shell = ["sh", "--norc"] | ||
| ``` | ||
|
|
||
| ## CLI | ||
|
|
||
| The CLI uses [Clap](https://github.com/clap-rs/clap) with the `derive` construction mechanism and is stored in the [commands](src/commands) directory. | ||
|
|
||
| Every command group/namespace has its own directory with a `cli` module, including the root `vdev` command group. All commands have an `exec` method that provides the actual implementation, which in the case of command groups will be calling sub-commands. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,199 @@ | ||
| use anyhow::{bail, Result}; | ||
| use indicatif::{ProgressBar, ProgressStyle}; | ||
| use log::{Level, LevelFilter}; | ||
| use once_cell::sync::OnceCell; | ||
| use owo_colors::{ | ||
| OwoColorize, | ||
| Stream::{Stderr, Stdout}, | ||
| }; | ||
| use std::time::Duration; | ||
| use std::{borrow::Cow, process::Command}; | ||
|
|
||
| use crate::config::{Config, ConfigFile}; | ||
|
|
||
| static VERBOSITY: OnceCell<LevelFilter> = OnceCell::new(); | ||
| static CONFIG_FILE: OnceCell<ConfigFile> = OnceCell::new(); | ||
| static CONFIG: OnceCell<Config> = OnceCell::new(); | ||
| static PATH: OnceCell<String> = OnceCell::new(); | ||
|
|
||
| pub fn verbosity() -> &'static LevelFilter { | ||
| VERBOSITY.get().expect("verbosity is not initialized") | ||
| } | ||
|
|
||
| pub fn config_file() -> &'static ConfigFile { | ||
| CONFIG_FILE.get().expect("config file is not initialized") | ||
| } | ||
|
|
||
| pub fn config() -> &'static Config { | ||
| CONFIG.get().expect("config is not initialized") | ||
| } | ||
|
|
||
| pub fn path() -> &'static String { | ||
| PATH.get().expect("path is not initialized") | ||
| } | ||
|
|
||
| pub fn display<T: AsRef<str>>(text: T) { | ||
| // Simply bold rather than bright white for terminals with white backgrounds | ||
| println!( | ||
| "{}", | ||
| text.as_ref().if_supports_color(Stdout, |text| text.bold()) | ||
| ); | ||
| } | ||
|
|
||
| #[allow(dead_code)] | ||
| pub fn display_trace<T: AsRef<str>>(text: T) { | ||
| if Level::Trace <= *verbosity() { | ||
| eprintln!( | ||
| "{}", | ||
| text.as_ref().if_supports_color(Stderr, |text| text.bold()) | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| #[allow(dead_code)] | ||
| pub fn display_debug<T: AsRef<str>>(text: T) { | ||
| if Level::Debug <= *verbosity() { | ||
| eprintln!( | ||
| "{}", | ||
| text.as_ref().if_supports_color(Stderr, |text| text.bold()) | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| #[allow(dead_code)] | ||
| pub fn display_info<T: AsRef<str>>(text: T) { | ||
| if Level::Info <= *verbosity() { | ||
| eprintln!( | ||
| "{}", | ||
| text.as_ref().if_supports_color(Stderr, |text| text.bold()) | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| #[allow(dead_code)] | ||
| pub fn display_success<T: AsRef<str>>(text: T) { | ||
| if Level::Info <= *verbosity() { | ||
| eprintln!( | ||
| "{}", | ||
| text.as_ref() | ||
| .if_supports_color(Stderr, |text| text.bright_cyan()) | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| #[allow(dead_code)] | ||
| pub fn display_waiting<T: AsRef<str>>(text: T) { | ||
| if Level::Info <= *verbosity() { | ||
| eprintln!( | ||
| "{}", | ||
| text.as_ref() | ||
| .if_supports_color(Stderr, |text| text.bright_magenta()) | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| #[allow(dead_code)] | ||
| pub fn display_warning<T: AsRef<str>>(text: T) { | ||
| if Level::Warn <= *verbosity() { | ||
| eprintln!( | ||
| "{}", | ||
| text.as_ref() | ||
| .if_supports_color(Stderr, |text| text.bright_yellow()) | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| pub fn display_error<T: AsRef<str>>(text: T) { | ||
| if Level::Error <= *verbosity() { | ||
| eprintln!( | ||
| "{}", | ||
| text.as_ref() | ||
| .if_supports_color(Stderr, |text| text.bright_red()) | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| pub fn construct_command(program: &str) -> Command { | ||
| let mut command = Command::new(program); | ||
| command.current_dir(path()); | ||
|
|
||
| command | ||
| } | ||
|
|
||
| pub fn capture_output(command: &mut Command) -> Result<String> { | ||
| Ok(String::from_utf8(command.output()?.stdout)?) | ||
| } | ||
|
|
||
| pub fn run_command(command: &mut Command) -> Result<()> { | ||
| let status = command.status()?; | ||
| if status.success() { | ||
| Ok(()) | ||
| } else { | ||
| bail!( | ||
| "command: {}\nfailed with exit code: {}", | ||
| render_command(command), | ||
| status.code().unwrap() | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| pub fn wait_for_command( | ||
| command: &mut Command, | ||
| message: impl Into<Cow<'static, str>>, | ||
| ) -> Result<()> { | ||
| let progress_bar = get_progress_bar()?; | ||
| progress_bar.set_message(message); | ||
|
|
||
| let result = command.output(); | ||
| progress_bar.finish_and_clear(); | ||
| let output = match result { | ||
| Ok(output) => output, | ||
| Err(_) => bail!("could not run command"), | ||
| }; | ||
|
|
||
| if output.status.success() { | ||
| Ok(()) | ||
| } else { | ||
| bail!( | ||
| "{}\nfailed with exit code: {}", | ||
| String::from_utf8(output.stdout)?, | ||
| output.status.code().unwrap() | ||
| ) | ||
| } | ||
| } | ||
|
bruceg marked this conversation as resolved.
|
||
|
|
||
| fn get_progress_bar() -> Result<ProgressBar> { | ||
| let progress_bar = ProgressBar::new_spinner(); | ||
| progress_bar.enable_steady_tick(Duration::from_millis(125)); | ||
| progress_bar.set_style( | ||
| ProgressStyle::with_template("{spinner} {msg:.magenta.bold}")? | ||
| // https://github.com/sindresorhus/cli-spinners/blob/master/spinners.json | ||
| .tick_strings(&["∙∙∙", "●∙∙", "∙●∙", "∙∙●", "∙∙∙"]), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yup that's correct as you can see in the link
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not seeing it. All the strings I'm seeing at that link don't have any repeats.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| ); | ||
|
|
||
| Ok(progress_bar) | ||
| } | ||
|
|
||
| fn render_command(command: &mut Command) -> String { | ||
| format!( | ||
| "{} {}", | ||
| command.get_program().to_str().unwrap(), | ||
| Vec::from_iter(command.get_args().map(|arg| arg.to_str().unwrap())).join(" ") | ||
| ) | ||
| } | ||
|
|
||
| pub fn set_global_verbosity(verbosity: LevelFilter) { | ||
| VERBOSITY.set(verbosity).unwrap() | ||
| } | ||
|
|
||
| pub fn set_global_config_file(config_file: ConfigFile) { | ||
| CONFIG_FILE.set(config_file).unwrap() | ||
| } | ||
|
|
||
| pub fn set_global_config(config: Config) { | ||
| CONFIG.set(config).unwrap() | ||
| } | ||
|
|
||
| pub fn set_global_path(path: String) { | ||
| PATH.set(path).unwrap() | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| use anyhow::{bail, Result}; | ||
| use clap::Args; | ||
|
|
||
| use crate::app; | ||
| use crate::platform; | ||
|
|
||
| /// Build Vector | ||
| #[derive(Args, Debug)] | ||
| #[command()] | ||
| pub struct Cli { | ||
| /// The build target e.g. x86_64-unknown-linux-musl | ||
| target: Option<String>, | ||
|
|
||
| /// Build with optimizations | ||
| #[arg(short, long)] | ||
| release: bool, | ||
|
|
||
| /// The feature to activate (multiple allowed) | ||
| #[arg(short = 'F', long)] | ||
| feature: Vec<String>, | ||
| } | ||
|
|
||
| impl Cli { | ||
| pub fn exec(&self) -> Result<()> { | ||
| let mut command = app::construct_command("cargo"); | ||
| command.args(["build", "--no-default-features"]); | ||
|
|
||
| if self.release { | ||
| command.arg("--release"); | ||
| } | ||
|
|
||
| command.arg("--features"); | ||
| if !self.feature.is_empty() { | ||
| command.args([self.feature.join(",")]); | ||
| } else { | ||
| if platform::windows() { | ||
| command.arg("default-msvc"); | ||
| } else { | ||
| command.arg("default"); | ||
| } | ||
| }; | ||
|
Comment on lines
+30
to
+41
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You may also find
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah nice, I will incorporate that soon |
||
|
|
||
| if let Some(target) = self.target.as_deref() { | ||
| command.args(["--target", target]); | ||
| } else { | ||
| command.args(["--target", &platform::default_target()]); | ||
| }; | ||
|
|
||
| app::display_waiting("Building Vector"); | ||
| app::run_command(&mut command)?; | ||
|
|
||
| Ok(()) | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.