diff --git a/.github/workflows/flake-check.yaml b/.github/workflows/flake-check.yaml index 250e7aa..b5b88dc 100644 --- a/.github/workflows/flake-check.yaml +++ b/.github/workflows/flake-check.yaml @@ -25,6 +25,7 @@ jobs: - test-inputs - test-flake - test-unflake + - test-nixlock - test-npins - test-npins-follows - test-npins-transitive @@ -82,12 +83,14 @@ jobs: cd templates/npins sed -i 's/# flake-file = import/flake-file = import/' default.nix echo "{ inputs, ... }: { npins.pkgs = import inputs.nixpkgs {}; }" | tee modules/pkgs.nix - nix-shell . -A npins.env --run write-npins + nix-shell . -A flake-file.sh --run write-npins unflake: needs: [dev] name: Check unflake runs-on: ubuntu-latest if: ${{ contains(github.event.pull_request.labels.*.name, 'unflake') }} + env: + NIX_PATH: "nixpkgs=https://github.com/NixOS/nixpkgs/archive/nixos-unstable.tar.gz" steps: - uses: actions/checkout@v4 - uses: wimpysworld/nothing-but-nix@main @@ -97,8 +100,24 @@ jobs: set -e -o pipefail cd templates/unflake sed -i 's/# flake-file = import/flake-file = import/' default.nix - echo "{ inputs, ... }: { unflake.pkgs = import inputs.nixpkgs {}; }" | tee modules/pkgs.nix - nix-shell . -A unflake.env --run 'write-unflake --verbose' + nix-shell . -A flake-file.sh --run 'write-unflake --verbose' + nixlock: + needs: [dev] + name: Check nixlock + runs-on: ubuntu-latest + # if: ${{ contains(github.event.pull_request.labels.*.name, 'unflake') }} + env: + NIX_PATH: "nixpkgs=https://github.com/NixOS/nixpkgs/archive/nixos-unstable.tar.gz" + steps: + - uses: actions/checkout@v4 + - uses: wimpysworld/nothing-but-nix@main + - uses: cachix/install-nix-action@v31 + - uses: DeterminateSystems/magic-nix-cache-action@main + - run: | + set -e -o pipefail + cd templates/nixlock + sed -i 's/# flake-file = import/flake-file = import/' default.nix + nix-shell . -A flake-file.sh --run write-nixlock dev: needs: [bootstrap] name: Check flake dev diff --git a/README.md b/README.md index 43509b7..cceebb3 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ License

