@@ -25,14 +25,14 @@ def __init__(self):
2525 self .command = 'mv'
2626 self .help = 'to move sequences'
2727 self .description = str (colored .green ('''
28- Move sequences in a directory.
29- Rename sequences if the output directory is the same as the input .
28+ Move one or more sequences to a directory.
29+ Rename / retime a sequence .
3030 ''' ))
3131 self ._operation = shutil .move
3232
3333 def fillParser (self , parser ):
34- parser .add_argument ('inputs' , metavar = 'INPUTS' , nargs = '+' , action = 'store' , help = 'list of inputs' ).completer = samUtils .sequenceParserCompleter
35- parser .add_argument ('output' , metavar = 'OUTPUT' , help = 'the output to write' ).completer = samUtils .sequenceParserCompleter
34+ parser .add_argument ('inputs' , metavar = 'INPUTS' , nargs = '+' , action = 'store' , help = 'list of inputs (only sequences) ' ).completer = samUtils .sequenceParserCompleter
35+ parser .add_argument ('output' , metavar = 'OUTPUT' , help = 'the output to write (sequence or directory) ' ).completer = samUtils .sequenceParserCompleter
3636
3737 # Options
3838 parser .add_argument ('-o' , '--offset' , dest = 'offset' , type = int , help = 'retime the sequence with the given offset' )
@@ -48,6 +48,7 @@ def fillParser(self, parser):
4848
4949 parser .add_argument ('--detect-negative' , dest = 'detectNegative' , action = 'store_true' , help = 'detect negative numbers instead of detecting "-" as a non-digit character' )
5050 parser .add_argument ('-v' , '--verbose' , dest = 'verbose' , action = samUtils .SamSetVerboseAction , default = 2 , help = 'verbose level (0/fatal, 1/error, 2/warn(by default), 3/info, 4(or upper)/debug)' )
51+ parser .add_argument ('--dry-run' , dest = 'dryRun' , action = 'store_true' , help = 'only print what it will do (will force verbosity to info)' )
5152
5253 def _getSequenceManipulators (self , inputSequence , args ):
5354 """
@@ -86,10 +87,11 @@ def _getSequenceManipulators(self, inputSequence, args):
8687
8788 return {'first' : first , 'last' : last , 'offset' : offset , 'holes' : holesToRemove }
8889
89- def _processSequence (self , inputItem , outputSequence , outputSequencePath , moveManipulators ):
90+ def _processSequence (self , inputItem , outputSequence , outputSequencePath , moveManipulators , dryRun ):
9091 """
9192 Apply operation to the sequence contained in inputItem (used by sam-mv and sam-cp).
9293 Depending on args, update the frame ranges of the output sequence.
94+ Return if the operation was a success or not.
9395
9496 :param inputItem: the item which contains the input sequence to process (move, copy...)
9597 :param outputSequence: the output sequence to write (destination of move, copy...)
@@ -101,17 +103,20 @@ def _processSequence(self, inputItem, outputSequence, outputSequencePath, moveMa
101103 offset used to retime the output sequence,
102104 list of holes to remove in the output sequence
103105 }
106+ :param dryRun: only print what it will do.
104107 """
105108 # create output directory if not exists
106109 try :
107110 if not os .path .exists (outputSequencePath ):
108- os .makedirs (outputSequencePath )
111+ # sam-rm --dry-run
112+ if not dryRun :
113+ os .makedirs (outputSequencePath )
109114 except Exception as e :
110115 self .logger .error ('Cannot create directory tree for "' + outputSequencePath + '": ' + str (e ))
111- exit ( - 1 )
116+ return 1
112117
113- # print brief of the operation
114- self .logger .info (os .path .join (inputItem .getFolder (), str (inputItem .getSequence ())) + ' -> ' + os .path .join (outputSequencePath , str (outputSequence )))
118+ # log brief of the operation
119+ self .logger .info (os .path .join (self . command + ' ' + inputItem .getFolder (), str (inputItem .getSequence ())) + ' to ' + os .path .join (outputSequencePath , str (outputSequence )))
115120
116121 # get frame ranges
117122 inputFrameList = list (inputItem .getSequence ().getFramesIterable (moveManipulators ['first' ], moveManipulators ['last' ]))
@@ -128,14 +133,18 @@ def _processSequence(self, inputItem, outputSequence, outputSequencePath, moveMa
128133 # security: check if file already exist
129134 if os .path .exists (outputPath ):
130135 self .logger .error ('The output path "' + outputPath + '" already exist!' )
131- exit ( - 1 )
136+ return 1
132137
133138 # process the image at time
134- self ._operation (inputPath , outputPath )
139+ self .logger .info (inputPath + ' -> ' + outputPath )
140+ # sam-rm --dry-run
141+ if not dryRun :
142+ self ._operation (inputPath , outputPath )
135143
136144 def _getSequenceItemFromPath (self , inputPath , detectNegative ):
137145 """
138- Get an Item (which corresponds to a sequence) from a path.
146+ Return an Item (which corresponds to a sequence) from a path.
147+ Return None if the operation failed.
139148 """
140149 # get input path and name
141150 inputSequencePath = os .path .dirname (inputPath )
@@ -152,16 +161,16 @@ def _getSequenceItemFromPath(self, inputPath, detectNegative):
152161 inputItems = sequenceParser .browse (inputSequencePath , detectionMethod , [inputSequenceName ])
153162 if not len (inputItems ):
154163 self .logger .error ('No existing file corresponds to the given input sequence: ' + inputPath )
155- exit ( - 1 )
164+ return None
156165 if len (inputItems ) > 1 :
157166 self .logger .error ('Several items ' + str ([item .getFilename () for item in inputItems ]) + ' correspond to the given input sequence: ' + inputPath )
158- exit ( - 1 )
167+ return None
159168
160169 # check if the item is a sequence
161170 inputItem = inputItems [0 ]
162171 if inputItem .getType () != sequenceParser .eTypeSequence :
163172 self .logger .error ('Input is not a sequence: ' + inputItem .getFilename ())
164- exit ( - 1 )
173+ return None
165174
166175 return inputItem
167176
@@ -173,26 +182,39 @@ def run(self, parser):
173182 args = parser .parse_args ()
174183
175184 # Set sam log level
176- self .setLogLevel (args .verbose )
185+ # sam-rm --dry-run
186+ if args .dryRun :
187+ self .setLogLevel (3 ) # info
188+ else :
189+ self .setLogLevel (args .verbose )
177190
178191 # check command line
179192 if args .offset and (args .outputFirst is not None or args .outputLast is not None ):
180193 self .logger .error ('You cannot cumulate multiple options to modify the time.' )
181194 exit (- 1 )
182195
183- # Get output path
184- outputSequencePath = os .path .dirname (args .output )
185- if not outputSequencePath :
186- outputSequencePath = '.'
187-
188196 # Get output sequence
189197 outputSequence = sequenceParser .Sequence ()
190198 outputSequenceName = os .path .basename (args .output )
191199 outputIsSequence = outputSequence .initFromPattern (outputSequenceName , sequenceParser .ePatternDefault )
192200
201+ # Get output path
202+ if outputIsSequence :
203+ outputSequencePath = os .path .dirname (args .output )
204+ # if output path is the same as input
205+ if not len (outputSequencePath ):
206+ outputSequencePath = '.'
207+ else :
208+ outputSequencePath = args .output
209+ self .logger .debug ('Output sequence path is "' + outputSequencePath + '".' )
210+
193211 # For each input
194- for input in args .inputs :
195- inputItem = self ._getSequenceItemFromPath (input , args .detectNegative )
212+ error = 0
213+ for inputPath in args .inputs :
214+ inputItem = self ._getSequenceItemFromPath (inputPath , args .detectNegative )
215+ if inputItem is None :
216+ error = 1
217+ continue
196218
197219 if not outputIsSequence :
198220 outputSequence = sequenceParser .Sequence (inputItem .getSequence ())
@@ -201,8 +223,11 @@ def run(self, parser):
201223 moveManipulators = self ._getSequenceManipulators (inputItem .getSequence (), args )
202224
203225 # move sequence
204- self ._processSequence (inputItem , outputSequence , outputSequencePath , moveManipulators )
226+ err = self ._processSequence (inputItem , outputSequence , outputSequencePath , moveManipulators , args .dryRun )
227+ if err :
228+ error = err
205229
230+ exit (error )
206231
207232if __name__ == '__main__' :
208233 # Create the tool
0 commit comments