From: Michael Tremer Date: Mon, 24 Oct 2022 17:57:30 +0000 (+0000) Subject: sources: Implement fetching a shallow clone of a Git repo X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4931f308a3a1b1b4ec3ca843c02e5af6bc06b8f1;p=pbs.git sources: Implement fetching a shallow clone of a Git repo Signed-off-by: Michael Tremer --- diff --git a/src/buildservice/sources.py b/src/buildservice/sources.py index 9e3b5cab..c1fc91e8 100644 --- a/src/buildservice/sources.py +++ b/src/buildservice/sources.py @@ -227,6 +227,12 @@ class Source(base.DataObject): def slug(self): return self.data.slug + # Repo + + @lazy_property + def repo(self): + return self.backend.repos.get_by_id(self.data.repo_id) + # URL def get_url(self): @@ -261,6 +267,21 @@ class Source(base.DataObject): def set_branch(self, branch): self._set_attribute("branch", branch) + branch = property(get_branch, set_branch) + + # Path + + @property + def path(self): + """ + Returns a unique path this repository lives in + """ + return self.backend.path( + "sources", + self.repo.path, + self.slug, + ) + # Commits def create_commit(self, revision, author, committer, subject, body, date): @@ -315,7 +336,13 @@ class Source(base.DataObject): """ log.debug("Fetching %s" % self) - # XXX + # Setup the Git repository + git = Git(self.backend, self.path, self.url, self.branch) + + # Clone the repository + if not git.is_cloned(): + await git.clone() + class Commit(base.DataObject): @@ -463,3 +490,66 @@ class Commit(base.DataObject): def packages(self): return self.backend.packages._get_packages("SELECT * FROM packages \ WHERE commit_id = %s", self.id) + + + +class Git(object): + """ + A simple abstraction layer to deal with Git repositories + """ + def __init__(self, backend, path, url, branch): + self.backend = backend + self.path = path + self.url = url + self.branch = branch + + def __repr__(self): + return "<%s %s>" % (self.__class__.__name__, self.path) + + async def command(self, *args): + """ + Executes a Git command + """ + cwd = None + + # Operate inside the repository once it has been cloned + if self.is_cloned(): + cwd = self.path + + return await self.backend.command("git", *args, cwd=cwd) + + def is_cloned(self): + """ + Returns True if this repository has already been cloned + """ + return os.path.exists(self.path) + + async def clone(self): + """ + Clones the Git repository + """ + if self.is_cloned(): + log.debug("%s is already cloned" % self) + return + + log.info("Cloning %s to %s" % (self.url, self.path)) + + await self.command( + "clone", + + # Keep a bare copy + "--bare", + + # Make it shallow + "--depth", "1", + + # Only copy the branch we are interested in + "--single-branch", + "--branch", self.branch, + + # URL + self.url, + + # Path + self.path, + )