hgkw/keyword.py
changeset 354 8e3364294d0c
parent 353 159bf80a4301
child 355 b3caec747375
equal deleted inserted replaced
353:159bf80a4301 354:8e3364294d0c
    89 commands.optionalrepo += ' kwdemo'
    89 commands.optionalrepo += ' kwdemo'
    90 
    90 
    91 def utcdate(date):
    91 def utcdate(date):
    92     '''Returns hgdate in cvs-like UTC format.'''
    92     '''Returns hgdate in cvs-like UTC format.'''
    93     return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0]))
    93     return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0]))
    94 
       
    95 _kwtemplater = None
       
    96 
    94 
    97 class kwtemplater(object):
    95 class kwtemplater(object):
    98     '''
    96     '''
    99     Sets up keyword templates, corresponding keyword regex, and
    97     Sets up keyword templates, corresponding keyword regex, and
   100     provides keyword substitution functions.
    98     provides keyword substitution functions.
   171         '''Returns text with all keyword substitutions removed.'''
   169         '''Returns text with all keyword substitutions removed.'''
   172         if util.binary(data):
   170         if util.binary(data):
   173             return data
   171             return data
   174         return self.re_kw.sub(r'$\1$', data)
   172         return self.re_kw.sub(r'$\1$', data)
   175 
   173 
   176 
       
   177 # store original patch.patchfile.__init__
   174 # store original patch.patchfile.__init__
   178 _patchfile_init = patch.patchfile.__init__
   175 _patchfile_init = patch.patchfile.__init__
   179 
   176 
   180 def _kwpatchfile_init(self, ui, fname, missing=False):
   177 
   181     '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
   178 def _iskwfile(f, link, kwt):
   182     rejects or conflicts due to expanded keywords in working dir.'''
   179     return not link(f) and kwt.matcher(f)
   183     _patchfile_init(self, ui, fname, missing=missing)
       
   184 
       
   185     if _kwtemplater.matcher(self.fname):
       
   186         # shrink keywords read from working dir
       
   187         kwshrunk = _kwtemplater.shrink(''.join(self.lines))
       
   188         self.lines = kwshrunk.splitlines(True)
       
   189 
       
   190 
       
   191 def _iskwfile(f, link):
       
   192     return not link(f) and _kwtemplater.matcher(f)
       
   193 
   180 
   194 def _status(ui, repo, *pats, **opts):
   181 def _status(ui, repo, *pats, **opts):
   195     '''Bails out if [keyword] configuration is not active.
   182     '''Bails out if [keyword] configuration is not active.
   196     Returns status of working directory.'''
   183     Returns status of working directory.'''
   197     if _kwtemplater:
   184     if hasattr(repo, '_kwt'):
   198         files, match, anypats = cmdutil.matchpats(repo, pats, opts)
   185         files, match, anypats = cmdutil.matchpats(repo, pats, opts)
   199         return repo.status(files=files, match=match, list_clean=True)
   186         return repo.status(files=files, match=match, list_clean=True)
   200     if ui.configitems('keyword'):
   187     if ui.configitems('keyword'):
   201         raise util.Abort(_('[keyword] patterns cannot match'))
   188         raise util.Abort(_('[keyword] patterns cannot match'))
   202     raise util.Abort(_('no [keyword] patterns configured'))
   189     raise util.Abort(_('no [keyword] patterns configured'))
   210         files = [f for f in ctx.files() if f in mf]
   197         files = [f for f in ctx.files() if f in mf]
   211         notify = ui.debug
   198         notify = ui.debug
   212     else:
   199     else:
   213         # kwexpand/kwshrink
   200         # kwexpand/kwshrink
   214         notify = ui.note
   201         notify = ui.note
   215     candidates = [f for f in files if _iskwfile(f, mf.linkf)]
   202     candidates = [f for f in files if _iskwfile(f, mf.linkf, repo._kwt)]
   216     if candidates:
   203     if candidates:
   217         candidates.sort()
   204         candidates.sort()
   218         action = expand and 'expanding' or 'shrinking'
   205         action = expand and 'expanding' or 'shrinking'
   219         for f in candidates:
   206         for f in candidates:
   220             data, kwfound = repo._wreadkwct(f, expand, ctx, node)
   207             data, kwfound = repo._wreadkwct(f, expand, ctx, node)
   339     modified, added, removed, deleted, unknown, ignored, clean = status
   326     modified, added, removed, deleted, unknown, ignored, clean = status
   340     files = modified + added + clean
   327     files = modified + added + clean
   341     if opts.get('untracked'):
   328     if opts.get('untracked'):
   342         files += unknown
   329         files += unknown
   343     files.sort()
   330     files.sort()
   344     kwfiles = [f for f in files if _iskwfile(f, repo._link)]
   331     kwfiles = [f for f in files if _iskwfile(f, repo._link, repo._kwt)]
   345     cwd = pats and repo.getcwd() or ''
   332     cwd = pats and repo.getcwd() or ''
   346     kwfstats = not opts.get('ignore') and (('K', kwfiles),) or ()
   333     kwfstats = not opts.get('ignore') and (('K', kwfiles),) or ()
   347     if opts.get('all') or opts.get('ignore'):
   334     if opts.get('all') or opts.get('ignore'):
   348         kwfstats += (('I', [f for f in files if f not in kwfiles]),)
   335         kwfstats += (('I', [f for f in files if f not in kwfiles]),)
   349     for char, filenames in kwfstats:
   336     for char, filenames in kwfstats:
   374         else:
   361         else:
   375             exc.append(pat)
   362             exc.append(pat)
   376     if not inc:
   363     if not inc:
   377         return
   364         return
   378 
   365 
   379     global _kwtemplater
       
   380     _kwtemplater = kwtemplater(ui, repo, inc, exc)
       
   381 
       
   382     class kwrepo(repo.__class__):
   366     class kwrepo(repo.__class__):
   383         def _wreadkwct(self, filename, expand, ctx, node):
   367         def _wreadkwct(self, filename, expand, ctx, node):
   384             '''Reads filename and returns tuple of data with keywords
   368             '''Reads filename and returns tuple of data with keywords
   385             expanded/shrunk and count of keywords (for _overwrite).'''
   369             expanded/shrunk and count of keywords (for _overwrite).'''
   386             data = super(kwrepo, self).wread(filename)
   370             data = super(kwrepo, self).wread(filename)
   387             return _kwtemplater.process(filename, data, expand, ctx, node)
   371             return self._kwt.process(filename, data, expand, ctx, node)
   388 
   372 
   389         def wread(self, filename):
   373         def wread(self, filename):
   390             data = super(kwrepo, self).wread(filename)
   374             data = super(kwrepo, self).wread(filename)
   391             if _kwtemplater.matcher(filename):
   375             if self._kwt.matcher(filename):
   392                 return _kwtemplater.shrink(data)
   376                 return self._kwt.shrink(data)
   393             return data
   377             return data
   394 
   378 
   395         def wwrite(self, filename, data, flags, overwrite=False):
   379         def wwrite(self, filename, data, flags, overwrite=False):
   396             if not overwrite and _kwtemplater.matcher(filename):
   380             if not overwrite and self._kwt.matcher(filename):
   397                 data = _kwtemplater.expand(filename, data)
   381                 data = self._kwt.expand(filename, data)
   398             super(kwrepo, self).wwrite(filename, data, flags)
   382             super(kwrepo, self).wwrite(filename, data, flags)
   399 
   383 
   400         def wwritedata(self, filename, data):
   384         def wwritedata(self, filename, data):
   401             if _kwtemplater.matcher(filename):
   385             if self._kwt.matcher(filename):
   402                 data = _kwtemplater.expand(filename, data)
   386                 data = self._kwt.expand(filename, data)
   403             return super(kwrepo, self).wwritedata(filename, data)
   387             return super(kwrepo, self).wwritedata(filename, data)
   404 
   388 
   405         def commit(self, files=None, text='', user=None, date=None,
   389         def commit(self, files=None, text='', user=None, date=None,
   406                    match=util.always, force=False, force_editor=False,
   390                    match=util.always, force=False, force_editor=False,
   407                    p1=None, p2=None, extra={}):
   391                    p1=None, p2=None, extra={}):
   442                     repo.hook('commit', node=node, parent1=_p1, parent2=_p2)
   426                     repo.hook('commit', node=node, parent1=_p1, parent2=_p2)
   443                 return node
   427                 return node
   444             finally:
   428             finally:
   445                 del wlock, lock
   429                 del wlock, lock
   446 
   430 
       
   431     kwt = kwrepo._kwt = kwtemplater(ui, repo, inc, exc)
       
   432 
       
   433     def kwpatchfile_init(self, ui, fname, missing=False):
       
   434         '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
       
   435         rejects or conflicts due to expanded keywords in working dir.'''
       
   436         _patchfile_init(self, ui, fname, missing=missing)
       
   437 
       
   438         if kwt.matcher(self.fname):
       
   439             # shrink keywords read from working dir
       
   440             kwshrunk = kwt.shrink(''.join(self.lines))
       
   441             self.lines = kwshrunk.splitlines(True)
       
   442 
   447     repo.__class__ = kwrepo
   443     repo.__class__ = kwrepo
   448     patch.patchfile.__init__ = _kwpatchfile_init
   444     patch.patchfile.__init__ = kwpatchfile_init
   449 
   445 
   450 
   446 
   451 cmdtable = {
   447 cmdtable = {
   452     'kwdemo':
   448     'kwdemo':
   453         (demo,
   449         (demo,