git.py: Search mirrors for tarballs before fetching, not just local directories
[bitbake.git] / lib / bb / fetch / git.py
1 # ex:ts=4:sw=4:sts=4:et
2 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3 """
4 BitBake 'Fetch' git implementation
5
6 """
7
8 #Copyright (C) 2005 Richard Purdie
9 #
10 # This program is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License version 2 as
12 # published by the Free Software Foundation.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License along
20 # with this program; if not, write to the Free Software Foundation, Inc.,
21 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
23 import os, re
24 import bb
25 from   bb    import data
26 from   bb.fetch import Fetch
27 from   bb.fetch import FetchError
28 from   bb.fetch import runfetchcmd
29
30 class Git(Fetch):
31     """Class to fetch a module or modules from git repositories"""
32     def supports(self, url, ud, d):
33         """
34         Check to see if a given url can be fetched with git.
35         """
36         return ud.type in ['git']
37
38     def localpath(self, url, ud, d):
39
40         if 'protocol' in ud.parm:
41             ud.proto = ud.parm['protocol']
42         elif not ud.host:
43             ud.proto = 'file'
44         else:
45             ud.proto = "rsync"
46
47         ud.branch = ud.parm.get("branch", "master")
48
49         tag = Fetch.srcrev_internal_helper(ud, d)
50         if tag is True:
51             ud.tag = self.latest_revision(url, ud, d)   
52         elif tag:
53             ud.tag = tag
54
55         if not ud.tag or ud.tag == "master":
56             ud.tag = self.latest_revision(url, ud, d)   
57
58         ud.localfile = data.expand('git_%s%s_%s.tar.gz' % (ud.host, ud.path.replace('/', '.'), ud.tag), d)
59
60         return os.path.join(data.getVar("DL_DIR", d, True), ud.localfile)
61
62     def go(self, loc, ud, d):
63         """Fetch url"""
64
65         if Fetch.try_mirror(d, ud.localfile):
66             bb.msg.debug(1, bb.msg.domain.Fetcher, "%s already exists (or was stashed). Skipping git checkout." % ud.localpath)
67             return
68
69         if ud.user:
70             username = ud.user + '@'
71         else:
72             username = ""
73
74         gitsrcname = '%s%s' % (ud.host, ud.path.replace('/', '.'))
75
76         repofilename = 'git_%s.tar.gz' % (gitsrcname)
77         repofile = os.path.join(data.getVar("DL_DIR", d, 1), repofilename)
78         repodir = os.path.join(data.expand('${GITDIR}', d), gitsrcname)
79
80         coname = '%s' % (ud.tag)
81         codir = os.path.join(repodir, coname)
82
83         if not os.path.exists(repodir):
84             if Fetch.try_mirror(d, repofilename):    
85                 bb.mkdirhier(repodir)
86                 os.chdir(repodir)
87                 runfetchcmd("tar -xzf %s" % (repofile), d)
88             else:
89                 runfetchcmd("git clone -n %s://%s%s%s %s" % (ud.proto, username, ud.host, ud.path, repodir), d)
90
91         os.chdir(repodir)
92         # Remove all but the .git directory
93         if not self._contains_ref(ud.tag, d):
94             runfetchcmd("rm * -Rf", d)
95             runfetchcmd("git fetch %s://%s%s%s %s" % (ud.proto, username, ud.host, ud.path, ud.branch), d)
96             runfetchcmd("git fetch --tags %s://%s%s%s" % (ud.proto, username, ud.host, ud.path), d)
97             runfetchcmd("git prune-packed", d)
98             runfetchcmd("git pack-redundant --all | xargs -r rm", d)
99
100         os.chdir(repodir)
101         mirror_tarballs = data.getVar("BB_GENERATE_MIRROR_TARBALLS", d, True)
102         if mirror_tarballs != "0": 
103             bb.msg.note(1, bb.msg.domain.Fetcher, "Creating tarball of git repository")
104             runfetchcmd("tar -czf %s %s" % (repofile, os.path.join(".", ".git", "*") ), d)
105
106         if os.path.exists(codir):
107             bb.utils.prunedir(codir)
108
109         bb.mkdirhier(codir)
110         os.chdir(repodir)
111         runfetchcmd("git read-tree %s" % (ud.tag), d)
112         runfetchcmd("git checkout-index -q -f --prefix=%s -a" % (os.path.join(codir, "git", "")), d)
113
114         os.chdir(codir)
115         bb.msg.note(1, bb.msg.domain.Fetcher, "Creating tarball of git checkout")
116         runfetchcmd("tar -czf %s %s" % (ud.localpath, os.path.join(".", "*") ), d)
117
118         os.chdir(repodir)
119         bb.utils.prunedir(codir)
120
121     def suppports_srcrev(self):
122         return True
123
124     def _contains_ref(self, tag, d):
125         output = runfetchcmd("git log --pretty=oneline -n 1 %s -- 2> /dev/null | wc -l" % tag, d, quiet=True)
126         return output.split()[0] != "0"
127
128     def _revision_key(self, url, ud, d):
129         """
130         Return a unique key for the url
131         """
132         return "git:" + ud.host + ud.path.replace('/', '.')
133
134     def _latest_revision(self, url, ud, d):
135         """
136         Compute the HEAD revision for the url
137         """
138         if ud.user:
139             username = ud.user + '@'
140         else:
141             username = ""
142
143         output = runfetchcmd("git ls-remote %s://%s%s%s %s" % (ud.proto, username, ud.host, ud.path, ud.branch), d, True)
144         return output.split()[0]
145
146     def _build_revision(self, url, ud, d):
147         return ud.tag
148
149     def _want_sortable_revision(self, url, ud, d):
150         return bb.data.getVar("BB_GIT_CLONE_FOR_SRCREV", d, True) or False
151
152     def _sortable_revision(self, url, ud, d):
153         """
154         This is only called when _want_sortable_revision called true
155
156         We will have to get the updated revision.
157         """
158         gitsrcname = '%s%s' % (ud.host, ud.path.replace('/', '.'))
159         repodir = os.path.join(data.expand('${GITDIR}', d), gitsrcname)
160
161         key = "GIT_CACHED_REVISION-%s-%s"  % (gitsrcname, ud.tag)
162         if bb.data.getVar(key, d):
163             return bb.data.getVar(key, d)
164
165
166         # Runtime warning on wrongly configured sources
167         if ud.tag == "1":
168             bb.msg.error(1, bb.msg.domain.Fetcher, "SRCREV is '1'. This indicates a configuration error of %s" % url)
169             return "0+1"
170
171         cwd = os.getcwd()
172
173         # Check if we have the rev already
174         if not os.path.exists(repodir):
175             print "no repo"
176             self.go(None, ud, d)
177
178         os.chdir(repodir)
179         if not self._contains_ref(ud.tag, d):
180             self.go(None, ud, d)
181
182         output = runfetchcmd("git rev-list %s -- 2> /dev/null | wc -l" % ud.tag, d, quiet=True)
183         os.chdir(cwd)
184
185         sortable_revision = "%s+%s" % (output.split()[0], ud.tag)
186         bb.data.setVar(key, sortable_revision, d)
187         return sortable_revision
188         
189