2 # ex:ts=4:sw=4:sts=4:et
3 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
5 BitBake 'Fetch' git implementation
7 Copyright (C) 2005 Richard Purdie
9 This program is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free Software
11 Foundation; either version 2 of the License, or (at your option) any later
14 This program is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License along with
19 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
20 Place, Suite 330, Boston, MA 02111-1307 USA.
26 from bb.fetch import Fetch
27 from bb.fetch import FetchError
30 # Delete everything reachable from the directory named in 'topdir'.
31 # CAUTION: This is dangerous!
32 for root, dirs, files in os.walk(topdir, topdown=False):
34 os.remove(os.path.join(root, name))
36 os.rmdir(os.path.join(root, name))
38 def runfetchcmd(cmd, d, quiet = False):
40 bb.debug(1, "Running %s" % cmd)
42 # Need to export PATH as git is likely to be in metadata paths
43 # rather than host provided
44 cmd = 'export PATH=%s; %s' % (data.expand('${PATH}', d), cmd)
46 # redirect stderr to stdout
47 stdout_handle = os.popen(cmd + " 2>&1", "r")
51 line = stdout_handle.readline()
58 status = stdout_handle.close() or 0
60 exitstatus = status & 0xff
63 raise FetchError("Fetch command %s failed with signal %s, output:\n%s" % (cmd, signal, output))
65 raise FetchError("Fetch command %s failed with exit code %s, output:\n%s" % (cmd, status, output))
69 def contains_ref(tag, d):
70 output = runfetchcmd("git log --pretty=oneline -n 1 %s -- 2> /dev/null | wc -l" % tag, d, True)
71 return output.split()[0] != "0"
73 def latest_revision(proto, user, host, path, branch, d):
75 Compute the HEAD revision for the url
82 output = runfetchcmd("git ls-remote %s://%s%s%s %s" % (proto, username, host, path, branch), d, True)
83 return output.split()[0]
87 branch = parm['branch']
95 def gettag(parm, proto, user, host, path, branch, d):
99 tag = latest_revision(proto, user, host, path, branch, d)
100 if not tag or tag == "master":
101 tag = latest_revision(proto, user, host, path, branch, d)
105 def getprotocol(parm):
106 if 'protocol' in parm:
107 proto = parm['protocol']
115 def localfile(url, d):
116 """Return the filename to cache the checkout in"""
117 (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
119 #if user sets localpath for file, use it instead.
120 if "localpath" in parm:
121 return parm["localpath"]
123 proto = getprotocol(parm)
124 branch = getbranch(parm)
125 tag = gettag(parm, proto, user, host, path, branch, d)
127 return data.expand('git_%s%s_%s.tar.gz' % (host, path.replace('/', '.'), tag), d)
130 """Class to fetch a module or modules from git repositories"""
131 def supports(url, d):
132 """Check to see if a given url can be fetched with cvs.
133 Expects supplied url in list form, as outputted by bb.decodeurl().
135 (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
136 return type in ['git']
137 supports = staticmethod(supports)
139 def localpath(url, d):
141 return os.path.join(data.getVar("DL_DIR", d, 1), localfile(url, d))
143 localpath = staticmethod(localpath)
145 def go(self, d, urls = []):
151 (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(loc, d))
153 proto = getprotocol(parm)
154 branch = getbranch(parm)
155 tag = gettag(parm, proto, user, host, path, branch, d)
158 username = user + '@'
162 gitsrcname = '%s%s' % (host, path.replace('/', '.'))
164 repofilename = 'git_%s.tar.gz' % (gitsrcname)
165 repofile = os.path.join(data.getVar("DL_DIR", d, 1), repofilename)
166 repodir = os.path.join(data.expand('${GITDIR}', d), gitsrcname)
168 coname = '%s' % (tag)
169 codir = os.path.join(repodir, coname)
171 if not os.path.exists(repodir):
172 if Fetch.try_mirror(d, repofilename):
173 bb.mkdirhier(repodir)
175 runfetchcmd("tar -xzf %s" % (repofile),d)
177 runfetchcmd("git clone -n %s://%s%s%s %s" % (proto, username, host, path, repodir),d)
180 # Remove all but the .git directory
181 if not contains_ref(tag, d):
182 runfetchcmd("rm * -Rf", d)
183 runfetchcmd("git fetch %s://%s%s%s %s" % (proto, username, host, path, branch), d)
184 runfetchcmd("git fetch --tags %s://%s%s%s" % (proto, username, host, path), d)
185 runfetchcmd("git prune-packed", d)
186 runfetchcmd("git pack-redundant --all | xargs -r rm", d)
189 bb.note("Creating tarball of git repository")
190 runfetchcmd("tar -czf %s %s" % (repofile, os.path.join(".", ".git", "*") ),d)
192 if os.path.exists(codir):
197 copath = os.path.join(codir, "git", "")
198 runfetchcmd("git read-tree %s" % (tag),d)
199 runfetchcmd("git checkout-index -q -f --prefix=%s -a" % (copath),d)
200 bb.mkdirhier(os.path.join(copath, ".git", ""))
201 runfetchcmd("LANG=\"en\" git log %s --max-count=1 --date=iso -- > %s.git/last_commit_info" % (tag, copath),d)
202 runfetchcmd("echo %s > %s.git/branch" % (branch, copath),d)
205 bb.note("Creating tarball of git checkout")
206 runfetchcmd("tar -czf %s %s" % (self.localpath(loc, d), os.path.join(".", "*") ),d)