mirror of
https://github.com/martinvonz/jj.git
synced 2024-11-28 00:56:57 +00:00
util: add exec command for arbitrary aliases
Some checks are pending
binaries / Build binary artifacts (linux-aarch64-gnu, ubuntu-24.04, aarch64-unknown-linux-gnu) (push) Waiting to run
binaries / Build binary artifacts (linux-aarch64-musl, ubuntu-24.04, aarch64-unknown-linux-musl) (push) Waiting to run
binaries / Build binary artifacts (linux-x86_64-gnu, ubuntu-24.04, x86_64-unknown-linux-gnu) (push) Waiting to run
binaries / Build binary artifacts (linux-x86_64-musl, ubuntu-24.04, x86_64-unknown-linux-musl) (push) Waiting to run
binaries / Build binary artifacts (macos-aarch64, macos-14, aarch64-apple-darwin) (push) Waiting to run
binaries / Build binary artifacts (macos-x86_64, macos-13, x86_64-apple-darwin) (push) Waiting to run
binaries / Build binary artifacts (win-x86_64, windows-2022, x86_64-pc-windows-msvc) (push) Waiting to run
nix / flake check (macos-14) (push) Waiting to run
nix / flake check (ubuntu-latest) (push) Waiting to run
build / build (, macos-13) (push) Waiting to run
build / build (, macos-14) (push) Waiting to run
build / build (, ubuntu-latest) (push) Waiting to run
build / build (, windows-latest) (push) Waiting to run
build / build (--all-features, ubuntu-latest) (push) Waiting to run
build / Build jj-lib without Git support (push) Waiting to run
build / Check protos (push) Waiting to run
build / Check formatting (push) Waiting to run
build / Check that MkDocs can build the docs (push) Waiting to run
build / Check that MkDocs can build the docs with Poetry 1.8 (push) Waiting to run
build / cargo-deny (advisories) (push) Waiting to run
build / cargo-deny (bans licenses sources) (push) Waiting to run
build / Clippy check (push) Waiting to run
Codespell / Codespell (push) Waiting to run
website / prerelease-docs-build-deploy (ubuntu-latest) (push) Waiting to run
Scorecards supply-chain security / Scorecards analysis (push) Waiting to run
Some checks are pending
binaries / Build binary artifacts (linux-aarch64-gnu, ubuntu-24.04, aarch64-unknown-linux-gnu) (push) Waiting to run
binaries / Build binary artifacts (linux-aarch64-musl, ubuntu-24.04, aarch64-unknown-linux-musl) (push) Waiting to run
binaries / Build binary artifacts (linux-x86_64-gnu, ubuntu-24.04, x86_64-unknown-linux-gnu) (push) Waiting to run
binaries / Build binary artifacts (linux-x86_64-musl, ubuntu-24.04, x86_64-unknown-linux-musl) (push) Waiting to run
binaries / Build binary artifacts (macos-aarch64, macos-14, aarch64-apple-darwin) (push) Waiting to run
binaries / Build binary artifacts (macos-x86_64, macos-13, x86_64-apple-darwin) (push) Waiting to run
binaries / Build binary artifacts (win-x86_64, windows-2022, x86_64-pc-windows-msvc) (push) Waiting to run
nix / flake check (macos-14) (push) Waiting to run
nix / flake check (ubuntu-latest) (push) Waiting to run
build / build (, macos-13) (push) Waiting to run
build / build (, macos-14) (push) Waiting to run
build / build (, ubuntu-latest) (push) Waiting to run
build / build (, windows-latest) (push) Waiting to run
build / build (--all-features, ubuntu-latest) (push) Waiting to run
build / Build jj-lib without Git support (push) Waiting to run
build / Check protos (push) Waiting to run
build / Check formatting (push) Waiting to run
build / Check that MkDocs can build the docs (push) Waiting to run
build / Check that MkDocs can build the docs with Poetry 1.8 (push) Waiting to run
build / cargo-deny (advisories) (push) Waiting to run
build / cargo-deny (bans licenses sources) (push) Waiting to run
build / Clippy check (push) Waiting to run
Codespell / Codespell (push) Waiting to run
website / prerelease-docs-build-deploy (ubuntu-latest) (push) Waiting to run
Scorecards supply-chain security / Scorecards analysis (push) Waiting to run
This commit is contained in:
parent
d77ca1526a
commit
db2b5890f8
6 changed files with 224 additions and 0 deletions
|
@ -20,6 +20,8 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|||
* The `jj desc` and `jj st` aliases are now hidden to not interfere with shell
|
||||
completion. They remain available.
|
||||
|
||||
* New command `jj util exec` that can be used for arbitrary aliases.
|
||||
|
||||
### Fixed bugs
|
||||
|
||||
## [0.23.0] - 2024-11-06
|
||||
|
|
95
cli/src/commands/util/exec.rs
Normal file
95
cli/src/commands/util/exec.rs
Normal file
|
@ -0,0 +1,95 @@
|
|||
// Copyright 2024 The Jujutsu Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::cli_util::CommandHelper;
|
||||
use crate::command_error::user_error;
|
||||
use crate::command_error::user_error_with_message;
|
||||
use crate::command_error::CommandError;
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Execute an external command via jj
|
||||
///
|
||||
/// This is useful for arbitrary aliases.
|
||||
///
|
||||
/// !! WARNING !!
|
||||
///
|
||||
/// The following technique just provides a convenient syntax for running
|
||||
/// arbitrary code on your system. Using it irresponsibly may cause damage
|
||||
/// ranging from breaking the behavior of `jj undo` to wiping your file system.
|
||||
/// Exercise the same amount of caution while writing these aliases as you would
|
||||
/// when typing commands into the terminal!
|
||||
///
|
||||
/// This feature may be removed or replaced by an embedded scripting language in
|
||||
/// the future.
|
||||
///
|
||||
/// Let's assume you have a script called "my-jj-script" in you $PATH and you
|
||||
/// would like to execute it as "jj my-script". You would add the following line
|
||||
/// to your configuration file to achieve that:
|
||||
///
|
||||
/// ```toml
|
||||
/// [aliases]
|
||||
/// my-script = ["util", "exec", "--", "my-jj-script"]
|
||||
/// # ^^^^
|
||||
/// # This makes sure that flags are passed to your script instead of parsed by jj.
|
||||
/// ```
|
||||
///
|
||||
/// If you don't want to manage your script as a separate file, you can even
|
||||
/// inline it into your config file:
|
||||
///
|
||||
/// ```toml
|
||||
/// [aliases]
|
||||
/// my-inline-script = ["util", "exec", "--", "bash", "-c", """
|
||||
/// #!/usr/bin/env bash
|
||||
/// set -euo pipefail
|
||||
/// echo "Look Ma, everything in one file!"
|
||||
/// echo "args: $@"
|
||||
/// """, ""]
|
||||
/// # ^^
|
||||
/// # This last empty string will become "$0" in bash, so your actual arguments
|
||||
/// # are all included in "$@" and start at "$1" as expected.
|
||||
/// ```
|
||||
#[derive(clap::Args, Clone, Debug)]
|
||||
#[command(verbatim_doc_comment)]
|
||||
pub(crate) struct UtilExecArgs {
|
||||
/// External command to execute
|
||||
command: String,
|
||||
/// Arguments to pass to the external command
|
||||
args: Vec<String>,
|
||||
}
|
||||
|
||||
pub fn cmd_util_exec(
|
||||
_ui: &mut Ui,
|
||||
_command: &CommandHelper,
|
||||
args: &UtilExecArgs,
|
||||
) -> Result<(), CommandError> {
|
||||
let status = std::process::Command::new(&args.command)
|
||||
.args(&args.args)
|
||||
.status()
|
||||
.map_err(|err| {
|
||||
user_error_with_message(
|
||||
format!("Failed to execute external command '{}'", &args.command),
|
||||
err,
|
||||
)
|
||||
})?;
|
||||
if !status.success() {
|
||||
let error_msg = if let Some(exit_code) = status.code() {
|
||||
format!("External command exited with {exit_code}")
|
||||
} else {
|
||||
// signal
|
||||
format!("External command was terminated by: {status}")
|
||||
};
|
||||
return Err(user_error(error_msg));
|
||||
}
|
||||
Ok(())
|
||||
}
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
mod completion;
|
||||
mod config_schema;
|
||||
mod exec;
|
||||
mod gc;
|
||||
mod mangen;
|
||||
mod markdown_help;
|
||||
|
@ -25,6 +26,8 @@ use self::completion::cmd_util_completion;
|
|||
use self::completion::UtilCompletionArgs;
|
||||
use self::config_schema::cmd_util_config_schema;
|
||||
use self::config_schema::UtilConfigSchemaArgs;
|
||||
use self::exec::cmd_util_exec;
|
||||
use self::exec::UtilExecArgs;
|
||||
use self::gc::cmd_util_gc;
|
||||
use self::gc::UtilGcArgs;
|
||||
use self::mangen::cmd_util_mangen;
|
||||
|
@ -40,6 +43,7 @@ use crate::ui::Ui;
|
|||
pub(crate) enum UtilCommand {
|
||||
Completion(UtilCompletionArgs),
|
||||
ConfigSchema(UtilConfigSchemaArgs),
|
||||
Exec(UtilExecArgs),
|
||||
Gc(UtilGcArgs),
|
||||
Mangen(UtilMangenArgs),
|
||||
MarkdownHelp(UtilMarkdownHelp),
|
||||
|
@ -54,6 +58,7 @@ pub(crate) fn cmd_util(
|
|||
match subcommand {
|
||||
UtilCommand::Completion(args) => cmd_util_completion(ui, command, args),
|
||||
UtilCommand::ConfigSchema(args) => cmd_util_config_schema(ui, command, args),
|
||||
UtilCommand::Exec(args) => cmd_util_exec(ui, command, args),
|
||||
UtilCommand::Gc(args) => cmd_util_gc(ui, command, args),
|
||||
UtilCommand::Mangen(args) => cmd_util_mangen(ui, command, args),
|
||||
UtilCommand::MarkdownHelp(args) => cmd_util_markdown_help(ui, command, args),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
source: cli/tests/test_generate_md_cli_help.rs
|
||||
description: "AUTO-GENERATED FILE, DO NOT EDIT. This cli reference is generated by a test as an `insta` snapshot. MkDocs includes this snapshot from docs/cli-reference.md."
|
||||
snapshot_kind: text
|
||||
---
|
||||
<!-- BEGIN MARKDOWN-->
|
||||
|
||||
|
@ -92,6 +93,7 @@ This document contains the help content for the `jj` command-line program.
|
|||
* [`jj util`↴](#jj-util)
|
||||
* [`jj util completion`↴](#jj-util-completion)
|
||||
* [`jj util config-schema`↴](#jj-util-config-schema)
|
||||
* [`jj util exec`↴](#jj-util-exec)
|
||||
* [`jj util gc`↴](#jj-util-gc)
|
||||
* [`jj util mangen`↴](#jj-util-mangen)
|
||||
* [`jj util markdown-help`↴](#jj-util-markdown-help)
|
||||
|
@ -2117,6 +2119,7 @@ Infrequently used commands such as for generating shell completions
|
|||
|
||||
* `completion` — Print a command-line-completion script
|
||||
* `config-schema` — Print the JSON schema for the jj TOML config format
|
||||
* `exec` — Execute an external command via jj
|
||||
* `gc` — Run backend-dependent garbage collection
|
||||
* `mangen` — Print a ROFF (manpage)
|
||||
* `markdown-help` — Print the CLI help for all subcommands in Markdown
|
||||
|
@ -2162,6 +2165,59 @@ Print the JSON schema for the jj TOML config format
|
|||
|
||||
|
||||
|
||||
## `jj util exec`
|
||||
|
||||
Execute an external command via jj
|
||||
|
||||
This is useful for arbitrary aliases.
|
||||
|
||||
!! WARNING !!
|
||||
|
||||
The following technique just provides a convenient syntax for running
|
||||
arbitrary code on your system. Using it irresponsibly may cause damage
|
||||
ranging from breaking the behavior of `jj undo` to wiping your file system.
|
||||
Exercise the same amount of caution while writing these aliases as you would
|
||||
when typing commands into the terminal!
|
||||
|
||||
This feature may be removed or replaced by an embedded scripting language in
|
||||
the future.
|
||||
|
||||
Let's assume you have a script called "my-jj-script" in you $PATH and you
|
||||
would like to execute it as "jj my-script". You would add the following line
|
||||
to your configuration file to achieve that:
|
||||
|
||||
```toml
|
||||
[aliases]
|
||||
my-script = ["util", "exec", "--", "my-jj-script"]
|
||||
# ^^^^
|
||||
# This makes sure that flags are passed to your script instead of parsed by jj.
|
||||
```
|
||||
|
||||
If you don't want to manage your script as a separate file, you can even
|
||||
inline it into your config file:
|
||||
|
||||
```toml
|
||||
[aliases]
|
||||
my-inline-script = ["util", "exec", "--", "bash", "-c", """
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
echo "Look Ma, everything in one file!"
|
||||
echo "args: $@"
|
||||
""", ""]
|
||||
# ^^
|
||||
# This last empty string will become "$0" in bash, so your actual arguments
|
||||
# are all included in "$@" and start at "$1" as expected.
|
||||
```
|
||||
|
||||
**Usage:** `jj util exec <COMMAND> [ARGS]...`
|
||||
|
||||
###### **Arguments:**
|
||||
|
||||
* `<COMMAND>` — External command to execute
|
||||
* `<ARGS>` — Arguments to pass to the external command
|
||||
|
||||
|
||||
|
||||
## `jj util gc`
|
||||
|
||||
Run backend-dependent garbage collection
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
use insta::assert_snapshot;
|
||||
|
||||
use crate::common::strip_last_line;
|
||||
use crate::common::TestEnvironment;
|
||||
|
||||
#[test]
|
||||
|
@ -112,3 +113,33 @@ fn test_shell_completions() {
|
|||
test("nushell");
|
||||
test("zsh");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_util_exec() {
|
||||
let test_env = TestEnvironment::default();
|
||||
let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter");
|
||||
let (out, err) = test_env.jj_cmd_ok(
|
||||
test_env.env_root(),
|
||||
&[
|
||||
"util",
|
||||
"exec",
|
||||
"--",
|
||||
formatter_path.to_str().unwrap(),
|
||||
"--append",
|
||||
"hello",
|
||||
],
|
||||
);
|
||||
insta::assert_snapshot!(out, @"hello");
|
||||
// Ensures only stdout contains text
|
||||
assert!(err.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_util_exec_fail() {
|
||||
let test_env = TestEnvironment::default();
|
||||
let err = test_env.jj_cmd_failure(
|
||||
test_env.env_root(),
|
||||
&["util", "exec", "--", "missing-program"],
|
||||
);
|
||||
insta::assert_snapshot!(strip_last_line(&err), @"Error: Failed to execute external command 'missing-program'");
|
||||
}
|
||||
|
|
|
@ -528,6 +528,41 @@ You can define aliases for commands, including their arguments. For example:
|
|||
aliases.l = ["log", "-r", "(main..@):: | (main..@)-"]
|
||||
```
|
||||
|
||||
This alias syntax can only run a single jj command. However, you may want to
|
||||
execute multiple jj commands with a single alias, or run arbitrary scripts that
|
||||
complement your version control workflow. This can be done, but be aware of the
|
||||
danger:
|
||||
|
||||
!!! warning
|
||||
|
||||
The following technique just provides a convenient syntax for running
|
||||
arbitrary code on your system. Using it irresponsibly may cause damage
|
||||
ranging from breaking the behavior of `jj undo` to wiping your file system.
|
||||
Exercise the same amount of caution while writing these aliases as you would
|
||||
when typing commands into the terminal!
|
||||
|
||||
This feature may be removed or replaced by an embedded scripting language in
|
||||
the future.
|
||||
|
||||
The command `jj util exec` will simply run any command you pass to it as an
|
||||
argument. Additional arguments are passed through. Here are some examples:
|
||||
|
||||
```toml
|
||||
[aliases]
|
||||
my-script = ["util", "exec", "--", "my-jj-script"]
|
||||
# ^^^^
|
||||
# This makes sure that flags are passed to your script instead of parsed by jj.
|
||||
my-inline-script = ["util", "exec", "--", "bash", "-c", """
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
echo "Look Ma, everything in one file!"
|
||||
echo "args: $@"
|
||||
""", ""]
|
||||
# ^^
|
||||
# This last empty string will become "$0" in bash, so your actual arguments
|
||||
# are all included in "$@" and start at "$1" as expected.
|
||||
```
|
||||
|
||||
## Editor
|
||||
|
||||
The default editor is set via `ui.editor`, though there are several places to
|
||||
|
|
Loading…
Reference in a new issue