Commits

ZyX_I committed 689244b

@aurum/repo: Added rf-getroot function support
@aurum/drivers/subversion: Made cs.files, cs.changes, cs.removes (and cs.additions) be pulled in by parsecs

Comments (0)

Files changed (3)

 <   . Second is called once on paths that contain “://” in their string (it is 
     likely to return just 0 because normal work with remote repositories is 
     impossible in most VCS’es).
+  getroot :: path -> path|0                                 *aurum-rf-getroot*
+    Being given a path for which |aurum-rf-checkdir| returns true should 
+    return a repository root.
+    If absent acts like the below function, thus considering any directory for 
+    which |aurum-rf-checkdir| returns true being a repository root >
+        function s:driver.getroot(path)
+            return a:path
+        endfunction
 
 ------------------------------------------------------------------------------
 8.2. Changeset                                               *aurum-changeset*
          value of |aurum-rf-getchangesets| is not stated as ignored.
     2.1: Added |aurum-repo.iterfuncs| support.
     2.2: Added |aurum-repo.initprops|.
+    2.3: Added |aurum-rf-getroot| support.
 @aurum:
     0.1: Added :AuBranch and :AuName
 @aurum/edit:

plugin/aurum/drivers/subversion.vim

 "▶1
 scriptencoding utf-8
 if !exists('s:_pluginloaded')
-    execute frawor#Setup('0.1', {   '@aurum/repo': '2.0',
+    execute frawor#Setup('0.1', {   '@aurum/repo': '2.3',
                 \                          '@/os': '0.0',
                 \   '@aurum/drivers/common/utils': '0.0',
                 \'@aurum/drivers/common/hypsites': '0.0',}, 0)
             \   'annf': 'Failet to annotate revision %s of the file %s '.
             \           'in the repository %s: %s',
             \   'ignf': 'Failed to ignore %s in the repository %s: %s',
-            \  'irevf': 'Failed to get information about revision %s '.
-            \           'from the repository %s: %s',
             \  'infof': 'Failed to get information about repository %s: %s',
             \   'addf': 'Failed to add file %s to the repository %s: %s',
             \  'listf': 'Failed to list file of revision %s '.
             \   'derr': 'Program “date” failed to parse date “%s” obtained '.
             \           'by parsing “%s”: %s',
             \'infoerr': 'Failed to get information for the repository %s: '.
-            \           'there are no lines starting with “URL: ” or '.
-            \           '“Repository Root: ” in the output of “svn info”',
-            \'ireverr': 'Failed to get information about revision %s '.
-            \           'from the repository %s: there are no lines starting '.
-            \           'with “Revision: ” in the output of “svn info”',
+            \           'there are no lines starting with “%s: ” '.
+            \           'in the output of “svn info”',
             \  'ndate': 'You must install “date” programm in order to get '.
             \           'time information for Subversion revisions',
             \  'r2fst': 'Second revision was found before the first',
 function s:F.svnm(...)
     return s:_r.utils.printm(call(s:F.svn, a:000, {}))
 endfunction
+"▶1 getfrominfo
+function s:F.getfrominfo(repo, line)
+    let str=a:line.': '
+    let strlidx=len(str)-1
+    for line in s:F.svn(a:repo, 'info', [], {}, 0, 'infof')
+        if line[:(strlidx)] is# str
+            return line[strlidx+1:]
+        endif
+    endfor
+    call s:_f.throw('infoerr', a:repo.path, a:line)
+endfunction
 "▶1 svn.getrevhex :: repo, rev → hex
 function s:svn.getrevhex(repo, rev)
