xref: /OK3568_Linux_fs/yocto/bitbake/lib/bb/fetch2/crate.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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