-# Generate `flake.nix`/`unflake.nix`/`npins` from inputs defined as module options. +### Generate `flake.nix`/`unflake.nix`/`npins`/`nixlock` from inputs defined as module options. > `flake-file` and [vic](https://bsky.app/profile/oeiuwq.bsky.social)'s [dendritic libs](https://dendritic.oeiuwq.com) made for you with Love++ and AI--. If you like my work, consider [sponsoring](https://dendritic.oeiuwq.com/sponsor) @@ -23,11 +23,11 @@ This means - Your inputs follow a **typed Input Schema**. - Your outputs can be defined on a **typed Output Schema**. -> Despite the original flake-oriented name, it NOW also works on _stable Nix_, non-flakes environments via [npins](templates/npins) or [unflake](templates/unflake). +> Despite the original flake-oriented name, it NOW also works on _stable Nix_, non-flakes environments via [npins](templates/npins), [unflake](templates/unflake), [nixlock](https://codeberg.org/FrdrCkII/nixlock)
-## Features +### Features - Flake definition aggregated from Nix modules. - [Input](https://github.com/vic/flake-file/blob/main/modules/options/default.nix) and Output schemas based on Nix types. @@ -39,7 +39,7 @@ This means - Incrementally add [flake-parts-builder](#parts_templates) templates. - Pick flakeModules for different feature sets. - [Dendritic](https://vic.github.io/dendrix/Dendritic.html) flake template. -- Works on stable Nix, [npins](templates/npins) and [unflake](templates/unflake) environments. +- Works on stable Nix, [npins](templates/npins), [unflake](templates/unflake), [nixlock](templates/nixlock) environments. diff --git a/dev/_bootstrap-tests.nix b/dev/_bootstrap-tests.nix index 41f50d4..569ea67 100644 --- a/dev/_bootstrap-tests.nix +++ b/dev/_bootstrap-tests.nix @@ -106,6 +106,17 @@ let ''; }; + test-nixlock = pkgs.writeShellApplication { + name = "test-nixlock"; + runtimeInputs = [ + (empty.flake-file.apps.write-nixlock pkgs) + ]; + text = '' + write-nixlock + grep vic/empty-flake/archive ${outdir}/nixlock.lock.nix + ''; + }; + in pkgs.mkShell { buildInputs = [ @@ -115,5 +126,6 @@ pkgs.mkShell { test-npins test-npins-follows test-npins-transitive + test-nixlock ]; } diff --git a/docs/src/content/docs/explanation/what-is-flake-file.mdx b/docs/src/content/docs/explanation/what-is-flake-file.mdx index a255d8b..1c4f7da 100644 --- a/docs/src/content/docs/explanation/what-is-flake-file.mdx +++ b/docs/src/content/docs/explanation/what-is-flake-file.mdx @@ -36,7 +36,7 @@ move your outputs function into `outputs.nix` and use something like: Even if some people use unstable flakes, others should not be forced out of stable Nix. Each module defines inputs and flake-file can extract to whatever input-locking backend you need. -Be it `flake.nix`, `unflake.nix`, `npins`. +Be it `flake.nix`, `unflake.nix`, `nixlock`, `npins`. ## Everybody `.follows` @@ -66,7 +66,7 @@ Running `nix run .#write-flake` materialises all declared inputs into `flake.nix - **Modular:** Each module declares only its own dependencies. - **Composable:** Modules can be shared across projects — including their input declarations. -- **Backend-agnostic:** The same module options generate `flake.nix`, `unflake.nix`, or `npins/` depending on the chosen backend. +- **Backend-agnostic:** The same module options generate `flake.nix`, `unflake.nix`, `nixlock` or `npins/` depending on the chosen backend. - **Standard Nix:** Uses the Nix module system — `lib.mkDefault`, priority overrides, conditional inputs — all work as expected. ## Real-world Usage diff --git a/docs/src/content/docs/guides/flake-modules.mdx b/docs/src/content/docs/guides/flake-modules.mdx index e03ef46..8f39ecd 100644 --- a/docs/src/content/docs/guides/flake-modules.mdx +++ b/docs/src/content/docs/guides/flake-modules.mdx @@ -78,10 +78,16 @@ Source: [`modules/prune-lock/nix-auto-follow.nix`](https://github.com/vic/flake- Defines `flake-file` options for [npins](https://github.com/andir/npins)-based environments. Exposes `write-npins`. Supports `github`, `gitlab`, `channel`, `tarball`, and `git` schemes. Respects `follows` for deduplication. Prunes stale pins automatically. -Source: [`modules/npins.nix`](https://github.com/vic/flake-file/tree/main/modules/npins.nix) +Source: [`modules/npins`](https://github.com/vic/flake-file/tree/main/modules/npins) ## `flakeModules.unflake` Defines `flake-file` options for [unflake](https://codeberg.org/goldstein/unflake)-based environments. Exposes `write-unflake`. -Source: [`modules/unflake.nix`](https://github.com/vic/flake-file/tree/main/modules/unflake.nix) +Source: [`modules/unflake`](https://github.com/vic/flake-file/tree/main/modules/unflake) + +## `flakeModules.nixlock` + +Defines `flake-file` options for [nixlock](https://codeberg.org/FrdrCkII/nixlock)-based environments. Exposes `write-nixlock`. + +Source: [`modules/nixlock`](https://github.com/vic/flake-file/tree/main/modules/nixlock) diff --git a/docs/src/content/docs/guides/templates.mdx b/docs/src/content/docs/guides/templates.mdx index f873375..84f4238 100644 --- a/docs/src/content/docs/guides/templates.mdx +++ b/docs/src/content/docs/guides/templates.mdx @@ -60,6 +60,14 @@ For **non-flake** (stable Nix) environments. Uses [goldstein/unflake](https://co nix flake init -t github:vic/flake-file#unflake ``` +## `nixlock` + +For **non-flake** (stable Nix) environments. Uses [FrdrCkII/nixlock](https://codeberg.org/FrdrCkII/nixlock) to pin inputs. + +```shell +nix flake init -t github:vic/flake-file#unflake +``` + ## Tips > **Tip:** You can use the `write-flake` app as part of a devshell command or a git pre-commit hook to keep `flake.nix` always up to date. diff --git a/docs/src/content/docs/index.mdx b/docs/src/content/docs/index.mdx index af603d9..0fa4e5e 100644 --- a/docs/src/content/docs/index.mdx +++ b/docs/src/content/docs/index.mdx @@ -55,6 +55,6 @@ Ever wanted to interpolate a string just to discover inputs are **NOT REAL** Nix Built-in support for automatic `flake.lock` flattening via `allfollow` or `nix-auto-follow`. - Generate `flake.nix`, `unflake.nix`, or `npins/` from the same module options. Switch backends without rewriting your modules. + Generate `flake.nix`, `unflake.nix`, `nixlock`, or `npins/` from the same module options. Switch backends without rewriting your modules. diff --git a/docs/src/content/docs/overview.mdx b/docs/src/content/docs/overview.mdx index d2db7db..01a049a 100644 --- a/docs/src/content/docs/overview.mdx +++ b/docs/src/content/docs/overview.mdx @@ -44,7 +44,7 @@ flake-file treats `flake.nix` as a generated artifact. You declare inputs and se Learn More - Adopt flake-file in a non-flake project using npins or unflake. + Adopt flake-file in a non-flake project using npins, nixlock or unflake. Learn More diff --git a/docs/src/content/docs/reference/bootstrap.mdx b/docs/src/content/docs/reference/bootstrap.mdx index ec4f1e6..ffc27d5 100644 --- a/docs/src/content/docs/reference/bootstrap.mdx +++ b/docs/src/content/docs/reference/bootstrap.mdx @@ -5,7 +5,7 @@ description: All options for the flake-file bootstrap command. import { Aside } from '@astrojs/starlight/components'; -The bootstrap command lets you generate `flake.nix`, `unflake.nix`, or `npins/` from scratch — without being inside an existing flake. +The bootstrap command lets you generate `flake.nix`, `unflake.nix`, `nixlock.lock.nix`, or `npins/` from scratch — without being inside an existing flake. ```shell nix-shell https://github.com/vic/flake-file/archive/refs/heads/main.zip \ @@ -21,6 +21,7 @@ The `flake-file.sh` shell provides these commands: | `write-flake` | Generate a `flake.nix` file | | `write-inputs` | Generate an `inputs.nix` expression (for debugging) | | `write-unflake` | Generate `unflake.nix` via [unflake](https://codeberg.org/goldstein/unflake) | +| `write-nixlock` | Generate `nixlock.lock.nix` via [nixlock](https://codeberg.org/FrdrCkII/nixlock) | | `write-npins` | Generate/update `npins/` directory via [npins](https://github.com/andir/npins) | ## Arguments diff --git a/docs/src/content/docs/tutorials/bootstrap.mdx b/docs/src/content/docs/tutorials/bootstrap.mdx index f09454f..7e76d97 100644 --- a/docs/src/content/docs/tutorials/bootstrap.mdx +++ b/docs/src/content/docs/tutorials/bootstrap.mdx @@ -21,14 +21,14 @@ You can create a `flake.nix` from scratch — without running inside an existing # Write a minimal flake-file.nix file (or copy a flake.nix of yours) echo '{ inputs.flake-file.url = "github:vic/flake-file"; }' > flake-file.nix -# Generate flake.nix or unflake.nix or npins from flake-file.nix +# Generate flake.nix or unflake.nix or npins or nixlock from flake-file.nix nix-shell https://github.com/vic/flake-file/archive/refs/heads/main.zip \ -A flake-file.sh --run write-flake --arg modules ./flake-file.nix ``` > See also: all [bootstrap command args](/reference/bootstrap) -Replace `write-flake` with `write-inputs`, `write-unflake`, or `write-npins` to target a different backend. +Replace `write-flake` with `write-inputs`, `write-unflake`, `write-nixlock`, or `write-npins` to target a different backend. ## Using a modules directory diff --git a/docs/src/content/docs/tutorials/migrate-no-flakes.mdx b/docs/src/content/docs/tutorials/migrate-no-flakes.mdx index 6c9aad1..14e8e5c 100644 --- a/docs/src/content/docs/tutorials/migrate-no-flakes.mdx +++ b/docs/src/content/docs/tutorials/migrate-no-flakes.mdx @@ -12,6 +12,7 @@ of tools for that in the ecosystem. flake-file has support for [`unflake`](https://codeberg.org/goldstein/unflake) +and [`nixlock`](https://codeberg.org/FrdrCkII/nixlock) and [`npins`](https://github.com/andir/npins) send PR for others. diff --git a/modules/bootstrap/default.nix b/modules/bootstrap/default.nix index 6e75ab3..2152892 100644 --- a/modules/bootstrap/default.nix +++ b/modules/bootstrap/default.nix @@ -40,6 +40,7 @@ let ./../options ./../npins ./../unflake + ./../nixlock ./../write-inputs.nix ./../write-flake.nix ./../flake-options.nix diff --git a/modules/default.nix b/modules/default.nix index 146bca0..7ddea51 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -8,6 +8,7 @@ let import-tree npins unflake + nixlock flake-options ; }; @@ -29,6 +30,11 @@ let ./unflake ]; + nixlock.imports = [ + base + ./nixlock + ]; + default.imports = [ base ./write-flake.nix @@ -67,6 +73,11 @@ let path = ./../templates/unflake; }; + templates.nixlock = { + description = "nixlock template"; + path = ./../templates/nixlock; + }; + templates.dendritic = { description = "dendritic template"; path = ./../templates/dendritic; diff --git a/modules/nixlock/default.nix b/modules/nixlock/default.nix new file mode 100644 index 0000000..df888e2 --- /dev/null +++ b/modules/nixlock/default.nix @@ -0,0 +1,155 @@ +{ lib, config, ... }: +let + inherit (config) flake-file; + inherit (import ../lib.nix lib) inputsExpr; + + inputs = inputsExpr flake-file.inputs; + + nixlock-source = fetchTarball { + url = flake-file.nixlock.url; + sha256 = flake-file.nixlock.sha256; + }; + + nlLibs = (import "${nixlock-source}/${flake-file.nixlock.version}").libs; + + parseGithub = + path: + let + parts = lib.splitString "/" path; + owner = builtins.elemAt parts 0; + repo = builtins.elemAt parts 1; + ref = if builtins.length parts > 2 then builtins.elemAt parts 2 else "HEAD"; + in + { + type = "gitArchive"; + url = "https://github.com/${owner}/${repo}"; + inherit ref; + }; + + parseGitlab = + path: + let + parts = lib.splitString "/" path; + owner = builtins.elemAt parts 0; + repo = builtins.elemAt parts 1; + ref = if builtins.length parts > 2 then builtins.elemAt parts 2 else "HEAD"; + in + { + type = "gitArchive"; + url = "https://gitlab.com/${owner}/${repo}"; + inherit ref; + }; + + flakeUrlToNixlock = + url: + let + scheme = builtins.head (lib.splitString ":" url); + rest = lib.concatStringsSep ":" (builtins.tail (lib.splitString ":" url)); + in + if scheme == "github" then + parseGithub rest + else if scheme == "gitlab" then + parseGitlab rest + else if lib.hasPrefix "git+" url then + { + type = "git"; + url = lib.removePrefix "git+" url; + ref = "HEAD"; + } + else if lib.hasPrefix "http" url then + { + type = "archive"; + inherit url; + } + else + null; + + toNixlockInput = _name: input: if input ? url then flakeUrlToNixlock input.url else null; + + inputsFile = lib.filterAttrs (_: v: v != null) (lib.mapAttrs toNixlockInput inputs); + + lockListFor = + upType: lockFile: + lib.filterAttrs ( + name: value: + !(lockFile ? ${name}) + || value != lockFile.${name}.meta or { } + || (if upType == "update" then !(value.isFreeze or false) else false) + ) inputsFile; + + shellFor = + upType: lockFile: lockFileName: + let + entries = lockListFor upType lockFile; + in + nlLibs.toLockShell { + inherit lockFile lockFileName; + inputsFile = entries; + cmds = lib.concatStringsSep "\n" ( + lib.mapAttrsToList (n: v: nlLibs.types.${v.type}.fresh n v) entries + ); + }; + + write-nixlock = + pkgs: + let + rootPath = flake-file.intoPath; + lockFileName = flake-file.nixlock.lockFileName; + lockScript = shellFor "lock" { } lockFileName; + updateScript = shellFor "update" { } lockFileName; + in + pkgs.writeShellApplication { + name = "write-nixlock"; + excludeShellChecks = [ + "SC2016" + "SC2086" + "SC2089" + "SC2090" + ]; + runtimeInputs = with pkgs; [ + nix + nixfmt + git + nix-prefetch-git + curl + coreutils + gnugrep + gnused + gawk + jq + ]; + text = '' + cd ${rootPath} + case "''${1:-lock}" in + lock) ${lockScript} ;; + update) ${updateScript} ;; + *) echo "usage: write-nixlock [lock|update]" >&2; exit 1 ;; + esac + ''; + }; +in +{ + config.flake-file.apps = { inherit write-nixlock; }; + options.flake-file.nixlock = { + url = lib.mkOption { + type = lib.types.str; + description = "nixlock archive url"; + default = "https://codeberg.org/FrdrCkII/nixlock/archive/dad9155634ce5d5183429daaeef2bbf6de9afcbf.tar.gz"; + }; + sha256 = lib.mkOption { + type = lib.types.str; + description = "nixlock archive sha256"; + default = "sha256:0bycgfdar1xcxgbp75r7bpmfvm2qh8206q2h2vsx5qn8fr39x0li"; + }; + version = lib.mkOption { + type = lib.types.str; + description = "nixlock version to load"; + default = "v3"; + }; + lockFileName = lib.mkOption { + type = lib.types.str; + description = "nixlock lockfile name"; + default = "nixlock.lock.nix"; + }; + }; +} diff --git a/templates/nixlock/README.md b/templates/nixlock/README.md new file mode 100644 index 0000000..05e3d29 --- /dev/null +++ b/templates/nixlock/README.md @@ -0,0 +1,19 @@ +# Nixlock + +This template is an example of using `flake-file.inputs` in a non-flakes project. + +It uses [nixlock](https://codeberg.org/FrdrCkII/nixlock) to pin and fetch inputs defined as options inside `./modules`. + +## Generate nixlock + +The following command is a convenience for generating `nixlock.lock.nix`: + +```shell +nix-shell . -A flake-file.sh --run write-nixlock +``` + +You can also the `update` command. + +```shell +nix-shell . -A flake-file.sh --run 'write-nixlock update' +``` diff --git a/templates/nixlock/default.nix b/templates/nixlock/default.nix new file mode 100644 index 0000000..d16c6f0 --- /dev/null +++ b/templates/nixlock/default.nix @@ -0,0 +1,30 @@ +let + outputs = + inputs: + (inputs.nixpkgs.lib.evalModules { + modules = [ (inputs.import-tree ./modules) ]; + specialArgs = { inherit inputs; }; + }).config; + + input-overrides = { + # uncomment for local checkout on CI + # flake-file = import ./../../modules; + }; + + with-inputs = import (fetchTarball { + url = "https://github.com/vic/with-inputs/archive/f19ccc093928f4987ab56534e0de37b25d8f5817.zip"; + sha256 = "sha256:0bcfic6myy2qmyj40kxpxv04hp925l9b0wkd507v69d070qsg285"; + }); + + nixlock-inputs = builtins.mapAttrs ( + _n: v: + v + // { + outPath = fetchTarball { + url = v.lock.url; + sha256 = v.lock.hash; + }; + } + ) (import ./nixlock.lock.nix); +in +with-inputs nixlock-inputs input-overrides outputs diff --git a/templates/nixlock/modules/default.nix b/templates/nixlock/modules/default.nix new file mode 100644 index 0000000..5e8a931 --- /dev/null +++ b/templates/nixlock/modules/default.nix @@ -0,0 +1,10 @@ +{ inputs, ... }: +{ + imports = [ inputs.flake-file.flakeModules.nixlock ]; + + flake-file.inputs = { + flake-file.url = "github:vic/flake-file"; + import-tree.url = "github:vic/import-tree"; + nixpkgs.url = "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz"; + }; +} diff --git a/templates/nixlock/nixlock.lock.nix b/templates/nixlock/nixlock.lock.nix new file mode 100644 index 0000000..aed91b6 --- /dev/null +++ b/templates/nixlock/nixlock.lock.nix @@ -0,0 +1,35 @@ +{ + "flake-file" = { + "lock" = { + "hash" = "sha256-qIpm5BtK3EkqlGXBG0jCZ3sg3gdxyPxI10iubZwMGFk="; + "url" = "https://github.com/vic/flake-file/archive/8a5c8771ac5be1af11192bcd88e6a1cdabd038a5.tar.gz"; + }; + "meta" = { + "ref" = "HEAD"; + "type" = "gitArchive"; + "url" = "https://github.com/vic/flake-file"; + }; + }; + "import-tree" = { + "lock" = { + "hash" = "sha256-AkfVgWWxt1pa1SlfKzcL1oQpMzgP70U3fBtzXqEGOms="; + "url" = + "https://github.com/vic/import-tree/archive/78c35e32f2b499c25e0671e41662537a6b1edbf0.tar.gz"; + }; + "meta" = { + "ref" = "HEAD"; + "type" = "gitArchive"; + "url" = "https://github.com/vic/import-tree"; + }; + }; + "nixpkgs" = { + "lock" = { + "hash" = "sha256-OgUF+EoJ36hz3jo8qBuizb8suT0mu1n7mzmcGdeOjWE="; + "url" = "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz"; + }; + "meta" = { + "type" = "archive"; + "url" = "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz"; + }; + }; +} diff --git a/templates/npins/default.nix b/templates/npins/default.nix index 9c14086..e7161d6 100644 --- a/templates/npins/default.nix +++ b/templates/npins/default.nix @@ -1,26 +1,24 @@ let outputs = inputs: - let - nixpkgs = inputs.nixpkgs or (import { }); - import-tree = inputs.import-tree or (import ); - in - (nixpkgs.lib.evalModules { - modules = [ (import-tree ./modules) ]; + (inputs.nixpkgs.lib.evalModules { + modules = [ (inputs.import-tree ./modules) ]; specialArgs = { inherit inputs; - self = inputs.self or { }; + self = inputs.self; }; }).config; - withInputs = - inputs: outputs: - outputs ( - inputs - // { - # uncomment on CI for local checkout - # flake-file = import ./../../modules; - } - ); + with-inputs = import (builtins.fetchTarball { + url = "https://github.com/vic/with-inputs/archive/f19ccc093928f4987ab56534e0de37b25d8f5817.zip"; + sha256 = "sha256:0bcfic6myy2qmyj40kxpxv04hp925l9b0wkd507v69d070qsg285"; + }); + + inputs-overrides ={ + # uncomment on CI for local checkout + # flake-file = import ./../../modules; + }; + + sources = import ./npins; in -import ./with-inputs.nix withInputs outputs +with-inputs sources inputs-overrides outputs diff --git a/templates/npins/with-inputs.nix b/templates/npins/with-inputs.nix deleted file mode 100644 index 193ae03..0000000 --- a/templates/npins/with-inputs.nix +++ /dev/null @@ -1,40 +0,0 @@ -let - hasSources = builtins.pathExists ./npins; - sources = if hasSources then import ./npins else { }; - selfInputs = builtins.mapAttrs (name: value: mkInputs name value) sources; - # from Nixlock: https://codeberg.org/FrdrCkII/nixlock/src/branch/main/default.nix - mkInputs = - name: sourceInfo: - let - flakePath = sourceInfo.outPath + "/flake.nix"; - isFlake = sources.${name}.flake or true; - in - if isFlake && builtins.pathExists flakePath then - let - flake = import (sourceInfo.outPath + "/flake.nix"); - inputs = builtins.mapAttrs (name: _value: selfInputs.${name}) (flake.inputs or { }); - outputs = flake.outputs (inputs // { inherit self; }); - self = - sourceInfo - // outputs - // { - _type = "flake"; - inherit inputs outputs sourceInfo; - }; - in - self - else - sourceInfo - // { - inherit sourceInfo; - }; -in -selfInputs -// { - __functor = - selfInputs: outputs: - let - self = outputs (selfInputs // { inherit self; }); - in - self; -}