-    let info=s:F.svn(a:repo, 'info', [], {'revision': ''.a:rev}, 0,
-                \    'irevf', a:rev)
-    for line in info
-        if line[:9] is# 'Revision: '
-            return line[10:]
-        endif
-    endfor
-    call s:_f.throw('ireverr', a:rev, a:repo.path)
+    return s:F.getfrominfo(a:repo, 'Revision')
 endfunction
 "▶1 decodeentities :: String → String
 let s:entities={
             \'copies': {},
             \'tags': [],
             \'bookmarks': [],
+            \'files': [],
+            \'changes': [],
+            \'removes': [],
+            \'additions': [],
         \}
 let s:hasdateexe=executable('date')
 " TODO HEAD, ... in cs.tags
 " TODO use merge information if available
 function s:F.parsecs(csdata, line)
     let cs=deepcopy(s:csinit)
+    let lcsdata=len(a:csdata)
     "▶2 Check for logentry start
     let line=a:line
     if a:csdata[line][:8] isnot# '<logentry'
         let cs.time=0
     endif
     let line+=1
+    "▶2 paths
+    if a:csdata[line] is# '<paths>'
+        let line+=1
+        while line<lcsdata && a:csdata[line] isnot# '</paths>'
+            if a:csdata[line][:4] isnot# '<path' "▶3
+                call s:_f.throw('perr', '<path', a:csdata[line])
+            endif                                "▲3
+            let line+=1
+            let kind=matchstr(a:csdata[line], '\v(kind\=\")@<=\w+\"@=')
+            if empty(kind) "▶3
+                call s:_f.throw('perr', 'kind="..."', a:csdata[line])
+            endif          "▲3
+            let line+=1
+            let match=matchlist(a:csdata[line],
+                        \       'action="\([AMD]\)">/\(.\+\)</path>')[1:2]
+            if empty(match) "▶3
+                call s:_f.throw('perr','action="C">/path</path>',a:csdata[line])
+            endif           "▲3
+            let [action, file]=match
+            let cs.changes+=[file]
+            if action is# 'M'
+                let cs.files+=[file]
+            elseif action is# 'A'
+                let cs.files+=[file]
+                let cs.additions+=[file]
+            elseif action is# 'D'
+                let cs.removes=[file]
+            endif
+            let line+=1
+        endwhile
+        if line>=lcsdata "▶3
+            call s:_f.throw('perr', '</paths>', a:csdata[-1])
+        endif            "▲3
+        let line+=1
+    endif
     "▶2 description
     let idx=stridx(a:csdata[line], '<msg>')
     if idx==-1
     let idx=stridx(description, '</msg>')
     if idx==-1
         let cs.description=s:F.decodeentities(description)
-        let lcsdata=len(a:csdata)
         while line<lcsdata
             let idx=stridx(a:csdata[line], '</msg>')
             if idx==-1
 "▶1 getchangesets :: repo → [cs]
 function s:F.getchangesets(repo, ...)
     let args=[]
-    let kwargs={'xml': 1}
+    let kwargs={'xml': 1, 'verbose': 1}
     if a:0==1
         if type(a:1)==type(0)
             let kwargs.limit=''.a:1
     endif
     "▲2
     let cs=s:F.parsecs(s:F.svn(a:repo, 'log', [],
-                \              {'revision': rev, 'limit': '1', 'xml': 1},
+                \              {'revision': rev, 'limit': '1', 'xml': 1,
+                \               'verbose': 1},
                 \              0, 'csf', a:rev), 2)[0]
     " TODO Populate cs.parents
     let cs.parents=[]
     return [r, revstatus]
 endfunction
 "▶1 svn.status :: repo[, rev1[, rev2[, files]]]
+" TODO Try using diff --summarize
 function s:svn.status(repo, ...)
     "▶2 Simple case: we can use “svn status”
     if !a:0 || (a:1 is 0 && !(a:0>1 && a:2 isnot 0))
         if a:0>2 && !empty(a:3)
             let allfiles=filter(copy(allfiles), 'index(a:3, v:val)!=-1')
         endif
-    "▶2 Complicated case: we must use diff
+    "▶2 Complicated case: diff
     else
         "▶3 Get diff
         let dargs=[a:repo]
         "▲3
         let allfiles=rsallfiless[0]
     endif
