xref: /openbmc/openbmc/poky/bitbake/lib/bb/fetch2/crate.py (revision ac13d5f3)
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