mirror of
https://github.com/lucannez64/darling-lol.git
synced 2026-10-27 19:54:38 +00:00
feat(nix): add experimental rootless FHS package and desktop launcher
This commit is contained in:
1 parent
e287abb5d6
commit
f5e65e3cf1
28 files changed
+1684
-63
No files matched your search
+5
-1
@@ -20,4 +20,8 @@ cmake -S build/darling-src -B build/darling-src/build -G 'Unix Makefiles' \
|
||||
-DCMAKE_C_FLAGS="-O3 -march=native -mtune=generic -pipe" \
|
||||
-DCMAKE_CXX_FLAGS="-O3 -march=native -mtune=generic -pipe"
|
||||
cmake --build build/darling-src/build --parallel "${JOBS:-$(nproc)}"
|
||||
echo 'Build complete. Install the base runtime with: sudo cmake --install build/darling-src/build'
|
||||
if [ -n "${DARLING_WORKSPACE:-}" ]; then
|
||||
echo 'Build complete. Install the base runtime with: cmake --install build/darling-src/build'
|
||||
else
|
||||
echo 'Build complete. Install the base runtime with: sudo cmake --install build/darling-src/build'
|
||||
fi
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
: "${DARLING_HOST_UID:?missing Darling user namespace}"
|
||||
: "${DARLING_WORKSPACE:?missing Darling workspace}"
|
||||
if [ "${DARLING_SETUP:-0}" != 1 ] && [ "${1:-}" != shutdown ]; then
|
||||
python3 "$DARLING_WORKSPACE/scripts/nix-state.py" check || {
|
||||
echo 'Rootless runtime readiness missing; run darling-lol --installer in a terminal.' >&2
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
# This is namespace root (a subordinate host UID), not host root. Keep real
|
||||
# UID/GID intact so Darling initializes the correct guest account and ownership.
|
||||
exec setpriv --euid 0 --egid 0 --keep-groups \
|
||||
"$DARLING_WORKSPACE/usr-local/bin/darling" "$@"
|
||||
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
: "${DARLING_HOST_UID:?start this environment with darling-lol}"
|
||||
: "${DARLING_HOST_GID:?start this environment with darling-lol}"
|
||||
# Carry only namespace-scoped capabilities into the ordinary-user process.
|
||||
# Darling's shim temporarily switches effective IDs; real IDs stay the user's.
|
||||
exec setpriv --ruid "$DARLING_HOST_UID" --euid "$DARLING_HOST_UID" \
|
||||
--rgid "$DARLING_HOST_GID" --egid "$DARLING_HOST_GID" --keep-groups \
|
||||
--inh-caps +all --ambient-caps +all "$@"
|
||||
@@ -3,6 +3,13 @@
|
||||
set -eu
|
||||
repo=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
cd "$repo"
|
||||
if [ -n "${DARLING_WORKSPACE:-}" ]; then
|
||||
python3 scripts/nix-idle.py
|
||||
python3 scripts/nix-state.py check-base || { echo 'Base runtime readiness missing; run darling-lol --update.' >&2; exit 1; }
|
||||
python3 scripts/nix-state.py invalidate
|
||||
# Prefix initialization is a setup-only exception to the runner launch gate.
|
||||
export DARLING_SETUP=1
|
||||
fi
|
||||
python3 scripts/configure.py
|
||||
. build/runtime/tools/runtime-paths.sh
|
||||
if [ -d build/venv/bin ]; then PATH="$repo/build/venv/bin:$PATH"; export PATH; fi
|
||||
@@ -16,7 +23,7 @@ prefix=$prefix_dir
|
||||
mkdir -p "$prefix/private/tmp"
|
||||
chmod 1777 "$prefix/private/tmp"
|
||||
# Build the system root store now that the prefix exists; Darling is stopped next anyway.
|
||||
python3 build/runtime/tools/ensure-darling-root-certificates.py ||
|
||||
python3 build/runtime/tools/ensure-darling-root-certificates.py || \
|
||||
echo 'Darling system root store not installed; the launcher retries it' >&2
|
||||
python3 build/runtime/tools/stop-darling-runtime.py
|
||||
sh build/runtime/tools/install-riot-presentation-runtime.sh
|
||||
@@ -29,3 +36,9 @@ fi
|
||||
python3 build/runtime/tools/install-darling-system-profiler.py
|
||||
# Every guest process loads these overlays; refuse a set the compiler broke (check-darwin-tlv-calls.py).
|
||||
python3 build/runtime/tools/validate-riot-runtime.py
|
||||
# Mark this canonical prefix and configured guest ready only after validation.
|
||||
if [ -n "${DARLING_WORKSPACE:-}" ]; then
|
||||
# Overlay installation can also refresh darlingserver; record the final base.
|
||||
python3 scripts/nix-state.py stamp-base
|
||||
python3 scripts/nix-state.py stamp
|
||||
fi
|
||||
@@ -2,10 +2,13 @@
|
||||
set -eu
|
||||
repo=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
cd "$repo"
|
||||
if [ -n "${DARLING_WORKSPACE:-}" ] && ! python3 scripts/nix-state.py check; then
|
||||
echo 'Rootless runtime readiness is missing or incompatible; run darling-lol --installer in a terminal.' >&2
|
||||
exit 1
|
||||
fi
|
||||
export PATH="${DARLING_RUNNER_DIR:+$DARLING_RUNNER_DIR:}$repo/usr-local/bin:/usr/local/bin:$PATH"
|
||||
region=${1:-euw}
|
||||
# Riot publishes LAN, LAS and OCE installers under their platform codes.
|
||||
case "$region" in lan) region=la1;; las) region=la2;; oce) region=oc1;; esac
|
||||
case "$region" in euw|eune|na|br|kr|jp|la1|la2|oc1|ru|tr) ;; *) echo 'Use a Riot installer region code' >&2; exit 1;; esac
|
||||
case "$region" in euw|eune|na|br|kr|jp|lan|las|oce|ru|tr) ;; *) echo 'Use a Riot installer region code' >&2; exit 1;; esac
|
||||
python3 scripts/configure.py >/dev/null
|
||||
bash build/runtime/tools/fetch-installer.sh "$region" build/installer
|
||||
unzip -q -o "build/installer/live.$region.zip" -d build/installer
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Refresh managed package files without following mutable destination symlinks."""
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import stat
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
source, destination = map(Path, sys.argv[1:])
|
||||
items = 'docs patches research scripts tests tools upstream LICENSE NOTICE.md README.md requirements.txt'.split()
|
||||
# Preflight the entire managed tree before writing anything. Never chmod or copy
|
||||
# through a link planted by a previous installation (including directory links).
|
||||
for root in [destination, *destination.parents]:
|
||||
if root.is_symlink():
|
||||
raise SystemExit(f'Refusing symlink workspace ancestor: {root}')
|
||||
for item in items:
|
||||
for base in [source / item, destination / item]:
|
||||
for path in [base, *base.rglob('*')] if base.is_dir() else [base]:
|
||||
if path.is_symlink():
|
||||
raise SystemExit(f'Refusing symlink in managed package tree: {path}')
|
||||
if path.exists() and not (path.is_file() or path.is_dir()):
|
||||
raise SystemExit(f'Refusing special file in managed package tree: {path}')
|
||||
for item in items:
|
||||
src = source / item
|
||||
if not src.exists():
|
||||
continue
|
||||
for path in [src, *src.rglob('*')] if src.is_dir() else [src]:
|
||||
target = destination / path.relative_to(source)
|
||||
if path.is_dir():
|
||||
target.mkdir(parents=True, exist_ok=True)
|
||||
target.chmod(0o755)
|
||||
else:
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
fd, temporary = tempfile.mkstemp(prefix='.package-', dir=target.parent)
|
||||
try:
|
||||
with os.fdopen(fd, 'wb') as output, path.open('rb') as input_file:
|
||||
shutil.copyfileobj(input_file, output)
|
||||
# Keep executable bits, remove special bits, and keep owner writable.
|
||||
os.chmod(temporary, stat.S_IMODE(path.stat().st_mode) & 0o777 | 0o600)
|
||||
os.replace(temporary, target)
|
||||
finally:
|
||||
if os.path.exists(temporary):
|
||||
os.unlink(temporary)
|
||||
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Read-only, fail-closed rootless maintenance preflight. Never signal a process."""
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
prefix = Path(os.environ.get('DPREFIX', str(Path.home() / '.darling'))).resolve()
|
||||
try:
|
||||
pid = int((prefix / '.init.pid').read_text().strip())
|
||||
except FileNotFoundError:
|
||||
pid = 0
|
||||
except (OSError, ValueError):
|
||||
raise SystemExit('Cannot validate prefix server marker; inspect it before maintenance.')
|
||||
if pid > 0:
|
||||
try:
|
||||
status = (Path('/proc') / str(pid) / 'status').read_text()
|
||||
if not any(line.startswith('State:') and line.split()[1] == 'Z' for line in status.splitlines()):
|
||||
raise SystemExit('Prefix has a live server marker; exit Riot/League and run darling shutdown in the ORIGINAL namespace before updating. No process was stopped.')
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
# Only inspect same-user mappings under this exact prefix. An unrelated game's
|
||||
# command name is not grounds to stop or modify it. Unreadable same-user maps
|
||||
# fail closed because we cannot rule out a client still using these files.
|
||||
paths = [str(prefix / name) + '/' for name in (
|
||||
'Applications/Riot Client.app', 'Applications/League of Legends.app',
|
||||
'Users/Shared/Riot Games')]
|
||||
for process in Path('/proc').iterdir():
|
||||
if not process.name.isdigit():
|
||||
continue
|
||||
try:
|
||||
if process.stat().st_uid != os.getuid():
|
||||
continue
|
||||
mappings = (process / 'maps').read_text()
|
||||
if any(path in mappings for path in paths):
|
||||
raise SystemExit('A client maps this prefix; exit it before rootless maintenance. No process was stopped.')
|
||||
except (FileNotFoundError, ProcessLookupError, PermissionError):
|
||||
continue
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run setup and the client in the SAME namespace. Never reconnect by killing it.
|
||||
set -euo pipefail
|
||||
cd "${DARLING_WORKSPACE:?start with darling-lol}"
|
||||
ready() { python3 scripts/nix-state.py check; }
|
||||
interactive() {
|
||||
if [ ! -t 0 ]; then
|
||||
echo 'Setup needs an interactive terminal. Run darling-lol --installer in a terminal (or use the desktop entry with Terminal=true).' >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
if ! ready; then
|
||||
interactive
|
||||
echo "Prefix: $DPREFIX"
|
||||
if ! python3 scripts/nix-state.py check-base; then
|
||||
echo 'Base runtime missing or incompatible; building requires about 40–50 GB.'
|
||||
read -r -p 'Build/update the rootless runtime? [y/N] ' reply || exit 1
|
||||
case "$reply" in y|Y) ;; *) exit 1;; esac
|
||||
./scripts/update.sh
|
||||
else
|
||||
./scripts/install-runtime.sh
|
||||
fi
|
||||
fi
|
||||
# Ready existing installations never rebuild merely because the launcher opens.
|
||||
if [ "${1:-}" = --installer ] ||
|
||||
{ [ ! -e "$DPREFIX/Applications/Riot Client.app" ] &&
|
||||
[ ! -d "$DPREFIX/Users/Shared/Riot Games/Riot Client.app" ]; }; then
|
||||
interactive
|
||||
read -r -p 'Region [euw]: ' region || exit 1
|
||||
exec ./scripts/installer.sh "${region:-euw}"
|
||||
fi
|
||||
exec ./scripts/run.sh
|
||||
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Per-prefix rootless readiness; no Darling execution or prefix writes."""
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import pwd
|
||||
import sys
|
||||
|
||||
sys.dont_write_bytecode = True
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT / 'tools'))
|
||||
from runtime_paths import runtime_paths
|
||||
|
||||
|
||||
def selected_paths():
|
||||
config_path = ROOT / 'build/config.json'
|
||||
config = json.loads(config_path.read_text()) if config_path.exists() else {}
|
||||
guest = config.get('guest_user') or pwd.getpwuid(os.getuid()).pw_name
|
||||
config.setdefault('prefix', str(Path.home() / '.darling'))
|
||||
config.setdefault('guest_home', '/Users/' + guest)
|
||||
configured_prefix = Path(os.environ.get('DPREFIX') or config['prefix']).resolve()
|
||||
env_prefix = os.environ.get('DPREFIX')
|
||||
try:
|
||||
os.environ['DPREFIX'] = str(configured_prefix)
|
||||
prefix, home = runtime_paths(config)
|
||||
finally:
|
||||
if env_prefix is None:
|
||||
os.environ.pop('DPREFIX', None)
|
||||
else:
|
||||
os.environ['DPREFIX'] = env_prefix
|
||||
return prefix.resolve(), home.resolve(), guest
|
||||
|
||||
|
||||
def guest_user():
|
||||
return selected_paths()[2]
|
||||
|
||||
|
||||
def digest(paths):
|
||||
result = hashlib.sha256()
|
||||
for path in sorted(paths):
|
||||
if path.is_file():
|
||||
result.update(str(path.relative_to(ROOT)).encode() + b'\0' + path.read_bytes())
|
||||
return result.hexdigest()
|
||||
|
||||
|
||||
def base_identity():
|
||||
runtime_tree = ROOT / 'usr-local/libexec/darling'
|
||||
runtime_modes = {name: (ROOT / 'usr-local/bin' / name).stat().st_mode & 0o777
|
||||
if (ROOT / 'usr-local/bin' / name).exists() else None
|
||||
for name in ('darling', 'darlingserver')}
|
||||
return {'schema': 2, 'package': os.environ.get('DARLING_PACKAGE_ID', ''),
|
||||
'runtime_modes': runtime_modes,
|
||||
'runtime_tree': inventory(runtime_tree),
|
||||
'sources': digest([* (ROOT / 'patches').glob('*.patch'),
|
||||
ROOT / 'upstream/manifest.json',
|
||||
* (ROOT / 'scripts').glob('*.py'),
|
||||
* (ROOT / 'scripts').glob('*.sh'),
|
||||
* (ROOT / 'tools').glob('*')]),
|
||||
'runtime': digest([ROOT / 'usr-local/bin/darling',
|
||||
ROOT / 'usr-local/bin/darlingserver'])}
|
||||
|
||||
|
||||
def inventory(root):
|
||||
"""Include all required trees and modes without hashing large installed binaries."""
|
||||
if not root.is_dir():
|
||||
return None
|
||||
result = hashlib.sha256()
|
||||
def enumeration_error(error):
|
||||
raise error
|
||||
|
||||
for directory, dirs, files in os.walk(root, followlinks=False,
|
||||
onerror=enumeration_error):
|
||||
for name in sorted(dirs + files):
|
||||
path = Path(directory) / name
|
||||
if any(token in path.name for token in ('.before-', '.rt-', '.llvm')):
|
||||
continue
|
||||
info = path.lstat()
|
||||
target_str = ''
|
||||
if path.is_symlink():
|
||||
try:
|
||||
target_str = f':{os.readlink(path)}'
|
||||
except OSError:
|
||||
pass
|
||||
result.update(str(path.relative_to(root)).encode() + b'\0')
|
||||
result.update(f'{info.st_mode}:{info.st_size}:{info.st_mtime_ns}{target_str}'.encode())
|
||||
return result.hexdigest()
|
||||
|
||||
|
||||
def overlay_identity(home):
|
||||
result: dict[str, object] = {name: inventory(home / name) for name in
|
||||
('RuntimeLibraries', 'RuntimeFrameworks',
|
||||
'Library/Audio/Plug-Ins/Components/DarlingRiotAudio.component')}
|
||||
helper = home / 'libDarlingXShm.dylib'
|
||||
result['xshm'] = ([helper.stat().st_mode, helper.stat().st_size,
|
||||
helper.stat().st_mtime_ns] if helper.is_file() else None)
|
||||
return result
|
||||
|
||||
|
||||
def identity():
|
||||
prefix, home, guest = selected_paths()
|
||||
return dict(base_identity(), prefix=str(prefix), guest=guest, guest_home=str(home),
|
||||
overlays=overlay_identity(home), uid=os.getuid(), gid=os.getgid())
|
||||
|
||||
|
||||
def read(path):
|
||||
try:
|
||||
return json.loads(path.read_text())
|
||||
except (OSError, ValueError):
|
||||
return None
|
||||
|
||||
|
||||
def atomic(path, value):
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
temporary = path.with_suffix('.tmp')
|
||||
temporary.write_text(json.dumps(value, sort_keys=True) + '\n')
|
||||
temporary.replace(path)
|
||||
|
||||
|
||||
def main():
|
||||
action = sys.argv[1]
|
||||
state = identity()
|
||||
key = hashlib.sha256(state['prefix'].encode()).hexdigest()
|
||||
marker = ROOT / 'build/nix-ready' / (key + '.json')
|
||||
base_marker = ROOT / 'build/nix-base.json'
|
||||
if action == 'guest':
|
||||
print(state['guest'])
|
||||
elif action == 'check-base':
|
||||
return 0 if read(base_marker) == base_identity() else 1
|
||||
elif action == 'check':
|
||||
return 0 if read(marker) == state and read(base_marker) == base_identity() else 1
|
||||
elif action == 'stamp-base':
|
||||
if (not all((ROOT / 'usr-local/bin' / name).is_file() and
|
||||
os.access(ROOT / 'usr-local/bin' / name, os.X_OK)
|
||||
for name in ('darling', 'darlingserver')) or
|
||||
not (ROOT / 'usr-local/libexec/darling').is_dir() or not state['package']):
|
||||
raise SystemExit('Cannot stamp readiness without executable base runtime, SDK and package identity')
|
||||
atomic(base_marker, base_identity())
|
||||
elif action == 'stamp':
|
||||
if read(base_marker) != base_identity():
|
||||
raise SystemExit('Base runtime readiness is missing; run darling-lol --update in a terminal.')
|
||||
home = Path(str(state['guest_home']))
|
||||
if not home.is_dir() or not any((home / 'RuntimeLibraries').glob('*')) or not any((home / 'RuntimeFrameworks').glob('*')):
|
||||
raise SystemExit('Cannot stamp an empty or missing prefix runtime')
|
||||
# Reuse the complete installation gate; readiness must never mint an
|
||||
# apparently valid manifest for partial overlays, even when called directly.
|
||||
import importlib.util
|
||||
spec = importlib.util.spec_from_file_location('runtime_validation', ROOT / 'tools/validate-riot-runtime.py')
|
||||
assert spec is not None and spec.loader is not None
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
module.inputs(Path(str(state['prefix'])), home)
|
||||
atomic(marker, state)
|
||||
elif action in ('invalidate', 'invalidate-base'):
|
||||
marker.unlink(missing_ok=True)
|
||||
if action == 'invalidate-base':
|
||||
base_marker.unlink(missing_ok=True)
|
||||
else:
|
||||
raise SystemExit(f'Unknown state action: {action}')
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
raise SystemExit(main())
|
||||
+23
-13
@@ -1,7 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Fetch pinned Darling sources and apply each patch to its owning repository."""
|
||||
import argparse,json,os,subprocess,tempfile
|
||||
import argparse,json,os,subprocess,tempfile,sys
|
||||
from pathlib import Path
|
||||
# --check-only must not create import caches in the source package either.
|
||||
sys.dont_write_bytecode=True
|
||||
from common import ROOT,render
|
||||
p=argparse.ArgumentParser(description=__doc__)
|
||||
p.add_argument('--source',type=Path,default=ROOT/'build/darling-src')
|
||||
@@ -25,19 +27,27 @@ def previous_patches(component):
|
||||
if shown.returncode==0:yield render(shown.stdout)
|
||||
if not (source/'.git').exists():
|
||||
if a.check_only:p.error('check-only requires an existing pinned source checkout')
|
||||
if source.exists():p.error('refusing non-checkout destination; choose an empty source path')
|
||||
source.parent.mkdir(parents=True,exist_ok=True)
|
||||
run(['git','clone',manifest['upstream'],str(source)])
|
||||
run(['git','-C',str(source),'checkout','--detach',manifest['revision']])
|
||||
# Recursive initialization can spend a long time fetching nested repos (and
|
||||
# Git LFS assets). Explicit progress keeps the last completed submodule
|
||||
# from looking like the operation that is currently stuck. The pinned
|
||||
# darling-swift .lfsconfig points at the retired git-lfs.darlinghq.org, so
|
||||
# fetch that submodule's LFS objects from GitHub, which still serves them;
|
||||
# otherwise the checkout blocks on the dead host right after sqlite.
|
||||
print('Initializing Darling submodules (large repositories/LFS assets may take a while)...',flush=True)
|
||||
run(['git','-C',str(source),'-c','lfs.url=https://github.com/darlinghq/darling-swift.git/info/lfs',
|
||||
'submodule','update','--init','--recursive','--progress'])
|
||||
print('Darling submodules initialized.',flush=True)
|
||||
# Fetch the exact pin, not today's master. Publish only a complete checkout;
|
||||
# failed downloads are removed without touching an existing user checkout.
|
||||
with tempfile.TemporaryDirectory(prefix='darling-clone-',dir=source.parent) as temporary:
|
||||
checkout=Path(temporary)/'source'
|
||||
run(['git','init',str(checkout)])
|
||||
run(['git','-C',str(checkout),'remote','add','origin',manifest['upstream']])
|
||||
run(['git','-C',str(checkout),'fetch','--depth','1','origin',manifest['revision']])
|
||||
run(['git','-C',str(checkout),'checkout','--detach','FETCH_HEAD'])
|
||||
print('Initializing Darling submodules (large repositories/LFS assets may take a while)...',flush=True)
|
||||
for attempt in range(1,4):
|
||||
try:
|
||||
run(['git','-C',str(checkout),'-c','lfs.url=https://github.com/darlinghq/darling-swift.git/info/lfs',
|
||||
'submodule','update','--init','--recursive','--depth','1','--progress'])
|
||||
break
|
||||
except subprocess.CalledProcessError:
|
||||
if attempt==3:raise
|
||||
print(f'Submodule fetch interrupted (attempt {attempt}/3). Retrying...',flush=True)
|
||||
checkout.rename(source)
|
||||
|
||||
# Never reset someone else's checkout to make a patch apply.
|
||||
for component in manifest['components']:
|
||||
repo=source/component['path']
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
set -eu
|
||||
repo=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
cd "$repo"
|
||||
if [ -n "${DARLING_WORKSPACE:-}" ] && ! python3 scripts/nix-state.py check; then
|
||||
echo 'Rootless runtime readiness is missing or incompatible; run darling-lol --installer in a terminal.' >&2
|
||||
exit 1
|
||||
fi
|
||||
export PATH="${DARLING_RUNNER_DIR:+$DARLING_RUNNER_DIR:}$repo/usr-local/bin:/usr/local/bin:$PATH"
|
||||
python3 scripts/configure.py >/dev/null
|
||||
if [ -d build/venv/bin ]; then PATH="$repo/build/venv/bin:$PATH"; export PATH; fi
|
||||
# darling-lol perf: optionally wrap with gamemoderun for automatic
|
||||
|
||||
+20
-1
@@ -1,10 +1,29 @@
|
||||
#!/bin/sh
|
||||
# Bring an existing build and installation up to date after `git pull`: re-apply the patches that changed
|
||||
# (prepare.py reverts the earlier version it finds applied), rebuild incrementally, and reinstall the base
|
||||
# runtime and the per-user overrides. Run it with no Riot/League session open; it never stops one.
|
||||
# runtime, and the per-user overrides. Run it after manually closing Riot/League.
|
||||
# Rootless callers must remain in their original namespace; the outer launcher
|
||||
# refuses a live prefix marker instead of trying to reconnect or stop a session.
|
||||
set -eu
|
||||
repo=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
cd "$repo"
|
||||
if [ -n "${DARLING_WORKSPACE:-}" ]; then
|
||||
python3 scripts/nix-idle.py
|
||||
# Initial setup and upgrades use the same supported user-owned install path.
|
||||
# Keep each package closure rooted: copied ELF files can retain its loader.
|
||||
package=${DARLING_PACKAGE_ID%/share/darling-lol}
|
||||
case "$package" in /nix/store/*) ;; *) echo 'Missing Nix package identity' >&2; exit 1;; esac
|
||||
mkdir -p build/nix-gcroots
|
||||
nix-store --realise "$package" --add-root "$repo/build/nix-gcroots/$(basename "$package")" --indirect >/dev/null
|
||||
python3 scripts/nix-state.py invalidate-base
|
||||
./scripts/build.sh
|
||||
python3 build/runtime/tools/stop-darling-runtime.py
|
||||
cmake --install build/darling-src/build
|
||||
python3 scripts/nix-state.py stamp-base
|
||||
./scripts/install-runtime.sh
|
||||
echo 'Rootless update installed. In this shell use scripts/run.sh; otherwise exit this shell and start darling-lol.'
|
||||
exit 0
|
||||
fi
|
||||
if [ ! -d build/darling-src/build ]; then
|
||||
echo 'No existing build; follow the first-time setup in README.md instead.' >&2
|
||||
exit 1
|
||||
|
||||
@@ -12,6 +12,9 @@ errors=[]
|
||||
secret_patterns=[r'gh[pousr]_[A-Za-z0-9]{30,}',r'AKIA[0-9A-Z]{16}',r'eyJ[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}',r'-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----']
|
||||
for name in filter(None,files):
|
||||
p=ROOT/name;data=p.read_bytes()
|
||||
# The Nix desktop package intentionally ships this icon, not a runtime binary.
|
||||
if name == 'darling-lol.png' and data.startswith(b'\x89PNG\r\n\x1a\n'):
|
||||
continue
|
||||
if data.startswith((b'\x7fELF',b'MZ',b'\xcf\xfa\xed\xfe',b'\xca\xfe\xba\xbe')) or b'\0' in data:
|
||||
errors.append(name+': binary content is not part of this source package');continue
|
||||
try:text=data.decode()
|
||||
|
||||
Reference in new issue
Block a user