#!/usr/bin/env python3 # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/.
"""
This script downloads and repacks official rust language builds with the necessary tool and target support for the Firefox
build environment. """
def fetch_file(url): """Download a file from the given url if it's not already present.
Returns the SHA-2 256-bit hash of the received file."""
filename = os.path.basename(url)
sha = hashlib.sha256()
size = 4096 if os.path.exists(filename): with open(filename, "rb") as fd: whileTrue:
block = fd.read(size) ifnot block: return sha.hexdigest()
sha.update(block)
log("Could not calculate checksum!") returnNone
r = requests.get(url, stream=True)
r.raise_for_status() with open(filename, "wb") as fd: for chunk in r.iter_content(size):
fd.write(chunk)
sha.update(chunk) return sha.hexdigest()
def check_call_with_input(cmd, input_data): """Invoke a command, passing the input String over stdin.
This is like subprocess.check_call, but allows piping
input to interactive commands."""
p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
p.communicate(input_data) if p.wait(): raise subprocess.CalledProcessError(p.returncode, cmd)
def setup_gpg(): """Add the signing key to the current gpg config.
Import a hard-coded copy of the release signing public key and mark it trusted in the gpg database so subsequent
signature checks can succeed or fail cleanly."""
keyid = "0x85AB96E6FA1BE5FE"
log("Importing signing key %s..." % keyid)
key = b"""
-----BEGIN PGP PUBLIC KEY BLOCK-----
def verify_sha(filename, sha): """Verify that the checksum file matches the given sha digest."""
sha_filename = filename + ".sha256" with open(sha_filename) as f: # Older sha256 files would contain `sha filename`, but more recent # ones only contain `sha`.
checksum = f.readline().split()[0] if checksum != sha: raise ValueError("Checksum mismatch in %s" % filename) returnTrue
log("No checksum file for %s!" % filename) returnFalse
def fetch(url, validate=True): """Download and verify a package url."""
base = os.path.basename(url)
log("Fetching %s..." % base) if validate:
fetch_file(url + ".asc")
fetch_file(url + ".sha256")
sha = fetch_file(url) if validate:
log("Verifying %s..." % base)
verify_sha(base, sha)
subprocess.check_call(
["gpg", "--keyid-format", "0xlong", "--verify", base + ".asc", base]
) return sha
def package(manifest, pkg, target): """Pull out the package dict for a particular package and target from the given manifest."""
version = manifest["pkg"][pkg]["version"] if target in manifest["pkg"][pkg]["target"]:
info = manifest["pkg"][pkg]["target"][target] else: # rust-src is the same for all targets, and has a literal '*' in the # section key/name instead of a target
info = manifest["pkg"][pkg]["target"]["*"] if"xz_url"in info:
info["url"] = info.pop("xz_url")
info["hash"] = info.pop("xz_hash") return (version, info)
log("%s %s\n %s\n %s" % (pkg, version, info["url"], info["hash"]))
sha = fetch(info["url"], info["hash"] isnotNone) if info["hash"] and sha != info["hash"]:
log( "Checksum mismatch: package resource is different from manifest" "\n %s" % sha
) raise AssertionError return info
def fetch_std(manifest, targets):
stds = [] for target in targets:
stds.append(fetch_package(manifest, "rust-std", target))
analysis = fetch_optional(manifest, "rust-analysis", target) if analysis:
stds.append(analysis) else:
log(f"Missing rust-analysis for {target}") # If it's missing for one of the searchfox targets, explicitly # error out. if target in ( "x86_64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-pc-windows-msvc", "thumbv7neon-linux-androideabi",
): raise AssertionError
return stds
def fetch_optional(manifest, pkg, host): try: return fetch_package(manifest, pkg, host) except KeyError: # The package is not available, oh well! returnNone
def build_tar_package(name, base, directory):
name = os.path.realpath(name)
log("tarring {} from {}/{}".format(name, base, directory)) assert name.endswith(".tar.zst")
cctx = zstandard.ZstdCompressor() with open(name, "wb") as f, cctx.stream_writer(f) as z: with tarfile.open(mode="w|", fileobj=z) as tf: with chdir(base):
tf.add(directory)
# Clear and remake any previous install directory. try:
shutil.rmtree(install_dir) except OSError as e: if e.errno != errno.ENOENT: raise
os.makedirs(install_dir)
# Patch the src (see the --patch flag's description for details) for p in patches:
module, colon, file = p.partition(":") ifnot colon:
module, file = "", p
patch_file = os.path.join(patch_dir, file)
patch_module = os.path.join(rust_dir, module)
patch_src(patch_file, patch_module)
log("Building Rust...")
example_config = "" for example_toml in ("config.example.toml", "config.toml.example"):
path = os.path.join(rust_dir, example_toml) if os.path.exists(path): with open(path) as file:
example_config = file.read() break
# Rust builds are configured primarily through a config.toml file. # # `sysconfdir` is overloaded to be relative instead of absolute. # This is the default of `install.sh`, but for whatever reason # `x.py install` has its own default of `/etc` which we don't want.
base_config = textwrap.dedent( """
[build]
docs = false
sanitizers = true
profiler = true
extended = true
tools = ["analysis", "cargo", "rustfmt", "clippy", "src", "rust-analyzer"]
cargo-native-static = true
# Rust requires these to be specified per-target
target_config = textwrap.dedent( """
[target.{target}]
cc = "clang"
cxx = "clang++"
linker = "clang"
"""
)
final_config = base_config for target in sorted(set(targets) | set([host])):
final_config = final_config + target_config.format(target=target)
with open(os.path.join(rust_dir, "config.toml"), "w") as file:
file.write(final_config)
# Setup the env so compilers and toolchains are visible
clang = os.path.join(fetches, "clang")
clang_bin = os.path.join(clang, "bin")
clang_lib = os.path.join(clang, "lib")
sysroot = os.path.join(fetches, "sysroot")
# The rust build doesn't offer much in terms of overriding compiler flags # when it builds LLVM's compiler-rt, but we want to build with a sysroot. # So, we create wrappers for clang and clang++ that add the sysroot to the # command line. with tempfile.TemporaryDirectory() as tmpdir: for exe in ("clang", "clang++"):
tmp_exe = os.path.join(tmpdir, exe) with open(tmp_exe, "w") as fh:
fh.write("#!/bin/sh\n")
fh.write(f'exec {clang_bin}/{exe} --sysroot={sysroot} "$@"\n')
os.chmod(tmp_exe, 0o755)
# x.py install does everything we need for us. # If you're running into issues, consider using `-vv` to debug it.
command = ["python3", "x.py", "install", "-v", "--host", host] for target in targets:
command.extend(["--target", target])
upload_dir = os.environ.get("UPLOAD_DIR") if upload_dir: # Create the upload directory if it doesn't exist. try:
log("Creating upload directory in %s..." % os.path.abspath(upload_dir))
os.makedirs(upload_dir) except OSError as e: if e.errno != errno.EEXIST: raise # Move the tarball to the output directory for upload.
log("Moving %s to the upload directory..." % tar_file)
shutil.move(tar_file, upload_dir)
def expand_platform(name): """Expand a shortcut name to a full Rust platform string."""
platforms = { "android": "armv7-linux-androideabi", "android_x86": "i686-linux-android", "android_x86-64": "x86_64-linux-android", "android_aarch64": "aarch64-linux-android", "linux64": "x86_64-unknown-linux-gnu", "linux32": "i686-unknown-linux-gnu", "mac": "x86_64-apple-darwin", "macos": "x86_64-apple-darwin", "mac64": "x86_64-apple-darwin", "mac32": "i686-apple-darwin", "win64": "x86_64-pc-windows-msvc", "win32": "i686-pc-windows-msvc", "mingw32": "i686-pc-windows-gnu",
} return platforms.get(name, name)
def validate_channel(channel): """Require a specific release version.
Packaging from meta-channels, like `stable`, `beta`, or `nightly`
doesn't give repeatable output. Reject such channels."""
channel_prefixes = ("stable", "beta", "nightly") if any([channel.startswith(c) for c in channel_prefixes]): if"-"notin channel: raise ValueError( 'Generic channel "%s" specified!' "\nPlease give a specific release version" ' like "1.24.0" or "beta-2018-02-20".' % channel
)
def args(): """Read command line arguments and return options."""
parser = argparse.ArgumentParser()
parser.add_argument( "--channel",
help="Release channel to use:" " 1.xx.y, beta-yyyy-mm-dd," " nightly-yyyy-mm-dd," " bors-$rev (grab a build from rust's CI)," " or dev (build from source).",
required=True,
)
parser.add_argument( "--allow-generic-channel",
action="store_true",
help='Allow to use e.g. "nightly" without a date as a channel.',
)
parser.add_argument( "--patch",
dest="patches",
action="append",
default=[],
help="apply the given patch file to a dev build." " Patch files should be placed in /build/build-rust." " Patches can be prefixed with `module-path:` to specify they" " apply to that git submodule in the Rust source." " e.g. `src/llvm-project:mypatch.diff` patches rust's llvm." " Can be given more than once.",
)
parser.add_argument( "--cargo-channel",
help="Release channel version to use for cargo." " Defaults to the same as --channel.",
)
parser.add_argument( "--host",
help="Host platform for the toolchain executable:" " e.g. linux64 or aarch64-linux-android." " Defaults to linux64.",
)
parser.add_argument( "--target",
dest="targets",
action="append",
default=[],
help="Additional target platform to support:" " e.g. linux32 or i686-pc-windows-gnu." " can be given more than once.",
)
args = parser.parse_args() ifnot args.cargo_channel:
args.cargo_channel = args.channel ifnot args.allow_generic_channel:
validate_channel(args.channel)
validate_channel(args.cargo_channel) ifnot args.host:
args.host = "linux64"
args.host = expand_platform(args.host)
args.targets = [expand_platform(t) for t in args.targets]
delattr(args, "allow_generic_channel")
return args
if __name__ == "__main__":
args = vars(args())
setup_gpg()
repack(**args)
¤ Dauer der Verarbeitung: 0.20 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.