ZyX_I avatar ZyX_I committed 66eff25

@%aurum/drivers/git: Made it use pygit2 for a* functions if possible
Ref #81
@%aurum/drivers/mercurial: Moved some common code from python/aurum/aumercurial.py to python/aurum/auutils.py
@%aurum/drivers/common/utils: Made _r.utils.pystring work for lists and dictionaries

Comments (0)

Files changed (7)

aurum-addon-info.txt

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

autoload/aurum/drivers/common/utils.vim

     endfunction
 endif
 "▶1 utils.pystring
-" Only works with numbers and strings
 function s:utils.pystring(v)
-    return type(a:v)==type(0) ? string(a:v)
-                \             : '"'.substitute(escape(a:v, '\"'),
-                \                              "\n", '\\n', '').'"'
+    return type(a:v)==type(0)  ?
+                \string(a:v) :
+                \substitute(string(a:v), "''", '\\''', 'g')
 endfunction
 "▶1 utils.emptystatdct
 let s:utils.emptystatdct={

autoload/aurum/drivers/git.vim

             \                   '@%aurum/drivers/common/utils': '1.1',
             \                                           '@/os': '0.1',
             \                                      '@/options': '0.0',})
+let s:usepythondriver=0
+if has('python')
+    let s:py='python'
+    let s:pp='aurum.augit'
+    let s:pya=s:py.' '.s:pp.'.'
+    try
+        execute s:py 'import '.s:pp
+        let s:usepythondriver=1
+    catch
+        " s:usepythondriver stays equal to 0, errors are ignored
+    endtry
+    if s:usepythondriver
+        " FIXME Does not work in python3.
+        execute s:py 'reload('.s:pp.')'
+    endif
+endif
 let s:_messages={
             \   'hexf': 'Failed to obtain hex string for revision %s '.
             \           'in the repository %s: %s',
             \    'ppf': 'Failed to run “git %s” for the repository %s: %s',
             \'anbnimp': 'Can only get branch property using agetrepoprop',
             \'aconimp': 'Can only get current status for one file',
+            \'as2nimp': 'Can only get current status',
         \}
 let s:git={}
 let s:_options={
 let s:iterfuncs.ancestors=s:iterfuncs.revrange
 "▶1 astatus, agetcs, agetrepoprop
 if s:_r.repo.userepeatedcmd
-    try
-        python import aurum.rcdriverfuncs
-        let s:addafuncs=1
-    catch
-        let s:addafuncs=0
-    endtry
-    if s:addafuncs
+    if s:usepythondriver
         function s:git.astatus(repo, interval, ...)
-            if a:0<3 || a:1 isnot 0 || a:2 isnot 0 ||
-                        \type(a:3)!=type([]) || len(a:3)!=1
-                call s:_f.throw('aconimp')
+            if a:0<3 || a:1 isnot 0 || a:2 isnot 0
+                call s:_f.throw('as2nimp')
             endif
             return s:_r.utils.pyeval('aurum.repeatedcmd.new('.
                         \        string(a:interval).', '.
-                        \       'aurum.rcdriverfuncs.git_status, '.
+                        \        s:pp.'._get_status, '.
                         \        s:_r.utils.pystring(a:repo.path).', '.
-                        \        s:_r.utils.pystring(a:3[0]).')')
+                        \        s:_r.utils.pystring(a:3).', True, True)')
         endfunction
         function s:git.agetrepoprop(repo, interval, prop)
-            if a:prop isnot# 'branch'
-                call s:_f.throw('anbnimp')
-            endif
             return s:_r.utils.pyeval('aurum.repeatedcmd.new('.
                         \        string(a:interval).', '.
-                        \       'aurum.rcdriverfuncs.git_branch, '.
-                        \        s:_r.utils.pystring(a:repo.path).')')
+                        \       'aurum.auutils.get_one_prop, '.
+                        \        s:pp.'._get_repo_prop, '.
+                        \        s:_r.utils.pystring(a:repo.path).', '.
+                        \        string(a:prop).')')
         endfunction
+    else
+        try
+            python import aurum.rcdriverfuncs
+            let s:addafuncs=1
+        catch
+            let s:addafuncs=0
+        endtry
+        if s:addafuncs
+            function s:git.astatus(repo, interval, ...)
+                if a:0<3 || a:1 isnot 0 || a:2 isnot 0 ||
+                            \type(a:3)!=type([]) || len(a:3)!=1
+                    call s:_f.throw('aconimp')
+                endif
+                return s:_r.utils.pyeval('aurum.repeatedcmd.new('.
+                            \        string(a:interval).', '.
+                            \       'aurum.rcdriverfuncs.git_status, '.
+                            \        s:_r.utils.pystring(a:repo.path).', '.
+                            \        s:_r.utils.pystring(a:3[0]).')')
+            endfunction
+            function s:git.agetrepoprop(repo, interval, prop)
+                if a:prop isnot# 'branch'
+                    call s:_f.throw('anbnimp')
+                endif
+                return s:_r.utils.pyeval('aurum.repeatedcmd.new('.
+                            \        string(a:interval).', '.
+                            \       'aurum.rcdriverfuncs.git_branch, '.
+                            \        s:_r.utils.pystring(a:repo.path).')')
+            endfunction
+        endif
     endif
 endif
 "▶1 Register driver

autoload/aurum/drivers/mercurial.vim

         function s:hg.agetrepoprop(repo, interval, prop)
             return s:_r.utils.pyeval('aurum.repeatedcmd.new('.
                         \                 string(a:interval).', '.
-                        \                 s:pp.'.get_one_prop, '.
+                        \                'aurum.auutils.get_one_prop, '.
+                        \                 s:pp.'._get_repo_prop, '.
                         \                 s:_r.utils.pystring(a:repo.path).', '.
-                        \                 s:_r.utils.pystring(a:prop).')')
+                        \                 string(a:prop).')')
         endfunction
     else
         try

