+class SvnRepository:
+ type = "svn"
+
+ def __init__(self, path, options):
+ self.path = path
+ self.options = options
+
+ def name(self):
+ return os.path.basename(self.path)
+
+ def url(self):
+ out = Command("svn info %s" % self.path, self.options).output_of()
+ for line in out.split('\n'):
+ if line.startswith("URL:"):
+ return line.split()[1].strip()
+
+ def repo_root(self):
+ out = Command("svn info %s" % self.path, self.options).output_of()
+ for line in out.split('\n'):
+ if line.startswith("Repository Root:"):
+ root = line.split()[2].strip()
+ return "%s/%s" % (root, self.name())
+
+ @classmethod
+ def checkout(cls, remote, local, options, recursive=False):
+ if recursive:
+ svncommand = "svn co %s %s" % (remote, local)
+ else:
+ svncommand = "svn co -N %s %s" % (remote, local)
+ Command("rm -rf %s" % local, options).run_silent()
+ Command(svncommand, options).run_fatal()
+
+ return SvnRepository(local, options)
+
+ @classmethod
+ def remote_exists(cls, remote):
+ return os.system("svn list %s &> /dev/null" % remote) == 0
+
+ def tag_exists(self, tagname):
+ url = "%s/tags/%s" % (self.repo_root(), tagname)
+ return SvnRepository.remote_exists(url)
+
+ def update(self, subdir="", recursive=True, branch=None):
+ path = os.path.join(self.path, subdir)
+ if recursive:
+ svncommand = "svn up %s" % path
+ else:
+ svncommand = "svn up -N %s" % path
+ Command(svncommand, self.options).run_fatal()
+
+ def commit(self, logfile):
+ # add all new files to the repository
+ Command("svn status %s | grep '^\?' | sed -e 's/? *//' | sed -e 's/ /\\ /g' | xargs svn add" %
+ self.path, self.options).output_of()
+ Command("svn commit -F %s %s" % (logfile, self.path), self.options).run_fatal()
+
+ def to_branch(self, branch):
+ remote = "%s/branches/%s" % (self.repo_root(), branch)
+ SvnRepository.checkout(remote, self.path, self.options, recursive=True)
+
+ def to_tag(self, tag):
+ remote = "%s/tags/%s" % (self.repo_root(), branch)
+ SvnRepository.checkout(remote, self.path, self.options, recursive=True)
+
+ def tag(self, tagname, logfile):
+ tag_url = "%s/tags/%s" % (self.repo_root(), tagname)
+ self_url = self.url()
+ Command("svn copy -F %s %s %s" % (logfile, self_url, tag_url), self.options).run_fatal()
+
+ def diff(self, f=""):
+ if f:
+ f = os.path.join(self.path, f)
+ else:
+ f = self.path
+ return Command("svn diff %s" % f, self.options).output_of(True)
+
+ def diff_with_tag(self, tagname):
+ tag_url = "%s/tags/%s" % (self.repo_root(), tagname)
+ return Command("svn diff %s %s" % (tag_url, self.url()),
+ self.options).output_of(True)
+
+ def revert(self, f=""):
+ if f:
+ Command("svn revert %s" % os.path.join(self.path, f), self.options).run_fatal()
+ else:
+ # revert all
+ Command("svn revert %s -R" % self.path, self.options).run_fatal()
+ Command("svn status %s | grep '^\?' | sed -e 's/? *//' | sed -e 's/ /\\ /g' | xargs rm -rf " %
+ self.path, self.options).run_silent()
+
+ def is_clean(self):
+ command="svn status %s" % self.path
+ return len(Command(command,self.options).output_of(True)) == 0
+
+ def is_valid(self):
+ return os.path.exists(os.path.join(self.path, ".svn"))
+
+
+class GitRepository:
+ type = "git"
+
+ def __init__(self, path, options):
+ self.path = path
+ self.options = options
+
+ def name(self):
+ return os.path.basename(self.path)
+
+ def url(self):
+ self.repo_root()
+
+ def repo_root(self):
+ c = Command("git remote show origin", self.options)
+ out = self.__run_in_repo(c.output_of)
+ for line in out.split('\n'):
+ if line.strip().startswith("Fetch URL:"):
+ repo = line.split()[2]
+
+ @classmethod
+ def checkout(cls, remote, local, options, depth=1):
+ Command("rm -rf %s" % local, options).run_silent()
+ Command("git clone --depth %d %s %s" % (depth, remote, local), options).run_fatal()
+ return GitRepository(local, options)
+
+ @classmethod
+ def remote_exists(cls, remote):
+ return os.system("git --no-pager ls-remote %s &> /dev/null" % remote) == 0
+
+ def tag_exists(self, tagname):
+ command = 'git tag -l | grep "^%s$"' % tagname
+ c = Command(command, self.options)
+ out = self.__run_in_repo(c.output_of, with_stderr=True)
+ return len(out) > 0
+
+ def __run_in_repo(self, fun, *args, **kwargs):
+ cwd = os.getcwd()
+ os.chdir(self.path)
+ ret = fun(*args, **kwargs)
+ os.chdir(cwd)
+ return ret
+
+ def __run_command_in_repo(self, command, ignore_errors=False):
+ c = Command(command, self.options)
+ if ignore_errors:
+ return self.__run_in_repo(c.output_of)
+ else:
+ return self.__run_in_repo(c.run_fatal)
+
+ def update(self, subdir=None, recursive=None, branch="master"):
+ if branch == "master":
+ self.__run_command_in_repo("git checkout %s" % branch)
+ else:
+ self.__run_command_in_repo("git checkout origin/%s" % branch)
+ self.__run_command_in_repo("git fetch origin --tags")
+ self.__run_command_in_repo("git fetch origin")
+ self.__run_command_in_repo("git merge --ff origin/%s" % branch)
+
+ def to_branch(self, branch, remote=True):
+ if remote:
+ branch = "origin/%s" % branch
+ return self.__run_command_in_repo("git checkout %s" % branch)
+
+ def to_tag(self, tag):
+ return self.__run_command_in_repo("git checkout %s" % tag)
+
+ def tag(self, tagname, logfile):
+ self.__run_command_in_repo("git tag %s -F %s" % (tagname, logfile))
+ self.commit(logfile)
+
+ def diff(self, f=""):
+ c = Command("git diff %s" % f, self.options)
+ return self.__run_in_repo(c.output_of, with_stderr=True)
+
+ def diff_with_tag(self, tagname):
+ c = Command("git diff %s" % tagname, self.options)
+ return self.__run_in_repo(c.output_of, with_stderr=True)
+
+ def commit(self, logfile):
+ self.__run_command_in_repo("git add .", ignore_errors=True)
+ self.__run_command_in_repo("git add -u", ignore_errors=True)
+ self.__run_command_in_repo("git commit -F %s" % logfile, ignore_errors=True)
+ self.__run_command_in_repo("git push")
+ self.__run_command_in_repo("git push --tags")
+
+ def revert(self, f=""):
+ if f:
+ self.__run_command_in_repo("git checkout %s" % f)
+ else:
+ # revert all
+ self.__run_command_in_repo("git --no-pager reset --hard")
+ self.__run_command_in_repo("git --no-pager clean -f")
+
+ def is_clean(self):
+ def check_commit():
+ command="git status"
+ s="nothing to commit (working directory clean)"
+ return Command(command, self.options).output_of(True).find(s) >= 0
+ return self.__run_in_repo(check_commit)
+
+ def is_valid(self):
+ return os.path.exists(os.path.join(self.path, ".git"))
+
+
+class Repository:
+ """ Generic repository """
+ supported_repo_types = [SvnRepository, GitRepository]
+
+ def __init__(self, path, options):
+ self.path = path
+ self.options = options
+ for repo in self.supported_repo_types:
+ self.repo = repo(self.path, self.options)
+ if self.repo.is_valid():
+ break
+
+ @classmethod
+ def has_moved_to_git(cls, module, config):
+ module = git_to_svn_name(module)
+ # check if the module is already in Git
+# return SvnRepository.remote_exists("%s/%s/aaaa-has-moved-to-git" % (config['svnpath'], module))
+ return GitRepository.remote_exists(Module.git_remote_dir(module))
+