]>
Commit | Line | Data |
---|---|---|
83be3106 MT |
1 | #!/usr/bin/python |
2 | ||
3 | import datetime | |
4 | import logging | |
5 | import os | |
6 | import subprocess | |
7 | ||
8 | import base | |
9 | import sources | |
10 | ||
11 | class Repo(base.Object): | |
12 | def __init__(self, pakfire, id, mode="normal"): | |
13 | base.Object.__init__(self, pakfire) | |
14 | ||
15 | assert mode in ("normal", "bare", "mirror") | |
16 | ||
17 | # Get the source object. | |
18 | self.source = sources.Source(pakfire, id) | |
19 | self.mode = mode | |
20 | ||
21 | @property | |
22 | def path(self): | |
23 | return os.path.join("/var/cache/pakfire/git-repos", self.source.identifier, self.mode) | |
24 | ||
25 | def git(self, cmd, path=None): | |
26 | if not path: | |
27 | path = self.path | |
28 | ||
29 | cmd = "cd %s && git %s" % (path, cmd) | |
30 | ||
31 | logging.debug("Running command: %s" % cmd) | |
32 | ||
33 | return subprocess.check_output(["/bin/sh", "-c", cmd]) | |
34 | ||
35 | @property | |
36 | def cloned(self): | |
37 | """ | |
38 | Say if the repository is already cloned. | |
39 | """ | |
40 | return os.path.exists(self.path) | |
41 | ||
42 | def clone(self): | |
43 | if self.cloned: | |
44 | return | |
45 | ||
46 | path = os.path.dirname(self.path) | |
47 | repo = os.path.basename(self.path) | |
48 | ||
49 | # Create the repository home directory if not exists. | |
50 | if not os.path.exists(path): | |
51 | os.makedirs(path) | |
52 | ||
53 | command = ["clone"] | |
54 | if self.mode == "bare": | |
55 | command.append("--bare") | |
56 | elif self.mode == "mirror": | |
57 | command.append("--mirror") | |
58 | ||
59 | command.append(self.source.url) | |
60 | command.append(repo) | |
61 | ||
62 | # Clone the repository. | |
63 | try: | |
64 | self.git(" ".join(command), path=path) | |
65 | except Exception: | |
66 | shutil.rmtree(self.path) | |
67 | raise | |
68 | ||
69 | def fetch(self): | |
70 | # Make sure, the repository was already cloned. | |
71 | if not self.cloned: | |
72 | self.clone() | |
73 | ||
74 | self.git("fetch") | |
75 | ||
76 | def rev_list(self, revision=None): | |
77 | if not revision: | |
78 | if self.source.head_revision: | |
79 | revision = self.source.head_revision.revision | |
80 | else: | |
81 | revision = self.source.start_revision | |
82 | ||
83 | command = "rev-list %s..%s" % (revision, self.source.branch) | |
84 | ||
85 | # Get all merge commits. | |
86 | merges = self.git("%s --merges" % command).splitlines() | |
87 | ||
88 | revisions = [] | |
89 | for commit in self.git(command).splitlines(): | |
90 | # Check if commit is a normal commit or merge commit. | |
91 | merge = commit in merges | |
92 | ||
93 | revisions.append((commit, merge)) | |
94 | ||
95 | return [r for r in reversed(revisions)] | |
96 | ||
97 | def import_revisions(self): | |
98 | # Get all pending revisions. | |
99 | revisions = self.rev_list() | |
100 | ||
101 | for revision, merge in revisions: | |
102 | # Actually import the revision. | |
103 | self._import_revision(revision, merge) | |
104 | ||
105 | def _import_revision(self, revision, merge): | |
106 | logging.debug("Going to import revision %s (merge: %s)." % (revision, merge)) | |
107 | ||
108 | rev_author = self.git("log -1 --format=\"%%an <%%ae>\" %s" % revision) | |
109 | rev_committer = self.git("log -1 --format=\"%%cn <%%ce>\" %s" % revision) | |
110 | rev_subject = self.git("log -1 --format=\"%%s\" %s" % revision) | |
111 | rev_body = self.git("log -1 --format=\"%%b\" %s" % revision) | |
112 | rev_date = self.git("log -1 --format=\"%%at\" %s" % revision) | |
113 | rev_date = datetime.datetime.utcfromtimestamp(float(rev_date)) | |
114 | ||
115 | # Convert strings properly. No idea why I have to do that. | |
116 | #rev_author = rev_author.decode("latin-1").strip() | |
117 | #rev_committer = rev_committer.decode("latin-1").strip() | |
118 | #rev_subject = rev_subject.decode("latin-1").strip() | |
119 | #rev_body = rev_body.decode("latin-1").rstrip() | |
120 | ||
121 | # Create a new commit object in the database | |
122 | commit = sources.Commit.create(self.pakfire, self.source, revision, | |
123 | rev_author, rev_committer, rev_subject, rev_body, rev_date) | |
124 | ||
125 | def checkout(self, revision, update=False): | |
126 | for update in (0, 1): | |
127 | if update: | |
128 | self.fetch() | |
129 | ||
130 | try: | |
131 | self.git("checkout %s" % revision) | |
132 | ||
133 | except subprocess.CalledProcessError: | |
134 | if not update: | |
135 | continue | |
136 | ||
137 | raise | |
138 | ||
139 | def changed_files(self, revision): | |
140 | files = self.git("diff --name-only %s^ %s" % (revision, revision)) | |
141 | ||
142 | return [os.path.join(self.path, f) for f in files.splitlines()] | |
143 | ||
144 | def get_all_files(self): | |
145 | files = self.git("ls-files") | |
146 | ||
147 | return [os.path.join(self.path, f) for f in files.splitlines()] |