lib/bb/fetch/git.py:
[bitbake.git] / lib / bb / fetch / git.py
1 #!/usr/bin/env python
2 # ex:ts=4:sw=4:sts=4:et
3 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4 """
5 BitBake 'Fetch' git implementation
6
7 Copyright (C) 2005 Richard Purdie
8
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
12 version.
13
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.
17
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. 
21 """
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
29 def prunedir(topdir):
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):
33         for name in files:
34             os.remove(os.path.join(root, name))
35         for name in dirs:
36             os.rmdir(os.path.join(root, name))
37
38 def rungitcmd(cmd,d):
39
40     bb.debug(1, "Running %s" % cmd)
41
42     # Need to export PATH as git is likely to be in metadata paths 
43     # rather than host provided
44     pathcmd = 'export PATH=%s; %s' % (data.expand('${PATH}', d), cmd)
45
46     myret = os.system(pathcmd)
47
48     if myret != 0:
49         raise FetchError("Git: %s failed" % pathcmd)
50
51 def gettag(parm):
52     if 'tag' in parm:
53         tag = parm['tag']
54     else:
55         tag = ""
56     if not tag:
57         tag = "master"
58
59     return tag
60
61 def getprotocol(parm):
62     if 'protocol' in parm:
63         proto = parm['protocol']
64     else:
65         proto = ""
66     if not proto:
67         proto = "rsync"
68
69     return proto
70
71 def localfile(url, d):
72     """Return the filename to cache the checkout in"""
73     (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
74
75     #if user sets localpath for file, use it instead.
76     if "localpath" in parm:
77         return parm["localpath"]
78
79     tag = gettag(parm)
80
81     return data.expand('git_%s%s_%s.tar.gz' % (host, path.replace('/', '.'), tag), d)
82
83 class Git(Fetch):
84     """Class to fetch a module or modules from git repositories"""
85     def supports(url, d):
86         """Check to see if a given url can be fetched with cvs.
87            Expects supplied url in list form, as outputted by bb.decodeurl().
88         """
89         (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(url, d))
90         return type in ['git']
91     supports = staticmethod(supports)
92
93     def localpath(url, d):
94
95         return os.path.join(data.getVar("DL_DIR", d, 1), localfile(url, d))
96
97     localpath = staticmethod(localpath)
98
99     def go(self, d, urls = []):
100         """Fetch urls"""
101         if not urls:
102             urls = self.urls
103
104         for loc in urls:
105             (type, host, path, user, pswd, parm) = bb.decodeurl(data.expand(loc, d))
106
107             tag = gettag(parm)
108             proto = getprotocol(parm)
109
110             gitsrcname = '%s%s' % (host, path.replace('/', '.'))
111
112             repofilename = 'git_%s.tar.gz' % (gitsrcname)
113             repofile = os.path.join(data.getVar("DL_DIR", d, 1), repofilename)
114             repodir = os.path.join(data.expand('${GITDIR}', d), gitsrcname)
115
116             coname = '%s' % (tag)
117             codir = os.path.join(repodir, coname)
118
119             cofile = self.localpath(loc, d)
120
121             # tag=="master" must always update
122             if (tag != "master") and Fetch.try_mirror(d, localfile(loc, d)):
123                 bb.debug(1, "%s already exists (or was stashed). Skipping git checkout." % cofile)
124                 continue
125
126             if not os.path.exists(repodir):
127                 if Fetch.try_mirror(d, repofilename):    
128                     bb.mkdirhier(repodir)
129                     os.chdir(repodir)
130                     rungitcmd("tar -xzf %s" % (repofile),d)
131                 else:
132                     rungitcmd("git clone -n %s://%s%s %s" % (proto, host, path, repodir),d)
133
134             os.chdir(repodir)
135             rungitcmd("git pull %s://%s%s" % (proto, host, path),d)
136             rungitcmd("git pull --tags %s://%s%s" % (proto, host, path),d)
137             rungitcmd("git prune-packed", d)
138             # old method of downloading tags
139             #rungitcmd("rsync -a --verbose --stats --progress rsync://%s%s/ %s" % (host, path, os.path.join(repodir, ".git", "")),d)
140
141             os.chdir(repodir)
142             bb.note("Creating tarball of git repository")
143             rungitcmd("tar -czf %s %s" % (repofile, os.path.join(".", ".git", "*") ),d)
144
145             if os.path.exists(codir):
146                 prunedir(codir)
147
148             bb.mkdirhier(codir)
149             os.chdir(repodir)
150             rungitcmd("git read-tree %s" % (tag),d)
151             rungitcmd("git checkout-index -q -f --prefix=%s -a" % (os.path.join(codir, "git", "")),d)
152
153             os.chdir(codir)
154             bb.note("Creating tarball of git checkout")
155             rungitcmd("tar -czf %s %s" % (cofile, os.path.join(".", "*") ),d)