Changeset 315 in tailor for vcpx/session.py


Ignore:
Timestamp:
05/23/05 16:15:46 (8 years ago)
Author:
lele@…
Hash name:
20050523141546-97f81-316eb82b8236d5e403581507651e4f4863e7b767
Message:

Reworked the interactive session, separating configuration from state

File:
1 edited

Legend:

Unmodified
Added
Removed
  • vcpx/session.py

    r312 r315  
    1313steps tipically performed by tailor, using an interaction with the user 
    1414instead of pushing options madness on him. 
    15  
    16 Each session's data may persist in *state file*, that may be specified 
    17 either thru the ``state_file`` command:: 
    18  
    19   bash $ tailor --verbose --interactive 
    20   Welcome to the Tailor interactive session: you can issue several commands 
    21   with the usual `readline` facilities. With "help" you'll get a list of 
    22   available commands. 
    23  
    24   tailor $ state_file ~/tailored/someproj.state 
    25    
    26 or directly as the only non-option argument on the tailor's command line:: 
    27  
    28   bash $ tailor -vi ~/tailored/someproj.state 
    29  
    30 with the same meaning. The content of the file overrides the options. 
    3115""" 
    3216 
     
    4933    prompt = "tailor $ " 
    5034     
    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      
    5635    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         
    5744        Cmd.__init__(self) 
    5845        self.options = options         
     
    6249        self.source_kind = options.source_kind 
    6350        self.source_module = options.module 
    64         self.source_revision = None 
    6551        self.target_repository = None 
    6652        self.target_kind = options.target_kind 
    6753        self.target_module = None 
    68         self.state_file = args and args[0] or None 
    6954        self.current_directory = getcwd() 
    7055        self.sub_directory = None 
    7156         
     57        self.state_file = 'tailor.state' 
     58         
    7259        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 
    9976    def __log(self, what): 
     77        if self.logger: 
     78            self.logger.info(what) 
     79             
    10080        if self.options.verbose: 
    10181            self.stdout.write(what) 
    10282 
    10383    def __err(self, what): 
     84        if self.logger: 
     85            self.logger.error(what) 
     86             
    10487        self.stdout.write('Error: ') 
    10588        self.stdout.write(what) 
     
    10992 
    11093    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 
    11396         
    11497    def do_exit(self, arg): 
     
    124107 
    125108    def do_save(self, arg): 
    126         """Save the commands history.""" 
     109        """Save the commands history on the specified file.""" 
    127110 
    128111        import readline 
    129112 
    130113        if not arg: 
    131             arg = '/tmp/tailor.cmds' 
     114            return 
    132115             
    133116        readline.write_history_file(arg) 
     
    141124                chdir(arg) 
    142125                self.current_directory = getcwd() 
    143                 self.changed = True 
    144126            except: 
    145127                self.__log('Cannot change current directory to %s\n' % 
     
    158140         
    159141        if arg and self.sub_directory <> arg: 
    160             self.sub_directory = getcwd() 
    161             self.changed = True 
     142            self.sub_directory = arg 
    162143 
    163144        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 
    165162    def do_source_kind(self, arg): 
    166163        """Print or set the source repository kind.""" 
     
    168165        if arg and self.source_kind <> arg: 
    169166            self.source_kind = arg 
    170             self.changed = True 
    171167 
    172168        self.__log('Current source kind: %s\n' % self.source_kind) 
     
    177173        if arg and self.target_kind <> arg: 
    178174            self.target_kind = arg 
    179             self.changed = True 
    180175 
    181176        self.__log('Current target kind: %s\n' % self.target_kind) 
     
    190185                arg = arg[:-1] 
    191186            self.source_repository = arg 
    192             self.changed = True 
    193187 
    194188        self.__log('Current source repository: %s\n' % self.source_repository) 
     
    203197                arg = arg[:-1] 
    204198            self.target_repository = arg 
    205             self.changed = True 
    206199 
    207200        self.__log('Current target repository: %s\n' % self.target_repository) 
     
    216209                arg = arg[:-1] 
    217210            self.source_module = arg 
    218             self.changed = True 
    219211 
    220212        self.__log('Current target kind: %s\n' % self.source_module) 
     
    229221                arg = arg[:-1] 
    230222            self.target_module = arg 
    231             self.changed = True 
    232223 
    233224        self.__log('Current target kind: %s\n' % self.target_module) 
    234225 
    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() 
    243244         
    244245    def do_state_file(self, arg): 
    245246        """ 
    246247        Print or set the current state_file. 
    247  
    248         When specified, this is used as the persistent storage for this 
    249         session, automatically saved upon clean exit. 
    250248 
    251249        The argument must be a file name, possibly with the usual 
     
    253251        """ 
    254252 
    255         from os.path import exists, isabs, abspath, expanduser 
     253        from os.path import isabs, abspath, expanduser 
    256254 
    257255        if arg: 
     
    262260        if arg and self.state_file <> arg: 
    263261            self.state_file = arg 
    264             self.changed = True 
    265  
     262                 
    266263        self.__log('Current state file: %s\n' % self.state_file) 
    267264 
    268         if exists(self.state_file): 
    269             self.__loadState() 
    270              
    271265    def do_get_changes(self, arg): 
    272266        """Fetch information on upstream changes.""" 
    273          
     267 
     268        source_revision = self.readSourceRevision() 
    274269        if self.source_kind and \ 
    275270           self.source_repository and \ 
    276271           self.source_module and \ 
    277            self.source_revision: 
     272           source_revision: 
    278273 
    279274            dwd = DualWorkingDir(self.source_kind, self.target_kind) 
     
    281276                                                        self.source_repository, 
    282277                                                        self.source_module, 
    283                                                         self.source_revision) 
     278                                                        source_revision) 
    284279            self.__log('Collected %d upstream changesets\n' % 
    285280                       len(self.changesets)) 
    286281        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") 
    289284 
    290285    def do_show_changes(self, arg): 
     
    296291        else: 
    297292            self.__err("needs `get_changes` to proceed.\n") 
    298              
     293 
    299294    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         
    302301        from os.path import join, split, sep 
    303302        from dualwd import DualWorkingDir 
     
    308307            subdir = split(self.source_module or self.source_repository)[1] or '' 
    309308            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         
    313312        dwd = DualWorkingDir(self.source_kind, self.target_kind) 
    314313        self.__log("Getting %s revision '%s' of '%s' from '%s'\n" % ( 
    315             self.source_kind, self.source_revision, 
     314            self.source_kind, revision, 
    316315            self.source_module, self.source_repository)) 
    317316 
     
    320319                                                  self.source_repository, 
    321320                                                  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 
    328330        try: 
    329331            dwd.initializeNewWorkingDir(self.current_directory, 
    330332                                        self.target_repository, 
    331333                                        self.target_module, 
    332                                         subdir, actual) 
     334                                        self.sub_directory, 
     335                                        actual) 
    333336        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') 
    339340 
    340341         
Note: See TracChangeset for help on using the changeset viewer.