aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libbe/storage/vcs/arch.py199
-rw-r--r--libbe/storage/vcs/base.py19
2 files changed, 135 insertions, 83 deletions
diff --git a/libbe/storage/vcs/arch.py b/libbe/storage/vcs/arch.py
index 45a3284..8afdca9 100644
--- a/libbe/storage/vcs/arch.py
+++ b/libbe/storage/vcs/arch.py
@@ -30,62 +30,80 @@ import sys
import time
import libbe
-from beuuid import uuid_gen
-import config
-import vcs
+import libbe.ui.util.user
+import libbe.storage.util.config
+from libbe.util.id import uuid_gen
+import base
+
if libbe.TESTING == True:
import unittest
import doctest
-DEFAULT_CLIENT = "tla"
+class CantAddFile(Exception):
+ def __init__(self, file):
+ self.file = file
+ Exception.__init__(self, "Can't automatically add file %s" % file)
+
+DEFAULT_CLIENT = 'tla'
-client = config.get_val("arch_client", default=DEFAULT_CLIENT)
+client = libbe.storage.util.config.get_val(
+ 'arch_client', default=DEFAULT_CLIENT)
def new():
return Arch()
-class Arch(vcs.VCS):
- name = "arch"
+class Arch(base.VCS):
+ name = 'arch'
client = client
- versioned = True
_archive_name = None
_archive_dir = None
_tmp_archive = False
_project_name = None
_tmp_project = False
- _arch_paramdir = os.path.expanduser("~/.arch-params")
+ _arch_paramdir = os.path.expanduser('~/.arch-params')
+
+ def __init__(self, *args, **kwargs):
+ base.VCS.__init__(self, *args, **kwargs)
+ self.versioned = True
+ self.interspersed_vcs_files = True
+ self.paranoid = False
+
def _vcs_version(self):
- status,output,error = self._u_invoke_client("--version")
+ status,output,error = self._u_invoke_client('--version')
return output
+
def _vcs_detect(self, path):
"""Detect whether a directory is revision-controlled using Arch"""
- if self._u_search_parent_directories(path, "{arch}") != None :
- config.set_val("arch_client", client)
+ if self._u_search_parent_directories(path, '{arch}') != None :
+ libbe.storage.util.config.set_val('arch_client', client)
return True
return False
+
def _vcs_init(self, path):
self._create_archive(path)
self._create_project(path)
self._add_project_code(path)
+
def _create_archive(self, path):
"""
Create a temporary Arch archive in the directory PATH. This
archive will be removed by
- cleanup->_vcs_cleanup->_remove_archive
+ destroy->_vcs_destroy->_remove_archive
"""
# http://regexps.srparish.net/tutorial-tla/new-archive.html#Creating_a_New_Archive
assert self._archive_name == None
id = self.get_user_id()
- name, email = self._u_parse_id(id)
+ name, email = libbe.ui.util.user.parse_user_id(id)
if email == None:
- email = "%s@example.com" % name
- trailer = "%s-%s" % ("bugs-everywhere-auto", uuid_gen()[0:8])
- self._archive_name = "%s--%s" % (email, trailer)
- self._archive_dir = "/tmp/%s" % trailer
+ email = '%s@example.com' % name
+ trailer = '%s-%s' % ('bugs-everywhere-auto', uuid_gen()[0:8])
+ self._archive_name = '%s--%s' % (email, trailer)
+ self._archive_dir = '/tmp/%s' % trailer
self._tmp_archive = True
- self._u_invoke_client("make-archive", self._archive_name,
+ self._u_invoke_client('make-archive', self._archive_name,
self._archive_dir, cwd=path)
+
def _invoke_client(self, *args, **kwargs):
"""
Invoke the client on our archive.
@@ -96,35 +114,38 @@ class Arch(vcs.VCS):
tailargs = args[1:]
else:
tailargs = []
- arglist = [command, "-A", self._archive_name]
+ arglist = [command, '-A', self._archive_name]
arglist.extend(tailargs)
args = tuple(arglist)
return self._u_invoke_client(*args, **kwargs)
+
def _remove_archive(self):
assert self._tmp_archive == True
assert self._archive_dir != None
assert self._archive_name != None
os.remove(os.path.join(self._arch_paramdir,
- "=locations", self._archive_name))
+ '=locations', self._archive_name))
shutil.rmtree(self._archive_dir)
self._tmp_archive = False
self._archive_dir = False
self._archive_name = False
+
def _create_project(self, path):
"""
Create a temporary Arch project in the directory PATH. This
project will be removed by
- cleanup->_vcs_cleanup->_remove_project
+ destroy->_vcs_destroy->_remove_project
"""
# http://mwolson.org/projects/GettingStartedWithArch.html
# http://regexps.srparish.net/tutorial-tla/new-project.html#Starting_a_New_Project
- category = "bugs-everywhere"
- branch = "mainline"
- version = "0.1"
- self._project_name = "%s--%s--%s" % (category, branch, version)
- self._invoke_client("archive-setup", self._project_name,
+ category = 'bugs-everywhere'
+ branch = 'mainline'
+ version = '0.1'
+ self._project_name = '%s--%s--%s' % (category, branch, version)
+ self._invoke_client('archive-setup', self._project_name,
cwd=path)
self._tmp_project = True
+
def _remove_project(self):
assert self._tmp_project == True
assert self._project_name != None
@@ -132,10 +153,12 @@ class Arch(vcs.VCS):
shutil.rmtree(os.path.join(self._archive_dir, self._project_name))
self._tmp_project = False
self._project_name = False
+
def _archive_project_name(self):
assert self._archive_name != None
assert self._project_name != None
- return "%s/%s" % (self._archive_name, self._project_name)
+ return '%s/%s' % (self._archive_name, self._project_name)
+
def _adjust_naming_conventions(self, path):
"""
By default, Arch restricts source code filenames to
@@ -148,47 +171,53 @@ class Arch(vcs.VCS):
The conventions are specified in
project-root/{arch}/=tagging-method
"""
- tagpath = os.path.join(path, "{arch}", "=tagging-method")
+ tagpath = os.path.join(path, '{arch}', '=tagging-method')
lines_out = []
- f = codecs.open(tagpath, "r", self.encoding)
+ f = codecs.open(tagpath, 'r', self.encoding)
for line in f:
- if line.startswith("source "):
- lines_out.append("source ^[._=a-zA-X0-9].*$\n")
+ if line.startswith('source '):
+ lines_out.append('source ^[._=a-zA-X0-9].*$\n')
else:
lines_out.append(line)
f.close()
- f = codecs.open(tagpath, "w", self.encoding)
- f.write("".join(lines_out))
+ f = codecs.open(tagpath, 'w', self.encoding)
+ f.write(''.join(lines_out))
f.close()
def _add_project_code(self, path):
# http://mwolson.org/projects/GettingStartedWithArch.html
# http://regexps.srparish.net/tutorial-tla/new-source.html
# http://regexps.srparish.net/tutorial-tla/importing-first.html
- self._invoke_client("init-tree", self._project_name,
+ self._invoke_client('init-tree', self._project_name,
cwd=path)
self._adjust_naming_conventions(path)
- self._invoke_client("import", "--summary", "Began versioning",
+ self._invoke_client('import', '--summary', 'Began versioning',
cwd=path)
- def _vcs_cleanup(self):
+
+ def _vcs_destroy(self):
if self._tmp_project == True:
self._remove_project()
if self._tmp_archive == True:
self._remove_archive()
+ vcs_dir = os.path.join(self.repo, '{arch}')
+ if os.path.exists(vcs_dir):
+ shutil.rmtree(vcs_dir)
+ self._archive_name = None
def _vcs_root(self, path):
if not os.path.isdir(path):
dirname = os.path.dirname(path)
else:
dirname = path
- status,output,error = self._u_invoke_client("tree-root", dirname)
+ status,output,error = self._u_invoke_client('tree-root', dirname)
root = output.rstrip('\n')
self._get_archive_project_name(root)
return root
+
def _get_archive_name(self, root):
- status,output,error = self._u_invoke_client("archives")
+ status,output,error = self._u_invoke_client('archives')
lines = output.split('\n')
# e.g. output:
# jdoe@example.com--bugs-everywhere-auto-2008.22.24.52
@@ -198,14 +227,16 @@ class Arch(vcs.VCS):
if os.path.realpath(location) == os.path.realpath(root):
self._archive_name = archive
assert self._archive_name != None
+
def _get_archive_project_name(self, root):
# get project names
- status,output,error = self._u_invoke_client("tree-version", cwd=root)
+ status,output,error = self._u_invoke_client('tree-version', cwd=root)
# e.g output
# jdoe@example.com--bugs-everywhere-auto-2008.22.24.52/be--mainline--0.1
archive_name,project_name = output.rstrip('\n').split('/')
self._archive_name = archive_name
self._project_name = project_name
+
def _vcs_get_user_id(self):
try:
status,output,error = self._u_invoke_client('my-id')
@@ -215,25 +246,26 @@ class Arch(vcs.VCS):
return None
else:
raise
- def _vcs_set_user_id(self, value):
- self._u_invoke_client('my-id', value)
+
def _vcs_add(self, path):
- self._u_invoke_client("add-id", path)
+ self._u_invoke_client('add-id', path)
realpath = os.path.realpath(self._u_abspath(path))
- pathAdded = realpath in self._list_added(self.rootdir)
+ pathAdded = realpath in self._list_added(self.repo)
if self.paranoid and not pathAdded:
self._force_source(path)
+
def _list_added(self, root):
assert os.path.exists(root)
assert os.access(root, os.X_OK)
root = os.path.realpath(root)
- status,output,error = self._u_invoke_client("inventory", "--source",
- "--both", "--all", root)
+ status,output,error = self._u_invoke_client('inventory', '--source',
+ '--both', '--all', root)
inv_str = output.rstrip('\n')
return [os.path.join(root, p) for p in inv_str.split('\n')]
+
def _add_dir_rule(self, rule, dirname, root):
inv_path = os.path.join(dirname, '.arch-inventory')
- f = codecs.open(inv_path, "a", self.encoding)
+ f = codecs.open(inv_path, 'a', self.encoding)
f.write(rule)
f.close()
if os.path.realpath(inv_path) not in self._list_added(root):
@@ -241,47 +273,50 @@ class Arch(vcs.VCS):
self.paranoid = False
self.add(inv_path)
self.paranoid = paranoid
+
def _force_source(self, path):
- rule = "source %s\n" % self._u_rel_path(path)
- self._add_dir_rule(rule, os.path.dirname(path), self.rootdir)
- if os.path.realpath(path) not in self._list_added(self.rootdir):
+ rule = 'source %s\n' % self._u_rel_path(path)
+ self._add_dir_rule(rule, os.path.dirname(path), self.repo)
+ if os.path.realpath(path) not in self._list_added(self.repo):
raise CantAddFile(path)
+
def _vcs_remove(self, path):
- if not '.arch-ids' in path:
- self._u_invoke_client("delete-id", path)
+ if self._vcs_is_versioned(path):
+ self._u_invoke_client('delete-id', path)
+ arch_ids = os.path.join(self.repo, path, '.arch-ids')
+ if os.path.exists(arch_ids):
+ shutil.rmtree(arch_ids)
+
def _vcs_update(self, path):
pass
- def _vcs_get_file_contents(self, path, revision=None, binary=False):
+
+ def _vcs_is_versioned(self, path):
+ if '.arch-ids' in path:
+ return False
+ return True
+
+ def _vcs_get_file_contents(self, path, revision=None):
if revision == None:
- return vcs.VCS._vcs_get_file_contents(self, path, revision, binary=binary)
+ return base.VCS._vcs_get_file_contents(self, path, revision)
else:
status,output,error = \
- self._invoke_client("file-find", path, revision)
+ self._invoke_client('file-find', path, revision)
relpath = output.rstrip('\n')
- abspath = os.path.join(self.rootdir, relpath)
- f = codecs.open(abspath, "r", self.encoding)
- contents = f.read()
- f.close()
- return contents
- def _vcs_duplicate_repo(self, directory, revision=None):
- if revision == None:
- vcs.VCS._vcs_duplicate_repo(self, directory, revision)
- else:
- status,output,error = \
- self._u_invoke_client("get", revision, directory)
+ return base.VCS._vcs_get_file_contents(self, relpath)
+
def _vcs_commit(self, commitfile, allow_empty=False):
if allow_empty == False:
# arch applies empty commits without complaining, so check first
- status,output,error = self._u_invoke_client("changes",expect=(0,1))
+ status,output,error = self._u_invoke_client('changes',expect=(0,1))
if status == 0:
- raise vcs.EmptyCommit()
+ raise base.EmptyCommit()
summary,body = self._u_parse_commitfile(commitfile)
- args = ["commit", "--summary", summary]
+ args = ['commit', '--summary', summary]
if body != None:
- args.extend(["--log-message",body])
+ args.extend(['--log-message',body])
status,output,error = self._u_invoke_client(*args)
revision = None
- revline = re.compile("[*] committed (.*)")
+ revline = re.compile('[*] committed (.*)')
match = revline.search(output)
assert match != None, output+error
assert len(match.groups()) == 1
@@ -290,26 +325,26 @@ class Arch(vcs.VCS):
assert revpath.startswith(self._archive_project_name()+'--')
revision = revpath[len(self._archive_project_name()+'--'):]
return revpath
+
def _vcs_revision_id(self, index):
- status,output,error = self._u_invoke_client("logs")
+ status,output,error = self._u_invoke_client('logs')
logs = output.splitlines()
first_log = logs.pop(0)
- assert first_log == "base-0", first_log
+ assert first_log == 'base-0', first_log
try:
- log = logs[index]
+ if index > 0:
+ log = logs[index-1]
+ elif index < 0:
+ log = logs[index]
+ else:
+ return None
except IndexError:
return None
- return "%s--%s" % (self._archive_project_name(), log)
-
-class CantAddFile(Exception):
- def __init__(self, file):
- self.file = file
- Exception.__init__(self, "Can't automatically add file %s" % file)
-
+ return '%s--%s' % (self._archive_project_name(), log)
if libbe.TESTING == True:
- vcs.make_vcs_testcase_subclasses(Arch, sys.modules[__name__])
+ base.make_vcs_testcase_subclasses(Arch, sys.modules[__name__])
unitsuite =unittest.TestLoader().loadTestsFromModule(sys.modules[__name__])
suite = unittest.TestSuite([unitsuite, doctest.DocTestSuite()])
diff --git a/libbe/storage/vcs/base.py b/libbe/storage/vcs/base.py
index 662fc30..69e412e 100644
--- a/libbe/storage/vcs/base.py
+++ b/libbe/storage/vcs/base.py
@@ -446,6 +446,7 @@ os.listdir(self.get_path("bugs")):
kwargs['encoding'] = libbe.util.encoding.get_filesystem_encoding()
libbe.storage.base.VersionedStorage.__init__(self, *args, **kwargs)
self.versioned = False
+ self.interspersed_vcs_files = False
self.verbose_invoke = False
self._cached_path_id = CachedPathID()
self._rooted = False
@@ -514,6 +515,18 @@ os.listdir(self.get_path("bugs")):
"""
pass
+ def _vcs_is_versioned(self, path):
+ """
+ Return true if a path is under version control, False
+ otherwise. You only need to set this if the VCS goes about
+ dumping VCS-specific files into the .be directory.
+
+ If you do need to implement this method (e.g. Arch), set
+ self.interspersed_vcs_files = True
+ """
+ assert self.interspersed_vcs_files == False
+ raise NotImplementedError
+
def _vcs_get_file_contents(self, path, revision=None):
"""
Get the file contents as they were in a given revision.
@@ -704,7 +717,11 @@ os.listdir(self.get_path("bugs")):
for i,c in enumerate(children):
if c == None: continue
cpath = os.path.join(path, c)
- children[i] = self._cached_path_id.id(cpath)
+ if self.interspersed_vcs_files == True \
+ and self._vcs_is_versioned(cpath) == False:
+ children[i] = None
+ else:
+ children[i] = self._cached_path_id.id(cpath)
return [c for c in children if c != None]
def _get(self, id, default=libbe.util.InvalidObject, revision=None):