summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/fetch2/git.py
diff options
context:
space:
mode:
authorAdrian Dudau <adrian.dudau@enea.com>2013-12-12 13:38:32 +0100
committerAdrian Dudau <adrian.dudau@enea.com>2013-12-12 13:50:20 +0100
commite2e6f6fe07049f33cb6348780fa975162752e421 (patch)
treeb1813295411235d1297a0ed642b1346b24fdfb12 /bitbake/lib/bb/fetch2/git.py
downloadpoky-e2e6f6fe07049f33cb6348780fa975162752e421.tar.gz
initial commit of Enea Linux 3.1
Migrated from the internal git server on the dora-enea branch Signed-off-by: Adrian Dudau <adrian.dudau@enea.com>
Diffstat (limited to 'bitbake/lib/bb/fetch2/git.py')
-rw-r--r--bitbake/lib/bb/fetch2/git.py326
1 files changed, 326 insertions, 0 deletions
diff --git a/bitbake/lib/bb/fetch2/git.py b/bitbake/lib/bb/fetch2/git.py
new file mode 100644
index 0000000000..6175e4c7c9
--- /dev/null
+++ b/bitbake/lib/bb/fetch2/git.py
@@ -0,0 +1,326 @@
1# ex:ts=4:sw=4:sts=4:et
2# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3"""
4BitBake 'Fetch' git implementation
5
6git fetcher support the SRC_URI with format of:
7SRC_URI = "git://some.host/somepath;OptionA=xxx;OptionB=xxx;..."
8
9Supported SRC_URI options are:
10
11- branch
12 The git branch to retrieve from. The default is "master"
13
14 This option also supports multiple branch fetching, with branches
15 separated by commas. In multiple branches case, the name option
16 must have the same number of names to match the branches, which is
17 used to specify the SRC_REV for the branch
18 e.g:
19 SRC_URI="git://some.host/somepath;branch=branchX,branchY;name=nameX,nameY"
20 SRCREV_nameX = "xxxxxxxxxxxxxxxxxxxx"
21 SRCREV_nameY = "YYYYYYYYYYYYYYYYYYYY"
22
23- tag
24 The git tag to retrieve. The default is "master"
25
26- protocol
27 The method to use to access the repository. Common options are "git",
28 "http", "https", "file", "ssh" and "rsync". The default is "git".
29
30- rebaseable
31 rebaseable indicates that the upstream git repo may rebase in the future,
32 and current revision may disappear from upstream repo. This option will
33 remind fetcher to preserve local cache carefully for future use.
34 The default value is "0", set rebaseable=1 for rebaseable git repo.
35
36- nocheckout
37 Don't checkout source code when unpacking. set this option for the recipe
38 who has its own routine to checkout code.
39 The default is "0", set nocheckout=1 if needed.
40
41- bareclone
42 Create a bare clone of the source code and don't checkout the source code
43 when unpacking. Set this option for the recipe who has its own routine to
44 checkout code and tracking branch requirements.
45 The default is "0", set bareclone=1 if needed.
46
47"""
48
49#Copyright (C) 2005 Richard Purdie
50#
51# This program is free software; you can redistribute it and/or modify
52# it under the terms of the GNU General Public License version 2 as
53# published by the Free Software Foundation.
54#
55# This program is distributed in the hope that it will be useful,
56# but WITHOUT ANY WARRANTY; without even the implied warranty of
57# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
58# GNU General Public License for more details.
59#
60# You should have received a copy of the GNU General Public License along
61# with this program; if not, write to the Free Software Foundation, Inc.,
62# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
63
64import os
65import bb
66from bb import data
67from bb.fetch2 import FetchMethod
68from bb.fetch2 import runfetchcmd
69from bb.fetch2 import logger
70
71class Git(FetchMethod):
72 """Class to fetch a module or modules from git repositories"""
73 def init(self, d):
74 pass
75
76 def supports(self, url, ud, d):
77 """
78 Check to see if a given url can be fetched with git.
79 """
80 return ud.type in ['git']
81
82 def supports_checksum(self, urldata):
83 return False
84
85 def urldata_init(self, ud, d):
86 """
87 init git specific variable within url data
88 so that the git method like latest_revision() can work
89 """
90 if 'protocol' in ud.parm:
91 ud.proto = ud.parm['protocol']
92 elif not ud.host:
93 ud.proto = 'file'
94 else:
95 ud.proto = "git"
96
97 if not ud.proto in ('git', 'file', 'ssh', 'http', 'https', 'rsync'):
98 raise bb.fetch2.ParameterError("Invalid protocol type", ud.url)
99
100 ud.nocheckout = ud.parm.get("nocheckout","0") == "1"
101
102 ud.rebaseable = ud.parm.get("rebaseable","0") == "1"
103
104 # bareclone implies nocheckout
105 ud.bareclone = ud.parm.get("bareclone","0") == "1"
106 if ud.bareclone:
107 ud.nocheckout = 1
108
109 branches = ud.parm.get("branch", "master").split(',')
110 if len(branches) != len(ud.names):
111 raise bb.fetch2.ParameterError("The number of name and branch parameters is not balanced", ud.url)
112 ud.branches = {}
113 for name in ud.names:
114 branch = branches[ud.names.index(name)]
115 ud.branches[name] = branch
116
117 ud.basecmd = data.getVar("FETCHCMD_git", d, True) or "git"
118
119 ud.write_tarballs = ((data.getVar("BB_GENERATE_MIRROR_TARBALLS", d, True) or "0") != "0") or ud.rebaseable
120
121 ud.setup_revisons(d)
122
123 for name in ud.names:
124 # Ensure anything that doesn't look like a sha256 checksum/revision is translated into one
125 if not ud.revisions[name] or len(ud.revisions[name]) != 40 or (False in [c in "abcdef0123456789" for c in ud.revisions[name]]):
126 if ud.revisions[name]:
127 ud.branches[name] = ud.revisions[name]
128 ud.revisions[name] = self.latest_revision(ud.url, ud, d, name)
129
130 gitsrcname = '%s%s' % (ud.host.replace(':','.'), ud.path.replace('/', '.').replace('*', '.'))
131 # for rebaseable git repo, it is necessary to keep mirror tar ball
132 # per revision, so that even the revision disappears from the
133 # upstream repo in the future, the mirror will remain intact and still
134 # contains the revision
135 if ud.rebaseable:
136 for name in ud.names:
137 gitsrcname = gitsrcname + '_' + ud.revisions[name]
138 ud.mirrortarball = 'git2_%s.tar.gz' % (gitsrcname)
139 ud.fullmirror = os.path.join(d.getVar("DL_DIR", True), ud.mirrortarball)
140 gitdir = d.getVar("GITDIR", True) or (d.getVar("DL_DIR", True) + "/git2/")
141 ud.clonedir = os.path.join(gitdir, gitsrcname)
142
143 ud.localfile = ud.clonedir
144
145 def localpath(self, url, ud, d):
146 return ud.clonedir
147
148 def need_update(self, u, ud, d):
149 if not os.path.exists(ud.clonedir):
150 return True
151 os.chdir(ud.clonedir)
152 for name in ud.names:
153 if not self._contains_ref(ud.revisions[name], d):
154 return True
155 if ud.write_tarballs and not os.path.exists(ud.fullmirror):
156 return True
157 return False
158
159 def try_premirror(self, u, ud, d):
160 # If we don't do this, updating an existing checkout with only premirrors
161 # is not possible
162 if d.getVar("BB_FETCH_PREMIRRORONLY", True) is not None:
163 return True
164 if os.path.exists(ud.clonedir):
165 return False
166 return True
167
168 def download(self, loc, ud, d):
169 """Fetch url"""
170
171 if ud.user:
172 username = ud.user + '@'
173 else:
174 username = ""
175
176 ud.repochanged = not os.path.exists(ud.fullmirror)
177
178 # If the checkout doesn't exist and the mirror tarball does, extract it
179 if not os.path.exists(ud.clonedir) and os.path.exists(ud.fullmirror):
180 bb.utils.mkdirhier(ud.clonedir)
181 os.chdir(ud.clonedir)
182 runfetchcmd("tar -xzf %s" % (ud.fullmirror), d)
183
184 repourl = "%s://%s%s%s" % (ud.proto, username, ud.host, ud.path)
185
186 # If the repo still doesn't exist, fallback to cloning it
187 if not os.path.exists(ud.clonedir):
188 # We do this since git will use a "-l" option automatically for local urls where possible
189 if repourl.startswith("file://"):
190 repourl = repourl[7:]
191 clone_cmd = "%s clone --bare --mirror %s %s" % (ud.basecmd, repourl, ud.clonedir)
192 if ud.proto.lower() != 'file':
193 bb.fetch2.check_network_access(d, clone_cmd)
194 runfetchcmd(clone_cmd, d)
195
196 os.chdir(ud.clonedir)
197 # Update the checkout if needed
198 needupdate = False
199 for name in ud.names:
200 if not self._contains_ref(ud.revisions[name], d):
201 needupdate = True
202 if needupdate:
203 try:
204 runfetchcmd("%s remote rm origin" % ud.basecmd, d)
205 except bb.fetch2.FetchError:
206 logger.debug(1, "No Origin")
207
208 runfetchcmd("%s remote add --mirror=fetch origin %s" % (ud.basecmd, repourl), d)
209 fetch_cmd = "%s fetch -f --prune %s refs/*:refs/*" % (ud.basecmd, repourl)
210 if ud.proto.lower() != 'file':
211 bb.fetch2.check_network_access(d, fetch_cmd, ud.url)
212 runfetchcmd(fetch_cmd, d)
213 runfetchcmd("%s prune-packed" % ud.basecmd, d)
214 runfetchcmd("%s pack-redundant --all | xargs -r rm" % ud.basecmd, d)
215 ud.repochanged = True
216
217 def build_mirror_data(self, url, ud, d):
218 # Generate a mirror tarball if needed
219 if ud.write_tarballs and (ud.repochanged or not os.path.exists(ud.fullmirror)):
220 # it's possible that this symlink points to read-only filesystem with PREMIRROR
221 if os.path.islink(ud.fullmirror):
222 os.unlink(ud.fullmirror)
223
224 os.chdir(ud.clonedir)
225 logger.info("Creating tarball of git repository")
226 runfetchcmd("tar -czf %s %s" % (ud.fullmirror, os.path.join(".") ), d)
227 runfetchcmd("touch %s.done" % (ud.fullmirror), d)
228
229 def unpack(self, ud, destdir, d):
230 """ unpack the downloaded src to destdir"""
231
232 subdir = ud.parm.get("subpath", "")
233 if subdir != "":
234 readpathspec = ":%s" % (subdir)
235 def_destsuffix = "%s/" % os.path.basename(subdir)
236 else:
237 readpathspec = ""
238 def_destsuffix = "git/"
239
240 destsuffix = ud.parm.get("destsuffix", def_destsuffix)
241 destdir = ud.destdir = os.path.join(destdir, destsuffix)
242 if os.path.exists(destdir):
243 bb.utils.prunedir(destdir)
244
245 cloneflags = "-s -n"
246 if ud.bareclone:
247 cloneflags += " --mirror"
248
249 # Versions of git prior to 1.7.9.2 have issues where foo.git and foo get confused
250 # and you end up with some horrible union of the two when you attempt to clone it
251 # The least invasive workaround seems to be a symlink to the real directory to
252 # fool git into ignoring any .git version that may also be present.
253 #
254 # The issue is fixed in more recent versions of git so we can drop this hack in future
255 # when that version becomes common enough.
256 clonedir = ud.clonedir
257 if not ud.path.endswith(".git"):
258 indirectiondir = destdir[:-1] + ".indirectionsymlink"
259 if os.path.exists(indirectiondir):
260 os.remove(indirectiondir)
261 bb.utils.mkdirhier(os.path.dirname(indirectiondir))
262 os.symlink(ud.clonedir, indirectiondir)
263 clonedir = indirectiondir
264
265 runfetchcmd("git clone %s %s/ %s" % (cloneflags, clonedir, destdir), d)
266 if not ud.nocheckout:
267 os.chdir(destdir)
268 if subdir != "":
269 runfetchcmd("%s read-tree %s%s" % (ud.basecmd, ud.revisions[ud.names[0]], readpathspec), d)
270 runfetchcmd("%s checkout-index -q -f -a" % ud.basecmd, d)
271 else:
272 runfetchcmd("%s checkout %s" % (ud.basecmd, ud.revisions[ud.names[0]]), d)
273 return True
274
275 def clean(self, ud, d):
276 """ clean the git directory """
277
278 bb.utils.remove(ud.localpath, True)
279 bb.utils.remove(ud.fullmirror)
280
281 def supports_srcrev(self):
282 return True
283
284 def _contains_ref(self, tag, d):
285 basecmd = data.getVar("FETCHCMD_git", d, True) or "git"
286 cmd = "%s log --pretty=oneline -n 1 %s -- 2> /dev/null | wc -l" % (basecmd, tag)
287 output = runfetchcmd(cmd, d, quiet=True)
288 if len(output.split()) > 1:
289 raise bb.fetch2.FetchError("The command '%s' gave output with more then 1 line unexpectedly, output: '%s'" % (cmd, output))
290 return output.split()[0] != "0"
291
292 def _revision_key(self, url, ud, d, name):
293 """
294 Return a unique key for the url
295 """
296 return "git:" + ud.host + ud.path.replace('/', '.') + ud.branches[name]
297
298 def _latest_revision(self, url, ud, d, name):
299 """
300 Compute the HEAD revision for the url
301 """
302 if ud.user:
303 username = ud.user + '@'
304 else:
305 username = ""
306
307 basecmd = data.getVar("FETCHCMD_git", d, True) or "git"
308 cmd = "%s ls-remote %s://%s%s%s %s" % \
309 (basecmd, ud.proto, username, ud.host, ud.path, ud.branches[name])
310 if ud.proto.lower() != 'file':
311 bb.fetch2.check_network_access(d, cmd)
312 output = runfetchcmd(cmd, d, True)
313 if not output:
314 raise bb.fetch2.FetchError("The command %s gave empty output unexpectedly" % cmd, url)
315 return output.split()[0]
316
317 def _build_revision(self, url, ud, d, name):
318 return ud.revisions[name]
319
320 def checkstatus(self, uri, ud, d):
321 fetchcmd = "%s ls-remote %s" % (ud.basecmd, uri)
322 try:
323 runfetchcmd(fetchcmd, d, quiet=True)
324 return True
325 except FetchError:
326 return False