Changeset 315 in tailor
- Timestamp:
- 05/23/05 16:15:46 (8 years ago)
- Hash name:
- 20050523141546-97f81-316eb82b8236d5e403581507651e4f4863e7b767
- Files:
-
- 2 edited
-
README (modified) (2 diffs)
-
vcpx/session.py (modified) (19 diffs)
Legend:
- Unmodified
- Added
- Removed
-
README
r310 r315 46 46 .. _baazar-ng: http://www.bazaar-ng.org/ 47 47 48 48 49 Installation 49 50 ============ … … 204 205 205 206 207 Interactive sessions 208 -------------------- 209 210 Tailor offers an alternative way of driving its activity by using an 211 interactive session, bringing the configuration more similar to a 212 script. 213 214 Although this is still a work-in-progress, it's quickly becoming my 215 preferred usage, as its functionality cover the underlying tailor 216 features. 217 218 For example, this is the script I'm using to test it:: 219 220 cd /tmp/p/wc 221 state_file tailor.state 222 source_kind darcs 223 target_kind svn 224 source_repository /home/lele/WiP/cvsync 225 sub_directory cvsync 226 227 that, as you can see, specifies the context needed by tailor to do its 228 work. With the following command line:: 229 230 $ tailor.py --verbose --interactive tailor.cmds 231 Welcome to the Tailor interactive session: you can issue several commands 232 with the usual `readline` facilities. With "help" you'll get a list of 233 available commands. 234 235 Current directory: /tmp/p/wc 236 Current state file: /tmp/p/wc/tailor.state 237 Current source kind: darcs 238 Current target kind: svn 239 Current source repository: /home/lele/WiP/cvsync 240 Sub directory: cvsync 241 tailor $ help 242 243 Documented commands (type help <topic>): 244 ======================================== 245 EOF get_changes source_module target_module 246 bootstrap logfile source_repository target_repository 247 cd save state_file 248 current_directory show_changes sub_directory 249 exit source_kind target_kind 250 251 Undocumented commands: 252 ====================== 253 help 254 255 tailor $ help bootstrap 256 257 Checkout the initial upstream revision, by default HEAD (or 258 specified by argument), then import the subtree into the 259 target repository. 260 261 206 262 Further help 207 263 ============ -
vcpx/session.py
r312 r315 13 13 steps tipically performed by tailor, using an interaction with the user 14 14 instead of pushing options madness on him. 15 16 Each session's data may persist in *state file*, that may be specified17 either thru the ``state_file`` command::18 19 bash $ tailor --verbose --interactive20 Welcome to the Tailor interactive session: you can issue several commands21 with the usual `readline` facilities. With "help" you'll get a list of22 available commands.23 24 tailor $ state_file ~/tailored/someproj.state25 26 or directly as the only non-option argument on the tailor's command line::27 28 bash $ tailor -vi ~/tailored/someproj.state29 30 with the same meaning. The content of the file overrides the options.31 15 """ 32 16 … … 49 33 prompt = "tailor $ " 50 34 51 PERSIST_ATTRS = ('source_repository', 'source_kind', 'source_module',52 'source_revision', 'target_repository',53 'target_kind', 'target_module', 'current_directory',54 'sub_directory')55 56 35 def __init__(self, options, args): 36 """ 37 Initialize a new interactive session. 38 39 Set the default values, and override them with option settings, 40 then slurp in each command line argument that should contain 41 a list of commands to be executed. 42 """ 43 57 44 Cmd.__init__(self) 58 45 self.options = options … … 62 49 self.source_kind = options.source_kind 63 50 self.source_module = options.module 64 self.source_revision = None65 51 self.target_repository = None 66 52 self.target_kind = options.target_kind 67 53 self.target_module = None 68 self.state_file = args and args[0] or None69 54 self.current_directory = getcwd() 70 55 self.sub_directory = None 71 56 57 self.state_file = 'tailor.state' 58 72 59 self.changesets = None 73 self.changed = False 74 75 if self.state_file: 76 self.__loadState() 77 78 def __del__(self): 79 if self.state_file and self.changed: 80 self.__saveState() 81 82 def __saveState(self): 83 self.__log('Saving state file...\n') 84 state = file(self.state_file, 'w') 85 for attr in self.PERSIST_ATTRS: 86 value = getattr(self, attr) 87 if not value is None: 88 state.write('%s=%s\n' % (attr, value)) 89 state.close() 90 91 def __loadState(self): 92 state = file(self.state_file, 'r') 93 for line in state: 94 attr, value = line[:-1].split('=',1) 95 meth = getattr(self, 'do_' + attr) 96 meth(value) 97 state.close() 98 60 self.logfile = None 61 self.logger = None 62 63 self.__processArgs() 64 65 def __processArgs(self): 66 """ 67 Process optional command line arguments. 68 69 Each argument is assumed to contain a list of tailor commands 70 to execute in order. 71 """ 72 73 for arg in self.args: 74 self.cmdqueue.extend(file(arg).readlines()) 75 99 76 def __log(self, what): 77 if self.logger: 78 self.logger.info(what) 79 100 80 if self.options.verbose: 101 81 self.stdout.write(what) 102 82 103 83 def __err(self, what): 84 if self.logger: 85 self.logger.error(what) 86 104 87 self.stdout.write('Error: ') 105 88 self.stdout.write(what) … … 109 92 110 93 def emptyline(self): 111 for attr in self.PERSIST_ATTRS:112 print '%s=%s' % (attr, getattr(self, attr))94 """Override the default impl of reexecuting last command.""" 95 pass 113 96 114 97 def do_exit(self, arg): … … 124 107 125 108 def do_save(self, arg): 126 """Save the commands history ."""109 """Save the commands history on the specified file.""" 127 110 128 111 import readline 129 112 130 113 if not arg: 131 arg = '/tmp/tailor.cmds'114 return 132 115 133 116 readline.write_history_file(arg) … … 141 124 chdir(arg) 142 125 self.current_directory = getcwd() 143 self.changed = True144 126 except: 145 127 self.__log('Cannot change current directory to %s\n' % … … 158 140 159 141 if arg and self.sub_directory <> arg: 160 self.sub_directory = getcwd() 161 self.changed = True 142 self.sub_directory = arg 162 143 163 144 self.__log('Sub directory: %s\n' % self.sub_directory) 164 145 146 def do_logfile(self, arg): 147 """Print or set the logfile of operations.""" 148 149 import logging 150 151 if arg: 152 self.logfile = arg 153 self.logger = logging.getLogger('tailor') 154 hdlr = logging.FileHandler(self.logfile) 155 formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(message)s') 156 hdlr.setFormatter(formatter) 157 self.logger.addHandler(hdlr) 158 self.logger.setLevel(logging.INFO) 159 160 self.__log('Logging to: %s\n' % self.logfile) 161 165 162 def do_source_kind(self, arg): 166 163 """Print or set the source repository kind.""" … … 168 165 if arg and self.source_kind <> arg: 169 166 self.source_kind = arg 170 self.changed = True171 167 172 168 self.__log('Current source kind: %s\n' % self.source_kind) … … 177 173 if arg and self.target_kind <> arg: 178 174 self.target_kind = arg 179 self.changed = True180 175 181 176 self.__log('Current target kind: %s\n' % self.target_kind) … … 190 185 arg = arg[:-1] 191 186 self.source_repository = arg 192 self.changed = True193 187 194 188 self.__log('Current source repository: %s\n' % self.source_repository) … … 203 197 arg = arg[:-1] 204 198 self.target_repository = arg 205 self.changed = True206 199 207 200 self.__log('Current target repository: %s\n' % self.target_repository) … … 216 209 arg = arg[:-1] 217 210 self.source_module = arg 218 self.changed = True219 211 220 212 self.__log('Current target kind: %s\n' % self.source_module) … … 229 221 arg = arg[:-1] 230 222 self.target_module = arg 231 self.changed = True232 223 233 224 self.__log('Current target kind: %s\n' % self.target_module) 234 225 235 def do_source_revision(self, arg): 236 """Print or set the current source revision.""" 237 238 if arg and self.source_revision <> arg: 239 self.source_revision = arg 240 self.changed = True 241 242 self.__log('Current source revision: %s\n' % self.source_revision) 226 def readSourceRevision(self): 227 """Read the source revision from the state file.""" 228 229 try: 230 sf = open(self.state_file) 231 revision = sf.read() 232 sf.close() 233 except IOError: 234 revision = None 235 236 return revision 237 238 def saveSourceRevision(self, revision): 239 """Write current source revision in the state file.""" 240 241 sf = open(self.state_file, 'w') 242 sf.write(revision) 243 sf.close() 243 244 244 245 def do_state_file(self, arg): 245 246 """ 246 247 Print or set the current state_file. 247 248 When specified, this is used as the persistent storage for this249 session, automatically saved upon clean exit.250 248 251 249 The argument must be a file name, possibly with the usual … … 253 251 """ 254 252 255 from os.path import exists,isabs, abspath, expanduser253 from os.path import isabs, abspath, expanduser 256 254 257 255 if arg: … … 262 260 if arg and self.state_file <> arg: 263 261 self.state_file = arg 264 self.changed = True 265 262 266 263 self.__log('Current state file: %s\n' % self.state_file) 267 264 268 if exists(self.state_file):269 self.__loadState()270 271 265 def do_get_changes(self, arg): 272 266 """Fetch information on upstream changes.""" 273 267 268 source_revision = self.readSourceRevision() 274 269 if self.source_kind and \ 275 270 self.source_repository and \ 276 271 self.source_module and \ 277 s elf.source_revision:272 source_revision: 278 273 279 274 dwd = DualWorkingDir(self.source_kind, self.target_kind) … … 281 276 self.source_repository, 282 277 self.source_module, 283 s elf.source_revision)278 source_revision) 284 279 self.__log('Collected %d upstream changesets\n' % 285 280 len(self.changesets)) 286 281 else: 287 self.__err("needs 'source_kind', 'source_repository' ,"288 "'source_module' and 'source_revision'to proceed.\n")282 self.__err("needs 'source_kind', 'source_repository' and " 283 "'source_module' to proceed.\n") 289 284 290 285 def do_show_changes(self, arg): … … 296 291 else: 297 292 self.__err("needs `get_changes` to proceed.\n") 298 293 299 294 def do_bootstrap(self, arg): 300 """Bootstrap a new tailorized module.""" 301 295 """ 296 Checkout the initial upstream revision, by default HEAD (or 297 specified by argument), then import the subtree into the 298 target repository. 299 """ 300 302 301 from os.path import join, split, sep 303 302 from dualwd import DualWorkingDir … … 308 307 subdir = split(self.source_module or self.source_repository)[1] or '' 309 308 self.do_sub_directory(subdir) 310 311 self.__log("Bootstrapping '%s'\n" % join(self.current_directory, subdir))312 309 310 revision = arg or self.options.revision or 'HEAD' 311 313 312 dwd = DualWorkingDir(self.source_kind, self.target_kind) 314 313 self.__log("Getting %s revision '%s' of '%s' from '%s'\n" % ( 315 self.source_kind, self.source_revision,314 self.source_kind, revision, 316 315 self.source_module, self.source_repository)) 317 316 … … 320 319 self.source_repository, 321 320 self.source_module, 322 self.source_revision, 323 subdir=subdir) 324 except: 325 self.__err('Checkout failed!\n') 326 raise 327 321 revision, 322 subdir=subdir, 323 logger=self.logger) 324 self.saveSourceRevision(actual) 325 except Exception, exc: 326 self.__err('Checkout failed: %s, %s' % (exc.__doc__, exc)) 327 if self.logger: 328 self.logger.exception('Checkout failed') 329 328 330 try: 329 331 dwd.initializeNewWorkingDir(self.current_directory, 330 332 self.target_repository, 331 333 self.target_module, 332 subdir, actual) 334 self.sub_directory, 335 actual) 333 336 except: 334 self.__err('Working copy initialization failed!\n') 335 raise 336 337 self.do_source_revision(actual) 338 self.__log("Bootstrap completed") 337 self.__err('Working copy initialization failed: %s, %s' % (exc.__doc__, exc)) 338 if self.logger: 339 self.logger.exception('Working copy initialization failed') 339 340 340 341
Note: See TracChangeset
for help on using the changeset viewer.