+    "▲2
     let r.clean=filter(copy(allfiles), '!has_key(revstatus, v:val)')
     return r
 endfunction
 "▶1 svn.getrepoprop :: repo, propname → a
 function s:svn.getrepoprop(repo, prop)
     if a:prop is# 'url'
-        let info=s:F.svn(a:repo, 'info', [], {}, 0, 'infof')
-        for line in info
-            if line[:4] is# 'URL: '
-                return line[5:]
-            elseif line[:16] is# 'Repository Root: '
-                return line[17:]
-            endif
-        endfor
-        call s:_f.throw('infoerr', a:repo.path)
+        return s:F.getfrominfo(a:repo, 'URL')
     elseif a:prop is# 'tagslist'
         return ['HEAD', 'BASE', 'COMMITTED', 'PREV']
     elseif a:prop[-4:] is# 'list'
                 \'requires_sort': 0, 'has_octopus_merges': 0,
                 \'initprops': ['rev', 'hex', 'parents', 'tags', 'bookmarks',
                 \              'branch', 'time', 'user', 'description',
-                \              'renames', 'copies'],
+                \              'renames', 'copies', 'files', 'changes',
+                \              'removes'],
                 \'has_merges': 0,
                 \}
     return repo
 endfunction
 "▶1 svn.checkdir :: dir → Bool
-function s:svn.checkdir(dir)
+function s:F.checkdir(dir)
     return s:_r.os.path.isdir(s:_r.os.path.join(a:dir, '.svn'))
 endfunction
+let s:svn.checkdir=s:F.checkdir
+"▶1 svn.getroot :: dir → Maybe dir
+function s:svn.getroot(dir)
+    let checkeddirs=[]
+    let dir=s:_r.os.path.dirname(a:dir)
+    while !(dir is# get(checkeddirs, -1, 0))
+        if !s:F.checkdir(dir)
+            break
+        endif
+        call insert(checkeddirs, dir)
+        let dir=s:_r.os.path.dirname(dir)
+    endwhile
+    if empty(checkeddirs)
+        return a:dir
+    endif
+    let uuid=s:F.getfrominfo({'path': a:dir}, 'Repository UUID')
+    for dir in checkeddirs
+        if s:F.getfrominfo({'path': dir}, 'Repository UUID') is# uuid
+            return dir
+        endif
+    endfor
+    return a:dir
+endfunction
 "▶1 Register driver
 call s:_f.regdriver('Subversion', s:svn)
 "▶1

plugin/aurum/repo.vim

 "▶1
 scriptencoding utf-8
 if !exists('s:_pluginloaded')
-    execute frawor#Setup('2.2', {'@/resources': '0.0',
+    execute frawor#Setup('2.3', {'@/resources': '0.0',
                 \                       '@/os': '0.0',
                 \                  '@/options': '0.0',
                 \             '@aurum/bufvars': '0.0',}, 0)
             unlet driver
             let driver=s:F.getdriver(path, 'dir')
             if driver isnot 0
+                if has_key(driver.functions, 'getroot')
+                    let newpath=driver.functions.getroot(path)
+                    if newpath is 0
+                        continue
+                    endif
+                    let path=newpath
+                endif
                 break
             endif
             let olddir=path
 "▶1 regdriver feature
 let s:requiredfuncs=['repo', 'getcs', 'checkdir']
 let s:optfuncs=['readfile', 'annotate', 'diff', 'status', 'commit', 'update',
-            \   'dirty', 'diffre', 'getrepoprop', 'forget', 'branch', 'label']
+            \   'dirty', 'diffre', 'getrepoprop', 'forget', 'branch', 'label',
+            \   'getroot']
 "▶2 regdriver :: {f}, name, funcs → + s:drivers
 function s:F.regdriver(plugdict, fdict, name, funcs)
     "▶3 Check arguments