{#─────────────────────────────────────────────────────────────────────────────┐
│ SPDX-FileCopyrightText: 2026 toastal <https://toast.al/contact/>             │
│ SPDX-License-Identifier: ISC                                                 │
└───────────────────────────────────────────────────────────────────────────#}/*
SPDX-FileCopyrightText: {{ maker_year_range }} toastal
SPDX-FileCopyrightText: {{ hackmates_year_range }} Nixtamal contributors
SPDX-License-Identifier: ISC

Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
& this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED “AS IS” & ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO
THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY & FITNESS. IN
NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
────────────────────────────────────────────────────────────────────────────────
┏┓╻+╻ ╱┏┳┓┏┓┏┳┓┏┓╻
┃┃┃┃┗━┓╹┃╹┣┫┃┃┃┣┫┃   This file was generated by Nixtamal.
╹┗┛╹╱ ╹ ╹ ╹╹╹ ╹╹╹┗┛  Do not edit as it will be overwritten.
────────────────────────────────────────────────────────────────────────────────
*/
{
	system ? null,
	bootstrap-nixpkgs ? null,
	bootstrap-nixpkgs-lock-name ? null,
	bootstrap-pkgs ? null,
}:

let lock = builtins.fromJSON (builtins.readFile ./lock.json); in
assert (lock.v == "{{ schema_version }}");
let
	isNonemptyString = x: builtins.isString x && x != "";

	isNonemptyList = xs: builtins.isList xs && xs != [ ];

	hash-token = {
		{%- for (enum_key, hash_algo) in hash_tokens %}
		"{{ enum_key }}" = "{{ hash_algo }}";
		{%- endfor %}
	};
{% if using_patches %}
{%- if local_patches %}
	local-patches = {
		{% for (patch_name, patch_path) in local_patches -%}
		"{{ patch_name }}" = {{ patch_path }};
		{%- endfor %}
	};
{%- else %}
	local-patches = { };
{%- endif %}
{% endif %}
	try-fetch = input-name: fetcher:
		let
			try-fetch' = failed-urls: url: urls:
				let result = builtins.tryEval (fetcher url); in
				if result.success then
					result.value
				else
					let failed-urls' = [ url ] ++ failed-urls; in
					if urls == [ ] then
						let fus = builtins.concatStringsSep " " failed-urls'; in
						throw "Input 「${input-name}」fetchable @ [ ${fus} ]"
					else
						try-fetch' failed-urls' (builtins.head urls) (builtins.tail urls);
		in
		try-fetch' [ ];
{% if fetchers.file is defined %}
	builtin-fetch-url = { input-name, name, kind, hash }:
		try-fetch input-name (url:
			builtins.fetchurl ({
				inherit url;
				${hash-token.${builtins.toString hash.al}} = hash.vl;
			}
			// (if isNonemptyString name then { inherit name; } else { }))
		) kind.ur kind.ms;
{% endif %}
{%- if fetchers.archive is defined %}
	builtin-fetch-tarball = { input-name, name, kind, hash }:
		try-fetch input-name (url:
			builtins.fetchTarball ({
				inherit url;
				${hash-token.${builtins.toString hash.al}} = hash.vl;
			}
			// (if isNonemptyString name then { inherit name; } else { }))
		) kind.ur kind.ms;
{% endif %}
{%- if fetchers.git is defined %}
	builtin-fetch-git = { input-name, name, kind }:
		let
			ref =
				let
					type = builtins.elemAt kind.rf 0;
					valu = builtins.elemAt kind.rf 1;
				in
				if type == 0 then # ref
					valu
				else if type == 1 then # branch
					"refs/heads/${valu}"
				else if type == 2 then # tag
					"refs/tags/${valu}"
				else
					throw "Unsupported reference type “${builtins.toString type}”.";
		in
		try-fetch input-name (url:
			let
				args = {
					inherit url ref;
					rev = kind.lr;
					submodules = kind.sm;
					shallow = true;
				}
				// (if builtins.compareVersions builtins.nixVersion "2.26" < 0 then { } else { lfs = kind.lf; })
				// (if isNonemptyString name then { inherit name; } else { });
			in
			builtins.fetchGit args
		) kind.rp kind.ms;
{%- endif %}

	builtin-to-input = input-name: input:
		let
			name = input.sn;
			hash = input.ha;
			kind = builtins.elemAt input.kd 1;
			k = builtins.head input.kd;
		in
{%- for (fetcher, enum) in builtin_fetchers %}
		{% if not loop.first -%}else {% endif -%}if k == {{ enum }} then
			{%- switch fetcher -%}
			{%- case "file" %}
			builtin-fetch-url { inherit input-name name hash kind; }
			{%- case "archive" %}
			builtin-fetch-tarball { inherit input-name name hash kind; }
			{%- case "git" %}
			builtin-fetch-git { inherit input-name name kind; }
			{%- endswitch -%}
{%- endfor %}
		else
			throw "Unsupported builtin fetcher “${builtins.toString k}”";

	local-bootstrap-nixpkgs =
		if builtins.isAttrs bootstrap-nixpkgs then
			bootstrap-nixpkgs
		else
			builtin-to-input "bootstrap-nixpkgs-for-nixtamal" (
				if builtins.isString bootstrap-nixpkgs-lock-name then
					lock.i.${bootstrap-nixpkgs-lock-name}
				else
					lock.i.nixpkgs-nixtamal or lock.i.nixpkgs
			);

	pkgs =
		if builtins.isAttrs bootstrap-pkgs then
			bootstrap-pkgs
		else
			import local-bootstrap-nixpkgs {
				system = if builtins.isString system then system else builtins.currentSystem;
			};

	inherit (pkgs) lib;

{% if fetchers.file is defined %}
	fetch-url = { input-name, name, kind, hash }:
		pkgs.fetchurl (
			{
				hash = hash.vl;
			}
			// (if isNonemptyList kind.ms then
					{ urls = [ kind.ur ] ++ kind.ms; }
				else
					{ url = kind.ur; }
				)
			// lib.optionalAttrs (isNonemptyString name) { inherit name; }
		);
{% endif %}
{%- if fetchers.archive is defined %}
	fetch-zip = { input-name, name, kind, hash }:
		pkgs.fetchzip (
			{
				# base gnutar doesn’t support Zstandard
				nativeBuildInputs = [ pkgs.zstd ];
				hash = hash.vl;
			}
			// (if isNonemptyList kind.ms then
					{ urls = [ kind.ur ] ++ kind.ms; }
				else
					{ url = kind.ur; }
			   )
			// lib.optionalAttrs (isNonemptyString name) { inherit name; }
			// lib.optionalAttrs (isNonemptyString kind.ex) { extension = kind.ex; }
		);
{% endif %}
{%- if fetchers.git is defined %}
	fetch-git = { input-name, name, kind, hash }:
		let
			has-mirrors = isNonemptyList kind.ms;
			has-mirror-support = pkgs.fetchgit.__functionArgs ? "mirrors";
		in
		lib.warnIf (has-mirrors && !has-mirror-support)
			"Upstream pkgs.fetchgit doesn’t yet support mirrors for 「${input-name}」"
			pkgs.fetchgit ({
				url = kind.rp;
				rev = kind.lr;
				fetchSubmodules = kind.sm;
				fetchLFS = kind.lf;
				deepClone = false;
				hash = hash.vl;
			}
			// lib.optionalAttrs (isNonemptyString name) { inherit name; }
			// lib.optionalAttrs (has-mirrors && has-mirror-support) { mirrors = kind.ms; }
		);
{% endif %}
{%- if fetchers.darcs is defined %}
	fetch-darcs = { input-name, name, kind, hash }:
		let
			has-mirrors = isNonemptyList kind.ms;
			has-mirror-support = pkgs.fetchdarcs.__functionArgs ? "mirrors";
			reference =
				let
					type = builtins.elemAt kind.rf 0;
					value = builtins.elemAt kind.rf 1;
				in
				if type == 0 then
					let ctx-path = builtins.elemAt value 1; in
					assert (lib.hasSuffix ".txt" ctx-path);
					let
						txt-files = lib.sourceFilesBySuffices ./. [ ".txt" ];
						dir = lib.fileset.toSource {
							root = ./.;
							fileset = lib.fileset.fromSource txt-files;
						};
					in
					{ context = "${dir}/${ctx-path}"; }
				else if type == 1 then
					{ rev = value; }
				else
					throw "Invalid Darcs reference";
		in
		lib.warnIf (has-mirrors && !has-mirror-support)
			"Upstream pkgs.fetchdarcs doesn’t yet support mirrors for 「${input-name}」"
			pkgs.fetchdarcs (
				{
					url = kind.rp;
					hash = hash.vl;
				}
				// reference
				// lib.optionalAttrs (isNonemptyString name) { inherit name; }
				// lib.optionalAttrs (has-mirrors && has-mirror-support) { mirrors = kind.ms; }
			);
{% endif %}
{%- if fetchers.pijul is defined %}
	fetch-pijul = { input-name, name, kind, hash }:
		let
			has-mirrors = isNonemptyList kind.ms;
			has-mirror-support = pkgs.fetchpijul.__functionArgs ? "mirrors";
		in
		lib.warnIf (has-mirrors && !has-mirror-support)
			"Upstream pkgs.fetchpijul doesn’t yet support mirrors for 「${input-name}」"
			pkgs.fetchpijul (
				{
					url = kind.rm;
					state = kind.ls;
					hash = hash.vl;
				}
				// lib.optionalAttrs (isNonemptyString name) { inherit name; }
				// lib.optionalAttrs (has-mirrors && has-mirror-support) { mirrors = kind.ms; }
		);
{% endif %}
{%- if fetchers.fossil is defined %}
	fetch-fossil = { input-name, name, kind, hash }:
		pkgs.fetchfossil (
			{
				url = kind.rp;
				rev = kind.lc;
				hash = hash.vl;
			}
			// lib.optionalAttrs (isNonemptyString name) { inherit name; }
		);
{% endif %}
{%- if using_patches %}

	fetch-patch = patch-name: { ur, ha, sn ? null, ... }:
		pkgs.fetchpatch2 {
			url = ur;
			hash = ha.vl;
			name = if isNonemptyString sn then sn else "${patch-name}-patch";
		};
{% endif %}
	to-input = input-name: input:
		let
			name = input.sn;
			hash = input.ha;
			kind = builtins.elemAt input.kd 1;
			k = builtins.head input.kd;
			raw-input =
{%- for (fetcher, enum) in fetchers %}
				{% if not loop.first -%}else {% endif -%}if k == {{ enum }} then
					{%- switch fetcher -%}
					{%- case "file" %}
					let fetch-time = kind.ft; in
					if fetch-time == 0 then
						fetch-url { inherit input-name name kind hash; }
					else if fetch-time == 1 then
						builtin-fetch-url { inherit input-name name kind hash; }
					else
						throw "Unsupported fetch time ${fetch-time}."
					{%- case "archive" %}
					let fetch-time = kind.ft; in
					if fetch-time == 0 then
						fetch-zip { inherit input-name name kind hash; }
					else if fetch-time == 1 then
						builtin-fetch-tarball { inherit input-name name kind hash; }
					else
						throw "Unsupported fetch time ${fetch-time}."
					{%- case "git" %}
					let fetch-time = kind.ft; in
					if fetch-time == 0 then
						fetch-git { inherit input-name name kind hash; }
					else if fetch-time == 1 then
						builtin-fetch-git { inherit input-name name kind; }
					else
						throw "Unsupported fetch time ${fetch-time}."
					{%- case "darcs" %}
					fetch-darcs { inherit input-name name kind hash; }
					{%- case "pijul" %}
					fetch-pijul { inherit input-name name kind hash; }
					{%- case "fossil" %}
					fetch-fossil { inherit input-name name kind hash; }
					{%- endswitch -%}
{%- endfor %}
				else
					throw "Unsupported input kind “${builtins.toString k}”";
		in
{%- if using_patches %}
		if input.ps == [ ] then
			raw-input
		else
			pkgs.applyPatches {
				src = raw-input;
				name = "${if isNonemptyString name then name else "src"}-patched";
				patches = map (p:
					if local-patches ? "${p}" then
						local-patches."${p}"
					else
						fetch-patch p lock.p."${p}"
				) input.ps;
			};
{%- else %}
		raw-input;
{%- endif %}
in
builtins.mapAttrs to-input lock.i
