svn.py: Handle case where SRCREV=None
[bitbake.git] / lib / bb / fetch / svn.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' implementation for svn.
5
6 """
7
8 # Copyright (C) 2003, 2004  Chris Larson
9 # Copyright (C) 2004        Marcin Juszkiewicz
10 #
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License version 2 as
13 # published by the Free Software Foundation.
14 #
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 # GNU General Public License for more details.
19 #
20 # You should have received a copy of the GNU General Public License along
21 # with this program; if not, write to the Free Software Foundation, Inc.,
22 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #
24 # Based on functions from the base bb module, Copyright 2003 Holger Schurig
25
26 import os, re
27 import sys
28 import bb
29 from   bb import data
30 from   bb.fetch import Fetch
31 from   bb.fetch import FetchError
32 from   bb.fetch import MissingParameterError
33 from   bb.fetch import runfetchcmd
34
35 class Svn(Fetch):
36     """Class to fetch a module or modules from svn repositories"""
37     def supports(self, url, ud, d):
38         """
39         Check to see if a given url can be fetched with svn.
40         """
41         return ud.type in ['svn']
42
43     def localpath(self, url, ud, d):
44         if not "module" in ud.parm:
45             raise MissingParameterError("svn method needs a 'module' parameter")
46
47         ud.module = ud.parm["module"]
48
49         # Create paths to svn checkouts
50         relpath = ud.path
51         if relpath.startswith('/'):
52             # Remove leading slash as os.path.join can't cope
53             relpath = relpath[1:]
54         ud.pkgdir = os.path.join(data.expand('${SVNDIR}', d), ud.host, relpath)
55         ud.moddir = os.path.join(ud.pkgdir, ud.module)
56
57         if 'rev' in ud.parm:
58             ud.date = ""
59             ud.revision = ud.parm['rev']
60         elif 'date' in ud.date:
61             ud.date = ud.parm['date']
62             ud.revision = ""
63         else:
64             #
65             # ***Nasty hacks***
66             # If DATE in unexpanded PV, use ud.date (which is set from SRCDATE)
67             # Will warn people to switch to SRCREV here
68             #
69             # How can we tell when a user has overriden SRCDATE? 
70             # check for "get_srcdate" in unexpanded SRCREV - ugly
71             #
72             pv = data.getVar("PV", d, 0)
73             if "DATE" in pv:
74                 ud.revision = ""
75             else:
76                 rev = data.getVar("SRCREV", d, 0)
77                 if rev and "get_srcrev" in rev:
78                     ud.revision = self.latest_revision(url, ud, d)
79                     ud.date = ""
80                 else if rev:
81                     ud.revision = rev
82                     ud.date = ""
83                 else:
84                     ud.revision = ""            
85
86         ud.localfile = data.expand('%s_%s_%s_%s_%s.tar.gz' % (ud.module.replace('/', '.'), ud.host, ud.path.replace('/', '.'), ud.revision, ud.date), d)
87
88         return os.path.join(data.getVar("DL_DIR", d, True), ud.localfile)
89
90     def _buildsvncommand(self, ud, d, command):
91         """
92         Build up an svn commandline based on ud
93         command is "fetch", "update", "info"
94         """
95
96         basecmd = data.expand('${FETCHCMD_svn}', d)
97
98         proto = "svn"
99         if "proto" in ud.parm:
100             proto = ud.parm["proto"]
101
102         svn_rsh = None
103         if proto == "svn+ssh" and "rsh" in ud.parm:
104             svn_rsh = ud.parm["rsh"]
105
106         svnroot = ud.host + ud.path
107
108         # either use the revision, or SRCDATE in braces,
109         options = []
110
111         if ud.user:
112             options.append("--username %s" % ud.user)
113
114         if ud.pswd:
115             options.append("--password %s" % ud.pswd)
116
117         if command is "info":
118             svncmd = "%s info %s %s://%s/%s/" % (basecmd, " ".join(options), proto, svnroot, ud.module)
119         else:
120             if ud.revision:
121                 options.append("-r %s" % ud.revision)
122             elif ud.date:
123                 options.append("-r {%s}" % ud.date)
124
125             if command is "fetch":
126                 svncmd = "%s co %s %s://%s/%s %s" % (basecmd, " ".join(options), proto, svnroot, ud.module, ud.module)
127             elif command is "update":
128                 svncmd = "%s update %s" % (basecmd, " ".join(options))
129             else:
130                 raise FetchError("Invalid svn command %s" % command)
131
132         if svn_rsh:
133             svncmd = "svn_RSH=\"%s\" %s" % (svn_rsh, svncmd)
134
135         return svncmd
136
137     def go(self, loc, ud, d):
138         """Fetch url"""
139
140         # try to use the tarball stash
141         if Fetch.try_mirror(d, ud.localfile):
142             bb.msg.debug(1, bb.msg.domain.Fetcher, "%s already exists or was mirrored, skipping svn checkout." % ud.localpath)
143             return
144
145         bb.msg.debug(2, bb.msg.domain.Fetcher, "Fetch: checking for module directory '" + ud.moddir + "'")
146
147         if os.access(os.path.join(ud.moddir, '.svn'), os.R_OK):
148             svnupdatecmd = self._buildsvncommand(ud, d, "update")
149             bb.msg.note(1, bb.msg.domain.Fetcher, "Update " + loc)
150             # update sources there
151             os.chdir(ud.moddir)
152             bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % svnupdatecmd)
153             runfetchcmd(svnupdatecmd, d)
154         else:
155             svnfetchcmd = self._buildsvncommand(ud, d, "fetch")
156             bb.msg.note(1, bb.msg.domain.Fetcher, "Fetch " + loc)
157             # check out sources there
158             bb.mkdirhier(ud.pkgdir)
159             os.chdir(ud.pkgdir)
160             bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s" % svnfetchcmd)
161             runfetchcmd(svnfetchcmd, d)
162
163         os.chdir(ud.pkgdir)
164         # tar them up to a defined filename
165         try:
166             runfetchcmd("tar -czf %s %s" % (ud.localpath, os.path.basename(ud.module)), d)
167         except:
168             t, v, tb = sys.exc_info()
169             try:
170                 os.unlink(ud.localpath)
171             except OSError:
172                 pass
173             raise t, v, tb
174
175     def suppports_srcrev(self):
176         return True
177
178     def _revision_key(self, url, ud, d):
179         """
180         Return a unique key for the url
181         """
182         return "svn:" + ud.moddir
183
184     def _latest_revision(self, url, ud, d):
185         """
186         Return the latest upstream revision number
187         """
188         bb.msg.debug(2, bb.msg.domain.Fetcher, "SVN fetcher hitting network for %s" % url)
189
190         output = runfetchcmd("LANG=C LC_ALL=C " + self._buildsvncommand(ud, d, "info"), d, True)
191
192         revision = None
193         for line in output.splitlines():
194             if "Last Changed Rev" in line:
195                 revision = line.split(":")[1].strip()
196
197         return revision
198
199     def _sortable_revision(self, url, ud, d):
200         """
201         Return a sortable revision number which in our case is the revision number
202         (use the cached version to avoid network access)
203         """
204
205         return self.latest_revision(url, ud, d)
206