From patchwork Fri Dec 20 11:26:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Herbrechtsmeier X-Patchwork-Id: 54444 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 516AEE7718D for ; Fri, 20 Dec 2024 11:26:41 +0000 (UTC) Received: from EUR05-DB8-obe.outbound.protection.outlook.com (EUR05-DB8-obe.outbound.protection.outlook.com [40.107.20.118]) by mx.groups.io with SMTP id smtpd.web11.149744.1734693993154756588 for ; Fri, 20 Dec 2024 03:26:36 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: body hash did not verify" header.i=@weidmueller.com header.s=selector2 header.b=VO5ow6Ql; spf=pass (domain: weidmueller.com, ip: 40.107.20.118, mailfrom: stefan.herbrechtsmeier-oss@weidmueller.com) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=DOc4Uii8RJ7gwMAeVZU0jcdv83q2Pa3Ba9imBH75HKpk7zr2uSy/F9xyupEVMoih8uCSdy+9in+Q4k5HrWISsstSUBYgXuGd/3gW1XFX7IXS7wZKC9rXJDw2gG/rtgPVrMSL7hZ3PeFFjXWxx8/bhEElL9LgJR2u/auqrD0SVPZzms1ULBetyNNTLcolgb2ru8GDgru1MJlPCbMyGrVDn0aw+kmWUudO/6dHc+BFn/xFHZZoDSWKOEAP0AfAedJuZEVAUT2tnfPNmuJcKRiFyYBjWtNpyeQlf3YBcMCGcAD1p+bk2IH4s70Qn8avMXQpz/GYjrAT/dfulZASLHMzuQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=fUnEYLBpnFS6KFFX+hiKjOr98Rh4ZfH9Nvm05jFPbj4=; b=V/Fq/Nv77HZgipuacnOJIeF9yCE40J7khw8XzjacL0z565rGR+FvIQ24//Ev5dH4JhgU1x0pwNGccmbZpuimW4Jx3Zmelp1Y8iaDfLWUH/owkuI50kP1AKFa3ZY/WriWdg/Ru9EqfZjRhCTLzpDjcXZScDMT/uvZQrQx/IPzqdtx03yFsmEClJFh2CWuooUHQLBW0qU8ydPNCnsYj7xSpNuFAEUFqBM6TvWDqEtWX1P9hxkY+Qw5KGZ/B2ldHDf/TcogXKHzVadEHzcbSHg8oxG0B8aHJdG2Shrprhi4Xcq5XJIyZDyjDpR1Ayxv0GbSyVuxhjkUqhscGrLrozkrpg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=weidmueller.com; dmarc=pass action=none header.from=weidmueller.com; dkim=pass header.d=weidmueller.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=weidmueller.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=fUnEYLBpnFS6KFFX+hiKjOr98Rh4ZfH9Nvm05jFPbj4=; b=VO5ow6QlI8FcMDXD3ZFfPSRBWr3Q8MtR0JNCUYdo2iEHRO39hnd3gTOzfWUJkO2P9zexswyivWwgV+urzqLNVJwhMhgGD5K4+X7xfCFB/pLK8zxdx2QHF+UCXVvXxEFt+Xtl/NeztV5kMsoq1R/NczEqUvwCUSHOkFioJmnpIE/mSMAE4OfVEyVZwhF3duZOKiJ39omXbyCpCxGmW6iiv6SL8rKjwmfHPKTFVp8vBw+OKlm5EhF48xiMkWCFojaFzX5q5KVji0+KSi3Cmg5T5FGfPyEAOLsU6d/by1SOtg7aMqSJ9Rj1Ujfh0AXdhjllKLoMSQSu/SMKnMjAnLp8Gg== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=weidmueller.com; Received: from PAXPR08MB6969.eurprd08.prod.outlook.com (2603:10a6:102:1d8::23) by DU0PR08MB8256.eurprd08.prod.outlook.com (2603:10a6:10:410::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8272.14; Fri, 20 Dec 2024 11:26:27 +0000 Received: from PAXPR08MB6969.eurprd08.prod.outlook.com ([fe80::3b1:b329:1ed9:dad4]) by PAXPR08MB6969.eurprd08.prod.outlook.com ([fe80::3b1:b329:1ed9:dad4%3]) with mapi id 15.20.8272.013; Fri, 20 Dec 2024 11:26:27 +0000 From: Stefan Herbrechtsmeier To: bitbake-devel@lists.openembedded.org CC: Stefan Herbrechtsmeier Subject: [RFC PATCH 10/21] fetch: npm: rework Date: Fri, 20 Dec 2024 12:26:01 +0100 Message-ID: <20241220112613.22647-11-stefan.herbrechtsmeier-oss@weidmueller.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20241220112613.22647-1-stefan.herbrechtsmeier-oss@weidmueller.com> References: <20241220112613.22647-1-stefan.herbrechtsmeier-oss@weidmueller.com> X-ClientProxiedBy: FR0P281CA0106.DEUP281.PROD.OUTLOOK.COM (2603:10a6:d10:a8::7) To PAXPR08MB6969.eurprd08.prod.outlook.com (2603:10a6:102:1d8::23) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PAXPR08MB6969:EE_|DU0PR08MB8256:EE_ X-MS-Office365-Filtering-Correlation-Id: 71c27570-ec4a-4cfc-6699-08dd20e924c2 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|52116014|1800799024|376014|38350700014; X-Microsoft-Antispam-Message-Info: Tsm+zvu1Wrq9wXmFWkb+2zmr8EqMIfc8j6Gdni6GLExrJl+Bi15BqL4eVCKRj9rHsMFQ7nfwFMviHq+yXd6fn044Ga8Sxz+d0fhmFRQengkqZrWaEVGUC1lchzRWIafSqDqEEZFFu6yQC+NCMLtmKww/Xl5Dj8J+TSN0Y5x2kE40niSIxvOuVu9XvLNzVRWS6QIZvwQrqtYN3grBEOocFKTQH3WlwkEhb2f8OrMV7y7J3peTKyE+zXZsTVTLb2TZcMj+nez3hO40CLxLWFQzBeqI/UrPjzD3bI6gmRpsDcPap3jCQpMdauGzwKWUkXyh8BuTBmVERn6d6/8oASGEfB1cm2gx+b2yN0fhQb/9Mq/6umpkfZbY6ohwPrfw1RcUFn/p8FCQonK8oronNQysMVyF7p3xb4tkeKMrL6A9CQchOdKBFb6ad8c4ehOv7bcCOj8WSoPmENf2T54BTNc4ArE8S7AwBCl75s9M+rLrjAOlW3ewEAwpJif/osYG1ZI88zI7DnStKJR6ni/FEPAkRSvIW2uzXvPwMI421F9syzTJy1LWii/yl1DlMWAb+H4RHt33d0AxIGRtTLT+l0G1bQeaF/kqYz/pwEfTq2sYkJ6fbKJv8TNUv4lTchWtWjHNkAHcaCSNw4xXWqtco5xv1xOvzXKGLA5LPofiVee+wxAsH9oa3a4MRmJOQMSeWWWN6xnXwC3QtAYBRAs1Ws/QxWLPNgCM7LD3sEiCK9wdpGs3ZWsxCeYHkWtXpK6Ywk6i5C/vDDg6uST5ffWsXIQni3QcbvmFmrHtvlmMmaPWv0tAK2uQ2vRb6VOLwWI8qpvHkJ/uoRDwnYO5t/rGjENX2flrZ8OiNttsl7mvxMx8wwzl8QumtUDz73OvtyUbgNeCjfWBVHLLSRbpMYSUNpTcpj46sf9xx1LH/jfHFA/+7izbgQdTfmkT4jgBWcln4D+JLeeVps0Coi1EBz8DeJPt+6IdPxpjelIaTdKe2UFdAjz3JwpoN7qf8bnWgsckRAn7/9rnQ+318QT3TcAlUNQqR0fLIlB2hfUv2hZAxshkhGgQdCOC5WBLqsw6+adm3qzE/JaPMbhnt2ChdBehugLhlBUqhs4/WJH4XlMJrF6vZYDEhaJk73WrGdkcrETfIRroOD4+MozCRRJ8kwCj8aePH9FQa7m28p4k8aBXdb91qptQ5NWz4tX4nu8lSB03WCLtZAaWlUjbZ2HRzZomH9gwGJV9hhGJNfbHJPd6o/nIFW8RojxA2HA/B0xfFMWtyr0HIgAxxEIPeWFQFdKZl2XpaYj/zaxmqGOWKSaIkEfDG9RkNm0pBelrSiZQ487V+7b/B0iCuaoly6RtZMGN1nnb8jI+fPOERicowX3ChqePDmRRN7FglHlRmhuBLeZuxJUpMhZ6Pi0ZLcg4P6UXR6JrZw== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:PAXPR08MB6969.eurprd08.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(366016)(52116014)(1800799024)(376014)(38350700014);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: I7GVUc5oZEAYKcbvAUPhpb+ipCwUiD+rxjxHjEuIo1YYPyJH/4QP/qDtv0EL/LGpSD11nH1gxZSZyj4HBYo6HC8na8rrcCW6b6citvaV9+SCF0igCl+24IQb7lpXqATry2DIBgoPOSXOGncJhKqCsET40Es53qVeQedLTOVeiFb40w6ov53A9IjHDildOs06Dq8X/DkL9tqYntglYMWIXval9lqwd21ccrFog0Nixn6kbcr7hSTvMU7L9IuoVX7Vl9me2vuyv//R0LnO6EHTGhecjfydSnxHTqbPp2hq48RrjCnqcvtBXFvBDY/sp46vubClJrMpXwpmaTT5/gTgeRslXDkNn3jnlIcDMVh8ZbdbXoCBvLD9Kf5zXZXpuSmDU4bqWdahtZ9hDwuJ3Ge7AOKI+DCY2PE+QSbRFG3qKocDR5sGmmWiIFZvydNBdFm7gejUy3qJvVdrhumoaqDefOlWlVDX0PdchioDX0vaHL1rFVqh0xoaV5sJiPM8j3cMeuIE6hrZtVH+wWo8uGGIHX2ofvqfLH73+smmsThzY3m5nBHvamYA/L7Na3oKknordrZ5RpjfggmMejwfz7ucRRKaiP4SrvtD/aVZQm4uihRbrKQSWsWacuIDvyFQSdcxkD8uVH6cAFO5e6HFZoBkuFICItVqe/GM50UVT9tOYlFQTEMwaxqHBrtRHj3PNI1FAqqfE59iiNcpsa3VKprWjabo8ctMWzy0b234nASvTD64piDdV3P0z/FEe3tKdFp8Fj+8bLis5Qmg+07Vu1Bz6btUlxyEf02abNWC1BSNxxlhmCSjXWdpQB9bNdaGZs1qAAq+svwNUQYqsc7g4/8779Lat8xSDnpsqhGBJSA/jtEOjz3b98Dae/eqNYDzu6BsnGQswo25Earf79EjWpNuhAocoE5ID3hc2ELk5ECpxpk8+bLARl9xAYzqr3PInoFIfClh3n1KNF6xuE0TgRK+98bOwpREte+QKu0SZ1MYet9bEU84EfpH/DA7Z5WovBl4h62BRKpWEyrLgpd7YZRX9pAJLwRoLE1Xjr+xqKzJPQt5GadW9GcBhDim5UcY84VyvfKGElDSz2qRZvZPHDYJNP8s5xP2nIwU3WSK2RmYjdo8e+i9hgcJLYQb36D6I/96nmxs9g3N83FKyWsFrmNXRQS0gaGeoUlPJkxgYOM7/IkymB+q0wgA8esgYUeMaQ+jcdwNNG7+Mot9RMDAE7VROGJubupaQDZIW7v89Llbquw3U9fvP3KtEFhz02P5xpH0GWyScqodJw09UDDqig2+BMiWIhNolO+Hny6VCffa16cPbDU9CFw6qLJP3cEz+rv9TDovix0DmMEEepkgx+kmNOOvOo8Pv9q8nb8hqlJ9e9NLiQd5FOZTn6yCT439fppU3bQX3SQe9oo5rwKXt3Lv02Hn6VZgQg7PlsLzBqD1RJK9EGVik/y9FkxqLVvB8jByQVOKEUGMmzSvzvhIwuDGPo2HoZGu2iHevzPE4sSc60lzXE4eF52ZvPJjOXncNuUGrNwExwh3NhfDdZtq/xzJwKIj5isaInpxo0u6zqxZiMnZHzw1wWQiaTFXP7FKkhNxkLqCWlAWRJU0PO4he8Dxag== X-OriginatorOrg: weidmueller.com X-MS-Exchange-CrossTenant-Network-Message-Id: 71c27570-ec4a-4cfc-6699-08dd20e924c2 X-MS-Exchange-CrossTenant-AuthSource: PAXPR08MB6969.eurprd08.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 20 Dec 2024 11:26:27.4102 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: e4289438-1c5f-4c95-a51a-ee553b8b18ec X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 8W69tXbIjo2br34uvBslC5qI/yn48+WzEaUXidBjvbH07vNdq3Qd0NnQoiAGuIheursbaU4iKyozO0KjjZ51OQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DU0PR08MB8256 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Fri, 20 Dec 2024 11:26:41 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/bitbake-devel/message/16932 From: Stefan Herbrechtsmeier Rework the npm class regarding testability and integrity: * Remove dependency to npm binary. * Construct URL via a fix style and don’t resolve the URL via package registry. * Use the checksum from the recipe or URI and don’t depend on the checksum from the package registry. * Add common name and version schema. * Mark unused NpmEnvironment and npm_unpack function as deprecated. * Use Wget class as base and remove foreign done stamp handling. * Add support to compute the latest release version. * Remove support for latest version because it requires a package registry and should be rarely used. Signed-off-by: Stefan Herbrechtsmeier --- lib/bb/fetch2/npm.py | 244 +++++++++++-------------------------------- 1 file changed, 63 insertions(+), 181 deletions(-) diff --git a/lib/bb/fetch2/npm.py b/lib/bb/fetch2/npm.py index ac76d64cd..120dddbfd 100644 --- a/lib/bb/fetch2/npm.py +++ b/lib/bb/fetch2/npm.py @@ -10,20 +10,19 @@ SRC_URI = "npm://some.registry.url;OptionA=xxx;OptionB=xxx;..." Supported SRC_URI options are: -- package +- dn The npm package name. This is a mandatory parameter. -- version +- dv The npm package version. This is a mandatory parameter. - downloadfilename Specifies the filename used when storing the downloaded file. - destsuffix - Specifies the directory to use to unpack the package (default: npm). + The name of the path in which to place the package (default: npm). """ -import base64 import json import os import re @@ -40,6 +39,8 @@ from bb.fetch2 import check_network_access from bb.fetch2 import runfetchcmd from bb.utils import is_semver +from bb.fetch2.wget import Wget + def npm_package(package): """Convert the npm package name to remove unsupported character""" # For scoped package names ('@user/package') the '/' is replaced by a '-'. @@ -64,14 +65,7 @@ def npm_localfile(package, version=None): filename = package return os.path.join("npm2", filename) -def npm_integrity(integrity): - """ - Get the checksum name and expected value from the subresource integrity - https://www.w3.org/TR/SRI/ - """ - algo, value = integrity.split("-", maxsplit=1) - return "%ssum" % algo, base64.b64decode(value).hex() - +# Deprecated def npm_unpack(tarball, destdir, d): """Unpack a npm tarball""" bb.utils.mkdirhier(destdir) @@ -80,8 +74,8 @@ def npm_unpack(tarball, destdir, d): cmd += " --delay-directory-restore" cmd += " --strip-components=1" runfetchcmd(cmd, d, workdir=destdir) - runfetchcmd("chmod -R +X '%s'" % (destdir), d, quiet=True, workdir=destdir) +# Deprecated class NpmEnvironment(object): """ Using a npm config file seems more reliable than using cli arguments. @@ -130,7 +124,15 @@ class NpmEnvironment(object): return _run(cmd) -class Npm(FetchMethod): + +def construct_url_path(name, version): + return f"/{name}/-/{name.split('/')[-1]}-{version}.tgz" + +def construct_url(registry, name, version): + path = construct_url_path(name, version) + return f"https://{registry}{path}" + +class Npm(Wget): """Class to fetch a package from a npm registry""" def supports(self, ud, d): @@ -139,178 +141,58 @@ class Npm(FetchMethod): def urldata_init(self, ud, d): """Init npm specific variables within url data""" - ud.package = None - ud.version = None - ud.registry = None - # Get the 'package' parameter if "package" in ud.parm: - ud.package = ud.parm.get("package") + bb.warn(f"Parameter 'package' in '{ud.url}' is deprecated." + "Please use 'dn' parameter instead.") + ud.parm["dn"] = ud.parm["package"] + del ud.parm["package"] + if "version" in ud.parm: + bb.warn(f"Parameter 'version' in '{ud.url}' is deprecated." + "Please use 'dv' parameter instead.") + ud.parm["dv"] = ud.parm["version"] + del ud.parm["version"] + + if any(x not in ud.parm for x in ["dn", "dv"]): + return + + registry = ud.host + if ud.path != '/': + registry += ud.path + name = ud.parm["dn"] + version = ud.parm["dv"] + + if not is_semver(version): + if version == "latest": + raise ParameterError("Value 'latest' for parameter 'version' is no longer supported", ud.url) + else: + raise ParameterError("Invalid 'version' parameter", ud.url) - if not ud.package: - raise MissingParameterError("Parameter 'package' required", ud.url) + ud.url = construct_url(registry, name, version) + ud.info_url = f"https://{registry}/{name}" - # Get the 'version' parameter - if "version" in ud.parm: - ud.version = ud.parm.get("version") + if not "downloadfilename" in ud.parm: + ud.parm['downloadfilename'] = npm_localfile(name, version) - if not ud.version: - raise MissingParameterError("Parameter 'version' required", ud.url) + destsuffix = ud.parm.get("destsuffix", "npm") + subdir = ud.parm.get("subdir", "") + ud.parm["destsuffix"] = destsuffix + ud.parm["subdir"] = os.path.join(subdir, destsuffix) - if not is_semver(ud.version) and not ud.version == "latest": - raise ParameterError("Invalid 'version' parameter", ud.url) + if 'name' not in ud.parm: + ud.parm["name"] = f"{npm_package(name)}-{version}" - # Extract the 'registry' part of the url - ud.registry = re.sub(r"^npm://", "https://", ud.url.split(";")[0]) + ud.parm["striplevel"] = 1 - # Using the 'downloadfilename' parameter as local filename - # or the npm package name. - if "downloadfilename" in ud.parm: - ud.localfile = npm_localfile(d.expand(ud.parm["downloadfilename"])) - else: - ud.localfile = npm_localfile(ud.package, ud.version) - - # Get the base 'npm' command - ud.basecmd = d.getVar("FETCHCMD_npm") or "npm" - - # This fetcher resolves a URI from a npm package name and version and - # then forwards it to a proxy fetcher. A resolve file containing the - # resolved URI is created to avoid unwanted network access (if the file - # already exists). The management of the donestamp file, the lockfile - # and the checksums are forwarded to the proxy fetcher. - ud.proxy = None - ud.needdonestamp = False - ud.resolvefile = self.localpath(ud, d) + ".resolved" - - def _resolve_proxy_url(self, ud, d): - def _npm_view(): - args = [] - args.append(("json", "true")) - args.append(("registry", ud.registry)) - pkgver = shlex.quote(ud.package + "@" + ud.version) - cmd = ud.basecmd + " view %s" % pkgver - env = NpmEnvironment(d) - check_network_access(d, cmd, ud.registry) - view_string = env.run(cmd, args=args) - - if not view_string: - raise FetchError("Unavailable package %s" % pkgver, ud.url) - - try: - view = json.loads(view_string) - - error = view.get("error") - if error is not None: - raise FetchError(error.get("summary"), ud.url) - - if ud.version == "latest": - bb.warn("The npm package %s is using the latest " \ - "version available. This could lead to " \ - "non-reproducible builds." % pkgver) - elif ud.version != view.get("version"): - raise ParameterError("Invalid 'version' parameter", ud.url) - - return view - - except Exception as e: - raise FetchError("Invalid view from npm: %s" % str(e), ud.url) - - def _get_url(view): - tarball_url = view.get("dist", {}).get("tarball") - - if tarball_url is None: - raise FetchError("Invalid 'dist.tarball' in view", ud.url) - - uri = URI(tarball_url) - uri.params["downloadfilename"] = ud.localfile - - integrity = view.get("dist", {}).get("integrity") - shasum = view.get("dist", {}).get("shasum") - - if integrity is not None: - checksum_name, checksum_expected = npm_integrity(integrity) - uri.params[checksum_name] = checksum_expected - elif shasum is not None: - uri.params["sha1sum"] = shasum - else: - raise FetchError("Invalid 'dist.integrity' in view", ud.url) - - return str(uri) - - url = _get_url(_npm_view()) - - bb.utils.mkdirhier(os.path.dirname(ud.resolvefile)) - with open(ud.resolvefile, "w") as f: - f.write(url) - - def _setup_proxy(self, ud, d): - if ud.proxy is None: - if not os.path.exists(ud.resolvefile): - self._resolve_proxy_url(ud, d) - - with open(ud.resolvefile, "r") as f: - url = f.read() - - # Avoid conflicts between the environment data and: - # - the proxy url checksum - data = bb.data.createCopy(d) - data.delVarFlags("SRC_URI") - ud.proxy = Fetch([url], data) - - def _get_proxy_method(self, ud, d): - self._setup_proxy(ud, d) - proxy_url = ud.proxy.urls[0] - proxy_ud = ud.proxy.ud[proxy_url] - proxy_d = ud.proxy.d - proxy_ud.setup_localpath(proxy_d) - return proxy_ud.method, proxy_ud, proxy_d - - def verify_donestamp(self, ud, d): - """Verify the donestamp file""" - proxy_m, proxy_ud, proxy_d = self._get_proxy_method(ud, d) - return proxy_m.verify_donestamp(proxy_ud, proxy_d) - - def update_donestamp(self, ud, d): - """Update the donestamp file""" - proxy_m, proxy_ud, proxy_d = self._get_proxy_method(ud, d) - proxy_m.update_donestamp(proxy_ud, proxy_d) - - def need_update(self, ud, d): - """Force a fetch, even if localpath exists ?""" - if not os.path.exists(ud.resolvefile): - return True - if ud.version == "latest": - return True - proxy_m, proxy_ud, proxy_d = self._get_proxy_method(ud, d) - return proxy_m.need_update(proxy_ud, proxy_d) - - def try_mirrors(self, fetch, ud, d, mirrors): - """Try to use a mirror""" - proxy_m, proxy_ud, proxy_d = self._get_proxy_method(ud, d) - return proxy_m.try_mirrors(fetch, proxy_ud, proxy_d, mirrors) - - def download(self, ud, d): - """Fetch url""" - self._setup_proxy(ud, d) - ud.proxy.download() - - def unpack(self, ud, rootdir, d): - """Unpack the downloaded archive""" - destsuffix = ud.parm.get("destsuffix", "npm") - destdir = os.path.join(rootdir, destsuffix) - npm_unpack(ud.localpath, destdir, d) - ud.unpack_tracer.unpack("npm", destdir) - - def clean(self, ud, d): - """Clean any existing full or partial download""" - if os.path.exists(ud.resolvefile): - self._setup_proxy(ud, d) - ud.proxy.clean() - bb.utils.remove(ud.resolvefile) - - def done(self, ud, d): - """Is the download done ?""" - if not os.path.exists(ud.resolvefile): - return False - proxy_m, proxy_ud, proxy_d = self._get_proxy_method(ud, d) - return proxy_m.done(proxy_ud, proxy_d) + super().urldata_init(ud, d) + + def latest_versionstring(self, ud, d): + from functools import cmp_to_key + info = json.loads(self._fetch_index(ud.info_url, ud, d)) + versions = [(0, v, "") for v in info["versions"]] + versions = sorted(versions, key=cmp_to_key(bb.utils.vercmp)) + + return (versions[-1][1], "") + + def require_download_metadata(self): + return True