]> git.ipfire.org Git - people/jschlag/pbs.git/blame - src/buildservice/git.py
Merge branch 'master' of git://git.ipfire.org/pbs
[people/jschlag/pbs.git] / src / buildservice / git.py
CommitLineData
83be3106
MT
1#!/usr/bin/python
2
3import datetime
4import logging
5import os
6import subprocess
7
2c909128 8from . import base
29e226fc 9from .decorators import *
83be3106
MT
10
11class Repo(base.Object):
29e226fc 12 def init(self, source, mode="normal"):
83be3106
MT
13 assert mode in ("normal", "bare", "mirror")
14
78366294 15 self.source = source
83be3106
MT
16 self.mode = mode
17
29e226fc
MT
18 def __enter__(self):
19 return RepoContext(self.backend, self)
83be3106 20
29e226fc
MT
21 def __exit__(self, type, value, traceback):
22 pass
83be3106 23
29e226fc
MT
24 @lazy_property
25 def path(self):
26 path = os.path.join("~/.pakfire/cache/git-repos", self.source.identifier, self.mode)
83be3106 27
29e226fc 28 return os.path.expanduser(path)
83be3106
MT
29
30 @property
31 def cloned(self):
32 """
33 Say if the repository is already cloned.
34 """
35 return os.path.exists(self.path)
36
29e226fc
MT
37
38class RepoContext(base.Object):
39 def init(self, repo):
40 self.repo = repo
41
42 # Clone repository if not cloned, yet
43 if not self.repo.cloned:
44 self.clone()
45
46 self._lock()
47
48 def __del__(self):
49 self._release()
50
51 def _lock(self):
52 pass # XXX needs to be implemented
53
54 def _release(self):
55 pass
56
57 def git(self, cmd, path=None):
58 if not path:
59 path = self.repo.path
60
61 cmd = "cd %s && git %s" % (path, cmd)
62
63 logging.debug("Running command: %s" % cmd)
64
65 return subprocess.check_output(["/bin/sh", "-c", cmd])
66
83be3106 67 def clone(self):
29e226fc 68 if self.repo.cloned:
83be3106
MT
69 return
70
29e226fc 71 path, repo = os.path.dirname(self.repo.path), os.path.basename(self.repo.path)
83be3106
MT
72
73 # Create the repository home directory if not exists.
74 if not os.path.exists(path):
75 os.makedirs(path)
76
77 command = ["clone"]
29e226fc 78 if self.repo.mode == "bare":
83be3106 79 command.append("--bare")
29e226fc 80 elif self.repo.mode == "mirror":
83be3106
MT
81 command.append("--mirror")
82
29e226fc 83 command.append(self.repo.source.url)
83be3106
MT
84 command.append(repo)
85
86 # Clone the repository.
87 try:
88 self.git(" ".join(command), path=path)
89 except Exception:
29e226fc 90 shutil.rmtree(self.repo.path)
83be3106
MT
91 raise
92
93 def fetch(self):
83be3106
MT
94 self.git("fetch")
95
96 def rev_list(self, revision=None):
97 if not revision:
29e226fc
MT
98 if self.repo.source.head_revision:
99 revision = self.repo.source.head_revision.revision
83be3106 100 else:
29e226fc 101 revision = self.repo.source.start_revision
83be3106 102
29e226fc 103 command = "rev-list %s..%s" % (revision, self.repo.source.branch)
83be3106 104
29e226fc 105 # Get all merge commits
83be3106
MT
106 merges = self.git("%s --merges" % command).splitlines()
107
108 revisions = []
109 for commit in self.git(command).splitlines():
110 # Check if commit is a normal commit or merge commit.
111 merge = commit in merges
112
113 revisions.append((commit, merge))
114
115 return [r for r in reversed(revisions)]
116
117 def import_revisions(self):
118 # Get all pending revisions.
119 revisions = self.rev_list()
120
121 for revision, merge in revisions:
122 # Actually import the revision.
123 self._import_revision(revision, merge)
124
125 def _import_revision(self, revision, merge):
126 logging.debug("Going to import revision %s (merge: %s)." % (revision, merge))
127
128 rev_author = self.git("log -1 --format=\"%%an <%%ae>\" %s" % revision)
129 rev_committer = self.git("log -1 --format=\"%%cn <%%ce>\" %s" % revision)
130 rev_subject = self.git("log -1 --format=\"%%s\" %s" % revision)
131 rev_body = self.git("log -1 --format=\"%%b\" %s" % revision)
132 rev_date = self.git("log -1 --format=\"%%at\" %s" % revision)
133 rev_date = datetime.datetime.utcfromtimestamp(float(rev_date))
134
83be3106 135 # Create a new commit object in the database
29e226fc
MT
136 return self.repo.source.create_commit(revision,
137 rev_author, rev_committer, rev_subject, rev_body, rev_date)
83be3106
MT
138
139 def checkout(self, revision, update=False):
140 for update in (0, 1):
141 if update:
142 self.fetch()
143
144 try:
145 self.git("checkout %s" % revision)
146
147 except subprocess.CalledProcessError:
148 if not update:
149 continue
150
151 raise
152
153 def changed_files(self, revision):
154 files = self.git("diff --name-only %s^ %s" % (revision, revision))
155
29e226fc 156 return [os.path.join(self.repo.path, f) for f in files.splitlines()]
83be3106
MT
157
158 def get_all_files(self):
159 files = self.git("ls-files")
160
29e226fc 161 return [os.path.join(self.repo.path, f) for f in files.splitlines()]