add branch support to the git fetcher -- thanks Otavio Salvador.
[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 def prunedir(topdir):
31     # Delete everything reachable from the directory named in 'topdir'.
32     # CAUTION:  This is dangerous!
33     for root, dirs, files in os.walk(topdir, topdown=False):
34         for name in files:
35             os.remove(os.path.join(root, name))
36         for name in dirs:
37             os.rmdir(os.path.join(root, name))
38
39 class Git(Fetch):
40     """Class to fetch a module or modules from git repositories"""
41     def supports(self, url, ud, d):
42         """
43         Check to see if a given url can be fetched with git.
44         """
45         return ud.type in ['git']
46
47     def localpath(self, url, ud, d):
48
49         ud.proto = "rsync"
50         if 'protocol' in ud.parm:
51             ud.proto = ud.parm['protocol']
52
53         ud.branch = ud.parm.get("branch", "")
54
55         tag = Fetch.srcrev_internal_helper(ud, d)
56         if tag is True:
57             ud.tag = self.latest_revision(url, ud, d)   
58         elif tag:
59             ud.tag = tag
60
61         if not ud.tag:
62             ud.tag = self.latest_revision(url, ud, d)   
63
64         if ud.tag == "master":
65             ud.tag = self.latest_revision(url, ud, d)
66
67         ud.localfile = data.expand('git_%s%s_%s.tar.gz' % (ud.host, ud.path.replace('/', '.'), ud.tag), d)
68
69         return os.path.join(data.getVar("DL_DIR", d, True), ud.localfile)
70
71     def go(self, loc, ud, d):
72         """Fetch url"""
73
74         if Fetch.try_mirror(d, ud.localfile):
75             bb.msg.debug(1, bb.msg.domain.Fetcher, "%s already exists (or was stashed). Skipping git checkout." % ud.localpath)
76             return
77
78         gitsrcname = '%s%s' % (ud.host, ud.path.replace('/', '.'))
79
80         repofilename = 'git_%s.tar.gz' % (gitsrcname)
81         repofile = os.path.join(data.getVar("DL_DIR", d, 1), repofilename)
82         repodir = os.path.join(data.expand('${GITDIR}', d), gitsrcname)
83
84         coname = '%s' % (ud.tag)
85         codir = os.path.join(repodir, coname)
86
87         if not os.path.exists(repodir):
88             if Fetch.try_mirror(d, repofilename):    
89                 bb.mkdirhier(repodir)
90                 os.chdir(repodir)
91                 runfetchcmd("tar -xzf %s" % (repofile), d)
92             else:
93                 runfetchcmd("git clone -n %s://%s%s %s" % (ud.proto, ud.host, ud.path, repodir), d)
94
95         os.chdir(repodir)
96         # Remove all but the .git directory
97         runfetchcmd("rm * -Rf", d)
98         runfetchcmd("git fetch %s://%s%s" % (ud.proto, ud.host, ud.path), d)
99         runfetchcmd("git pull --tags %s://%s%s" % (ud.proto, ud.host, ud.path), d)
100         runfetchcmd("git prune-packed", d)
101         runfetchcmd("git pack-redundant --all | xargs -r rm", d)
102
103         os.chdir(repodir)
104         mirror_tarballs = data.getVar("BB_GENERATE_MIRROR_TARBALLS", d, True)
105         if mirror_tarballs != "0": 
106             bb.msg.note(1, bb.msg.domain.Fetcher, "Creating tarball of git repository")
107             runfetchcmd("tar -czf %s %s" % (repofile, os.path.join(".", ".git", "*") ), d)
108
109         if os.path.exists(codir):
110             prunedir(codir)
111
112         bb.mkdirhier(codir)
113         os.chdir(repodir)
114         runfetchcmd("git read-tree %s" % (ud.tag), d)
115         runfetchcmd("git checkout-index -q -f --prefix=%s -a" % (os.path.join(codir, "git", "")), d)
116
117         os.chdir(codir)
118         bb.msg.note(1, bb.msg.domain.Fetcher, "Creating tarball of git checkout")
119         runfetchcmd("tar -czf %s %s" % (ud.localpath, os.path.join(".", "*") ), d)
120
121         os.chdir(repodir)
122         prunedir(codir)
123
124     def suppports_srcrev(self):
125         return True
126
127     def _revision_key(self, url, ud, d):
128         """
129         Return a unique key for the url
130         """
131         return "git:" + ud.host + ud.path.replace('/', '.')
132
133     def _latest_revision(self, url, ud, d):
134
135         bb.msg.note(1, bb.msg.domain.Fetcher, "Calling git ls-remote %s://%s%s %s" % (ud.proto, ud.host, ud.path, ud.branch ) )
136         output = runfetchcmd("git ls-remote %s://%s%s %s" % (ud.proto, ud.host, ud.path, ud.branch), d, True)
137         return output.split()[0]
138
139     def _build_revision(self, url, ud, d):
140         return ud.tag
141