[git] Do not run git-rev-list everytime to increase the speed
[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         ud.proto = "rsync"
41         if 'protocol' in ud.parm:
42             ud.proto = ud.parm['protocol']
43
44         ud.branch = ud.parm.get("branch", "master")
45
46         tag = Fetch.srcrev_internal_helper(ud, d)
47         if tag is True:
48             ud.tag = self.latest_revision(url, ud, d)   
49         elif tag:
50             ud.tag = tag
51
52         if not ud.tag:
53             ud.tag = self.latest_revision(url, ud, d)   
54
55         if 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 os.access(os.path.join(data.getVar("DL_DIR", d, True), ud.localfile), os.R_OK):
66             bb.msg.debug(1, bb.msg.domain.Fetcher, "%s already exists (or was stashed). Skipping git checkout." % ud.localpath)
67             return
68
69         gitsrcname = '%s%s' % (ud.host, ud.path.replace('/', '.'))
70
71         repofilename = 'git_%s.tar.gz' % (gitsrcname)
72         repofile = os.path.join(data.getVar("DL_DIR", d, 1), repofilename)
73         repodir = os.path.join(data.expand('${GITDIR}', d), gitsrcname)
74
75         coname = '%s' % (ud.tag)
76         codir = os.path.join(repodir, coname)
77
78         if not os.path.exists(repodir):
79             if Fetch.try_mirror(d, repofilename):    
80                 bb.mkdirhier(repodir)
81                 os.chdir(repodir)
82                 runfetchcmd("tar -xzf %s" % (repofile), d)
83             else:
84                 runfetchcmd("git clone -n %s://%s%s %s" % (ud.proto, ud.host, ud.path, repodir), d)
85
86         os.chdir(repodir)
87         # Remove all but the .git directory
88         if not self._contains_ref(ud.tag, d):
89             runfetchcmd("rm * -Rf", d)
90             runfetchcmd("git fetch %s://%s%s %s" % (ud.proto, ud.host, ud.path, ud.branch), d)
91             runfetchcmd("git fetch --tags %s://%s%s" % (ud.proto, ud.host, ud.path), d)
92             runfetchcmd("git prune-packed", d)
93             runfetchcmd("git pack-redundant --all | xargs -r rm", d)
94
95         os.chdir(repodir)
96         mirror_tarballs = data.getVar("BB_GENERATE_MIRROR_TARBALLS", d, True)
97         if mirror_tarballs != "0": 
98             bb.msg.note(1, bb.msg.domain.Fetcher, "Creating tarball of git repository")
99             runfetchcmd("tar -czf %s %s" % (repofile, os.path.join(".", ".git", "*") ), d)
100
101         if os.path.exists(codir):
102             bb.utils.prunedir(codir)
103
104         bb.mkdirhier(codir)
105         os.chdir(repodir)
106         runfetchcmd("git read-tree %s" % (ud.tag), d)
107         runfetchcmd("git checkout-index -q -f --prefix=%s -a" % (os.path.join(codir, "git", "")), d)
108
109         os.chdir(codir)
110         bb.msg.note(1, bb.msg.domain.Fetcher, "Creating tarball of git checkout")
111         runfetchcmd("tar -czf %s %s" % (ud.localpath, os.path.join(".", "*") ), d)
112
113         os.chdir(repodir)
114         bb.utils.prunedir(codir)
115
116     def suppports_srcrev(self):
117         return True
118
119     def _contains_ref(self, tag, d):
120         output = runfetchcmd("git log --pretty=oneline -n 1 %s -- 2> /dev/null | wc -l" % tag, d, quiet=True)
121         return output.split()[0] != "0"
122
123     def _revision_key(self, url, ud, d):
124         """
125         Return a unique key for the url
126         """
127         return "git:" + ud.host + ud.path.replace('/', '.')
128
129     def _latest_revision(self, url, ud, d):
130         """
131         Compute the HEAD revision for the url
132         """
133         output = runfetchcmd("git ls-remote %s://%s%s %s" % (ud.proto, ud.host, ud.path, ud.branch), d, True)
134         return output.split()[0]
135
136     def _build_revision(self, url, ud, d):
137         return ud.tag
138
139     def _want_sortable_revision(self, url, ud, d):
140         return bb.data.getVar("BB_GIT_CLONE_FOR_SRCREV", d, True) or False
141
142     def _sortable_revision(self, url, ud, d):
143         """
144         This is only called when _want_sortable_revision called true
145
146         We will have to get the updated revision.
147         """
148         gitsrcname = '%s%s' % (ud.host, ud.path.replace('/', '.'))
149         repodir = os.path.join(data.expand('${GITDIR}', d), gitsrcname)
150
151         key = "GIT_CACHED_REVISION-%s-%s"  % (gitsrcname, ud.tag)
152         if bb.data.getVar(key, d):
153             return bb.data.getVar(key, d)
154
155
156         # Runtime warning on wrongly configured sources
157         if ud.tag == "1":
158             bb.msg.error(1, bb.msg.domain.Fetcher, "SRCREV is '1'. This indicates a configuration error of %s" % url)
159             return "0+1"
160
161         cwd = os.getcwd()
162
163         # Check if we have the rev already
164         if not os.path.exists(repodir):
165             print "no repo"
166             self.go(None, ud, d)
167
168         os.chdir(repodir)
169         if not self._contains_ref(ud.tag, d):
170             self.go(None, ud, d)
171
172         output = runfetchcmd("git rev-list %s -- 2> /dev/null | wc -l" % ud.tag, d, quiet=True)
173         os.chdir(cwd)
174
175         sortable_revision = "%s+%s" % (output.split()[0], ud.tag)
176         bb.data.setVar(key, sortable_revision, d)
177         return sortable_revision
178         
179