From 77a6e02964f2f7607bd5f6163de5df5a1c13661d Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Wed, 29 May 2024 02:28:45 -0700 Subject: [PATCH] Add `--timestamp-format` (#2106) --- .github/workflows/ci.yaml | 2 +- README.md | 37 +++++++++++++++++++ ...enerate-completions => update-completions} | 0 completions/just.bash | 6 ++- completions/just.elvish | 3 +- completions/just.fish | 3 +- completions/just.powershell | 3 +- completions/just.zsh | 3 +- justfile | 4 +- src/config.rs | 26 ++++++++++--- src/lib.rs | 1 - src/recipe.rs | 8 +++- tests/timestamps.rs | 17 ++++++++- 13 files changed, 95 insertions(+), 18 deletions(-) rename bin/{generate-completions => update-completions} (100%) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9db21da..590ba9e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -32,7 +32,7 @@ jobs: - name: Completion Scripts run: | - ./bin/generate-completions + ./bin/update-completions git diff --no-ext-diff --quiet --exit-code ./tests/completions/just.bash diff --git a/README.md b/README.md index 72e55c7..b55b431 100644 --- a/README.md +++ b/README.md @@ -3372,6 +3372,43 @@ Since `set windows-shell` has higher precedence than `set shell`, you can use `set windows-shell` to pick a shell on Windows, and `set shell` to pick a shell for all other platforms. +### Timestamps + +`just` can print timestamps before each recipe commands: + +```just +recipe: + echo one + sleep 2 + echo two +``` + +``` +$ just --timestamp recipe +[07:28:46] echo one +one +[07:28:46] sleep 2 +[07:28:48] echo two +two +``` + +By default, timestamps are formatted as `HH:MM:SS`. The format can be changed +with `--timestamp-format`: + +``` +$ just --timestamp recipe --timestamp-format '%H:%M:%S%.3f %Z' +[07:32:11:.349 UTC] echo one +one +[07:32:11:.350 UTC] sleep 2 +[07:32:13:.352 UTC] echo two +two +``` + +The argument to `--timestamp-format` is a `strftime`-style format string, see +the +[`chrono` library docs](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) +for details. + Changelog --------- diff --git a/bin/generate-completions b/bin/update-completions similarity index 100% rename from bin/generate-completions rename to bin/update-completions diff --git a/completions/just.bash b/completions/just.bash index 1566f3c..c539779 100644 --- a/completions/just.bash +++ b/completions/just.bash @@ -30,7 +30,7 @@ _just() { case "${cmd}" in just) - opts="-n -f -q -u -v -d -c -e -l -s -E -g -h -V --check --chooser --color --command-color --yes --dry-run --dump-format --highlight --list-heading --list-prefix --no-aliases --no-deps --no-dotenv --no-highlight --justfile --quiet --set --shell --shell-arg --shell-command --clear-shell-args --unsorted --unstable --verbose --working-directory --changelog --choose --command --completions --dump --edit --evaluate --fmt --init --list --groups --man --show --summary --variables --dotenv-filename --dotenv-path --global-justfile --timestamps --help --version [ARGUMENTS]..." + opts="-n -f -q -u -v -d -c -e -l -s -E -g -h -V --check --chooser --color --command-color --yes --dry-run --dump-format --highlight --list-heading --list-prefix --no-aliases --no-deps --no-dotenv --no-highlight --justfile --quiet --set --shell --shell-arg --shell-command --clear-shell-args --unsorted --unstable --verbose --working-directory --changelog --choose --command --completions --dump --edit --evaluate --fmt --init --list --groups --man --show --summary --variables --dotenv-filename --dotenv-path --global-justfile --timestamp --timestamp-format --help --version [ARGUMENTS]..." if [[ ${cur} == -* ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -144,6 +144,10 @@ _just() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --timestamp-format) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; diff --git a/completions/just.elvish b/completions/just.elvish index 4340780..41524df 100644 --- a/completions/just.elvish +++ b/completions/just.elvish @@ -40,6 +40,7 @@ set edit:completion:arg-completer[just] = {|@words| cand --dotenv-filename 'Search for environment file named instead of `.env`' cand -E 'Load as environment file instead of searching for one' cand --dotenv-path 'Load as environment file instead of searching for one' + cand --timestamp-format 'Timestamp format string' cand --check 'Run `--fmt` in ''check'' mode. Exits with 0 if justfile is formatted correctly. Exits with 1 and prints a diff if formatting is required.' cand --yes 'Automatically confirm all recipes.' cand -n 'Print what just would do without doing it' @@ -72,7 +73,7 @@ set edit:completion:arg-completer[just] = {|@words| cand --variables 'List names of variables' cand -g 'Use global justfile' cand --global-justfile 'Use global justfile' - cand --timestamps 'Print recipe command timestamps' + cand --timestamp 'Print recipe command timestamps' cand -h 'Print help' cand --help 'Print help' cand -V 'Print version' diff --git a/completions/just.fish b/completions/just.fish index 50556ca..4a4615d 100644 --- a/completions/just.fish +++ b/completions/just.fish @@ -52,6 +52,7 @@ complete -c just -s l -l list -d 'List available recipes and their arguments' -r complete -c just -s s -l show -d 'Show information about ' -r complete -c just -l dotenv-filename -d 'Search for environment file named instead of `.env`' -r complete -c just -s E -l dotenv-path -d 'Load as environment file instead of searching for one' -r -F +complete -c just -l timestamp-format -d 'Timestamp format string' -r complete -c just -l check -d 'Run `--fmt` in \'check\' mode. Exits with 0 if justfile is formatted correctly. Exits with 1 and prints a diff if formatting is required.' complete -c just -l yes -d 'Automatically confirm all recipes.' complete -c just -s n -l dry-run -d 'Print what just would do without doing it' @@ -78,6 +79,6 @@ complete -c just -l man -d 'Print man page' complete -c just -l summary -d 'List names of available recipes' complete -c just -l variables -d 'List names of variables' complete -c just -s g -l global-justfile -d 'Use global justfile' -complete -c just -l timestamps -d 'Print recipe command timestamps' +complete -c just -l timestamp -d 'Print recipe command timestamps' complete -c just -s h -l help -d 'Print help' complete -c just -s V -l version -d 'Print version' diff --git a/completions/just.powershell b/completions/just.powershell index 66210d3..88098f0 100644 --- a/completions/just.powershell +++ b/completions/just.powershell @@ -43,6 +43,7 @@ Register-ArgumentCompleter -Native -CommandName 'just' -ScriptBlock { [CompletionResult]::new('--dotenv-filename', 'dotenv-filename', [CompletionResultType]::ParameterName, 'Search for environment file named instead of `.env`') [CompletionResult]::new('-E', 'E ', [CompletionResultType]::ParameterName, 'Load as environment file instead of searching for one') [CompletionResult]::new('--dotenv-path', 'dotenv-path', [CompletionResultType]::ParameterName, 'Load as environment file instead of searching for one') + [CompletionResult]::new('--timestamp-format', 'timestamp-format', [CompletionResultType]::ParameterName, 'Timestamp format string') [CompletionResult]::new('--check', 'check', [CompletionResultType]::ParameterName, 'Run `--fmt` in ''check'' mode. Exits with 0 if justfile is formatted correctly. Exits with 1 and prints a diff if formatting is required.') [CompletionResult]::new('--yes', 'yes', [CompletionResultType]::ParameterName, 'Automatically confirm all recipes.') [CompletionResult]::new('-n', 'n', [CompletionResultType]::ParameterName, 'Print what just would do without doing it') @@ -75,7 +76,7 @@ Register-ArgumentCompleter -Native -CommandName 'just' -ScriptBlock { [CompletionResult]::new('--variables', 'variables', [CompletionResultType]::ParameterName, 'List names of variables') [CompletionResult]::new('-g', 'g', [CompletionResultType]::ParameterName, 'Use global justfile') [CompletionResult]::new('--global-justfile', 'global-justfile', [CompletionResultType]::ParameterName, 'Use global justfile') - [CompletionResult]::new('--timestamps', 'timestamps', [CompletionResultType]::ParameterName, 'Print recipe command timestamps') + [CompletionResult]::new('--timestamp', 'timestamp', [CompletionResultType]::ParameterName, 'Print recipe command timestamps') [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help') [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help') [CompletionResult]::new('-V', 'V ', [CompletionResultType]::ParameterName, 'Print version') diff --git a/completions/just.zsh b/completions/just.zsh index 7805d86..b8e0a2c 100644 --- a/completions/just.zsh +++ b/completions/just.zsh @@ -38,6 +38,7 @@ _just() { '(-E --dotenv-path)--dotenv-filename=[Search for environment file named instead of \`.env\`]: : ' \ '-E+[Load as environment file instead of searching for one]: :_files' \ '--dotenv-path=[Load as environment file instead of searching for one]: :_files' \ +'--timestamp-format=[Timestamp format string]: : ' \ '--check[Run \`--fmt\` in '\''check'\'' mode. Exits with 0 if justfile is formatted correctly. Exits with 1 and prints a diff if formatting is required.]' \ '--yes[Automatically confirm all recipes.]' \ '(-q --quiet)-n[Print what just would do without doing it]' \ @@ -70,7 +71,7 @@ _just() { '--variables[List names of variables]' \ '(-f --justfile -d --working-directory)-g[Use global justfile]' \ '(-f --justfile -d --working-directory)--global-justfile[Use global justfile]' \ -'--timestamps[Print recipe command timestamps]' \ +'--timestamp[Print recipe command timestamps]' \ '-h[Print help]' \ '--help[Print help]' \ '-V[Print version]' \ diff --git a/justfile b/justfile index 98fc422..6ad4dd8 100755 --- a/justfile +++ b/justfile @@ -164,8 +164,8 @@ watch-readme: just render-readme fswatch -ro README.adoc | xargs -n1 -I{} just render-readme -generate-completions: - ./bin/generate-completions +update-completions: + ./bin/update-completions test-completions: ./tests/completions/just.bash diff --git a/src/config.rs b/src/config.rs index c609529..9f31eec 100644 --- a/src/config.rs +++ b/src/config.rs @@ -39,7 +39,8 @@ pub(crate) struct Config { pub(crate) shell_args: Option>, pub(crate) shell_command: bool, pub(crate) subcommand: Subcommand, - pub(crate) timestamps: bool, + pub(crate) timestamp: bool, + pub(crate) timestamp_format: String, pub(crate) unsorted: bool, pub(crate) unstable: bool, pub(crate) verbosity: Verbosity, @@ -109,7 +110,8 @@ mod arg { pub(crate) const SHELL: &str = "SHELL"; pub(crate) const SHELL_ARG: &str = "SHELL-ARG"; pub(crate) const SHELL_COMMAND: &str = "SHELL-COMMAND"; - pub(crate) const TIMESTAMPS: &str = "TIMESTAMPS"; + pub(crate) const TIMESTAMP: &str = "TIMESTAMP"; + pub(crate) const TIMESTAMP_FORMAT: &str = "TIMESTAMP_FORMAT"; pub(crate) const UNSORTED: &str = "UNSORTED"; pub(crate) const UNSTABLE: &str = "UNSTABLE"; pub(crate) const VERBOSE: &str = "VERBOSE"; @@ -486,12 +488,20 @@ impl Config { .help("Use global justfile") ) .arg( - Arg::new(arg::TIMESTAMPS) + Arg::new(arg::TIMESTAMP) .action(ArgAction::SetTrue) - .long("timestamps") - .env("JUST_TIMESTAMPS") + .long("timestamp") + .env("JUST_TIMESTAMP") .help("Print recipe command timestamps") ) + .arg( + Arg::new(arg::TIMESTAMP_FORMAT) + .action(ArgAction::Set) + .long("timestamp-format") + .env("JUST_TIMESTAMP_FORMAT") + .default_value("%H:%M:%S") + .help("Timestamp format string") + ) } fn color_from_matches(matches: &ArgMatches) -> ConfigResult { @@ -743,7 +753,11 @@ impl Config { shell_args, shell_command: matches.get_flag(arg::SHELL_COMMAND), subcommand, - timestamps: matches.get_flag(arg::TIMESTAMPS), + timestamp: matches.get_flag(arg::TIMESTAMP), + timestamp_format: matches + .get_one::(arg::TIMESTAMP_FORMAT) + .unwrap() + .into(), unsorted: matches.get_flag(arg::UNSORTED), unstable, verbosity, diff --git a/src/lib.rs b/src/lib.rs index 959ee56..10cd391 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,7 +61,6 @@ pub(crate) use { }, { camino::Utf8Path, - chrono::Utc, derivative::Derivative, edit_distance::edit_distance, lexiclean::Lexiclean, diff --git a/src/recipe.rs b/src/recipe.rs index d41bfff..97dc847 100644 --- a/src/recipe.rs +++ b/src/recipe.rs @@ -243,10 +243,14 @@ impl<'src, D> Recipe<'src, D> { .unwrap_or(config.color) .stderr(); - if config.timestamps { + if config.timestamp { eprint!( "[{}] ", - color.paint(&Utc::now().format("%H:%M:%S").to_string()) + color.paint( + &chrono::Local::now() + .format(&config.timestamp_format) + .to_string() + ), ); } diff --git a/tests/timestamps.rs b/tests/timestamps.rs index 8b18b60..f296d14 100644 --- a/tests/timestamps.rs +++ b/tests/timestamps.rs @@ -9,8 +9,23 @@ fn print_timestamps() { echo 'one' ", ) - .arg("--timestamps") + .arg("--timestamp") .stderr_regex(concat!(r"\[\d\d:\d\d:\d\d\] echo 'one'", "\n")) .stdout("one\n") .run(); } + +#[test] +fn print_timestamps_with_format_string() { + Test::new() + .justfile( + " + recipe: + echo 'one' + ", + ) + .args(["--timestamp", "--timestamp-format", "%H:%M:%S.%3f"]) + .stderr_regex(concat!(r"\[\d\d:\d\d:\d\d\.\d\d\d] echo 'one'", "\n")) + .stdout("one\n") + .run(); +}