Commits

ZyX_I committed 38b90d6

@%aurum/drivers/bazaar: Added python implementation of rf-status
Made non-python version use status --short, it is more precise
Note: due to sorting issues currently tests fail for non-python version
python/repeatedcmd: Made all signals be handled by default handlers

Comments (0)

Files changed (8)

aurum-addon-info.txt

         "plugin/aurum.vim",
         "plugin/aurum/cache.vim",
         "python/aurum/__init__.py",
+        "python/aurum/aubazaar.py",
         "python/aurum/augit.py",
         "python/aurum/aumercurial.py",
         "python/aurum/auutils.py",

autoload/aurum/drivers/bazaar.vim

 "▶1
 scriptencoding utf-8
+let s:pp='aurum.aubazaar'
 execute frawor#Setup('0.0', {'@%aurum/drivers/common/hypsites': '0.0',
             \                                   '@%aurum/repo': '5.0',
-            \                   '@%aurum/drivers/common/utils': '1.1',
+            \                   '@%aurum/drivers/common/utils': '1.2',
             \                                           '@/os': '0.1',
             \                                      '@/options': '0.0',})
 let s:_messages={
     let indent=stridx(remove(a:csdata, 0), '-')
     " FIXME children:[]
     let cs={'parents': [], 'copies': {}, 'children': [], 'phase': 'unknown',
-                \'bookmarks': [], 'tags': []}
+                \'bookmarks': [], 'tags': [], 'branch': 'default'}
     while !empty(a:csdata) && a:csdata[0]!~#'\v^\s*\-{60}$'
         let line=remove(a:csdata, 0)[(indent):]
         if line is# 'message:'
 function s:bzr.gettiphex(repo)
     return a:repo.functions.getrevhex(a:repo, '-1')
 endfunction
-"▶1 getstatdict :: repo, kwargs → statdict
+"▶1 getstatdict :: repo, args, kwargs → statdict
+let s:emptystatdict=extend({'renamed': []}, deepcopy(s:_r.utils.emptystatdct))
 function s:F.getstatdict(repo, args, kwargs)
