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