python/aurum/augit.py

+import pygit2 as git
+from aurum.auutils import vim_throw, outermethodgen, autoexportmethodgen, emptystatdct, \
+                          get_repo_prop_gen
+
+def flush(repo):
+    pass
+
+# TODO Maybe cache repo and cs? It seems that unlike with mercurial it is supported in pygit2
+
+def g_repo(path):
+    try:
+        return git.Repository(path)
+    except KeyError:
+        vim_throw('norepo', path)
+
+outermethod      = outermethodgen(g_repo, flush)
+autoexportmethod = autoexportmethodgen(g_repo, globals())
+
+# XXX Does not support references like HEAD^. Must be used after getrevhex using normal git was run.
+# FIXME libgit2 does support HEAD^, make pygit2 and this code use this support
+def g_cs(repo, rev):
+    try:
+        ref = repo.lookup_reference(rev)
+        r = repo[ref.resolve().oid]
+    except KeyError:
+        try:
+            r = repo[unicode(rev, 'utf-8')]
+        except KeyError:
+            vim_throw('norev', rev, repo.path)
+
+    while not isinstance(r, git.Commit):
+        if isinstance(r, git.Tag):
+            r = repo[r.target]
+        else:
+            vim_throw('uresrev', repr(r), rev, repo.path)
+
+    return r
+
+def all_refs(repo):
+    return ((rname, g_cs(repo, rname).hex)
+            for rname in ('HEAD',)+repo.listall_references())
+
+def get_branch(repo):
+    try:
+        ref = repo.lookup_reference('HEAD')
+    except KeyError:
+        vim_throw('nohead', path)
+
+    try:
+        target = ref.target
+    except ValueError:
+        return ''
+
+    if target.startswith('refs/heads/'):
+        return target[11:]
+    else:
+        return ''
+
+def get_url(repo):
+    cfg = repo.config
+    try:
+        return cfg['remote.origin.pushurl']
+    except KeyError:
+        try:
+            return cfg['remote.origin.url']
+        except KeyError:
+            return None
+
+repo_props={
+    'branch':        get_branch,
+    'url':           get_url,
+    'bookmarkslist': lambda repo: (),
+    'brancheslist':  lambda repo: [s[11:] for s in repo.listall_references()
+                                   if s.startswith('refs/heads/')],
+    'tagslist':      lambda repo: [s[10:] for s in repo.listall_references()
+                                   if s.startswith('refs/tags/')],
+}
+repo_props['branchslist'] = repo_props['brancheslist']
+
+get_repo_prop = outermethod(autoexportmethod()(get_repo_prop_gen(repo_props)))
+
+def list_tree_files(tree, prefix=None):
+    for tentry in tree:
+        fname = prefix+'/'+tentry.name if prefix else tentry.name
+        ntree = tentry.to_object()
+        if isinstance(ntree, git.Tree):
+            for nfname in list_tree_files(ntree, prefix=fname):
+                yield nfname
+        else:
+            yield fname
+
+@outermethod
+@autoexportmethod()
+def get_status(repo, files=None, clean=None, ignored=None):
+    r = emptystatdct()
+    if files:
+        statuses = ((fname, repo.status_file(fname)) for fname in files)
+    else:
+        status = repo.status()
+        statuses = status.iteritems()
+        if clean:
+            r['clean'] = [fname for fname in list_tree_files(g_cs('HEAD').tree)
+                          if fname not in status]
+    while True:
+        try:
+            fname, status = statuses.next()
+        except StopIteration:
+            break
+        except KeyError:
+            # File is not known
+            continue
+        except ValueError:
+            # File is a directory
+            continue
+        if status == git.GIT_STATUS_CURRENT:
+            r['clean'].append(fname)
+        elif status & (git.GIT_STATUS_INDEX_MODIFIED | git.GIT_STATUS_WT_MODIFIED):
+            r['modified'].append(fname)
+        elif status & git.GIT_STATUS_IGNORED:
+            r['ignored'].append(fname)
+        elif status & git.GIT_STATUS_INDEX_DELETED:
+            r['removed'].append(fname)
+        elif status & git.GIT_STATUS_WT_DELETED:
+            r['deleted'].append(fname)
+        elif status & git.GIT_STATUS_INDEX_NEW:
+            r['added'].append(fname)
+        elif status & git.GIT_STATUS_WT_NEW:
+            r['unknown'].append(fname)
+    return r
+
+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'
+    # TODO 'rev', 'tags'
+    return cs_vim
+
+def get_revlist(repo, startrev):
+    return (set_rev_dict(cs, {}) for cs in repo.walk(g_cs(repo, startrev).oid, 0))
+
+# TODO Diff only specific files, diff options (libgit2 supports them, pygit2 will thus eventually do 
+#      the same)
+def get_diff(repo, rev1, rev2):
+    return g_cs(repo, rev1).tree.diff(g_cs(repo, rev2).tree)
+
+# vim: ft=python ts=4 sw=4 sts=4 et tw=100

python/aurum/aumercurial.py

 
 get_repo_prop = outermethod(autoexportmethod()(get_repo_prop_gen(repo_props)))
 
-def get_one_prop(path, prop):
-    return _get_repo_prop(path, prop)[prop]
-
 @outermethod
 def call_cmd(repo, attr, bkwargs, *args, **kwargs):
     if bkwargs:

python/aurum/auutils.py

             vim_throw('nocfg', repo.path, prop)
     return get_repo_prop
 
+def get_one_prop(_get_repo_prop, path, prop):
+    return _get_repo_prop(path, prop)[prop]
+
 # vim: ft=python ts=4 sw=4 sts=4 et tw=100
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.