Skip to content
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

Feature: Helper to convert expressions to shell command strings #79

Open
anowell opened this issue Oct 22, 2019 · 2 comments
Open

Feature: Helper to convert expressions to shell command strings #79

anowell opened this issue Oct 22, 2019 · 2 comments

Comments

@anowell
Copy link

anowell commented Oct 22, 2019

I was creating complex expressions using duct and found myself wanting ways to easily print out the shell command in a way that I could easily copy-paste debug in a bash (or similar) shell to debug, to be able to do something like:

let expr = cmd("foo", &args);
println!("Running: {}", expr.to_sh_string());

I started with some custom simple escaping that seemed good enough for my use case, but I found shell_escape to be more a bit more complete and ended up with something like this:

use shell_escape::escape;

fn to_sh_string(cmd: &str, args: &[&str]) -> String {
    let arg_str = args
        .into_iter()
        .map(|&a| escape(a.into()))
        .collect::<Vec<_>>()
        .join(" ");
    format!("{} {}", escape(cmd.into()), arg_str)
}

Which allowed me to print out abnormally complex expressions like:

ssh -o PasswordAuthentication=no -p 22 -t -i /path/to/identity.pem -o 'ProxyCommand=ssh -p 1234 anowell@somehost.com nc %h %p -w 300' 'ubuntu@10.0.0.99' 'docker run --rm -it -v /home/ubuntu/proj/:/proj -w /proj -e KUBECONFIG=/proj/admin-k8s.conf -e PS1='\''\e[33m\A\e[0m:\e[97;41mproj\e[0m$ '\'' -u $UID --entrypoint bash anowell/some-image:latest --norc -i'

I could also imagine extending this to prefix environment variables to the shell string (e.g. foo=bar mycmd arg1 'another arg'). Just an idea; feel free to close if this doesn't fit into the scope of duct.

@oconnor663
Copy link
Owner

oconnor663 commented Oct 22, 2019

That sounds like it could be useful, and it might be a nice improvement over our current debug printing also. I wonder how we would want to represent some of these more complicated features in a cross-platform way:

  • full_env
  • stdout_stderr_swap
  • before_spawn (This one involves arbitrary Rust code and definitely can't be represented in the shell. So we'd need to decide whether to print some placeholder or maybe return an error.)

@anowell
Copy link
Author

anowell commented Oct 22, 2019

Interesting. I could go either way on displaying all the extra complexity, and I won't pretend to know how cross-platform this is, but for unix:

  • I suppose full_env would typically be the default, and without the full env, you'd run env -i - mycmd or env -i - foo=bar mycmd to include specific env vars.
  • stdout_stderr_swap would probably be something like mycmd 3>&2 2>&1 1>&3-
  • before_spawn - I got nothing. I find this API a bit strange: what if I spawn the Command inside the before_spawn handler? Not that you should change the design based on my off-handed observations without context to historical decisions, but my inclination would be toward a simpler: to_command(&self) -> Command conversion helper (or impl From<Expression> for Command) for cases where you need to work with the raw Command type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants