commit
815fa068bc
@ -0,0 +1,3 @@ |
||||
result |
||||
result-* |
||||
*.tmp |
@ -0,0 +1,8 @@ |
||||
{ |
||||
"[nix]": { |
||||
"editor.tabSize": 2, |
||||
"files.trimFinalNewlines": true, |
||||
"files.insertFinalNewline": true, |
||||
"files.trimTrailingWhitespace": true |
||||
} |
||||
} |
@ -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 |
@ -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() |
@ -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 |
||||
} |
@ -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; |
||||
}; |
||||
}); |
||||
} |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,5 @@ |
||||
{ |
||||
"1.48.0" = import ./1.48.0.nix; |
||||
"1.49.0" = import ./1.49.0.nix; |
||||
latest = "1.49.0"; |
||||
} |
@ -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"; |
||||
} |
@ -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