]> git.ipfire.org Git - pbs.git/commitdiff
sources: Implement fetching a shallow clone of a Git repo
authorMichael Tremer <michael.tremer@ipfire.org>
Mon, 24 Oct 2022 17:57:30 +0000 (17:57 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 24 Oct 2022 17:57:30 +0000 (17:57 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/buildservice/sources.py

index 9e3b5cab607b6c6658bab352909e62425783a3d5..c1fc91e80b22e1b24b181fd2bb09e34baefa1d30 100644 (file)
@@ -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,
+               )