1*4882a593Smuzhiyun# ex:ts=4:sw=4:sts=4:et 2*4882a593Smuzhiyun# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- 3*4882a593Smuzhiyun""" 4*4882a593SmuzhiyunBitBake 'Fetch' implementation for crates.io 5*4882a593Smuzhiyun""" 6*4882a593Smuzhiyun 7*4882a593Smuzhiyun# Copyright (C) 2016 Doug Goldstein 8*4882a593Smuzhiyun# 9*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only 10*4882a593Smuzhiyun# 11*4882a593Smuzhiyun# Based on functions from the base bb module, Copyright 2003 Holger Schurig 12*4882a593Smuzhiyun 13*4882a593Smuzhiyunimport hashlib 14*4882a593Smuzhiyunimport json 15*4882a593Smuzhiyunimport os 16*4882a593Smuzhiyunimport subprocess 17*4882a593Smuzhiyunimport bb 18*4882a593Smuzhiyunfrom bb.fetch2 import logger, subprocess_setup, UnpackError 19*4882a593Smuzhiyunfrom bb.fetch2.wget import Wget 20*4882a593Smuzhiyun 21*4882a593Smuzhiyun 22*4882a593Smuzhiyunclass Crate(Wget): 23*4882a593Smuzhiyun 24*4882a593Smuzhiyun """Class to fetch crates via wget""" 25*4882a593Smuzhiyun 26*4882a593Smuzhiyun def _cargo_bitbake_path(self, rootdir): 27*4882a593Smuzhiyun return os.path.join(rootdir, "cargo_home", "bitbake") 28*4882a593Smuzhiyun 29*4882a593Smuzhiyun def supports(self, ud, d): 30*4882a593Smuzhiyun """ 31*4882a593Smuzhiyun Check to see if a given url is for this fetcher 32*4882a593Smuzhiyun """ 33*4882a593Smuzhiyun return ud.type in ['crate'] 34*4882a593Smuzhiyun 35*4882a593Smuzhiyun def recommends_checksum(self, urldata): 36*4882a593Smuzhiyun return False 37*4882a593Smuzhiyun 38*4882a593Smuzhiyun def urldata_init(self, ud, d): 39*4882a593Smuzhiyun """ 40*4882a593Smuzhiyun Sets up to download the respective crate from crates.io 41*4882a593Smuzhiyun """ 42*4882a593Smuzhiyun 43*4882a593Smuzhiyun if ud.type == 'crate': 44*4882a593Smuzhiyun self._crate_urldata_init(ud, d) 45*4882a593Smuzhiyun 46*4882a593Smuzhiyun super(Crate, self).urldata_init(ud, d) 47*4882a593Smuzhiyun 48*4882a593Smuzhiyun def _crate_urldata_init(self, ud, d): 49*4882a593Smuzhiyun """ 50*4882a593Smuzhiyun Sets up the download for a crate 51*4882a593Smuzhiyun """ 52*4882a593Smuzhiyun 53*4882a593Smuzhiyun # URL syntax is: crate://NAME/VERSION 54*4882a593Smuzhiyun # break the URL apart by / 55*4882a593Smuzhiyun parts = ud.url.split('/') 56*4882a593Smuzhiyun if len(parts) < 5: 57*4882a593Smuzhiyun raise bb.fetch2.ParameterError("Invalid URL: Must be crate://HOST/NAME/VERSION", ud.url) 58*4882a593Smuzhiyun 59*4882a593Smuzhiyun # last field is version 60*4882a593Smuzhiyun version = parts[len(parts) - 1] 61*4882a593Smuzhiyun # second to last field is name 62*4882a593Smuzhiyun name = parts[len(parts) - 2] 63*4882a593Smuzhiyun # host (this is to allow custom crate registries to be specified 64*4882a593Smuzhiyun host = '/'.join(parts[2:len(parts) - 2]) 65*4882a593Smuzhiyun 66*4882a593Smuzhiyun # if using upstream just fix it up nicely 67*4882a593Smuzhiyun if host == 'crates.io': 68*4882a593Smuzhiyun host = 'crates.io/api/v1/crates' 69*4882a593Smuzhiyun 70*4882a593Smuzhiyun ud.url = "https://%s/%s/%s/download" % (host, name, version) 71*4882a593Smuzhiyun ud.parm['downloadfilename'] = "%s-%s.crate" % (name, version) 72*4882a593Smuzhiyun ud.parm['name'] = name 73*4882a593Smuzhiyun 74*4882a593Smuzhiyun logger.debug("Fetching %s to %s" % (ud.url, ud.parm['downloadfilename'])) 75*4882a593Smuzhiyun 76*4882a593Smuzhiyun def unpack(self, ud, rootdir, d): 77*4882a593Smuzhiyun """ 78*4882a593Smuzhiyun Uses the crate to build the necessary paths for cargo to utilize it 79*4882a593Smuzhiyun """ 80*4882a593Smuzhiyun if ud.type == 'crate': 81*4882a593Smuzhiyun return self._crate_unpack(ud, rootdir, d) 82*4882a593Smuzhiyun else: 83*4882a593Smuzhiyun super(Crate, self).unpack(ud, rootdir, d) 84*4882a593Smuzhiyun 85*4882a593Smuzhiyun def _crate_unpack(self, ud, rootdir, d): 86*4882a593Smuzhiyun """ 87*4882a593Smuzhiyun Unpacks a crate 88*4882a593Smuzhiyun """ 89*4882a593Smuzhiyun thefile = ud.localpath 90*4882a593Smuzhiyun 91*4882a593Smuzhiyun # possible metadata we need to write out 92*4882a593Smuzhiyun metadata = {} 93*4882a593Smuzhiyun 94*4882a593Smuzhiyun # change to the rootdir to unpack but save the old working dir 95*4882a593Smuzhiyun save_cwd = os.getcwd() 96*4882a593Smuzhiyun os.chdir(rootdir) 97*4882a593Smuzhiyun 98*4882a593Smuzhiyun pn = d.getVar('BPN') 99*4882a593Smuzhiyun if pn == ud.parm.get('name'): 100*4882a593Smuzhiyun cmd = "tar -xz --no-same-owner -f %s" % thefile 101*4882a593Smuzhiyun else: 102*4882a593Smuzhiyun cargo_bitbake = self._cargo_bitbake_path(rootdir) 103*4882a593Smuzhiyun 104*4882a593Smuzhiyun cmd = "tar -xz --no-same-owner -f %s -C %s" % (thefile, cargo_bitbake) 105*4882a593Smuzhiyun 106*4882a593Smuzhiyun # ensure we've got these paths made 107*4882a593Smuzhiyun bb.utils.mkdirhier(cargo_bitbake) 108*4882a593Smuzhiyun 109*4882a593Smuzhiyun # generate metadata necessary 110*4882a593Smuzhiyun with open(thefile, 'rb') as f: 111*4882a593Smuzhiyun # get the SHA256 of the original tarball 112*4882a593Smuzhiyun tarhash = hashlib.sha256(f.read()).hexdigest() 113*4882a593Smuzhiyun 114*4882a593Smuzhiyun metadata['files'] = {} 115*4882a593Smuzhiyun metadata['package'] = tarhash 116*4882a593Smuzhiyun 117*4882a593Smuzhiyun path = d.getVar('PATH') 118*4882a593Smuzhiyun if path: 119*4882a593Smuzhiyun cmd = "PATH=\"%s\" %s" % (path, cmd) 120*4882a593Smuzhiyun bb.note("Unpacking %s to %s/" % (thefile, os.getcwd())) 121*4882a593Smuzhiyun 122*4882a593Smuzhiyun ret = subprocess.call(cmd, preexec_fn=subprocess_setup, shell=True) 123*4882a593Smuzhiyun 124*4882a593Smuzhiyun os.chdir(save_cwd) 125*4882a593Smuzhiyun 126*4882a593Smuzhiyun if ret != 0: 127*4882a593Smuzhiyun raise UnpackError("Unpack command %s failed with return value %s" % (cmd, ret), ud.url) 128*4882a593Smuzhiyun 129*4882a593Smuzhiyun # if we have metadata to write out.. 130*4882a593Smuzhiyun if len(metadata) > 0: 131*4882a593Smuzhiyun cratepath = os.path.splitext(os.path.basename(thefile))[0] 132*4882a593Smuzhiyun bbpath = self._cargo_bitbake_path(rootdir) 133*4882a593Smuzhiyun mdfile = '.cargo-checksum.json' 134*4882a593Smuzhiyun mdpath = os.path.join(bbpath, cratepath, mdfile) 135*4882a593Smuzhiyun with open(mdpath, "w") as f: 136*4882a593Smuzhiyun json.dump(metadata, f) 137