Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 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 mercurial DRCS (hg). |
| 5 | |
| 6 | """ |
| 7 | |
| 8 | # Copyright (C) 2003, 2004 Chris Larson |
| 9 | # Copyright (C) 2004 Marcin Juszkiewicz |
| 10 | # Copyright (C) 2007 Robert Schuster |
| 11 | # |
| 12 | # This program is free software; you can redistribute it and/or modify |
| 13 | # it under the terms of the GNU General Public License version 2 as |
| 14 | # published by the Free Software Foundation. |
| 15 | # |
| 16 | # This program is distributed in the hope that it will be useful, |
| 17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 19 | # GNU General Public License for more details. |
| 20 | # |
| 21 | # You should have received a copy of the GNU General Public License along |
| 22 | # with this program; if not, write to the Free Software Foundation, Inc., |
| 23 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| 24 | # |
| 25 | # Based on functions from the base bb module, Copyright 2003 Holger Schurig |
| 26 | |
| 27 | import os |
| 28 | import sys |
| 29 | import logging |
| 30 | import bb |
Patrick Williams | f1e5d69 | 2016-03-30 15:21:19 -0500 | [diff] [blame] | 31 | import errno |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 32 | from bb.fetch2 import FetchMethod |
| 33 | from bb.fetch2 import FetchError |
| 34 | from bb.fetch2 import MissingParameterError |
| 35 | from bb.fetch2 import runfetchcmd |
| 36 | from bb.fetch2 import logger |
| 37 | |
| 38 | class Hg(FetchMethod): |
| 39 | """Class to fetch from mercurial repositories""" |
| 40 | def supports(self, ud, d): |
| 41 | """ |
| 42 | Check to see if a given url can be fetched with mercurial. |
| 43 | """ |
| 44 | return ud.type in ['hg'] |
| 45 | |
| 46 | def supports_checksum(self, urldata): |
| 47 | """ |
| 48 | Don't require checksums for local archives created from |
| 49 | repository checkouts. |
| 50 | """ |
| 51 | return False |
| 52 | |
| 53 | def urldata_init(self, ud, d): |
| 54 | """ |
| 55 | init hg specific variable within url data |
| 56 | """ |
| 57 | if not "module" in ud.parm: |
| 58 | raise MissingParameterError('module', ud.url) |
| 59 | |
| 60 | ud.module = ud.parm["module"] |
| 61 | |
| 62 | if 'protocol' in ud.parm: |
| 63 | ud.proto = ud.parm['protocol'] |
| 64 | elif not ud.host: |
| 65 | ud.proto = 'file' |
| 66 | else: |
| 67 | ud.proto = "hg" |
| 68 | |
Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 69 | ud.setup_revisions(d) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 70 | |
| 71 | if 'rev' in ud.parm: |
| 72 | ud.revision = ud.parm['rev'] |
| 73 | elif not ud.revision: |
| 74 | ud.revision = self.latest_revision(ud, d) |
| 75 | |
| 76 | # Create paths to mercurial checkouts |
| 77 | hgsrcname = '%s_%s_%s' % (ud.module.replace('/', '.'), \ |
| 78 | ud.host, ud.path.replace('/', '.')) |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 79 | mirrortarball = 'hg_%s.tar.gz' % hgsrcname |
| 80 | ud.fullmirror = os.path.join(d.getVar("DL_DIR"), mirrortarball) |
| 81 | ud.mirrortarballs = [mirrortarball] |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 82 | |
Brad Bishop | 1a4b7ee | 2018-12-16 17:11:34 -0800 | [diff] [blame] | 83 | hgdir = d.getVar("HGDIR") or (d.getVar("DL_DIR") + "/hg") |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 84 | ud.pkgdir = os.path.join(hgdir, hgsrcname) |
| 85 | ud.moddir = os.path.join(ud.pkgdir, ud.module) |
| 86 | ud.localfile = ud.moddir |
Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 87 | ud.basecmd = d.getVar("FETCHCMD_hg") or "/usr/bin/env hg" |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 88 | |
Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 89 | ud.write_tarballs = d.getVar("BB_GENERATE_MIRROR_TARBALLS") |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 90 | |
| 91 | def need_update(self, ud, d): |
| 92 | revTag = ud.parm.get('rev', 'tip') |
| 93 | if revTag == "tip": |
| 94 | return True |
| 95 | if not os.path.exists(ud.localpath): |
| 96 | return True |
| 97 | return False |
| 98 | |
| 99 | def try_premirror(self, ud, d): |
| 100 | # If we don't do this, updating an existing checkout with only premirrors |
| 101 | # is not possible |
Brad Bishop | 1932369 | 2019-04-05 15:28:33 -0400 | [diff] [blame] | 102 | if bb.utils.to_boolean(d.getVar("BB_FETCH_PREMIRRORONLY")): |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 103 | return True |
| 104 | if os.path.exists(ud.moddir): |
| 105 | return False |
| 106 | return True |
| 107 | |
| 108 | def _buildhgcommand(self, ud, d, command): |
| 109 | """ |
| 110 | Build up an hg commandline based on ud |
| 111 | command is "fetch", "update", "info" |
| 112 | """ |
| 113 | |
| 114 | proto = ud.parm.get('protocol', 'http') |
| 115 | |
| 116 | host = ud.host |
| 117 | if proto == "file": |
| 118 | host = "/" |
| 119 | ud.host = "localhost" |
| 120 | |
| 121 | if not ud.user: |
| 122 | hgroot = host + ud.path |
| 123 | else: |
| 124 | if ud.pswd: |
| 125 | hgroot = ud.user + ":" + ud.pswd + "@" + host + ud.path |
| 126 | else: |
| 127 | hgroot = ud.user + "@" + host + ud.path |
| 128 | |
| 129 | if command == "info": |
| 130 | return "%s identify -i %s://%s/%s" % (ud.basecmd, proto, hgroot, ud.module) |
| 131 | |
| 132 | options = []; |
| 133 | |
| 134 | # Don't specify revision for the fetch; clone the entire repo. |
| 135 | # This avoids an issue if the specified revision is a tag, because |
| 136 | # the tag actually exists in the specified revision + 1, so it won't |
| 137 | # be available when used in any successive commands. |
| 138 | if ud.revision and command != "fetch": |
| 139 | options.append("-r %s" % ud.revision) |
| 140 | |
| 141 | if command == "fetch": |
| 142 | if ud.user and ud.pswd: |
| 143 | cmd = "%s --config auth.default.prefix=* --config auth.default.username=%s --config auth.default.password=%s --config \"auth.default.schemes=%s\" clone %s %s://%s/%s %s" % (ud.basecmd, ud.user, ud.pswd, proto, " ".join(options), proto, hgroot, ud.module, ud.module) |
| 144 | else: |
| 145 | cmd = "%s clone %s %s://%s/%s %s" % (ud.basecmd, " ".join(options), proto, hgroot, ud.module, ud.module) |
| 146 | elif command == "pull": |
| 147 | # do not pass options list; limiting pull to rev causes the local |
| 148 | # repo not to contain it and immediately following "update" command |
| 149 | # will crash |
| 150 | if ud.user and ud.pswd: |
| 151 | cmd = "%s --config auth.default.prefix=* --config auth.default.username=%s --config auth.default.password=%s --config \"auth.default.schemes=%s\" pull" % (ud.basecmd, ud.user, ud.pswd, proto) |
| 152 | else: |
| 153 | cmd = "%s pull" % (ud.basecmd) |
| 154 | elif command == "update": |
| 155 | if ud.user and ud.pswd: |
| 156 | cmd = "%s --config auth.default.prefix=* --config auth.default.username=%s --config auth.default.password=%s --config \"auth.default.schemes=%s\" update -C %s" % (ud.basecmd, ud.user, ud.pswd, proto, " ".join(options)) |
| 157 | else: |
| 158 | cmd = "%s update -C %s" % (ud.basecmd, " ".join(options)) |
| 159 | else: |
| 160 | raise FetchError("Invalid hg command %s" % command, ud.url) |
| 161 | |
| 162 | return cmd |
| 163 | |
| 164 | def download(self, ud, d): |
| 165 | """Fetch url""" |
| 166 | |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 167 | logger.debug(2, "Fetch: checking for module directory '" + ud.moddir + "'") |
| 168 | |
| 169 | # If the checkout doesn't exist and the mirror tarball does, extract it |
| 170 | if not os.path.exists(ud.pkgdir) and os.path.exists(ud.fullmirror): |
| 171 | bb.utils.mkdirhier(ud.pkgdir) |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 172 | runfetchcmd("tar -xzf %s" % (ud.fullmirror), d, workdir=ud.pkgdir) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 173 | |
| 174 | if os.access(os.path.join(ud.moddir, '.hg'), os.R_OK): |
| 175 | # Found the source, check whether need pull |
| 176 | updatecmd = self._buildhgcommand(ud, d, "update") |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 177 | logger.debug(1, "Running %s", updatecmd) |
| 178 | try: |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 179 | runfetchcmd(updatecmd, d, workdir=ud.moddir) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 180 | except bb.fetch2.FetchError: |
| 181 | # Runnning pull in the repo |
| 182 | pullcmd = self._buildhgcommand(ud, d, "pull") |
| 183 | logger.info("Pulling " + ud.url) |
| 184 | # update sources there |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 185 | logger.debug(1, "Running %s", pullcmd) |
| 186 | bb.fetch2.check_network_access(d, pullcmd, ud.url) |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 187 | runfetchcmd(pullcmd, d, workdir=ud.moddir) |
Patrick Williams | d7e9631 | 2015-09-22 08:09:05 -0500 | [diff] [blame] | 188 | try: |
| 189 | os.unlink(ud.fullmirror) |
| 190 | except OSError as exc: |
| 191 | if exc.errno != errno.ENOENT: |
| 192 | raise |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 193 | |
| 194 | # No source found, clone it. |
| 195 | if not os.path.exists(ud.moddir): |
| 196 | fetchcmd = self._buildhgcommand(ud, d, "fetch") |
| 197 | logger.info("Fetch " + ud.url) |
| 198 | # check out sources there |
| 199 | bb.utils.mkdirhier(ud.pkgdir) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 200 | logger.debug(1, "Running %s", fetchcmd) |
| 201 | bb.fetch2.check_network_access(d, fetchcmd, ud.url) |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 202 | runfetchcmd(fetchcmd, d, workdir=ud.pkgdir) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 203 | |
| 204 | # Even when we clone (fetch), we still need to update as hg's clone |
| 205 | # won't checkout the specified revision if its on a branch |
| 206 | updatecmd = self._buildhgcommand(ud, d, "update") |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 207 | logger.debug(1, "Running %s", updatecmd) |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 208 | runfetchcmd(updatecmd, d, workdir=ud.moddir) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 209 | |
| 210 | def clean(self, ud, d): |
| 211 | """ Clean the hg dir """ |
| 212 | |
| 213 | bb.utils.remove(ud.localpath, True) |
| 214 | bb.utils.remove(ud.fullmirror) |
| 215 | bb.utils.remove(ud.fullmirror + ".done") |
| 216 | |
| 217 | def supports_srcrev(self): |
| 218 | return True |
| 219 | |
| 220 | def _latest_revision(self, ud, d, name): |
| 221 | """ |
| 222 | Compute tip revision for the url |
| 223 | """ |
Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 224 | bb.fetch2.check_network_access(d, self._buildhgcommand(ud, d, "info"), ud.url) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 225 | output = runfetchcmd(self._buildhgcommand(ud, d, "info"), d) |
| 226 | return output.strip() |
| 227 | |
| 228 | def _build_revision(self, ud, d, name): |
| 229 | return ud.revision |
| 230 | |
| 231 | def _revision_key(self, ud, d, name): |
| 232 | """ |
| 233 | Return a unique key for the url |
| 234 | """ |
| 235 | return "hg:" + ud.moddir |
| 236 | |
| 237 | def build_mirror_data(self, ud, d): |
| 238 | # Generate a mirror tarball if needed |
Patrick Williams | d7e9631 | 2015-09-22 08:09:05 -0500 | [diff] [blame] | 239 | if ud.write_tarballs == "1" and not os.path.exists(ud.fullmirror): |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 240 | # it's possible that this symlink points to read-only filesystem with PREMIRROR |
| 241 | if os.path.islink(ud.fullmirror): |
| 242 | os.unlink(ud.fullmirror) |
| 243 | |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 244 | logger.info("Creating tarball of hg repository") |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 245 | runfetchcmd("tar -czf %s %s" % (ud.fullmirror, ud.module), d, workdir=ud.pkgdir) |
| 246 | runfetchcmd("touch %s.done" % (ud.fullmirror), d, workdir=ud.pkgdir) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 247 | |
| 248 | def localpath(self, ud, d): |
| 249 | return ud.pkgdir |
| 250 | |
| 251 | def unpack(self, ud, destdir, d): |
| 252 | """ |
| 253 | Make a local clone or export for the url |
| 254 | """ |
| 255 | |
| 256 | revflag = "-r %s" % ud.revision |
| 257 | subdir = ud.parm.get("destsuffix", ud.module) |
| 258 | codir = "%s/%s" % (destdir, subdir) |
| 259 | |
| 260 | scmdata = ud.parm.get("scmdata", "") |
| 261 | if scmdata != "nokeep": |
| 262 | if not os.access(os.path.join(codir, '.hg'), os.R_OK): |
| 263 | logger.debug(2, "Unpack: creating new hg repository in '" + codir + "'") |
| 264 | runfetchcmd("%s init %s" % (ud.basecmd, codir), d) |
| 265 | logger.debug(2, "Unpack: updating source in '" + codir + "'") |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 266 | runfetchcmd("%s pull %s" % (ud.basecmd, ud.moddir), d, workdir=codir) |
| 267 | runfetchcmd("%s up -C %s" % (ud.basecmd, revflag), d, workdir=codir) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 268 | else: |
| 269 | logger.debug(2, "Unpack: extracting source to '" + codir + "'") |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 270 | runfetchcmd("%s archive -t files %s %s" % (ud.basecmd, revflag, codir), d, workdir=ud.moddir) |