diff --git a/.github/workflows/update-module-docs.yml b/.github/workflows/update-module-docs.yml new file mode 100644 index 00000000..c8d931d7 --- /dev/null +++ b/.github/workflows/update-module-docs.yml @@ -0,0 +1,51 @@ +name: Update module docs +on: + workflow_dispatch: # allows manual triggering + +jobs: + update-docs: + if: github.repository_owner == 'astro' + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Install Nix + uses: cachix/install-nix-action@v23 + with: + extra_nix_config: | + access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} + + - name: Set environment variables + shell: bash + run: | + echo "GIT_AUTHOR_NAME=github-actions[bot]" >> $GITHUB_ENV + echo "GIT_AUTHOR_EMAIL=" >> $GITHUB_ENV + echo "GIT_COMMITTER_NAME=github-actions[bot]" >> $GITHUB_ENV + echo "GIT_COMMITTER_EMAIL=" >> $GITHUB_ENV + + - name: Update docs + shell: bash + run: | + nix run .#update-module-docs + + - name: Check for changes + id: git-check + shell: bash + run: | + git diff --quiet || echo "changes_detected=true" >> $GITHUB_OUTPUT + + - name: Commit changes + if: steps.git-check.outputs.changes_detected + shell: bash + run: | + git commit --message "Update module docs" || true + + - name: Push changes + if: steps.git-check.outputs.changes_detected + uses: ad-m/github-push-action@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + branch: ${{ github.ref }} diff --git a/README.md b/README.md index 6cbcd8dc..30e2a9aa 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,13 @@ in ## Usage with Nix Flakes -```nix +### Using build module (recommended) + +nix-openwrt-imagebuilder exposes a builder module that leverages [nixpkgs' module system](https://nixos.org/manual/nixpkgs/stable/#module-system) to provide easy to use, self-documenting interface with strict option definitions, type-checks. + +See documentation for all available options in [docs](docs/). + +```nix { inputs = { openwrt-imagebuilder.url = "github:astro/nix-openwrt-imagebuilder"; @@ -67,36 +73,90 @@ in packages.x86_64-linux.my-router = let pkgs = nixpkgs.legacyPackages.x86_64-linux; - - profiles = openwrt-imagebuilder.lib.profiles { inherit pkgs; }; - - config = profiles.identifyProfile "avm_fritz7412" // { - # add package to include in the image, ie. packages that you don't - # want to install manually later - packages = [ "tcpdump" ]; - - disabledServices = [ "dnsmasq" ]; - - # include files in the images. - # to set UCI configuration, create a uci-defauts scripts as per - # official OpenWRT ImageBuilder recommendation. - files = pkgs.runCommand "image-files" {} '' - mkdir -p $out/etc/uci-defaults - cat > $out/etc/uci-defaults/99-custom < + + Code + + ```nix + { + inputs = { + openwrt-imagebuilder.url = "github:astro/nix-openwrt-imagebuilder"; + }; + outputs = { self, nixpkgs, openwrt-imagebuilder }: { + packages.x86_64-linux.my-router = + let + pkgs = nixpkgs.legacyPackages.x86_64-linux; + + profiles = openwrt-imagebuilder.lib.profiles { inherit pkgs; }; + + config = profiles.identifyProfile "avm_fritz7412" // { + # add package to include in the image, ie. packages that you don't + # want to install manually later + packages = [ "tcpdump" ]; + + disabledServices = [ "dnsmasq" ]; + + # include files in the images. + # to set UCI configuration, create a uci-defauts scripts as per + # official OpenWRT ImageBuilder recommendation. + files = pkgs.runCommand "image-files" {} '' + mkdir -p $out/etc/uci-defaults + cat > $out/etc/uci-defaults/99-custom < + ## Refreshing hashes **downloads.openwrt.org** appears to be never at rest. That's why we diff --git a/builder/build-module.nix b/builder/build-module.nix new file mode 100644 index 00000000..422e6bab --- /dev/null +++ b/builder/build-module.nix @@ -0,0 +1,16 @@ +{ lib }: +let + # Inspired by https://github.com/viperML/wrapper-manager/blob/c936f9203217e654a6074d206505c16432edbc70/default.nix + eval = { pkgs, modules }: lib.evalModules { + modules = [ + { _module.args = { inherit pkgs; }; } + ./module-options.nix + ./module-config.nix + ] ++ modules; + }; +in +{ + # Using functor here to provide a debug output with `eval` if needed, but by default just build the eval the result + inherit eval; + __functor = self: args: (self.eval args).config.build.out; +} diff --git a/builder/module-config.nix b/builder/module-config.nix new file mode 100644 index 00000000..47bef07e --- /dev/null +++ b/builder/module-config.nix @@ -0,0 +1,178 @@ +{ config, pkgs, lib, ... }: +let + inherit (import ../files.nix { + inherit pkgs; + inherit (config) release; + inherit (config.hardware) target; + variant = config.hardware.subtarget; + packagesArch = config.hardware.arch; + feedsSha256 = config.feedsHash; + kmodsSha256 = config.kmodsHash; + sha256 = config.sumsFileHash; + }) variantFiles profiles expandDeps corePackages packagesByFeed allPackages; + + + customPackagesFormatted = config.packages.include ++ (builtins.map (pkg: "-${pkg}") config.packages.exclude); + + requiredPackages = + profiles.default_packages or (builtins.attrNames packagesByFeed.base ++ builtins.attrNames corePackages) ++ + profiles.profiles.${config.hardware.profile}.device_packages or [ ] ++ + customPackagesFormatted; + + allRequiredPackageFiles = expandDeps allPackages requiredPackages; + + mkPackageSymlink = pname: + let + package = allPackages.${pname}; + in + lib.optional (package.type == "real") '' + [ -e "packages/${package.filename}" ] || ln -s ${package.file} "packages/${package.filename}" + ''; + + symlinkPackages = pkgs.writeScript "symlink-openwrt-packages" ( + lib.concatLines ( + lib.foldl' (acc: pname: acc ++ (mkPackageSymlink pname)) [ ] allRequiredPackageFiles + ) + ); + + mkCopyStatement = file: '' + ( + target_rel=${lib.escapeShellArg file.target} + target="files/''${target_rel#/}" + ${lib.optionalString (lib.pathIsRegularFile file.source) '' + mkdir -p "$(dirname "''${target}")" + ''} + cp -r --no-preserve=all "${file.source}" "''${target}" + ) + ''; + + copyFiles = pkgs.writeScript "copy-openwrt-files" ( + lib.concatLines (builtins.map mkCopyStatement config.files) + ); + + buildFlags = { + ".DEFAULT_GOAL" = "image"; + "PROFILE" = config.hardware.profile; + } // lib.optionalAttrs (customPackagesFormatted != [ ]) { + "PACKAGES" = lib.concatStringsSep " " customPackagesFormatted; + } // lib.optionalAttrs (config.disabledServices != [ ]) { + "DISABLED_SERVICES" = lib.concatStringsSep " " config.disabledServices; + } // lib.optionalAttrs (config.files != [ ]) { + "FILES" = "./files"; + } // lib.optionalAttrs (config.image.rootFsPartSize != null) { + "ROOTFS_PARTSIZE" = config.image.rootFsPartSize; + } // lib.optionalAttrs (config.image.extraName != null) { + "EXTRA_IMAGE_NAME" = config.image.extraName; + } // lib.optionalAttrs (config.image.addLocalKey != null) { + "ADD_LOCAL_KEY" = lib.boolToString config.image.addLocalKey; + } // config.build.extraFlags; + + buildFlagsArray = lib.concatStringsSep " " (lib.mapAttrsToList (name: value: ''${name}="${builtins.toString value}"'') buildFlags); + + name = lib.concatStringsSep "-" ( + [ "openwrt" config.release ] ++ + lib.optional (config.image.extraName != null) config.image.extraName ++ + [ config.hardware.target config.hardware.subtarget config.hardware.profile ] + ); + + src = + let + inherit (pkgs.stdenv.hostPlatform) uname; + imageBuilderPrefix = "openwrt-imagebuilder-${lib.optionalString (config.release != "snapshot") "${config.release}-"}"; + baseFileName = "${imageBuilderPrefix}${config.hardware.target}-${config.hardware.subtarget}.${uname.system}-${uname.processor}"; + possibleFileNames = builtins.map (extension: "${baseFileName}${extension}") [ ".tar.zst" ".tar.xz" ]; + matches = builtins.filter (fileName: builtins.hasAttr fileName variantFiles) possibleFileNames; + in + if matches != [ ] + then builtins.getAttr (builtins.elemAt matches 0) variantFiles + else + builtins.throw '' + No valid image builder found! + Expected filenames: ${lib.concatStringsSep ", " possibleFileNames} + ''; +in +{ + + config = { + build.out = pkgs.stdenv.mkDerivation ({ + inherit name src; + + nativeBuildInputs = with pkgs; [ + bash + bzip2 + dtc + file + getopt + git + ncurses + perl + python311 + rsync + unzip + wget + which + zlib + zstd + ] ++ lib.optional (lib.versionOlder config.release "21" && config.release != "snapshot") python2; + + postPatch = '' + patchShebangs scripts staging_dir/host/bin + substituteInPlace rules.mk \ + --replace "SHELL:=/usr/bin/env bash" "SHELL:=${pkgs.runtimeShell}" \ + --replace "/usr/bin/env true" "${pkgs.coreutils}/bin/true" \ + --replace "/usr/bin/env false" "${pkgs.coreutils}/bin/false" + ''; + + configurePhase = '' + runHook preConfigure + + ${symlinkPackages} + echo "src imagebuilder file:packages" > repositories.conf + + ${copyFiles} + + # if the user provided key-build, key-build.pub and key-build.ucert in /run/openwrt use it + # NOTE: they need to be owned by group nixbld and have permission 440 + # NOTE2: auto-allocate-uids must be disabled because of bug https://github.com/NixOS/nix/issues/9276 + if [[ -d /run/openwrt ]]; then + for file in /run/openwrt/*; do + ln -s $file $(basename $file) + done + fi + '' + lib.optionalString (config.files != [ ]) '' + ${copyFiles} + '' + lib.optionalString (lib.versionOlder config.release "19" && config.release != "snapshot") '' + # hack around broken check for gcc + touch staging_dir/host/.prereq-build + '' + '' + + runHook postConfigure + ''; + + preBuild = '' + buildFlagsArray+=(${buildFlagsArray}) + ''; + + installPhase = '' + runHook preInstall + + mkdir -p $out/nix-support + pushd bin/targets/${config.hardware.target}/${config.hardware.subtarget} + for src in *; do + dst="$out/$src" + cp -ar "$src" "$dst" + if [ -f "$dst" ]; then + filename=$(basename "$dst") + echo "file ''${filename##*.} $dst" >> $out/nix-support/hydra-build-products + fi + done + popd + + runHook postInstall + ''; + + dontFixup = true; + + } // config.build.extraDerivationArgs); + }; +} diff --git a/builder/module-docs.nix b/builder/module-docs.nix new file mode 100644 index 00000000..fae8b5b6 --- /dev/null +++ b/builder/module-docs.nix @@ -0,0 +1,77 @@ +{ pkgs, lib, ... }: +let + allModules = [ ./module-options.nix ]; + + mkNixosOptionsDoc = module: pkgs.nixosOptionsDoc { + inherit (lib.evalModules { + modules = [ + ({ lib, ... }: { + options._module.args = lib.mkOption { + internal = true; # Hide `_module` from the docs + }; + + config._module = { + check = false; # Don't check for unset variables + }; + }) + + module + ]; + }) options; + + transformOptions = opt: opt // { + declarations = builtins.map + (path: + let + root = builtins.toString ../.; + relativePath = lib.removePrefix root path; + in + if lib.hasPrefix root path + then { + name = "nix-openwrt-imagebuilder${relativePath}"; + url = "https://github.com/astro/nix-openwrt-imagebuilder/blob/main${relativePath}"; + } + else path + ) + opt.declarations; + }; + }; + + allOptions = builtins.map + (path: { + name = builtins.replaceStrings [ ".nix" ] [ "" ] (builtins.baseNameOf path); + options = mkNixosOptionsDoc path; + }) + allModules; + + packages = + let + mkDocsSymlink = { name, options }: "ln -s ${options.optionsCommonMark} $out/${name}.md"; + + mkJSONSymlink = { name, options }: "ln -s ${options.optionsJSON}/share/doc/nixos/options.json $out/${name}.json"; + + mkPackage = mkSymlink: suffix: pkgs.runCommand "nix-openwrt-imagebuilder-modules-${suffix}" { } '' + mkdir $out + + ${lib.concatLines (builtins.map mkSymlink allOptions)} + ''; + in + rec { + modules-docs = mkPackage mkDocsSymlink "docs"; + modules-json = mkPackage mkJSONSymlink "json"; + + update-module-docs = pkgs.writeShellApplication { + name = "update-module-docs"; + runtimeInputs = [ pkgs.gitMinimal ]; + text = '' + ROOT=$(git rev-parse --show-toplevel) + mkdir -p "$ROOT/docs" + + for file in ${modules-docs}/*.md; do + cp --no-preserve=mode,ownership "$file" "$ROOT/docs/" + done + ''; + }; + }; +in +packages diff --git a/builder/module-options.nix b/builder/module-options.nix new file mode 100644 index 00000000..29396aef --- /dev/null +++ b/builder/module-options.nix @@ -0,0 +1,301 @@ +{ config, lib, ... }: +# TODO: add support for assertions +let + latestRelease = import ../latest-release.nix; + + releaseHashesFile = ../hashes/${config.release}.nix; + releaseHashes = + if (builtins.pathExists releaseHashesFile) + then import releaseHashesFile + else builtins.throw "No hashed information found about OpenWRT ${config.release}"; + hashedTarget = releaseHashes.targets.${config.hardware.target}.${config.hardware.subtarget} or + (builtins.throw "No hashed information for OpenWRT ${config.release} found for ${config.hardware.target}/${config.hardware.subtarget}"); + hashedFeeds = releaseHashes.packages.${config.hardware.arch} or + (builtins.throw "No hashed information for OpenWRT ${config.release} about packages found for ${config.hardware.arch} architecture"); + kmodsFeeds = + if (lib.versionAtLeast config.release "24") + then releaseHashes.kmods.${config.hardware.target}.${config.hardware.subtarget} or + (builtins.throw "No hashed information for OpenWRT ${config.release} about Kmods found for ${config.hardware.target}/${config.hardware.subtarget}") + else { }; + + defaultSumsFileHash = hashedTarget.sha256; + + # TODO: get rid of `pkgs` + profiles = import ../profiles.nix { pkgs = null; inherit (config) release; }; + detectedProfile = profiles.identifyProfile config.hardware.profile; + # TODO: move arch to profiles + detectedArch = hashedTarget.packagesArch; + + + fileSubmodule = lib.types.submodule { + options = { + target = lib.mkOption { + type = lib.types.nonEmptyStr; + example = "/etc/uci-defaults/99-custom"; + description = '' + Path within the generated OpenWRT image to put the file + ''; + }; + + source = lib.mkOption { + type = lib.types.path; + example = lib.literalExpression "./uci-script"; + description = '' + Path to the source file or folder. + ''; + }; + }; + }; +in +{ + # Inspired by https://git.sr.ht/~tomeon/nix-openwrt-imagebuilder-module/tree/6c2a5fc19c5a6fd532b99c69e5b4ce14adfd80fe/item/module.nix + options = { + release = lib.mkOption { + type = lib.types.nonEmptyStr; + default = latestRelease; + defaultText = lib.literalMD "Value of `latest-release.nix`"; + example = "23.05.3"; + description = '' + The OpenWRT release to use. + ''; + }; + + hardware = { + profile = lib.mkOption { + type = lib.types.nonEmptyStr; + example = "asus_rt-ax59u"; + description = '' + The OpenWRT Device ID. + + Can be obtained from {command}`make info`. See [OpenWRT docs](https://openwrt.org/docs/guide-user/additional-software/imagebuilder#available_profiles) for more info. + + Also present in the field `profiles[].id` in file `.overview.json` on the release page + + For release `23.05.3`, for example: + + + For `snapshot`: + + ''; + }; + + target = lib.mkOption { + type = lib.types.nonEmptyStr; + default = detectedProfile.target; + defaultText = lib.literalMD "Target derived from {option}`hardware.profile`"; + example = "mediatek"; + description = '' + The OpenWRT target (board) without subtarget. + ''; + }; + + subtarget = lib.mkOption { + type = lib.types.nullOr lib.types.nonEmptyStr; + default = detectedProfile.variant; + defaultText = lib.literalMD "Subtarget derived from {option}`hardware.profile`"; + example = "filogic"; + description = '' + The OpenWRT subtarget without target (board). + ''; + }; + + arch = lib.mkOption { + type = lib.types.nullOr lib.types.nonEmptyStr; + default = detectedArch; + defaultText = lib.literalMD "Arch derived from {option}`hardware.profile`"; + example = "aarch64_cortex-a53"; + description = '' + Architecture of board's CPU. + + :::{.warning} + For OpenWRT <19 this is a required field! + ::: + ''; + }; + + }; + + packages = { + include = lib.mkOption { + type = lib.types.listOf lib.types.nonEmptyStr; + default = [ ]; + example = lib.options.literalExpression '' + [ + "curl" + "iperf3" + ] + ''; + description = '' + A list of package names to include in the generated image. + ''; + }; + + exclude = lib.mkOption { + type = lib.types.listOf lib.types.nonEmptyStr; + default = [ ]; + example = lib.options.literalExpression '' + [ + "luci" + ] + ''; + description = '' + A list of package names to exclude from the generated image. + ''; + }; + }; + + files = lib.mkOption { + type = lib.types.listOf fileSubmodule; + default = [ ]; + example = lib.literalExpression '' + [ + { + source = ./uci-script; + target = "/etc/uci-defaults/99-custom"; + } + ] + ''; + description = '' + List of files to include in the generated image. + + The path must be either a regular file or a directory of files. + + :::{.warning} + Symlinks are not supported! + ::: + ''; + }; + + disabledServices = lib.mkOption { + type = lib.types.listOf lib.types.nonEmptyStr; + default = [ ]; + example = lib.literalExpression '' + [ + "umount" + ] + ''; + description = '' + A list of services to disable + ''; + }; + + image = { + extraName = lib.mkOption { + type = lib.types.nullOr lib.types.nonEmptyStr; + default = null; + example = "test-1"; + description = '' + Arbitrary string to add to the generated OpenWRT image file name. + + Specify `null` if you want to use default from OpenWRT imagebuilder + ''; + }; + + rootFsPartSize = lib.mkOption { + type = lib.types.nullOr lib.types.ints.positive; + default = null; + example = 8; + description = '' + Override the default rootfs partition size in MegaBytes + + Specify `null` if you want to use default from OpenWRT imagebuilder + ''; + }; + + addLocalKey = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + default = null; + example = false; + description = '' + Store locally generated signing key in built images + + Specify `null` if you want to use default from OpenWRT imagebuilder + ''; + }; + }; + + sumsFileHash = lib.mkOption { + type = lib.types.nonEmptyStr; + default = defaultSumsFileHash; + example = "sha256-O/7C9+OlfTx+iSao/GITKgPktk9iqchRTQNNYsLil2g="; + internal = true; + description = '' + `sha256` sum of `sha256sums` file from OpenWRT + ''; + }; + + feedsHash = lib.mkOption { + type = lib.types.attrsOf lib.types.raw; + default = hashedFeeds; + example = lib.options.literalExpression '' + { + base.sha256 = "sha256-O2zArbz87CBZ0YDtk7NOF+lGknkZGE22Em0kmu6unI8="; + luci.sha256 = "sha256-Gjv3IG66u8K06YXA0c80VD4of1QLYaqshV1n69LftKo=" + packages.sha256 = "sha256-aESfuCkHkGAC4Hond0xSL5o2wA6JHbdZdBVL6UaLhY8="; + } + ''; + internal = true; + description = '' + A set of "feeds", where each value is a `sha256` sum of `Packages` file. + ''; + }; + + kmodsHash = lib.mkOption { + type = lib.types.attrsOf lib.types.raw; + default = kmodsFeeds; + example = lib.options.literalExpression '' + { + "6.6.67-1-a19d0a45cee591b95352ac365f8a784b".sha256 = "sha256-23n2qV9PDubOeGEf43i29o+qL5B9ZU4wQOYoanfPFSQ="; + "6.6.67-1-316f788de839e861f7fea23702a4776b".sha256 = "sha256-cM1S2NLATkxL3TzPzkCD1fEe36xf5C7sF4TPVPDIBGc="; + } + ''; + internal = true; + description = '' + A "feed", where each key is a kernel version and each value is a `sha256` sum of `Packages`. + + :::{.warning} + Must be created per target + subtarget combination. + ::: + ''; + }; + + build = { + extraDerivationArgs = lib.mkOption { + type = lib.types.raw; + default = { }; + description = '' + Extra arguments to pass to derivation + ''; + example = lib.literalExpression '' + postInstal = "mv $out/profile.json $out/result.json"; + ''; + internal = true; + }; + + extraFlags = lib.mkOption { + type = lib.types.attrsOf lib.types.str; + default = { }; + example = lib.literalExpression '' + { + "EXTRA_FLAG" = "example"; + } + ''; + description = '' + Extra arguments to pass to OpenWRT's Makefile + ''; + internal = true; + }; + + out = lib.mkOption { + type = lib.types.package; + internal = true; + readOnly = true; + description = '' + Built image + ''; + }; + }; + + }; + +} diff --git a/docs/module-options.md b/docs/module-options.md new file mode 100644 index 00000000..73801501 --- /dev/null +++ b/docs/module-options.md @@ -0,0 +1,396 @@ +## packages\.exclude + + + +A list of package names to exclude from the generated image\. + + + +*Type:* +list of non-empty string + + + +*Default:* +` [ ] ` + + + +*Example:* + +``` +[ + "luci" +] + +``` + +*Declared by:* + - [nix-openwrt-imagebuilder/builder/module-options\.nix](https://github.com/astro/nix-openwrt-imagebuilder/blob/main/builder/module-options.nix) + + + +## packages\.include + + + +A list of package names to include in the generated image\. + + + +*Type:* +list of non-empty string + + + +*Default:* +` [ ] ` + + + +*Example:* + +``` +[ + "curl" + "iperf3" +] + +``` + +*Declared by:* + - [nix-openwrt-imagebuilder/builder/module-options\.nix](https://github.com/astro/nix-openwrt-imagebuilder/blob/main/builder/module-options.nix) + + + +## disabledServices + +A list of services to disable + + + +*Type:* +list of non-empty string + + + +*Default:* +` [ ] ` + + + +*Example:* + +``` +[ + "umount" +] + +``` + +*Declared by:* + - [nix-openwrt-imagebuilder/builder/module-options\.nix](https://github.com/astro/nix-openwrt-imagebuilder/blob/main/builder/module-options.nix) + + + +## files + + + +List of files to include in the generated image\. + +The path must be either a regular file or a directory of files\. + +**Warning:** Symlinks are not supported! + + + +*Type:* +list of (submodule) + + + +*Default:* +` [ ] ` + + + +*Example:* + +``` +[ + { + source = ./uci-script; + target = "/etc/uci-defaults/99-custom"; + } +] + +``` + +*Declared by:* + - [nix-openwrt-imagebuilder/builder/module-options\.nix](https://github.com/astro/nix-openwrt-imagebuilder/blob/main/builder/module-options.nix) + + + +## files\.\*\.source + + + +Path to the source file or folder\. + + + +*Type:* +path + + + +*Example:* +` ./uci-script ` + +*Declared by:* + - [nix-openwrt-imagebuilder/builder/module-options\.nix](https://github.com/astro/nix-openwrt-imagebuilder/blob/main/builder/module-options.nix) + + + +## files\.\*\.target + + + +Path within the generated OpenWRT image to put the file + + + +*Type:* +non-empty string + + + +*Example:* +` "/etc/uci-defaults/99-custom" ` + +*Declared by:* + - [nix-openwrt-imagebuilder/builder/module-options\.nix](https://github.com/astro/nix-openwrt-imagebuilder/blob/main/builder/module-options.nix) + + + +## hardware\.arch + + + +Architecture of board’s CPU\. + +**Warning:** For OpenWRT \<19 this is a required field! + + + +*Type:* +null or non-empty string + + + +*Default:* +Arch derived from ` hardware.profile ` + + + +*Example:* +` "aarch64_cortex-a53" ` + +*Declared by:* + - [nix-openwrt-imagebuilder/builder/module-options\.nix](https://github.com/astro/nix-openwrt-imagebuilder/blob/main/builder/module-options.nix) + + + +## hardware\.profile + + + +The OpenWRT Device ID\. + +Can be obtained from ` make info `\. See [OpenWRT docs](https://openwrt\.org/docs/guide-user/additional-software/imagebuilder\#available_profiles) for more info\. + +Also present in the field ` profiles[].id ` in file ` .overview.json ` on the release page + +For release ` 23.05.3 `, for example: +[https://downloads\.openwrt\.org/releases/23\.05\.3/\.overview\.json](https://downloads\.openwrt\.org/releases/23\.05\.3/\.overview\.json) + +For ` snapshot `: +[https://downloads\.openwrt\.org/snapshots/\.overview\.json](https://downloads\.openwrt\.org/snapshots/\.overview\.json) + + + +*Type:* +non-empty string + + + +*Example:* +` "asus_rt-ax59u" ` + +*Declared by:* + - [nix-openwrt-imagebuilder/builder/module-options\.nix](https://github.com/astro/nix-openwrt-imagebuilder/blob/main/builder/module-options.nix) + + + +## hardware\.subtarget + + + +The OpenWRT subtarget without target (board)\. + + + +*Type:* +null or non-empty string + + + +*Default:* +Subtarget derived from ` hardware.profile ` + + + +*Example:* +` "filogic" ` + +*Declared by:* + - [nix-openwrt-imagebuilder/builder/module-options\.nix](https://github.com/astro/nix-openwrt-imagebuilder/blob/main/builder/module-options.nix) + + + +## hardware\.target + + + +The OpenWRT target (board) without subtarget\. + + + +*Type:* +non-empty string + + + +*Default:* +Target derived from ` hardware.profile ` + + + +*Example:* +` "mediatek" ` + +*Declared by:* + - [nix-openwrt-imagebuilder/builder/module-options\.nix](https://github.com/astro/nix-openwrt-imagebuilder/blob/main/builder/module-options.nix) + + + +## image\.addLocalKey + + + +Store locally generated signing key in built images + +Specify ` null ` if you want to use default from OpenWRT imagebuilder + + + +*Type:* +null or boolean + + + +*Default:* +` null ` + + + +*Example:* +` false ` + +*Declared by:* + - [nix-openwrt-imagebuilder/builder/module-options\.nix](https://github.com/astro/nix-openwrt-imagebuilder/blob/main/builder/module-options.nix) + + + +## image\.extraName + + + +Arbitrary string to add to the generated OpenWRT image file name\. + +Specify ` null ` if you want to use default from OpenWRT imagebuilder + + + +*Type:* +null or non-empty string + + + +*Default:* +` null ` + + + +*Example:* +` "test-1" ` + +*Declared by:* + - [nix-openwrt-imagebuilder/builder/module-options\.nix](https://github.com/astro/nix-openwrt-imagebuilder/blob/main/builder/module-options.nix) + + + +## image\.rootFsPartSize + + + +Override the default rootfs partition size in MegaBytes + +Specify ` null ` if you want to use default from OpenWRT imagebuilder + + + +*Type:* +null or (positive integer, meaning >0) + + + +*Default:* +` null ` + + + +*Example:* +` 8 ` + +*Declared by:* + - [nix-openwrt-imagebuilder/builder/module-options\.nix](https://github.com/astro/nix-openwrt-imagebuilder/blob/main/builder/module-options.nix) + + + +## release + + + +The OpenWRT release to use\. + + + +*Type:* +non-empty string + + + +*Default:* +Value of ` latest-release.nix ` + + + +*Example:* +` "23.05.3" ` + +*Declared by:* + - [nix-openwrt-imagebuilder/builder/module-options\.nix](https://github.com/astro/nix-openwrt-imagebuilder/blob/main/builder/module-options.nix) + + diff --git a/example-19.07.nix b/examples/example-19.07.nix similarity index 100% rename from example-19.07.nix rename to examples/example-19.07.nix diff --git a/examples/example-module.nix b/examples/example-module.nix new file mode 100644 index 00000000..1a6cfd12 --- /dev/null +++ b/examples/example-module.nix @@ -0,0 +1,32 @@ +{ pkgs +, build-module +}: +build-module { + inherit pkgs; + modules = [ + { + release = "23.05.5"; + hardware = { + profile = "tplink_archer-c7-v2"; + }; + packages = { + include = [ + "tcpdump" + "vxlan" + "kmod-vxlan" + ]; + }; + files = [ + { + source = pkgs.writeText "uci-defaults-99-custom" '' + uci -q batch << EOI + set system.@system[0].hostname='testap' + commit + EOI + ''; + target = "/etc/uci-defaults/99-custom"; + } + ]; + } + ]; +} diff --git a/example-x86-64.nix b/examples/example-x86-64.nix similarity index 100% rename from example-x86-64.nix rename to examples/example-x86-64.nix diff --git a/example.nix b/examples/example.nix similarity index 100% rename from example.nix rename to examples/example.nix diff --git a/files.nix b/files.nix index 2992aaa8..e2b08350 100644 --- a/files.nix +++ b/files.nix @@ -3,10 +3,13 @@ , release ? import ./latest-release.nix # OpenWRT target , target +# TODO: rename to subtarget , variant ? "generic" # Checksum of the `sha256sums` file +# TODO: rename to sha56sumsHash , sha256 # Checksum of a feed's `Packages` file +# TODO: rename to feedsHash , feedsSha256 # Attrset where key is kmodsTarget and value is checksum of `Packages` file. Required for OpenWRT >=24 , kmodsSha256 ? {} diff --git a/flake.nix b/flake.nix index 8e6630a7..9064c291 100644 --- a/flake.nix +++ b/flake.nix @@ -11,7 +11,7 @@ }; }; - outputs = inputs@{ flake-parts, systems, ... }: flake-parts.lib.mkFlake { inherit inputs; } ({ config, self, ... }: { + outputs = inputs@{ flake-parts, systems, ... }: flake-parts.lib.mkFlake { inherit inputs; } ({ config, self, lib, ... }: { systems = import systems; perSystem = { pkgs, ... }: rec { @@ -22,9 +22,11 @@ generate-all-hashes = pkgs.callPackage ./generate-all-hashes.nix { inherit generate-hashes; }; cached-profiles = pkgs.callPackage ./cached-profiles.nix { }; + inherit (pkgs.callPackage ./builder/module-docs.nix { }) modules-docs modules-json update-module-docs; + example-image = let - image = import ./example.nix rec { + image = import ./examples/example.nix rec { inherit pkgs; profiles = self.lib.profiles { inherit pkgs; @@ -39,7 +41,7 @@ example-x86-64-image = let - image = import ./example-x86-64.nix { + image = import ./examples/example-x86-64.nix { inherit pkgs; inherit (self.lib) build; }; @@ -48,8 +50,18 @@ pkgs.runCommand "example-x86-64-image" { } '' ln -s ${image} $out ''; + + example-image-module = + let + image = pkgs.callPackage ./examples/example-module.nix { inherit (self.lib) build-module; }; + in + # Wrap `image` once to avoid `nix flake show` breaking on IFD + pkgs.runCommand "example-image-module" { } '' + ln -s ${image} $out + ''; }; + checks = packages; }; @@ -58,6 +70,8 @@ build = import ./builder.nix; profiles = import ./profiles.nix; + + build-module = import ./builder/build-module.nix { inherit lib; }; }; hydraJobs = { inherit (self.packages.x86_64-linux) example-image; }; diff --git a/profiles.nix b/profiles.nix index c333f0b7..47d2757e 100644 --- a/profiles.nix +++ b/profiles.nix @@ -24,6 +24,7 @@ in rec { ) ) hashes.targets else + # TODO: check if file exists first import ./cached-profiles/${release}.nix; # filters hardware profiles from all boards.json files