Add --timestamp-format (#2106)

This commit is contained in:
Greg Shuflin 2024-05-29 02:28:45 -07:00 committed by GitHub
parent 9d2c6b8858
commit 77a6e02964
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 95 additions and 18 deletions

View File

@ -32,7 +32,7 @@ jobs:
- name: Completion Scripts - name: Completion Scripts
run: | run: |
./bin/generate-completions ./bin/update-completions
git diff --no-ext-diff --quiet --exit-code git diff --no-ext-diff --quiet --exit-code
./tests/completions/just.bash ./tests/completions/just.bash

View File

@ -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 `set windows-shell` to pick a shell on Windows, and `set shell` to pick a shell
for all other platforms. 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 Changelog
--------- ---------

View File

@ -30,7 +30,7 @@ _just() {
case "${cmd}" in case "${cmd}" in
just) 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 if [[ ${cur} == -* ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0 return 0
@ -144,6 +144,10 @@ _just() {
COMPREPLY=($(compgen -f "${cur}")) COMPREPLY=($(compgen -f "${cur}"))
return 0 return 0
;; ;;
--timestamp-format)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
*) *)
COMPREPLY=() COMPREPLY=()
;; ;;

View File

@ -40,6 +40,7 @@ set edit:completion:arg-completer[just] = {|@words|
cand --dotenv-filename 'Search for environment file named <DOTENV-FILENAME> instead of `.env`' cand --dotenv-filename 'Search for environment file named <DOTENV-FILENAME> instead of `.env`'
cand -E 'Load <DOTENV-PATH> as environment file instead of searching for one' cand -E 'Load <DOTENV-PATH> as environment file instead of searching for one'
cand --dotenv-path 'Load <DOTENV-PATH> as environment file instead of searching for one' cand --dotenv-path 'Load <DOTENV-PATH> 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 --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 --yes 'Automatically confirm all recipes.'
cand -n 'Print what just would do without doing it' 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 --variables 'List names of variables'
cand -g 'Use global justfile' cand -g 'Use global justfile'
cand --global-justfile '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 -h 'Print help'
cand --help 'Print help' cand --help 'Print help'
cand -V 'Print version' cand -V 'Print version'

View File

@ -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 <RECIPE>' -r complete -c just -s s -l show -d 'Show information about <RECIPE>' -r
complete -c just -l dotenv-filename -d 'Search for environment file named <DOTENV-FILENAME> instead of `.env`' -r complete -c just -l dotenv-filename -d 'Search for environment file named <DOTENV-FILENAME> instead of `.env`' -r
complete -c just -s E -l dotenv-path -d 'Load <DOTENV-PATH> as environment file instead of searching for one' -r -F complete -c just -s E -l dotenv-path -d 'Load <DOTENV-PATH> 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 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 -l yes -d 'Automatically confirm all recipes.'
complete -c just -s n -l dry-run -d 'Print what just would do without doing it' 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 summary -d 'List names of available recipes'
complete -c just -l variables -d 'List names of variables' 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 -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 h -l help -d 'Print help'
complete -c just -s V -l version -d 'Print version' complete -c just -s V -l version -d 'Print version'

View File

@ -43,6 +43,7 @@ Register-ArgumentCompleter -Native -CommandName 'just' -ScriptBlock {
[CompletionResult]::new('--dotenv-filename', 'dotenv-filename', [CompletionResultType]::ParameterName, 'Search for environment file named <DOTENV-FILENAME> instead of `.env`') [CompletionResult]::new('--dotenv-filename', 'dotenv-filename', [CompletionResultType]::ParameterName, 'Search for environment file named <DOTENV-FILENAME> instead of `.env`')
[CompletionResult]::new('-E', 'E ', [CompletionResultType]::ParameterName, 'Load <DOTENV-PATH> as environment file instead of searching for one') [CompletionResult]::new('-E', 'E ', [CompletionResultType]::ParameterName, 'Load <DOTENV-PATH> as environment file instead of searching for one')
[CompletionResult]::new('--dotenv-path', 'dotenv-path', [CompletionResultType]::ParameterName, 'Load <DOTENV-PATH> as environment file instead of searching for one') [CompletionResult]::new('--dotenv-path', 'dotenv-path', [CompletionResultType]::ParameterName, 'Load <DOTENV-PATH> 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('--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('--yes', 'yes', [CompletionResultType]::ParameterName, 'Automatically confirm all recipes.')
[CompletionResult]::new('-n', 'n', [CompletionResultType]::ParameterName, 'Print what just would do without doing it') [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('--variables', 'variables', [CompletionResultType]::ParameterName, 'List names of variables')
[CompletionResult]::new('-g', 'g', [CompletionResultType]::ParameterName, 'Use global justfile') [CompletionResult]::new('-g', 'g', [CompletionResultType]::ParameterName, 'Use global justfile')
[CompletionResult]::new('--global-justfile', 'global-justfile', [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('-h', 'h', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help') [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('-V', 'V ', [CompletionResultType]::ParameterName, 'Print version') [CompletionResult]::new('-V', 'V ', [CompletionResultType]::ParameterName, 'Print version')

View File

@ -38,6 +38,7 @@ _just() {
'(-E --dotenv-path)--dotenv-filename=[Search for environment file named <DOTENV-FILENAME> instead of \`.env\`]: : ' \ '(-E --dotenv-path)--dotenv-filename=[Search for environment file named <DOTENV-FILENAME> instead of \`.env\`]: : ' \
'-E+[Load <DOTENV-PATH> as environment file instead of searching for one]: :_files' \ '-E+[Load <DOTENV-PATH> as environment file instead of searching for one]: :_files' \
'--dotenv-path=[Load <DOTENV-PATH> as environment file instead of searching for one]: :_files' \ '--dotenv-path=[Load <DOTENV-PATH> 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.]' \ '--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.]' \ '--yes[Automatically confirm all recipes.]' \
'(-q --quiet)-n[Print what just would do without doing it]' \ '(-q --quiet)-n[Print what just would do without doing it]' \
@ -70,7 +71,7 @@ _just() {
'--variables[List names of variables]' \ '--variables[List names of variables]' \
'(-f --justfile -d --working-directory)-g[Use global justfile]' \ '(-f --justfile -d --working-directory)-g[Use global justfile]' \
'(-f --justfile -d --working-directory)--global-justfile[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]' \ '-h[Print help]' \
'--help[Print help]' \ '--help[Print help]' \
'-V[Print version]' \ '-V[Print version]' \

View File

@ -164,8 +164,8 @@ watch-readme:
just render-readme just render-readme
fswatch -ro README.adoc | xargs -n1 -I{} just render-readme fswatch -ro README.adoc | xargs -n1 -I{} just render-readme
generate-completions: update-completions:
./bin/generate-completions ./bin/update-completions
test-completions: test-completions:
./tests/completions/just.bash ./tests/completions/just.bash

View File

@ -39,7 +39,8 @@ pub(crate) struct Config {
pub(crate) shell_args: Option<Vec<String>>, pub(crate) shell_args: Option<Vec<String>>,
pub(crate) shell_command: bool, pub(crate) shell_command: bool,
pub(crate) subcommand: Subcommand, pub(crate) subcommand: Subcommand,
pub(crate) timestamps: bool, pub(crate) timestamp: bool,
pub(crate) timestamp_format: String,
pub(crate) unsorted: bool, pub(crate) unsorted: bool,
pub(crate) unstable: bool, pub(crate) unstable: bool,
pub(crate) verbosity: Verbosity, pub(crate) verbosity: Verbosity,
@ -109,7 +110,8 @@ mod arg {
pub(crate) const SHELL: &str = "SHELL"; pub(crate) const SHELL: &str = "SHELL";
pub(crate) const SHELL_ARG: &str = "SHELL-ARG"; pub(crate) const SHELL_ARG: &str = "SHELL-ARG";
pub(crate) const SHELL_COMMAND: &str = "SHELL-COMMAND"; 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 UNSORTED: &str = "UNSORTED";
pub(crate) const UNSTABLE: &str = "UNSTABLE"; pub(crate) const UNSTABLE: &str = "UNSTABLE";
pub(crate) const VERBOSE: &str = "VERBOSE"; pub(crate) const VERBOSE: &str = "VERBOSE";
@ -486,12 +488,20 @@ impl Config {
.help("Use global justfile") .help("Use global justfile")
) )
.arg( .arg(
Arg::new(arg::TIMESTAMPS) Arg::new(arg::TIMESTAMP)
.action(ArgAction::SetTrue) .action(ArgAction::SetTrue)
.long("timestamps") .long("timestamp")
.env("JUST_TIMESTAMPS") .env("JUST_TIMESTAMP")
.help("Print recipe command timestamps") .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<Color> { fn color_from_matches(matches: &ArgMatches) -> ConfigResult<Color> {
@ -743,7 +753,11 @@ impl Config {
shell_args, shell_args,
shell_command: matches.get_flag(arg::SHELL_COMMAND), shell_command: matches.get_flag(arg::SHELL_COMMAND),
subcommand, subcommand,
timestamps: matches.get_flag(arg::TIMESTAMPS), timestamp: matches.get_flag(arg::TIMESTAMP),
timestamp_format: matches
.get_one::<String>(arg::TIMESTAMP_FORMAT)
.unwrap()
.into(),
unsorted: matches.get_flag(arg::UNSORTED), unsorted: matches.get_flag(arg::UNSORTED),
unstable, unstable,
verbosity, verbosity,

View File

@ -61,7 +61,6 @@ pub(crate) use {
}, },
{ {
camino::Utf8Path, camino::Utf8Path,
chrono::Utc,
derivative::Derivative, derivative::Derivative,
edit_distance::edit_distance, edit_distance::edit_distance,
lexiclean::Lexiclean, lexiclean::Lexiclean,

View File

@ -243,10 +243,14 @@ impl<'src, D> Recipe<'src, D> {
.unwrap_or(config.color) .unwrap_or(config.color)
.stderr(); .stderr();
if config.timestamps { if config.timestamp {
eprint!( eprint!(
"[{}] ", "[{}] ",
color.paint(&Utc::now().format("%H:%M:%S").to_string()) color.paint(
&chrono::Local::now()
.format(&config.timestamp_format)
.to_string()
),
); );
} }

View File

@ -9,8 +9,23 @@ fn print_timestamps() {
echo 'one' echo 'one'
", ",
) )
.arg("--timestamps") .arg("--timestamp")
.stderr_regex(concat!(r"\[\d\d:\d\d:\d\d\] echo 'one'", "\n")) .stderr_regex(concat!(r"\[\d\d:\d\d:\d\d\] echo 'one'", "\n"))
.stdout("one\n") .stdout("one\n")
.run(); .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();
}