-    let status=s:F.bzr(a:repo, 'status', a:args,
-                \      extend({'no-classify': 1, 'no-pending': 1}, a:kwargs),
+    let lines=s:F.bzr(a:repo, 'status', a:args,
+                \      extend({'no-classify': 1, 'no-pending': 1, 'short': 1},
+                \             a:kwargs),
                 \      0)[:-2]
     let curstatus=0
-    let statdict={}
-    while !empty(status)
-        let line=remove(status, 0)
-        if line[:1] is# '  '
-            " XXX File name is not expected to contain " => "
-            let statdict[curstatus]+=[line[2:]]
-        elseif line =~# '\v^[a-z]+%(\ [a-z]+)*\:$'
-            let curstatus=line[:-2]
-            let statdict[curstatus]=[]
-        elseif !empty(get(statdict, curstatus, 0))
-            " XXX Support for file with newlines is very limited here: it 
-            "     does not expect them containing "\n  " or "\nabc:". Bazaar 
-            "     crashes when trying to commit file with newline in its 
-            "     name, though it is probably not a problem
-            let statdict[curstatus][-1].="\n".line
+    let statdict=deepcopy(s:emptystatdict)
+    while !empty(lines)
+        let line=remove(lines, 0)
+        let status=line[:2]
+        if (status!~#'^[ +\-?RIXCP][ KNMD!][ *]$' || line[3] isnot# ' ')
+                    \&& curstatus isnot 0
+            let statdict[curstatus][-1].=line
+        endif
+        let file=line[4:]
+        if status[0] is# 'R'
+            let statdict.renamed+=[file]
+            let curstatus='renamed'
+        elseif status[0] is# ' '
+            if status[1] is# 'N'
+                let statdict.added    += [file]
+                let curstatus='added'
+            elseif stridx('D!', status[1])!=-1
+                let statdict.deleted  += [file]
+                let curstatus='deleted'
+            elseif status[2] is# '*' || stridx('KM', status[1])!=-1
+                let statdict.modified += [file]
+                let curstatus='modified'
+            else
+                let statdict.clean    += [file]
+                let curstatus='clean'
+            endif
+        elseif status[0] is# '-'
+            let statdict.removed+=[file]
+            let curstatus='removed'
+        elseif status[0] is# '+'
+            if status[1] is# '!'
+                let statdict.deleted  += [file]
+                let curstatus='deleted'
+            else
+                let statdict.added    += [file]
+                let curstatus='added'
+            endif
+        elseif status[0] is# '?'
+            let statdict.unknown+=[file]
+            let curstatus='unknown'
+        elseif status[0] is# 'I'
+            let statdict.ignored+=[file]
+            let curstatus='ignored'
+        " elseif status[0] is# 'X'
+            " Nonexistent file
         endif
     endwhile
     return statdict
     elseif       a:prop is# 'renames' || a:prop is# 'changes' ||
                 \a:prop is# 'files'   || a:prop is# 'removes'
         let statdict=s:F.getstatdict(a:repo, [], {'change': 'revid:'.a:cs.hex})
-        let a:cs.removes=[]
-        let a:cs.files=[]
-        call map(['added', 'modified', 'kind changed'],
-                    \'extend(a:cs.files, get(statdict, v:val, []))')
-        if has_key(statdict, 'removed')
-            let a:cs.removes+=statdict.removed
-        endif
-        let a:cs.renames=s:F.getrenames(statdict)
-        let a:cs.removes+=sort(values(a:cs.renames))
-        let a:cs.files  +=sort(keys(  a:cs.renames))
-        let a:cs.changes=a:cs.removes+a:cs.files
+        let a:cs.removes  = copy(statdict.removed)
+        let a:cs.files    = statdict.added+statdict.modified
+        let a:cs.renames  = s:F.getrenames(statdict)
+        let a:cs.removes += sort(values(a:cs.renames))
+        let a:cs.files   += sort(keys(  a:cs.renames))
+        let a:cs.changes  = a:cs.removes+a:cs.files
         return a:cs[a:prop]
     endif
     let a:cs[a:prop]=r
     return r
 endfunction
 "▶1 bzr.status :: repo[, rev1[, rev2[, files[, clean[, ign]]]]] → {type:[file]}
-let s:statstats={'added': 'added', 'removed': 'removed', 'modified': 'modified',
-            \    'kind changed': 'modified', 'unknown': 'unknown',
-            \    'missing': 'deleted', 'ignored': 'ignored',
-            \    'nonexistent': 'unknown', 'conflicts': 'modified',}
+if s:usepythondriver "▶2
+let s:revargsexpr='v:val is 0? '.
+                \       '"None":'.
+                \ 'v:key>=3?'.
+                \       '(empty(v:val)?"False":"True"):'.
+                \       '"vim.eval(''a:".(v:key+1)."'')"'
+function s:bzr.status(repo, ...)
+    let revargs=join(map(copy(a:000), s:revargsexpr), ',')
+    let d={}
+    try
+        execute s:pya.'get_status(vim.eval("a:repo.path"), '.revargs.')'
+    endtry
+    return d
+endfunction
+else "▶2
 function s:bzr.status(repo, ...)
     let args=['--']+((a:0>2 && a:3 isnot 0)?(a:3):([]))
     let statdict=s:F.getstatdict(a:repo, args,
                 \                ((a:0>1 && a:2 isnot 0)?
                 \                   ({'revision': a:2.'..'}):
                 \                   ({})))))
-    let r=deepcopy(s:_r.utils.emptystatdct)
-    " XXX There cannot be deleted files similar to mercurial, but there can be 
-    "     files that have 2 statuses
-    "     (missing is a bit different: it is shown after deleting added file)
-    for [sdkey, skey] in items(filter(copy(s:statstats),
-                \                     'has_key(statdict, v:key)'))
-        let r[skey]+=statdict[sdkey]
-    endfor
+    let r=deepcopy(statdict)
     let renames=s:F.getrenames(statdict)
+    call remove(r, 'renamed')
     call filter(r.modified, '!has_key(renames, v:val)')
     if a:0>2 && !empty(a:3)
         let r.added   += sort(filter(keys(renames),   'index(a:3, v:val)!=-1'))
     endif
     return r
 endfunction
+endif
 "▶1 bzr.commit :: repo, message[, files[, user[, date[, _]]]]
 function s:bzr.commit(repo, message, ...)
     let kwargs={}

python/aurum/aubazaar.py

