just playing with tangled
at gvimdiff 95 lines 3.3 kB view raw
1// Copyright 2024 The Jujutsu Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15use crate::cli_util::CommandHelper; 16use crate::command_error::user_error; 17use crate::command_error::user_error_with_message; 18use crate::command_error::CommandError; 19use crate::ui::Ui; 20 21/// Execute an external command via jj 22/// 23/// This is useful for arbitrary aliases. 24/// 25/// !! WARNING !! 26/// 27/// The following technique just provides a convenient syntax for running 28/// arbitrary code on your system. Using it irresponsibly may cause damage 29/// ranging from breaking the behavior of `jj undo` to wiping your file system. 30/// Exercise the same amount of caution while writing these aliases as you would 31/// when typing commands into the terminal! 32/// 33/// This feature may be removed or replaced by an embedded scripting language in 34/// the future. 35/// 36/// Let's assume you have a script called "my-jj-script" in you $PATH and you 37/// would like to execute it as "jj my-script". You would add the following line 38/// to your configuration file to achieve that: 39/// 40/// ```toml 41/// [aliases] 42/// my-script = ["util", "exec", "--", "my-jj-script"] 43/// # ^^^^ 44/// # This makes sure that flags are passed to your script instead of parsed by jj. 45/// ``` 46/// 47/// If you don't want to manage your script as a separate file, you can even 48/// inline it into your config file: 49/// 50/// ```toml 51/// [aliases] 52/// my-inline-script = ["util", "exec", "--", "bash", "-c", """ 53/// #!/usr/bin/env bash 54/// set -euo pipefail 55/// echo "Look Ma, everything in one file!" 56/// echo "args: $@" 57/// """, ""] 58/// # ^^ 59/// # This last empty string will become "$0" in bash, so your actual arguments 60/// # are all included in "$@" and start at "$1" as expected. 61/// ``` 62#[derive(clap::Args, Clone, Debug)] 63#[command(verbatim_doc_comment)] 64pub(crate) struct UtilExecArgs { 65 /// External command to execute 66 command: String, 67 /// Arguments to pass to the external command 68 args: Vec<String>, 69} 70 71pub fn cmd_util_exec( 72 _ui: &mut Ui, 73 _command: &CommandHelper, 74 args: &UtilExecArgs, 75) -> Result<(), CommandError> { 76 let status = std::process::Command::new(&args.command) 77 .args(&args.args) 78 .status() 79 .map_err(|err| { 80 user_error_with_message( 81 format!("Failed to execute external command '{}'", &args.command), 82 err, 83 ) 84 })?; 85 if !status.success() { 86 let error_msg = if let Some(exit_code) = status.code() { 87 format!("External command exited with {exit_code}") 88 } else { 89 // signal 90 format!("External command was terminated by: {status}") 91 }; 92 return Err(user_error(error_msg)); 93 } 94 Ok(()) 95}