mirror of
https://github.com/oxalica/rust-overlay.git
synced 2024-10-03 20:57:47 +03:00
Init
This commit is contained in:
commit
815fa068bc
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
result
|
||||
result-*
|
||||
*.tmp
|
8
.vscode/settings.json
vendored
Normal file
8
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"[nix]": {
|
||||
"editor.tabSize": 2,
|
||||
"files.trimFinalNewlines": true,
|
||||
"files.insertFinalNewline": true,
|
||||
"files.trimTrailingWhitespace": true
|
||||
}
|
||||
}
|
72
default.nix
Normal file
72
default.nix
Normal file
@ -0,0 +1,72 @@
|
||||
final: prev:
|
||||
let
|
||||
inherit (prev.lib) filter hasAttr attrNames mapAttrs concatMap mapAttrs' replaceStrings;
|
||||
|
||||
targets = import ./manifests/targets.nix // { _ = "*"; };
|
||||
|
||||
distServer = "https://static.rust-lang.org";
|
||||
|
||||
# Extensions for mixed `rust` pkg.
|
||||
components = [
|
||||
"rustc"
|
||||
"rust-std"
|
||||
"cargo"
|
||||
];
|
||||
singleTargetExtensions = [
|
||||
"clippy-preview"
|
||||
"miri-preview"
|
||||
"rls-preview"
|
||||
"rust-analyzer-preview"
|
||||
"rustfmt-preview"
|
||||
"llvm-tools-preview"
|
||||
"rust-analysis"
|
||||
];
|
||||
multiTargetExtensions = [
|
||||
"rust-std"
|
||||
"rustc-dev"
|
||||
"rustc-docs"
|
||||
"rust-src" # This has only one special target `*`
|
||||
];
|
||||
rustPkgExtra = pkgs: target: let
|
||||
singleTargetTups = map
|
||||
(pkg: { inherit pkg target; })
|
||||
(filter (p: hasAttr p pkgs && hasAttr target pkgs.${p}.target) singleTargetExtensions);
|
||||
multiTargetTups = concatMap
|
||||
(pkg: map (target: { inherit pkg target; }) (attrNames pkgs.${pkg}.target))
|
||||
(filter (p: hasAttr p pkgs) multiTargetExtensions);
|
||||
in {
|
||||
components = map (pkg: { inherit pkg target; }) components;
|
||||
extensions = singleTargetTups ++ multiTargetTups;
|
||||
};
|
||||
|
||||
# version -> { pkgName = { _1 = "..."; } } -> { pkgName = { x86_64-unknown-linux-gnu = fetchurl { .. }; } }
|
||||
uncompressManifest = version: { date, ... }@manifest: rec {
|
||||
inherit date;
|
||||
pkg =
|
||||
mapAttrs (pkgName: { v, ... }@hashes: {
|
||||
version = v;
|
||||
target =
|
||||
mapAttrs' (targetIdx: hash: let
|
||||
target = targets.${targetIdx};
|
||||
pkgNameStripped = replaceStrings ["-preview"] [""] pkgName;
|
||||
targetTail = if targetIdx == "_" then "" else "-" + target;
|
||||
in {
|
||||
name = target;
|
||||
value = {
|
||||
xz_url = "${distServer}/dist/${date}/${pkgNameStripped}-${version}${targetTail}.tar.xz";
|
||||
xz_hash = hash;
|
||||
} // (if pkgName == "rust" then rustPkgExtra pkg target else {});
|
||||
}) (removeAttrs hashes ["v"]);
|
||||
}) (removeAttrs manifest ["date"]);
|
||||
};
|
||||
|
||||
uncompressManifestSet = set: let
|
||||
ret = mapAttrs uncompressManifest (removeAttrs set ["latest"]);
|
||||
in ret // { latest = ret.${set.latest}; };
|
||||
|
||||
manifests = {
|
||||
stable = uncompressManifestSet (import ./manifests/stable);
|
||||
};
|
||||
|
||||
# in { inherit manifests; }
|
||||
in import ./rust-overlay.nix final prev manifests
|
197
fetch.py
Executable file
197
fetch.py
Executable file
@ -0,0 +1,197 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i python3 -p "python3.withPackages (ps: with ps; [ toml requests ])"
|
||||
import base64
|
||||
import json
|
||||
import re
|
||||
import string
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
import toml
|
||||
import requests
|
||||
|
||||
MAX_TRIES = 3
|
||||
RETRY_DELAY = 3.0
|
||||
SYNC_MAX_FETCH = 5
|
||||
|
||||
STABLE_VERSION_FILTER = lambda v: parse_version(v) >= (1, 29, 0)
|
||||
|
||||
DIST_SERVER = 'https://static.rust-lang.org'
|
||||
NIX_KEYWORDS = {'', 'if', 'then', 'else', 'assert', 'with', 'let', 'in', 'rec', 'inherit', 'or'}
|
||||
MANIFEST_TMP_PATH = Path('manifest.tmp')
|
||||
TARGETS_PATH = Path('manifests/targets.nix')
|
||||
|
||||
RE_STABLE_VERSION = re.compile(r'^\d+\.\d+\.\d+$')
|
||||
|
||||
def to_base64(hash: str) -> str:
|
||||
assert len(hash) == 64
|
||||
return base64.b64encode(bytes.fromhex(hash)).decode()
|
||||
|
||||
def is_valid_nix_ident(name: str) -> bool:
|
||||
return name not in NIX_KEYWORDS and \
|
||||
(name[0] == '_' or name[0].isalpha()) and \
|
||||
all(c in "_-'" or c.isalnum() for c in name)
|
||||
|
||||
def escape_nix_string(s: str) -> str:
|
||||
return '"' + s.replace('\\', '\\\\').replace('"', '\\"') + '"'
|
||||
|
||||
def escape_nix_key(name: str) -> str:
|
||||
if is_valid_nix_ident(name):
|
||||
return name
|
||||
return escape_nix_string(name)
|
||||
|
||||
def parse_version(ver: str) -> tuple:
|
||||
return tuple(map(int, ver.split('.')))
|
||||
|
||||
def version_less(a: str, b: str):
|
||||
return parse_version(a) < parse_version(b)
|
||||
|
||||
target_map = dict((line.split('"')[1], i) for i, line in enumerate(TARGETS_PATH.read_text().strip().split('\n')[1:-1]))
|
||||
def compress_target(target: str) -> str:
|
||||
assert '"' not in target
|
||||
if target == '*':
|
||||
return '_'
|
||||
if target in target_map:
|
||||
return f'_{target_map[target]}'
|
||||
idx = len(target_map)
|
||||
target_map[target] = idx
|
||||
|
||||
with open(str(TARGETS_PATH), 'w') as f:
|
||||
f.write('{\n')
|
||||
for i, target in sorted((v, k) for k, v in target_map.items()):
|
||||
f.write(f' _{i} = "{target}";\n')
|
||||
f.write('}\n')
|
||||
return f'_{idx}'
|
||||
|
||||
def retry_with(f):
|
||||
i = 0
|
||||
while True:
|
||||
try:
|
||||
return f()
|
||||
except requests.exceptions.RequestException as e:
|
||||
i += 1
|
||||
if i >= MAX_TRIES:
|
||||
raise
|
||||
print(e)
|
||||
time.sleep(RETRY_DELAY)
|
||||
|
||||
def translate_dump_manifest(manifest: str, f):
|
||||
manifest = toml.loads(manifest)
|
||||
date = manifest['date']
|
||||
version = manifest['pkg']['rustc']['version'].split()[0]
|
||||
strip_tail = '-preview'
|
||||
|
||||
f.write('{')
|
||||
f.write(f'date={escape_nix_string(date)};')
|
||||
for pkg_name in sorted(manifest['pkg'].keys()):
|
||||
pkg = manifest['pkg'][pkg_name]
|
||||
pkg_name_stripped = pkg_name[:-len(strip_tail)] if pkg_name.endswith(strip_tail) else pkg_name
|
||||
pkg_targets = sorted(pkg['target'].keys())
|
||||
|
||||
pkg_version = version
|
||||
for target_name in pkg_targets:
|
||||
target = pkg['target'][target_name]
|
||||
if not target['available']:
|
||||
continue
|
||||
url = target['xz_url']
|
||||
target_tail = '' if target_name == '*' else '-' + target_name
|
||||
start = f'https://static.rust-lang.org/dist/{date}/{pkg_name_stripped}-'
|
||||
end = f'{target_tail}.tar.xz'
|
||||
assert url.startswith(start) and url.endswith(end), f'Unexpected url: {url}'
|
||||
pkg_version = url[len(start):-len(end)]
|
||||
|
||||
f.write(f'{pkg_name}={{')
|
||||
f.write(f'v={escape_nix_string(pkg["version"])};')
|
||||
for target_name in pkg_targets:
|
||||
target = pkg['target'][target_name]
|
||||
if not target['available']:
|
||||
continue
|
||||
url = target['xz_url']
|
||||
hash = to_base64(target['xz_hash']) # Hash must not contains quotes.
|
||||
target_tail = '' if target_name == '*' else '-' + target_name
|
||||
expect_url = f'https://static.rust-lang.org/dist/{date}/{pkg_name_stripped}-{pkg_version}{target_tail}.tar.xz'
|
||||
assert url == expect_url, f'Unexpected url: {url}, expecting: {expect_url}'
|
||||
f.write(f'{compress_target(target_name)}="{hash}";')
|
||||
f.write('};')
|
||||
f.write('}\n')
|
||||
|
||||
def fetch_stable_manifest(version: str, out_path: Path):
|
||||
tmp_path = out_path.with_suffix('.tmp')
|
||||
print(f'Fetching {version}')
|
||||
manifest = retry_with(lambda: requests.get(f'{DIST_SERVER}/dist/channel-rust-{version}.toml'))
|
||||
manifest.raise_for_status()
|
||||
manifest = manifest.text
|
||||
MANIFEST_TMP_PATH.write_text(manifest)
|
||||
with open(tmp_path, 'w') as fout:
|
||||
translate_dump_manifest(manifest, fout)
|
||||
tmp_path.rename(out_path)
|
||||
|
||||
def update_stable_index():
|
||||
dir = Path('manifests/stable')
|
||||
versions = sorted(
|
||||
(file.stem for file in dir.iterdir() if file.stem != 'default' and file.suffix == '.nix'),
|
||||
key=parse_version,
|
||||
)
|
||||
with open(str(dir / 'default.nix'), 'w') as f:
|
||||
f.write('{\n')
|
||||
for v in versions:
|
||||
f.write(f' {escape_nix_key(v)} = import ./{v}.nix;\n')
|
||||
f.write(f' latest = {escape_nix_string(versions[-1])};\n')
|
||||
f.write('}\n')
|
||||
|
||||
def sync_stable_channel(*, stop_if_exists, max_fetch=None):
|
||||
GITHUB_RELEASES_URL = 'https://api.github.com/repos/rust-lang/rust/releases'
|
||||
|
||||
page = 0
|
||||
count = 0
|
||||
try:
|
||||
while True:
|
||||
page += 1
|
||||
print(f'Fetching release page {page}')
|
||||
release_page = retry_with(lambda: requests.get(GITHUB_RELEASES_URL, params={'page': page}))
|
||||
release_page.raise_for_status()
|
||||
release_page = release_page.json()
|
||||
if not release_page:
|
||||
return
|
||||
for release in release_page:
|
||||
version = release['tag_name']
|
||||
if not RE_STABLE_VERSION.match(version) or not STABLE_VERSION_FILTER(version):
|
||||
continue
|
||||
out_path = Path(f'manifests/stable/{version}.nix')
|
||||
if out_path.exists():
|
||||
if stop_if_exists:
|
||||
print('Stopped on existing version')
|
||||
return
|
||||
continue
|
||||
fetch_stable_manifest(version, out_path)
|
||||
count += 1
|
||||
if max_fetch is not None and count >= max_fetch:
|
||||
print('Reached max fetch count')
|
||||
exit(1)
|
||||
finally:
|
||||
update_stable_index()
|
||||
|
||||
def init_sync_all():
|
||||
sync_stable_channel(stop_if_exists=False)
|
||||
|
||||
def main():
|
||||
args = sys.argv[1:]
|
||||
if len(args) == 0:
|
||||
print('Synchronizing channels')
|
||||
sync_stable_channel(stop_if_exists=True, max_fetch=SYNC_MAX_FETCH)
|
||||
elif len(args) == 1:
|
||||
version = args[0]
|
||||
assert RE_STABLE_VERSION.match(version), 'Invalid version'
|
||||
fetch_stable_manifest(version, Path(f'manifests/stable/{version}.nix'))
|
||||
update_stable_index()
|
||||
else:
|
||||
print(f'''
|
||||
Usage: {sys.argv[0]} [version]
|
||||
Run without arguments to auto-sync new versions from channels.
|
||||
Run with version to fetch a specific version.
|
||||
''')
|
||||
exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
40
flake.lock
Normal file
40
flake.lock
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"locked": {
|
||||
"lastModified": 1609246779,
|
||||
"narHash": "sha256-eq6ZXE/VWo3EMC65jmIT6H/rrUc9UWOWVujkzav025k=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "08c7ad4a0844adc4a7f9f5bb3beae482e789afa4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1609079092,
|
||||
"narHash": "sha256-KhyKfxBHtZlAgudpZ0EJVzeuqROjKfVOwj8j0cuhU50=",
|
||||
"path": "/nix/store/5pmay8rdvgw5ml1xi6189xhdbygc850k-source",
|
||||
"rev": "2f47650c2f28d87f86ab807b8a339c684d91ec56",
|
||||
"type": "path"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
40
flake.nix
Normal file
40
flake.nix
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
description = ''
|
||||
Pure and reproducible overlay for binary distributed rust toolchains.
|
||||
A better replacement for github:mozilla/nixpkgs-mozilla
|
||||
'';
|
||||
|
||||
inputs = {
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils, ... }@inputs: let
|
||||
inherit (nixpkgs) lib;
|
||||
overlay = import ./default.nix;
|
||||
|
||||
allSystems = [
|
||||
"aarch64-linux"
|
||||
"armv6l-linux"
|
||||
"armv7a-linux"
|
||||
"armv7l-linux"
|
||||
"x86_64-linux"
|
||||
"x86_64-darwin"
|
||||
# "aarch64-darwin"
|
||||
];
|
||||
|
||||
in {
|
||||
overlay = final: prev: overlay final prev;
|
||||
|
||||
} // flake-utils.lib.eachSystem allSystems (system: let
|
||||
pkgs = import nixpkgs { inherit system; overlays = [ overlay ]; };
|
||||
in rec {
|
||||
defaultApp = {
|
||||
type = "app";
|
||||
program = "${defaultPackage}/bin/rustc";
|
||||
};
|
||||
defaultPackage = packages.rust-stable;
|
||||
packages = {
|
||||
rust-stable = pkgs.latest.rustChannels.stable.rust;
|
||||
};
|
||||
});
|
||||
}
|
1
manifests/stable/1.48.0.nix
Normal file
1
manifests/stable/1.48.0.nix
Normal file
File diff suppressed because one or more lines are too long
1
manifests/stable/1.49.0.nix
Normal file
1
manifests/stable/1.49.0.nix
Normal file
File diff suppressed because one or more lines are too long
5
manifests/stable/default.nix
Normal file
5
manifests/stable/default.nix
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"1.48.0" = import ./1.48.0.nix;
|
||||
"1.49.0" = import ./1.49.0.nix;
|
||||
latest = "1.49.0";
|
||||
}
|
93
manifests/targets.nix
Normal file
93
manifests/targets.nix
Normal file
@ -0,0 +1,93 @@
|
||||
{
|
||||
_0 = "aarch64-apple-darwin";
|
||||
_1 = "aarch64-pc-windows-msvc";
|
||||
_2 = "aarch64-unknown-linux-gnu";
|
||||
_3 = "aarch64-unknown-linux-musl";
|
||||
_4 = "arm-unknown-linux-gnueabi";
|
||||
_5 = "arm-unknown-linux-gnueabihf";
|
||||
_6 = "armv7-unknown-linux-gnueabihf";
|
||||
_7 = "i686-pc-windows-gnu";
|
||||
_8 = "i686-pc-windows-msvc";
|
||||
_9 = "i686-unknown-linux-gnu";
|
||||
_10 = "mips-unknown-linux-gnu";
|
||||
_11 = "mips64-unknown-linux-gnuabi64";
|
||||
_12 = "mips64el-unknown-linux-gnuabi64";
|
||||
_13 = "mipsel-unknown-linux-gnu";
|
||||
_14 = "powerpc-unknown-linux-gnu";
|
||||
_15 = "powerpc64-unknown-linux-gnu";
|
||||
_16 = "powerpc64le-unknown-linux-gnu";
|
||||
_17 = "riscv64gc-unknown-linux-gnu";
|
||||
_18 = "s390x-unknown-linux-gnu";
|
||||
_19 = "x86_64-apple-darwin";
|
||||
_20 = "x86_64-pc-windows-gnu";
|
||||
_21 = "x86_64-pc-windows-msvc";
|
||||
_22 = "x86_64-unknown-freebsd";
|
||||
_23 = "x86_64-unknown-illumos";
|
||||
_24 = "x86_64-unknown-linux-gnu";
|
||||
_25 = "x86_64-unknown-linux-musl";
|
||||
_26 = "x86_64-unknown-netbsd";
|
||||
_27 = "aarch64-apple-ios";
|
||||
_28 = "aarch64-fuchsia";
|
||||
_29 = "aarch64-linux-android";
|
||||
_30 = "arm-linux-androideabi";
|
||||
_31 = "armv7-linux-androideabi";
|
||||
_32 = "armv7-unknown-linux-gnueabi";
|
||||
_33 = "armv7-unknown-linux-musleabi";
|
||||
_34 = "i586-pc-windows-msvc";
|
||||
_35 = "i686-linux-android";
|
||||
_36 = "i686-unknown-freebsd";
|
||||
_37 = "nvptx64-nvidia-cuda";
|
||||
_38 = "sparcv9-sun-solaris";
|
||||
_39 = "thumbv7neon-linux-androideabi";
|
||||
_40 = "wasm32-unknown-unknown";
|
||||
_41 = "wasm32-wasi";
|
||||
_42 = "x86_64-apple-ios";
|
||||
_43 = "x86_64-fortanix-unknown-sgx";
|
||||
_44 = "x86_64-fuchsia";
|
||||
_45 = "x86_64-linux-android";
|
||||
_46 = "x86_64-sun-solaris";
|
||||
_47 = "x86_64-unknown-linux-gnux32";
|
||||
_48 = "aarch64-unknown-none";
|
||||
_49 = "aarch64-unknown-none-softfloat";
|
||||
_50 = "arm-unknown-linux-musleabi";
|
||||
_51 = "arm-unknown-linux-musleabihf";
|
||||
_52 = "armebv7r-none-eabi";
|
||||
_53 = "armebv7r-none-eabihf";
|
||||
_54 = "armv5te-unknown-linux-gnueabi";
|
||||
_55 = "armv5te-unknown-linux-musleabi";
|
||||
_56 = "armv7-unknown-linux-musleabihf";
|
||||
_57 = "armv7a-none-eabi";
|
||||
_58 = "armv7r-none-eabi";
|
||||
_59 = "armv7r-none-eabihf";
|
||||
_60 = "asmjs-unknown-emscripten";
|
||||
_61 = "i586-unknown-linux-gnu";
|
||||
_62 = "i586-unknown-linux-musl";
|
||||
_63 = "i686-unknown-linux-musl";
|
||||
_64 = "mips-unknown-linux-musl";
|
||||
_65 = "mips64-unknown-linux-muslabi64";
|
||||
_66 = "mips64el-unknown-linux-muslabi64";
|
||||
_67 = "mipsel-unknown-linux-musl";
|
||||
_68 = "riscv32i-unknown-none-elf";
|
||||
_69 = "riscv32imac-unknown-none-elf";
|
||||
_70 = "riscv32imc-unknown-none-elf";
|
||||
_71 = "riscv64gc-unknown-none-elf";
|
||||
_72 = "riscv64imac-unknown-none-elf";
|
||||
_73 = "sparc64-unknown-linux-gnu";
|
||||
_74 = "thumbv6m-none-eabi";
|
||||
_75 = "thumbv7em-none-eabi";
|
||||
_76 = "thumbv7em-none-eabihf";
|
||||
_77 = "thumbv7m-none-eabi";
|
||||
_78 = "thumbv7neon-unknown-linux-gnueabihf";
|
||||
_79 = "thumbv8m.base-none-eabi";
|
||||
_80 = "thumbv8m.main-none-eabi";
|
||||
_81 = "thumbv8m.main-none-eabihf";
|
||||
_82 = "wasm32-unknown-emscripten";
|
||||
_83 = "x86_64-rumprun-netbsd";
|
||||
_84 = "x86_64-unknown-redox";
|
||||
_85 = "i686-apple-darwin";
|
||||
_86 = "armv7-apple-ios";
|
||||
_87 = "armv7s-apple-ios";
|
||||
_88 = "i386-apple-ios";
|
||||
_89 = "x86_64-unknown-cloudabi";
|
||||
_90 = "wasm32-unknown-wasi";
|
||||
}
|
301
rust-overlay.nix
Normal file
301
rust-overlay.nix
Normal file
@ -0,0 +1,301 @@
|
||||
# Modified from: https://github.com/mozilla/nixpkgs-mozilla/blob/8c007b60731c07dd7a052cce508de3bb1ae849b4/rust-overlay.nix
|
||||
|
||||
# This file provide a Rust overlay, which provides pre-packaged bleeding edge versions of rustc
|
||||
# and cargo.
|
||||
self: super:
|
||||
manifests:
|
||||
|
||||
let
|
||||
|
||||
# Manifest selector.
|
||||
fromManifest = { channel }: { stdenv, fetchurl, patchelf }: let
|
||||
inherit (builtins) match;
|
||||
byVersion = match "([0-9]+\\.[0-9]+\\.[0-9]+)" channel != null;
|
||||
|
||||
manifest =
|
||||
if channel == "stable" then manifests.stable.latest
|
||||
else if byVersion then manifests.stable.${channel} or (throw "Version ${channel} is not available")
|
||||
else throw "Unknown channel: ${channel}";
|
||||
|
||||
in fromManifestFile manifest { inherit stdenv fetchurl patchelf; };
|
||||
|
||||
getComponentsWithFixedPlatform = pkgs: pkgname: stdenv:
|
||||
let
|
||||
pkg = pkgs.${pkgname};
|
||||
srcInfo = pkg.target.${super.rust.toRustTarget stdenv.targetPlatform} or pkg.target."*";
|
||||
components = srcInfo.components or [];
|
||||
componentNamesList =
|
||||
builtins.map (pkg: pkg.pkg) (builtins.filter (pkg: (pkg.target != "*")) components);
|
||||
in
|
||||
componentNamesList;
|
||||
|
||||
getExtensions = pkgs: pkgname: stdenv:
|
||||
let
|
||||
inherit (super.lib) unique;
|
||||
pkg = pkgs.${pkgname};
|
||||
rustTarget = super.rust.toRustTarget stdenv.targetPlatform;
|
||||
srcInfo = pkg.target.${rustTarget} or pkg.target."*" or (throw "${pkgname} is no available");
|
||||
extensions = srcInfo.extensions or [];
|
||||
extensionNamesList = unique (builtins.map (pkg: pkg.pkg) extensions);
|
||||
in
|
||||
extensionNamesList;
|
||||
|
||||
hasTarget = pkgs: pkgname: target:
|
||||
pkgs ? ${pkgname}.target.${target};
|
||||
|
||||
getTuples = pkgs: name: targets:
|
||||
builtins.map (target: { inherit name target; }) (builtins.filter (target: hasTarget pkgs name target) targets);
|
||||
|
||||
# In the manifest, a package might have different components which are bundled with it, as opposed as the extensions which can be added.
|
||||
# By default, a package will include the components for the same architecture, and offers them as extensions for other architectures.
|
||||
#
|
||||
# This functions returns a list of { name, target } attribute sets, which includes the current system package, and all its components for the selected targets.
|
||||
# The list contains the package for the pkgTargets as well as the packages for components for all compTargets
|
||||
getTargetPkgTuples = pkgs: pkgname: pkgTargets: compTargets: stdenv:
|
||||
let
|
||||
inherit (builtins) elem;
|
||||
inherit (super.lib) intersectLists;
|
||||
components = getComponentsWithFixedPlatform pkgs pkgname stdenv;
|
||||
extensions = getExtensions pkgs pkgname stdenv;
|
||||
compExtIntersect = intersectLists components extensions;
|
||||
tuples = (getTuples pkgs pkgname pkgTargets) ++ (builtins.map (name: getTuples pkgs name compTargets) compExtIntersect);
|
||||
in
|
||||
tuples;
|
||||
|
||||
getFetchUrl = pkgs: pkgname: target: stdenv: fetchurl:
|
||||
let
|
||||
pkg = pkgs.${pkgname};
|
||||
srcInfo = pkg.target.${target};
|
||||
in
|
||||
(super.fetchurl { url = srcInfo.xz_url; sha256 = srcInfo.xz_hash; });
|
||||
|
||||
checkMissingExtensions = pkgs: pkgname: stdenv: extensions:
|
||||
let
|
||||
inherit (builtins) head;
|
||||
inherit (super.lib) concatStringsSep subtractLists;
|
||||
availableExtensions = getExtensions pkgs pkgname stdenv;
|
||||
missingExtensions = subtractLists availableExtensions extensions;
|
||||
extensionsToInstall =
|
||||
if missingExtensions == [] then extensions else throw ''
|
||||
While compiling ${pkgname}: the extension ${head missingExtensions} is not available.
|
||||
Select extensions from the following list:
|
||||
${concatStringsSep "\n" availableExtensions}'';
|
||||
in
|
||||
extensionsToInstall;
|
||||
|
||||
getComponents = pkgs: pkgname: targets: extensions: targetExtensions: stdenv: fetchurl:
|
||||
let
|
||||
inherit (builtins) head map;
|
||||
inherit (super.lib) flatten remove subtractLists unique;
|
||||
targetExtensionsToInstall = checkMissingExtensions pkgs pkgname stdenv targetExtensions;
|
||||
extensionsToInstall = checkMissingExtensions pkgs pkgname stdenv extensions;
|
||||
hostTargets = [ "*" (super.rust.toRustTarget stdenv.hostPlatform) (super.rust.toRustTarget stdenv.targetPlatform) ];
|
||||
pkgTuples = flatten (getTargetPkgTuples pkgs pkgname hostTargets targets stdenv);
|
||||
extensionTuples = flatten (map (name: getTargetPkgTuples pkgs name hostTargets targets stdenv) extensionsToInstall);
|
||||
targetExtensionTuples = flatten (map (name: getTargetPkgTuples pkgs name targets targets stdenv) targetExtensionsToInstall);
|
||||
pkgsTuples = pkgTuples ++ extensionTuples ++ targetExtensionTuples;
|
||||
missingTargets = subtractLists (map (tuple: tuple.target) pkgsTuples) (remove "*" targets);
|
||||
pkgsTuplesToInstall =
|
||||
if missingTargets == [] then pkgsTuples else throw ''
|
||||
While compiling ${pkgname}: the target ${head missingTargets} is not available for any package.'';
|
||||
in
|
||||
map (tuple: { name = tuple.name; src = (getFetchUrl pkgs tuple.name tuple.target stdenv fetchurl); }) pkgsTuplesToInstall;
|
||||
|
||||
installComponents = stdenv: namesAndSrcs:
|
||||
let
|
||||
inherit (builtins) map;
|
||||
installComponent = name: src:
|
||||
stdenv.mkDerivation {
|
||||
inherit name;
|
||||
inherit src;
|
||||
|
||||
# No point copying src to a build server, then copying back the
|
||||
# entire unpacked contents after just a little twiddling.
|
||||
preferLocalBuild = true;
|
||||
|
||||
# (@nbp) TODO: Check on Windows and Mac.
|
||||
# This code is inspired by patchelf/setup-hook.sh to iterate over all binaries.
|
||||
installPhase = ''
|
||||
patchShebangs install.sh
|
||||
CFG_DISABLE_LDCONFIG=1 ./install.sh --prefix=$out --verbose
|
||||
setInterpreter() {
|
||||
local dir="$1"
|
||||
[ -e "$dir" ] || return 0
|
||||
header "Patching interpreter of ELF executables and libraries in $dir"
|
||||
local i
|
||||
while IFS= read -r -d ''$'\0' i; do
|
||||
if [[ "$i" =~ .build-id ]]; then continue; fi
|
||||
if ! isELF "$i"; then continue; fi
|
||||
echo "setting interpreter of $i"
|
||||
|
||||
if [[ -x "$i" ]]; then
|
||||
# Handle executables
|
||||
patchelf \
|
||||
--set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \
|
||||
--set-rpath "${super.lib.makeLibraryPath [ self.zlib ]}:$out/lib" \
|
||||
"$i" || true
|
||||
else
|
||||
# Handle libraries
|
||||
patchelf \
|
||||
--set-rpath "${super.lib.makeLibraryPath [ self.zlib ]}:$out/lib" \
|
||||
"$i" || true
|
||||
fi
|
||||
done < <(find "$dir" -type f -print0)
|
||||
}
|
||||
setInterpreter $out
|
||||
'';
|
||||
|
||||
postFixup = ''
|
||||
# Function moves well-known files from etc/
|
||||
handleEtc() {
|
||||
local oldIFS="$IFS"
|
||||
# Directories we are aware of, given as substitution lists
|
||||
for paths in \
|
||||
"etc/bash_completion.d","share/bash_completion/completions","etc/bash_completions.d","share/bash_completions/completions";
|
||||
do
|
||||
# Some directoties may be missing in some versions. If so we just skip them.
|
||||
# See https://github.com/mozilla/nixpkgs-mozilla/issues/48 for more infomation.
|
||||
if [ ! -e $paths ]; then continue; fi
|
||||
IFS=","
|
||||
set -- $paths
|
||||
IFS="$oldIFS"
|
||||
local orig_path="$1"
|
||||
local wanted_path="$2"
|
||||
# Rename the files
|
||||
if [ -d ./"$orig_path" ]; then
|
||||
mkdir -p "$(dirname ./"$wanted_path")"
|
||||
fi
|
||||
mv -v ./"$orig_path" ./"$wanted_path"
|
||||
# Fail explicitly if etc is not empty so we can add it to the list and/or report it upstream
|
||||
rmdir ./etc || {
|
||||
echo Installer tries to install to /etc:
|
||||
find ./etc
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
}
|
||||
if [ -d "$out"/etc ]; then
|
||||
pushd "$out"
|
||||
handleEtc
|
||||
popd
|
||||
fi
|
||||
'';
|
||||
|
||||
dontStrip = true;
|
||||
};
|
||||
in
|
||||
map (nameAndSrc: (installComponent nameAndSrc.name nameAndSrc.src)) namesAndSrcs;
|
||||
|
||||
# Manifest files are organized as follow:
|
||||
# { date = "2017-03-03";
|
||||
# pkg.cargo.version= "0.18.0-nightly (5db6d64 2017-03-03)";
|
||||
# pkg.cargo.target.x86_64-unknown-linux-gnu = {
|
||||
# available = true;
|
||||
# hash = "abce..."; # sha256
|
||||
# url = "https://static.rust-lang.org/dist/....tar.gz";
|
||||
# xz_hash = "abce..."; # sha256
|
||||
# xz_url = "https://static.rust-lang.org/dist/....tar.xz";
|
||||
# };
|
||||
# }
|
||||
#
|
||||
# The packages available usually are:
|
||||
# cargo, rust-analysis, rust-docs, rust-src, rust-std, rustc, and
|
||||
# rust, which aggregates them in one package.
|
||||
#
|
||||
# For each package the following options are available:
|
||||
# extensions - The extensions that should be installed for the package.
|
||||
# For example, install the package rust and add the extension rust-src.
|
||||
# targets - The package will always be installed for the host system, but with this option
|
||||
# extra targets can be specified, e.g. "mips-unknown-linux-musl". The target
|
||||
# will only apply to components of the package that support being installed for
|
||||
# a different architecture. For example, the rust package will install rust-std
|
||||
# for the host system and the targets.
|
||||
# targetExtensions - If you want to force extensions to be installed for the given targets, this is your option.
|
||||
# All extensions in this list will be installed for the target architectures.
|
||||
# *Attention* If you want to install an extension like rust-src, that has no fixed architecture (arch *),
|
||||
# you will need to specify this extension in the extensions options or it will not be installed!
|
||||
fromManifestFile = pkgs: { stdenv, fetchurl, patchelf }:
|
||||
let
|
||||
inherit (builtins) elemAt;
|
||||
inherit (super) makeOverridable;
|
||||
inherit (super.lib) flip mapAttrs;
|
||||
in
|
||||
flip mapAttrs pkgs.pkg (name: pkg:
|
||||
makeOverridable ({extensions, targets, targetExtensions}:
|
||||
let
|
||||
version' = builtins.match "([^ ]*) [(]([^ ]*) ([^ ]*)[)]" pkg.version;
|
||||
version = if version' == null then pkg.version else "${elemAt version' 0}-${elemAt version' 2}-${elemAt version' 1}";
|
||||
namesAndSrcs = getComponents pkgs.pkg name targets extensions targetExtensions stdenv fetchurl;
|
||||
components = installComponents stdenv namesAndSrcs;
|
||||
componentsOuts = builtins.map (comp: (super.lib.strings.escapeNixString (super.lib.getOutput "out" comp))) components;
|
||||
in
|
||||
super.pkgs.symlinkJoin {
|
||||
name = name + "-" + version;
|
||||
paths = components;
|
||||
postBuild = ''
|
||||
# If rustc or rustdoc is in the derivation, we need to copy their
|
||||
# executable into the final derivation. This is required
|
||||
# for making them find the correct SYSROOT.
|
||||
for target in $out/bin/{rustc,rustdoc}; do
|
||||
if [ -e $target ]; then
|
||||
cp --remove-destination "$(realpath -e $target)" $target
|
||||
fi
|
||||
done
|
||||
'';
|
||||
|
||||
# Add the compiler as part of the propagated build inputs in order
|
||||
# to run:
|
||||
#
|
||||
# $ nix-shell -p rustChannels.stable.rust
|
||||
#
|
||||
# And get a fully working Rust compiler, with the stdenv linker.
|
||||
propagatedBuildInputs = [ stdenv.cc ];
|
||||
|
||||
meta.platforms = stdenv.lib.platforms.all;
|
||||
}
|
||||
) { extensions = []; targets = []; targetExtensions = []; }
|
||||
);
|
||||
|
||||
in
|
||||
|
||||
rec {
|
||||
lib = super.lib // {
|
||||
rustLib = {
|
||||
inherit fromManifest fromManifestFile;
|
||||
};
|
||||
};
|
||||
|
||||
rustChannelOf = manifest_args: fromManifest
|
||||
manifest_args
|
||||
{ inherit (self) stdenv fetchurl patchelf; };
|
||||
|
||||
# Set of packages which are automagically updated. Do not rely on these for
|
||||
# reproducible builds.
|
||||
latest = (super.latest or {}) // {
|
||||
rustChannels = {
|
||||
nightly = rustChannelOf { channel = "nightly"; };
|
||||
beta = rustChannelOf { channel = "beta"; };
|
||||
stable = rustChannelOf { channel = "stable"; };
|
||||
};
|
||||
};
|
||||
|
||||
# Helper builder
|
||||
rustChannelOfTargets = channel: date: targets:
|
||||
(rustChannelOf { inherit channel date; })
|
||||
.rust.override { inherit targets; };
|
||||
|
||||
# For backward compatibility
|
||||
rustChannels = latest.rustChannels;
|
||||
|
||||
# For each channel:
|
||||
# latest.rustChannels.nightly.cargo
|
||||
# latest.rustChannels.nightly.rust # Aggregate all others. (recommended)
|
||||
# latest.rustChannels.nightly.rustc
|
||||
# latest.rustChannels.nightly.rust-analysis
|
||||
# latest.rustChannels.nightly.rust-docs
|
||||
# latest.rustChannels.nightly.rust-src
|
||||
# latest.rustChannels.nightly.rust-std
|
||||
|
||||
# For a specific date:
|
||||
# (rustChannelOf { date = "2017-06-06"; channel = "beta"; }).rust
|
||||
}
|
Loading…
Reference in New Issue
Block a user