+from __future__ import with_statement
+import bzrlib
+from bzrlib.errors       import NotBranchError, NoSuchRevision, InvalidRevisionSpec
+from bzrlib.workingtree  import WorkingTree
+from bzrlib.revisionspec import RevisionSpec
+from bzrlib.delta        import report_changes
+from aurum.auutils import vim_throw, outermethodgen, autoexportmethodgen, emptystatdct, \
+                          get_repo_prop_gen
+
+def flush(repo):
+    pass
+
+def g_repo(path):
+    try:
+        return WorkingTree.open(path)
+    except NotBranchError:
+        vim_throw('norepo', path)
+
+def bzrmethod(func):
+    def f(*args, **kwargs):
+        with(bzrlib.initialize()):
+            return func(*args, **kwargs)
+    return f
+
+outermethod      = outermethodgen(g_repo, flush)
+autoexportmethod = autoexportmethodgen(g_repo, globals())
+
+def g_revid(repo, rev):
+    try:
+        if isinstance(rev, int) or isinstance(rev, long):
+            return repo.branch.get_rev_id(rev)
+        else:
+            return RevisionSpec.from_string(rev).in_history(repo.branch).rev_id
+    except (NoSuchRevision, InvalidRevisionSpec):
+        vim_throw('norev', rev, repo.basedir)
+
+def g_cs(repo, rev):
+    return repo.branch.repository.get_revision(g_revid(repo, rev))
+
+def sorted_str_keys(d):
+    r = [key.encode('utf-8') for key in d.iterkeys()]
+    r.sort()
+    return r
+
+repo_props={
+        'branch':        lambda repo: repo.branch.nick,
+        'url':           lambda repo: str(repo.branch.get_parent()),
+        'bookmarkslist': lambda repo: [],
+        'brancheslist':  lambda repo: [],
+        'tagslist':      lambda repo: sorted_str_keys(repo.branch.tags.get_tag_dict()),
+}
+
+get_repo_prop = outermethod(autoexportmethod()(get_repo_prop_gen(repo_props, pathattr='basedir')))
+
+class StatusReporter(object):
+    __slots__ = ('status', 'repo', 'ignored', 'files')
+
+    def __init__(self, repo, ignored, files):
+        self.status  = emptystatdct()
+        self.repo    = repo
+        self.ignored = ignored
+        self.files   = files
+
+    def report(self, file_id, paths, track_ch, renamed, modified, exe_ch, kind):
+        if paths[1] == '':
+            return
+        if track_ch == 'unchanged':
+            if renamed:
+                if paths[0] in self.files:
+                    self.status['removed' ].append(paths[0])
+                if paths[1] in self.files:
+                    self.status['added'   ].append(paths[1])
+            elif modified == 'created':
+                self.status['added'   ].append(paths[1])
+            elif modified in set(('deleted', 'missing')):
+                self.status['deleted' ].append(paths[1])
+            elif exe_ch or modified in set(('kind changed', 'modified')):
+                self.status['modified'].append(paths[1])
+            else:
+                self.status['clean'   ].append(paths[1])
+        elif track_ch == 'removed':
+            self.status['removed'].append(paths[0])
+        elif track_ch == 'added':
+            if modified == 'missing':
+                self.status['deleted' ].append(paths[1])
+            else:
+                self.status['added'   ].append(paths[1])
+        elif track_ch == 'unversioned':
+            if self.repo.is_ignored(paths[1]):
+                if self.ignored:
+                    self.status['ignored'].append(paths[1])
+            else:
+                self.status['unknown'].append(paths[1])
+
+class ReadLock(object):
+    def __init__(self, o):
+        self.o = o
+
+    def __enter__(self):
+        self.o.lock_read()
+
+    def __exit__(self, *args):
+        self.o.unlock()
+
+class ContainsEverything(object):
+    @staticmethod
+    def __contains__(o):
+        return True
+
+@outermethod
+@autoexportmethod()
+@bzrmethod
+def get_status(repo, rev1=None, rev2=None, files=None, clean=None, ignored=None):
+    if not files:
+        files = None
+
+    reverse = False
+    if not rev1 and rev2:
+        rev1, rev2 = rev2, rev1
+        reverse = True
+
+    if rev1 or rev2:
+        ignored = False
+
+    old = repo.branch.repository.revision_tree(g_revid(repo, rev1)) if rev1 else repo.basis_tree()
+    new = repo.branch.repository.revision_tree(g_revid(repo, rev2)) if rev2 else repo
+
+    reporter = StatusReporter(repo, ignored, set(files) if files else ContainsEverything())
+
+    with ReadLock(repo), ReadLock(old), ReadLock(new):
+        changes  = new.iter_changes(old, clean, files, require_versioned=False,
+                                    want_unversioned=True)
+        report_changes(changes, reporter)
+
+    r = reporter.status
+
+    if reverse:
+        r['deleted'], r['unknown'] = r['unknown'], r['deleted']
+        r['added'],   r['removed'] = r['removed'], r['added']
+
+    return r
+
+cs_vim_defaults = {
+        'phase'     : 'unknown',
+        'bookmarks' : [],
+}
+
+def set_rev_dict(cs, cs_vim, revid_revno_map, reverse_tag_dict):
+    cs_vim['hex']         = cs.revision_id
+    cs_vim['rev']         = revid_revno_map[cs.revision_id]
+    cs_vim['time']        = int(cs.timestamp)
+    cs_vim['description'] = cs.message.encode('utf-8')
+
+    try:
+        cs_vim['user']    = cs.get_apparent_authors()[0]
+    except IndexError:
+        cs_vim['user']    = ''
+
+    cs_vim['parents']     = cs.parent_ids
+    cs_vim['branch']      = cs.properties['branch-nick']
+    cs_vim['tags']        = [tag.encode('utf-8') for tag in reverse_tag_dict.get(cs.revision_id,[])]
+
+    cs_vim.update(cs_vim_defaults)
+    return cs_vim
+
+# vim: ft=python ts=4 sw=4 sts=4 et tw=100

