nushell icon indicating copy to clipboard operation
nushell copied to clipboard

How to passtrough any kind of argument / disable parsing

Open sadilekivan opened this issue 2 years ago • 3 comments

Question

I used fish to source a script to help me find my remote targets with avahi. It would wrap the ssh and rsync commands and if there is a certain keyword scan and cache the results for a little time so I can connect without any parameters.

I have converted most of my script to nushell and it is working much better and looking nicer, but I can't wrap a command silently / without any parsing.

I'd like to pass every argument and flag, and also disable the help page for the command if possible (so the original one shows).

I read about pre_execute hooks, and that seemed viable, but I need to access the command to parse it. So far I haven't found out if I can access the cli command from the hook.

Additional context and details

My working fish functions:

function wrap_ssh_based_command
    set bin $argv[1]
    set regex $argv[2]
    set args $argv[3..-1]
    function contains_keyword_arg --no-scope-shadowing
        for arg in $argv
            if echo $arg | string escape | string match -r "$regex" > /dev/null
                return 0
            end
        end
        return 1
    end

    contains_keyword_arg $args
    if [ $status -eq 0 ]
        cached_probe
        if [ $status -eq 0 ]
            eval "$bin $args"
            touch $DEVELOPMENT_CONFIG_PATH
        end
    else
        eval "$bin $args"
    end
end

alias ssh="wrap_ssh_based_command /usr/bin/ssh \"$KEYWORD\" $argv"
alias rsync="wrap_ssh_based_command /usr/bin/rsync \"$KEYWORD(?=:)\" $argv"

My current function works, but if I add any flags like -v for verbose it fails, because that flag is not defined for the function.

def wrap_ssh_based_command [bin, regex_pattern, ...args] {
    let cmd = ($args | prepend $bin | str collect " ")
	if not ($args | find --regex $regex_pattern | is-empty) {
		let scanned = cached_avahi_probe
		nu -c $cmd
		touch $target.config_path
	} else {
		nu -c $cmd
	}
}

alias ssh = wrap_ssh_based_command /usr/bin/ssh $keyword
alias rsync = wrap_ssh_based_command /usr/bin/rsync $"($keyword)\(?=:)"

sadilekivan avatar Sep 16 '22 12:09 sadilekivan

I'm thinking you're going to have to add flags to your custom command signature, like:

> def test [name, ...args, --verbose(-v)] { echo $"name=($name) args=($args) verbose=($verbose)" }
> test abc
name=abc args=[] verbose=false
> test abc def ghi
name=abc args=[def, ghi] verbose=false
> test abc def ghi -v
name=abc args=[def, ghi] verbose=true
> test abc def ghi -v -a
Error: nu::parser::unknown_flag (link)

  × The `test` command doesn't have flag `-a`.
   ╭─[entry #6:1:1]
 1 │ test abc def ghi -v -a
   ·                      ┬
   ·                      ╰── unknown flag
   ╰────
  help: use test --help for a list of flags

There may be other ways but I'm not sure exactly. You might look around in our nu_scripts repo to see if anyone else has solved this problem.

fdncred avatar Sep 16 '22 13:09 fdncred

There may be other ways but I'm not sure exactly. You might look around in our nu_scripts repo to see if anyone else has solved this problem.

Good idea, I missed that. I don't use arguments with ssh much, but rsync has the useful archive and recursive arguments. I guess at that amount of flags there's no problem just hard coding it.

sadilekivan avatar Sep 16 '22 13:09 sadilekivan

This issue has come up often before, see the issues linked in this PR: https://github.com/nushell/nushell/pull/6567

We need to find a good solution to being able to relax the signature parsing.

kubouch avatar Sep 16 '22 13:09 kubouch