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