1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: Apache-2.0
15 "git.arvados.org/arvados.git/lib/cmd"
19 Create = rubyArvCmd{"create"}
20 Edit = rubyArvCmd{"edit"}
22 Copy = externalCmd{"arv-copy"}
23 Tag = externalCmd{"arv-tag"}
24 Ws = externalCmd{"arv-ws"}
26 Keep = cmd.Multi(map[string]cmd.Handler{
27 "get": externalCmd{"arv-get"},
28 "put": externalCmd{"arv-put"},
29 "ls": externalCmd{"arv-ls"},
30 "normalize": externalCmd{"arv-normalize"},
31 "docker": externalCmd{"arv-keepdocker"},
33 // user, group, container, specimen, etc.
34 APICall = apiCallCmd{}
37 // When using the ruby "arv" command, flags must come before the
38 // subcommand: "arv --format=yaml get foo" works, but "arv get
39 // --format=yaml foo" does not work.
40 func legacyFlagsToFront(subcommand string, argsin []string) (argsout []string) {
41 flags, _ := LegacyFlagSet()
42 flags.SetOutput(ioutil.Discard)
45 argsout = append(argsout, argsin[:len(argsin)-narg]...)
46 argsout = append(argsout, subcommand)
47 argsout = append(argsout, argsin[len(argsin)-narg:]...)
51 type apiCallCmd struct{}
53 func (cmd apiCallCmd) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
54 split := strings.Split(prog, " ")
56 fmt.Fprintf(stderr, "internal error: no api model in %q\n", prog)
59 model := split[len(split)-1]
60 return rubyArvCmd{model}.RunCommand(prog, args, stdin, stdout, stderr)
63 type rubyArvCmd struct {
67 func (rc rubyArvCmd) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
68 wrapprog := "arv-ruby"
69 if _, err := exec.LookPath(wrapprog); err != nil && !strings.Contains(prog, "arv ") {
70 // arv-ruby isn't in PATH (i.e., installation method
71 // wasn't a recent "arvados-server install", which
72 // symlinks /usr/bin/arv-ruby ->
73 // /var/lib/arvados/bin/arv), so fall back to looking
74 // for the arvados-cli program as "arv". (But don't do
75 // this if we are being run as "arv" -- that would
76 // probably cause a recursive fork bomb.)
79 return externalCmd{wrapprog}.RunCommand(wrapprog, legacyFlagsToFront(rc.subcommand, args), stdin, stdout, stderr)
82 type externalCmd struct {
86 func (ec externalCmd) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
87 cmd := exec.Command(ec.prog, args...)
92 switch err := err.(type) {
96 status := err.Sys().(syscall.WaitStatus)
98 return status.ExitStatus()
100 fmt.Fprintf(stderr, "%s failed: %s\n", ec.prog, err)
103 fmt.Fprintln(stderr, err)
104 if ec.prog == "arv" || ec.prog == "arv-ruby" {
105 fmt.Fprint(stderr, rubyInstallHints)
106 } else if strings.HasPrefix(ec.prog, "arv-") {
107 fmt.Fprint(stderr, pythonInstallHints)
111 fmt.Fprintf(stderr, "error running %s: %s\n", ec.prog, err)
118 Note: This subcommand uses the arvados-cli Ruby gem. If that is not
119 installed, try "gem install arvados-cli", or see
120 https://doc.arvados.org/install for more details.
123 pythonInstallHints = `
124 Note: This subcommand uses the "arvados" Python module. If that is
126 * "pip install arvados" (either as root or in a virtualenv), or
127 * "sudo apt-get install python3-arvados-python-client", or
128 * see https://doc.arvados.org/install for more details.