1595f6308SAndrew Geissler# ex:ts=4:sw=4:sts=4:et 2595f6308SAndrew Geissler# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- 3595f6308SAndrew Geissler""" 4595f6308SAndrew GeisslerBitBake 'Fetch' implementation for crates.io 5595f6308SAndrew Geissler""" 6595f6308SAndrew Geissler 7595f6308SAndrew Geissler# Copyright (C) 2016 Doug Goldstein 8595f6308SAndrew Geissler# 9595f6308SAndrew Geissler# SPDX-License-Identifier: GPL-2.0-only 10595f6308SAndrew Geissler# 11595f6308SAndrew Geissler# Based on functions from the base bb module, Copyright 2003 Holger Schurig 12595f6308SAndrew Geissler 13595f6308SAndrew Geisslerimport hashlib 14595f6308SAndrew Geisslerimport json 15595f6308SAndrew Geisslerimport os 16595f6308SAndrew Geisslerimport subprocess 17595f6308SAndrew Geisslerimport bb 18595f6308SAndrew Geisslerfrom bb.fetch2 import logger, subprocess_setup, UnpackError 19595f6308SAndrew Geisslerfrom bb.fetch2.wget import Wget 20595f6308SAndrew Geissler 21595f6308SAndrew Geissler 22595f6308SAndrew Geisslerclass Crate(Wget): 23595f6308SAndrew Geissler 24595f6308SAndrew Geissler """Class to fetch crates via wget""" 25595f6308SAndrew Geissler 26595f6308SAndrew Geissler def _cargo_bitbake_path(self, rootdir): 27595f6308SAndrew Geissler return os.path.join(rootdir, "cargo_home", "bitbake") 28595f6308SAndrew Geissler 29595f6308SAndrew Geissler def supports(self, ud, d): 30595f6308SAndrew Geissler """ 31595f6308SAndrew Geissler Check to see if a given url is for this fetcher 32595f6308SAndrew Geissler """ 33595f6308SAndrew Geissler return ud.type in ['crate'] 34595f6308SAndrew Geissler 35595f6308SAndrew Geissler def recommends_checksum(self, urldata): 36fc113eadSAndrew Geissler return True 37595f6308SAndrew Geissler 38595f6308SAndrew Geissler def urldata_init(self, ud, d): 39595f6308SAndrew Geissler """ 40595f6308SAndrew Geissler Sets up to download the respective crate from crates.io 41595f6308SAndrew Geissler """ 42595f6308SAndrew Geissler 43595f6308SAndrew Geissler if ud.type == 'crate': 44595f6308SAndrew Geissler self._crate_urldata_init(ud, d) 45595f6308SAndrew Geissler 46595f6308SAndrew Geissler super(Crate, self).urldata_init(ud, d) 47595f6308SAndrew Geissler 48595f6308SAndrew Geissler def _crate_urldata_init(self, ud, d): 49595f6308SAndrew Geissler """ 50595f6308SAndrew Geissler Sets up the download for a crate 51595f6308SAndrew Geissler """ 52595f6308SAndrew Geissler 53595f6308SAndrew Geissler # URL syntax is: crate://NAME/VERSION 54595f6308SAndrew Geissler # break the URL apart by / 55595f6308SAndrew Geissler parts = ud.url.split('/') 56595f6308SAndrew Geissler if len(parts) < 5: 57595f6308SAndrew Geissler raise bb.fetch2.ParameterError("Invalid URL: Must be crate://HOST/NAME/VERSION", ud.url) 58595f6308SAndrew Geissler 59fc113eadSAndrew Geissler # version is expected to be the last token 60fc113eadSAndrew Geissler # but ignore possible url parameters which will be used 61fc113eadSAndrew Geissler # by the top fetcher class 62e760df85SPatrick Williams version = parts[-1].split(";")[0] 63595f6308SAndrew Geissler # second to last field is name 64e760df85SPatrick Williams name = parts[-2] 65595f6308SAndrew Geissler # host (this is to allow custom crate registries to be specified 66e760df85SPatrick Williams host = '/'.join(parts[2:-2]) 67595f6308SAndrew Geissler 68595f6308SAndrew Geissler # if using upstream just fix it up nicely 69595f6308SAndrew Geissler if host == 'crates.io': 70595f6308SAndrew Geissler host = 'crates.io/api/v1/crates' 71595f6308SAndrew Geissler 72595f6308SAndrew Geissler ud.url = "https://%s/%s/%s/download" % (host, name, version) 73595f6308SAndrew Geissler ud.parm['downloadfilename'] = "%s-%s.crate" % (name, version) 74fc113eadSAndrew Geissler if 'name' not in ud.parm: 758e7b46e2SPatrick Williams ud.parm['name'] = '%s-%s' % (name, version) 76595f6308SAndrew Geissler 7787f5cff0SAndrew Geissler logger.debug2("Fetching %s to %s" % (ud.url, ud.parm['downloadfilename'])) 78595f6308SAndrew Geissler 79595f6308SAndrew Geissler def unpack(self, ud, rootdir, d): 80595f6308SAndrew Geissler """ 81595f6308SAndrew Geissler Uses the crate to build the necessary paths for cargo to utilize it 82595f6308SAndrew Geissler """ 83595f6308SAndrew Geissler if ud.type == 'crate': 84595f6308SAndrew Geissler return self._crate_unpack(ud, rootdir, d) 85595f6308SAndrew Geissler else: 86595f6308SAndrew Geissler super(Crate, self).unpack(ud, rootdir, d) 87595f6308SAndrew Geissler 88595f6308SAndrew Geissler def _crate_unpack(self, ud, rootdir, d): 89595f6308SAndrew Geissler """ 90595f6308SAndrew Geissler Unpacks a crate 91595f6308SAndrew Geissler """ 92595f6308SAndrew Geissler thefile = ud.localpath 93595f6308SAndrew Geissler 94595f6308SAndrew Geissler # possible metadata we need to write out 95595f6308SAndrew Geissler metadata = {} 96595f6308SAndrew Geissler 97595f6308SAndrew Geissler # change to the rootdir to unpack but save the old working dir 98595f6308SAndrew Geissler save_cwd = os.getcwd() 99595f6308SAndrew Geissler os.chdir(rootdir) 100595f6308SAndrew Geissler 101e760df85SPatrick Williams bp = d.getVar('BP') 102e760df85SPatrick Williams if bp == ud.parm.get('name'): 103595f6308SAndrew Geissler cmd = "tar -xz --no-same-owner -f %s" % thefile 104*ac13d5f3SPatrick Williams ud.unpack_tracer.unpack("crate-extract", rootdir) 105595f6308SAndrew Geissler else: 106595f6308SAndrew Geissler cargo_bitbake = self._cargo_bitbake_path(rootdir) 107*ac13d5f3SPatrick Williams ud.unpack_tracer.unpack("cargo-extract", cargo_bitbake) 108595f6308SAndrew Geissler 109595f6308SAndrew Geissler cmd = "tar -xz --no-same-owner -f %s -C %s" % (thefile, cargo_bitbake) 110595f6308SAndrew Geissler 111595f6308SAndrew Geissler # ensure we've got these paths made 112595f6308SAndrew Geissler bb.utils.mkdirhier(cargo_bitbake) 113595f6308SAndrew Geissler 114595f6308SAndrew Geissler # generate metadata necessary 115595f6308SAndrew Geissler with open(thefile, 'rb') as f: 116595f6308SAndrew Geissler # get the SHA256 of the original tarball 117595f6308SAndrew Geissler tarhash = hashlib.sha256(f.read()).hexdigest() 118595f6308SAndrew Geissler 119595f6308SAndrew Geissler metadata['files'] = {} 120595f6308SAndrew Geissler metadata['package'] = tarhash 121595f6308SAndrew Geissler 122595f6308SAndrew Geissler path = d.getVar('PATH') 123595f6308SAndrew Geissler if path: 124595f6308SAndrew Geissler cmd = "PATH=\"%s\" %s" % (path, cmd) 125595f6308SAndrew Geissler bb.note("Unpacking %s to %s/" % (thefile, os.getcwd())) 126595f6308SAndrew Geissler 127595f6308SAndrew Geissler ret = subprocess.call(cmd, preexec_fn=subprocess_setup, shell=True) 128595f6308SAndrew Geissler 129595f6308SAndrew Geissler os.chdir(save_cwd) 130595f6308SAndrew Geissler 131595f6308SAndrew Geissler if ret != 0: 132595f6308SAndrew Geissler raise UnpackError("Unpack command %s failed with return value %s" % (cmd, ret), ud.url) 133595f6308SAndrew Geissler 134595f6308SAndrew Geissler # if we have metadata to write out.. 135595f6308SAndrew Geissler if len(metadata) > 0: 136595f6308SAndrew Geissler cratepath = os.path.splitext(os.path.basename(thefile))[0] 137595f6308SAndrew Geissler bbpath = self._cargo_bitbake_path(rootdir) 138595f6308SAndrew Geissler mdfile = '.cargo-checksum.json' 139595f6308SAndrew Geissler mdpath = os.path.join(bbpath, cratepath, mdfile) 140595f6308SAndrew Geissler with open(mdpath, "w") as f: 141595f6308SAndrew Geissler json.dump(metadata, f) 142