blob: 9dcf3eb090de30909bc3b55eadf6f689b0980296 [file] [log] [blame]
rjw91288f92022-11-01 13:59:36 +08001# ex:ts=4:sw=4:sts=4:et
2# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3"""
4BitBake '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
26import os
27import sys
28import logging
29import bb
30import re
31from bb.fetch2 import FetchMethod
32from bb.fetch2 import FetchError
33from bb.fetch2 import MissingParameterError
34from bb.fetch2 import runfetchcmd
35from bb.fetch2 import logger
36
37class Svn(FetchMethod):
38 """Class to fetch a module or modules from svn repositories"""
39 def supports(self, ud, d):
40 """
41 Check to see if a given url can be fetched with svn.
42 """
43 return ud.type in ['svn']
44
45 def urldata_init(self, ud, d):
46 """
47 init svn specific variable within url data
48 """
49 if not "module" in ud.parm:
50 raise MissingParameterError('module', ud.url)
51
52 ud.basecmd = d.getVar("FETCHCMD_svn") or "/usr/bin/env svn --non-interactive --trust-server-cert"
53
54 ud.module = ud.parm["module"]
55
56 if not "path_spec" in ud.parm:
57 ud.path_spec = ud.module
58 else:
59 ud.path_spec = ud.parm["path_spec"]
60
61 # Create paths to svn checkouts
62 svndir = d.getVar("SVNDIR") or (d.getVar("DL_DIR") + "/svn")
63 relpath = self._strip_leading_slashes(ud.path)
64 ud.pkgdir = os.path.join(svndir, ud.host, relpath)
65 ud.moddir = os.path.join(ud.pkgdir, ud.module)
66 # Protects the repository from concurrent updates, e.g. from two
67 # recipes fetching different revisions at the same time
68 ud.svnlock = os.path.join(ud.pkgdir, "svn.lock")
69
70 ud.setup_revisions(d)
71
72 if 'rev' in ud.parm:
73 ud.revision = ud.parm['rev']
74
75 ud.localfile = d.expand('%s_%s_%s_%s_.tar.gz' % (ud.module.replace('/', '.'), ud.host, ud.path.replace('/', '.'), ud.revision))
76
77 def _buildsvncommand(self, ud, d, command):
78 """
79 Build up an svn commandline based on ud
80 command is "fetch", "update", "info"
81 """
82
83 proto = ud.parm.get('protocol', 'svn')
84
85 svn_ssh = None
86 if proto == "svn+ssh" and "ssh" in ud.parm:
87 svn_ssh = ud.parm["ssh"]
88
89 svnroot = ud.host + ud.path
90
91 options = []
92
93 options.append("--no-auth-cache")
94
95 if ud.user:
96 options.append("--username %s" % ud.user)
97
98 if ud.pswd:
99 options.append("--password %s" % ud.pswd)
100
101 if command == "info":
102 svncmd = "%s info %s %s://%s/%s/" % (ud.basecmd, " ".join(options), proto, svnroot, ud.module)
103 elif command == "log1":
104 svncmd = "%s log --limit 1 %s %s://%s/%s/" % (ud.basecmd, " ".join(options), proto, svnroot, ud.module)
105 else:
106 suffix = ""
107 if ud.revision:
108 options.append("-r %s" % ud.revision)
109 suffix = "@%s" % (ud.revision)
110
111 if command == "fetch":
112 transportuser = ud.parm.get("transportuser", "")
113 svncmd = "%s co %s %s://%s%s/%s%s %s" % (ud.basecmd, " ".join(options), proto, transportuser, svnroot, ud.module, suffix, ud.path_spec)
114 elif command == "update":
115 svncmd = "%s update %s" % (ud.basecmd, " ".join(options))
116 else:
117 raise FetchError("Invalid svn command %s" % command, ud.url)
118
119 if svn_ssh:
120 svncmd = "SVN_SSH=\"%s\" %s" % (svn_ssh, svncmd)
121
122 return svncmd
123
124 def download(self, ud, d):
125 """Fetch url"""
126
127 logger.debug(2, "Fetch: checking for module directory '" + ud.moddir + "'")
128
129 lf = bb.utils.lockfile(ud.svnlock)
130
131 try:
132 if os.access(os.path.join(ud.moddir, '.svn'), os.R_OK):
133 svnupdatecmd = self._buildsvncommand(ud, d, "update")
134 logger.info("Update " + ud.url)
135 # We need to attempt to run svn upgrade first in case its an older working format
136 try:
137 runfetchcmd(ud.basecmd + " upgrade", d, workdir=ud.moddir)
138 except FetchError:
139 pass
140 logger.debug(1, "Running %s", svnupdatecmd)
141 bb.fetch2.check_network_access(d, svnupdatecmd, ud.url)
142 runfetchcmd(svnupdatecmd, d, workdir=ud.moddir)
143 else:
144 svnfetchcmd = self._buildsvncommand(ud, d, "fetch")
145 logger.info("Fetch " + ud.url)
146 # check out sources there
147 bb.utils.mkdirhier(ud.pkgdir)
148 logger.debug(1, "Running %s", svnfetchcmd)
149 bb.fetch2.check_network_access(d, svnfetchcmd, ud.url)
150 runfetchcmd(svnfetchcmd, d, workdir=ud.pkgdir)
151
152 scmdata = ud.parm.get("scmdata", "")
153 if scmdata == "keep":
154 tar_flags = ""
155 else:
156 tar_flags = "--exclude='.svn'"
157
158 # tar them up to a defined filename
159 runfetchcmd("tar %s -czf %s %s" % (tar_flags, ud.localpath, ud.path_spec), d,
160 cleanup=[ud.localpath], workdir=ud.pkgdir)
161 finally:
162 bb.utils.unlockfile(lf)
163
164 def clean(self, ud, d):
165 """ Clean SVN specific files and dirs """
166
167 bb.utils.remove(ud.localpath)
168 bb.utils.remove(ud.moddir, True)
169
170
171 def supports_srcrev(self):
172 return True
173
174 def _revision_key(self, ud, d, name):
175 """
176 Return a unique key for the url
177 """
178 return "svn:" + ud.moddir
179
180 def _latest_revision(self, ud, d, name):
181 """
182 Return the latest upstream revision number
183 """
184 bb.fetch2.check_network_access(d, self._buildsvncommand(ud, d, "log1"), ud.url)
185
186 output = runfetchcmd("LANG=C LC_ALL=C " + self._buildsvncommand(ud, d, "log1"), d, True)
187
188 # skip the first line, as per output of svn log
189 # then we expect the revision on the 2nd line
190 revision = re.search('^r([0-9]*)', output.splitlines()[1]).group(1)
191
192 return revision
193
194 def sortable_revision(self, ud, d, name):
195 """
196 Return a sortable revision number which in our case is the revision number
197 """
198
199 return False, self._build_revision(ud, d)
200
201 def _build_revision(self, ud, d):
202 return ud.revision