Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions .github/workflows/nix.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Nix

on:
push:
branches: [main]
pull_request:
types: [opened, synchronize, reopened, ready_for_review]

permissions:
contents: read

jobs:
build:
if: github.event_name == 'push' || github.event.pull_request.draft == false
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, ubuntu-24.04-arm, macos-latest]
steps:
- uses: actions/checkout@v4

- uses: cachix/install-nix-action@v31

- name: Build
run: nix build --print-build-logs

- name: Smoke test
run: |
./result/bin/lc --version
./result/bin/astra --version
./result/bin/git-annex version
cd "$RUNNER_TEMP"
"$GITHUB_WORKSPACE/result/bin/lc" init demo
"$GITHUB_WORKSPACE/result/bin/lc" init demo --check

version:
if: github.event_name == 'push' || github.event.pull_request.draft == false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: cachix/install-nix-action@v31

- name: Set up uv
uses: astral-sh/setup-uv@v6

- name: Flake evaluates on every system
run: nix flake check --all-systems

- name: lastRelease is the latest tag
run: |
expected=$(uvx --from setuptools-scm python -m setuptools_scm)
name=$(nix eval --raw .#packages.x86_64-linux.default.name)
actual=${name#lightcone-}
echo "hatch-vcs: $expected"
echo "nix: $actual"
if [ "${expected%%.dev*}" != "${actual%%.dev*}" ]; then
tag=$(git describe --tags --abbrev=0)
echo "::error file=flake.nix::set lastRelease = \"${tag#v}\";"
exit 1
fi
78 changes: 78 additions & 0 deletions docs/user/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ too, so there is no separate Python install step.
`uv` lands under `~/.local/bin` — make sure it's on your `PATH`.
git is already on the system.

=== "Nix"
The flake in step 2 installs both.

=== "NixOS"
The NixOS module in step 2 installs both.

## 2. lightcone-cli

The published name on PyPI is `lightcone-cli`; the command it provides
Expand All @@ -48,6 +54,57 @@ is `lc`.
python -m pip install lightcone-cli
```

=== "Nix"
```bash
nix profile install github:LightconeResearch/lightcone-cli
```

The flake builds for x86_64 and aarch64 Linux and for macOS on Apple
silicon. It installs `lc`, `astra`, git-annex, uv and git. `lc` runs
through `uv tool run`: the first time, uv installs Python and lc's
dependencies as they were published when that commit was made.

To try it without installing, open a shell with the same tools on your
`PATH`:

```bash
nix shell github:LightconeResearch/lightcone-cli
```

On NixOS, either needs nix-ld, which the module below enables.

=== "NixOS"
NixOS cannot run the interpreters and wheels uv downloads without
[nix-ld](https://github.com/nix-community/nix-ld), so install through
the module, which enables it. Add the input to your system flake:

```nix
inputs.lightcone.url = "github:LightconeResearch/lightcone-cli";
```

then, in your configuration:

```nix
imports = [ inputs.lightcone.nixosModules.default ];
programs.lightcone.enable = true;
```

The module installs the package from the Nix tab and enables
`programs.git` with the package's git. To use another uv (0.12 or
later), override the package:

```nix
programs.lightcone.package =
inputs.lightcone.packages.${pkgs.stdenv.hostPlatform.system}.default.override {
uv = pkgs.uv;
};
```

The module also sets `python-preference = "only-managed"` in
`/etc/uv/uv.toml`, so uv never builds a project on a Nix Python. Log
out and back in once after the first rebuild, so your session picks up
nix-ld.

Get a confirmation of the proper installation by running

lc --version # → lc, version ...
Expand Down Expand Up @@ -104,6 +161,18 @@ unset it (`unalias lc`) or use the full path (`$(which lc) --version`).
pip install -U lightcone-cli
```

=== "Nix"
```bash
nix profile upgrade lightcone-cli
```

=== "NixOS"
```bash
nix flake update lightcone
```

then rebuild your system.

An upgrade never invalidates your results: the engine's version is
recorded in every output's manifest, but it is not part of any output's
identity, so nothing gets rebuilt just because `lc` moved.
Expand All @@ -120,5 +189,14 @@ identity, so nothing gets rebuilt just because `lc` moved.
pip uninstall lightcone-cli
```

=== "Nix"
```bash
nix profile remove lightcone-cli
```

=== "NixOS"
Remove the input and the two lines from your configuration, then
rebuild.

Your projects are untouched — everything `lc` knows about an analysis
lives in the project's own repository, not in any global state.
27 changes: 27 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

122 changes: 122 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
{
description = "Lightcone Research: lc and astra";

inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";

outputs =
{ self, nixpkgs }:
let
inherit (nixpkgs) lib;
forAllSystems = lib.genAttrs [
"x86_64-linux"
"aarch64-linux"
"aarch64-darwin"
];
lastRelease = "0.5.0rc5";
nextVersion =
let
parts = builtins.match "(.*[^0-9])([0-9]+)" lastRelease;
in
"${builtins.elemAt parts 0}${toString (lib.toInt (builtins.elemAt parts 1) + 1)}";
commit = if self ? rev then builtins.substring 0 9 self.rev else self.dirtyShortRev or "unknown";
version = "${nextVersion}.dev0+g${commit}.nix";
excludeNewer =
let
at = start: length: builtins.substring start length self.lastModifiedDate;
in
"${at 0 4}-${at 4 2}-${at 6 2}T${at 8 2}:${at 10 2}:${at 12 2}Z";
in
{
packages = forAllSystems (
system:
let
pkgs = nixpkgs.legacyPackages.${system};
in
rec {
default = pkgs.callPackage (
{
lib,
python3Packages,
runCommand,
makeWrapper,
uv,
git,
}:
let
wheel = python3Packages.buildPythonPackage {
pname = "lightcone-cli";
inherit version;
pyproject = true;
src = ./.;
build-system = [
python3Packages.hatchling
python3Packages.hatch-vcs
];
env.SETUPTOOLS_SCM_PRETEND_VERSION = version;
dontCheckRuntimeDeps = true;
};
in
runCommand "lightcone-${version}"
{
nativeBuildInputs = [ makeWrapper ];
passthru = { inherit uv git; };
meta.mainProgram = "lc";
}
''
mkdir -p $out/bin
ln -s ${uv}/bin/* ${git}/bin/* $out/bin/
whl=$(echo ${wheel.dist}/*.whl)
for exe in lc astra git-annex git-annex-shell git-remote-annex git-remote-tor-annex; do
makeWrapper ${lib.getExe uv} $out/bin/$exe \
--prefix PATH : $out/bin \
--add-flags "tool run --quiet --exclude-newer ${excludeNewer} --from $whl $exe"
done
''
) { };
lc = default;
}
);

nixosModules.default =
{
config,
lib,
pkgs,
...
}:
let
cfg = config.programs.lightcone;
in
{
options.programs.lightcone = {
enable = lib.mkEnableOption "the Lightcone Research tools (lc, astra)";
package = lib.mkOption {
type = lib.types.package;
default = self.packages.${pkgs.stdenv.hostPlatform.system}.default;
defaultText = lib.literalExpression "lightcone.packages.\${system}.default";
description = "The package providing lc, astra, git-annex, uv and git.";
};
};

config = lib.mkIf cfg.enable {
assertions = [
{
assertion = lib.versionAtLeast cfg.package.uv.version "0.12";
message = "programs.lightcone needs uv 0.12 or later, got ${cfg.package.uv.version}.";
}
];
programs.nix-ld.enable = true;
programs.git = {
enable = true;
package = lib.mkDefault cfg.package.git;
};
environment = {
systemPackages = [ cfg.package ];
etc."uv/uv.toml".text = lib.mkDefault ''
python-preference = "only-managed"
'';
};
};
};
};
}
Loading