python/aurum/augit.py

         v.sort()
     return r
 
+cs_vim_defaults = {
+        'phase'     : 'unknown',
+        'branch'    : 'default',
+        'bookmarks' : [],
+}
+
 def set_rev_dict(cs, cs_vim):
     cs_vim['hex']         = str(cs.hex)
     cs_vim['time']        = cs.commit_time
     cs_vim['description'] = cs.message.encode('utf-8')
     cs_vim['user']        = (cs.author.name+u' <'+cs.author.email+u'>').encode('utf-8')
     cs_vim['parents']     = [str(parent.hex) for parent in cs.parents]
-    cs_vim['branch']      = 'default'
+    cs_vim.update(cs_vim_defaults)
     # TODO 'rev', 'tags'
     return cs_vim
 

python/aurum/aumercurial.py

         vim_throw('nofile', filepath, cs.hex(), cs._repo.path)
 
 def set_rev_dict(cs, cs_vim):
-    cs_vim['hex']         = cs.hex()
-    cs_vim['time']        = int(cs.date()[0])
-    cs_vim['description'] = cs.description()
-    cs_vim['user']        = cs.user()
-    cs_vim['parents']     = [parent.hex() for parent in cs.parents()]
+    cs_vim['hex']           = cs.hex()
+    cs_vim['time']          = int(cs.date()[0])
+    cs_vim['description']   = cs.description()
+    cs_vim['user']          = cs.user()
+    cs_vim['parents']       = [parent.hex() for parent in cs.parents()]
+
     try:
-        branch=cs.branch()
-        cs_vim['branch']=branch
-        cs_vim['tags']=cs.tags()
-        cs_vim['bookmarks']=cs.bookmarks()
+        cs_vim['branch']    = cs.branch()
+    except AttributeError:
+        cs_vim['branch']    = 'default'
+
+    try:
+        cs_vim['tags']      = cs.tags()
+    except AttributeError:
+        cs_vim['tags']      = []
+
+    try:
+        cs_vim['bookmarks'] = cs.bookmarks()
         # FIXME For some reason using cs.phasestr() here results in an exception
     except AttributeError:
-        pass
+        cs_vim['bookmarks'] = []
+
     return cs_vim
 
 def get_revlist(repo, startrev=0):

python/aurum/auutils.py

 echoe=lambda o, colinfo: pyecho(o, True )
 echom=lambda o, colinfo: pyecho(o, False)
 
-def get_repo_prop_gen(repo_props):
+def get_repo_prop_gen(repo_props, pathattr='path'):
     def get_repo_prop(repo, prop):
         if prop in repo_props:
             r=repo_props[prop](repo)
             if r is None:
-                vim_throw('failcfg', prop, repo.path)
+                vim_throw('failcfg', prop, getattr(repo, pathattr))
             else:
                 return {prop : r}
         else:
-            vim_throw('nocfg', repo.path, prop)
+            vim_throw('nocfg', getattr(repo, pathattr), prop)
     return get_repo_prop
 
 def get_one_prop(_get_repo_prop, path, prop):

python/aurum/repeatedcmd.py

     from Queue import Queue
     from threading import Lock
     from threading import Thread as Process
-    def signal(*_):
+    def use_default_signal_handlers():
         pass
-    SIGTERM=None
-    SIG_DFL=None
 else:
     from multiprocessing import Process, Queue, Value, Lock
-    from signal import signal, SIGTERM, SIG_DFL
+    from signal import signal, NSIG, SIG_DFL
+    def use_default_signal_handlers():
+        for sig in range(NSIG):
+            try:
+                signal(sig, SIG_DFL)
+            except Exception:
+                pass
 
 class ProcessHaltedError(Exception):
     pass
             self.process.join()
 
     def run(self):
-        # Override default signal vim handler with system default behavior (i.e. 
-        # just terminate). Without this hack process.terminate() may leave the 
-        # process alive. Bad, I do not know why it leaves it alive only in some 
-        # limited set of cases.
-        signal(SIGTERM, SIG_DFL)
+        # Override default signal vim handlers with system default behavior 
+        # (i.e. terminate or ignore), especially SIGTERM. Without this hack 
+        # process.terminate() may leave the process alive. Bad, I do not know 
+        # why it leaves it alive only in some limited set of cases.
+        use_default_signal_handlers()
         while self.interval.value > 0.0:
             starttime = time.clock()
             self.vlock.acquire()

Binary file modified.

Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.