1from __future__ import unicode_literals 2 3import argparse 4 5import dvc.logger as logger 6from dvc.command.base import CmdBase 7from dvc.exceptions import DvcException 8 9 10class CmdRun(CmdBase): 11 def run(self): 12 overwrite = self.args.yes or self.args.overwrite_dvcfile 13 14 if not any( 15 [ 16 self.args.deps, 17 self.args.outs, 18 self.args.outs_no_cache, 19 self.args.metrics, 20 self.args.metrics_no_cache, 21 self.args.command, 22 ] 23 ): # pragma: no cover 24 logger.error( 25 "too few arguments. Specify at least one: '-d', " 26 "'-o', '-O', '-m', '-M', 'command'." 27 ) 28 return 1 29 30 try: 31 self.repo.run( 32 cmd=self._parsed_cmd(), 33 outs=self.args.outs, 34 outs_no_cache=self.args.outs_no_cache, 35 metrics=self.args.metrics, 36 metrics_no_cache=self.args.metrics_no_cache, 37 deps=self.args.deps, 38 fname=self.args.file, 39 cwd=self.args.cwd, 40 wdir=self.args.wdir, 41 no_exec=self.args.no_exec, 42 overwrite=overwrite, 43 ignore_build_cache=self.args.ignore_build_cache, 44 remove_outs=self.args.remove_outs, 45 no_commit=self.args.no_commit, 46 ) 47 except DvcException: 48 logger.error("failed to run command") 49 return 1 50 51 return 0 52 53 def _parsed_cmd(self): 54 """ 55 We need to take into account two cases: 56 57 - ['python code.py foo bar']: Used mainly with dvc as a library 58 - ['echo', 'foo bar']: List of arguments received from the CLI 59 60 The second case would need quoting, as it was passed through: 61 dvc run echo "foo bar" 62 """ 63 if len(self.args.command) < 2: 64 return " ".join(self.args.command) 65 66 return " ".join(self._quote_argument(arg) for arg in self.args.command) 67 68 def _quote_argument(self, argument): 69 if " " not in argument or '"' in argument: 70 return argument 71 72 return '"{}"'.format(argument) 73 74 75def add_parser(subparsers, parent_parser): 76 RUN_HELP = ( 77 "Generate a stage file from a given " 78 "command and execute the command." 79 ) 80 run_parser = subparsers.add_parser( 81 "run", parents=[parent_parser], description=RUN_HELP, help=RUN_HELP 82 ) 83 run_parser.add_argument( 84 "-d", 85 "--deps", 86 action="append", 87 default=[], 88 help="Declare dependencies for reproducible cmd.", 89 ) 90 run_parser.add_argument( 91 "-o", 92 "--outs", 93 action="append", 94 default=[], 95 help="Declare output file or directory.", 96 ) 97 run_parser.add_argument( 98 "-O", 99 "--outs-no-cache", 100 action="append", 101 default=[], 102 help="Declare output file or directory " 103 "(do not put into DVC cache).", 104 ) 105 run_parser.add_argument( 106 "-m", 107 "--metrics", 108 action="append", 109 default=[], 110 help="Declare output metric file or directory.", 111 ) 112 run_parser.add_argument( 113 "-M", 114 "--metrics-no-cache", 115 action="append", 116 default=[], 117 help="Declare output metric file or directory " 118 "(do not put into DVC cache).", 119 ) 120 run_parser.add_argument( 121 "-f", 122 "--file", 123 help="Specify name of the stage file. It should be " 124 "either 'Dvcfile' or have a '.dvc' suffix (e.g. " 125 "'prepare.dvc', 'clean.dvc', etc) in order for " 126 "dvc to be able to find it later. By default " 127 "the first output basename + .dvc is used as " 128 "a stage filename.", 129 ) 130 run_parser.add_argument( 131 "-c", "--cwd", default=None, help="Deprecated, use -w and -f instead." 132 ) 133 run_parser.add_argument( 134 "-w", 135 "--wdir", 136 default=None, 137 help="Directory within your repo to run your command in.", 138 ) 139 run_parser.add_argument( 140 "--no-exec", 141 action="store_true", 142 default=False, 143 help="Only create stage file without actually running it.", 144 ) 145 run_parser.add_argument( 146 "-y", 147 "--yes", 148 action="store_true", 149 default=False, 150 help="Deprecated, use --overwrite-dvcfile instead", 151 ) 152 run_parser.add_argument( 153 "--overwrite-dvcfile", 154 action="store_true", 155 default=False, 156 help="Overwrite existing dvc file without asking for confirmation.", 157 ) 158 run_parser.add_argument( 159 "--ignore-build-cache", 160 action="store_true", 161 default=False, 162 help="Run this stage even if it has been already ran with the same " 163 "command/dependencies/outputs/etc before.", 164 ) 165 run_parser.add_argument( 166 "--remove-outs", 167 action="store_true", 168 default=False, 169 help="Remove outputs before running the command.", 170 ) 171 run_parser.add_argument( 172 "--no-commit", 173 action="store_true", 174 default=False, 175 help="Don't put files/directories into cache.", 176 ) 177 run_parser.add_argument( 178 "command", nargs=argparse.REMAINDER, help="Command to execute." 179 ) 180 run_parser.set_defaults(func=CmdRun) 181