diff --git a/quixos-package-helpers.nix b/quixos-package-helpers.nix index 02346ef..09776a9 100644 --- a/quixos-package-helpers.nix +++ b/quixos-package-helpers.nix @@ -491,7 +491,189 @@ EOF }; } ); + + mkCaminoSourcePackage = + { + pkgs, + src, + name ? "quixos-package-source", + }: + pkgs.stdenvNoCC.mkDerivation { + inherit name; + src = pkgs.lib.cleanSource src; + dontConfigure = true; + dontBuild = true; + installPhase = '' + runHook preInstall + cp -R . "$out" + runHook postInstall + ''; + }; + + mkCaminoTsYarnNixifyFlake = + { + inputs, + nixpkgs, + flake-utils, + packageRoot, + packageName ? null, + sourceName ? "quixos-package-source", + promptName ? null, + nodejsAttr ? "nodejs_24", + buildCommand ? "yarn build", + sourcePortals ? { }, + buildEnv ? { }, + nativeBuildInputs ? [ ], + devShellPackages ? [ ], + devShellHook ? "", + bundle ? null, + installServer ? null, + }: + flake-utils.lib.eachDefaultSystem ( + system: + let + pkgs = import nixpkgs { inherit system; }; + lib = pkgs.lib; + nodejs = pkgs.${nodejsAttr}; + + callOption = value: + if builtins.isFunction value + then value { inherit inputs pkgs system; } + else value; + + packageJson = builtins.fromJSON (builtins.readFile "${packageRoot}/package.json"); + packageNameFinal = if packageName != null then packageName else packageJson.name or "quixos-package"; + promptNameFinal = + if promptName != null + then promptName + else lib.strings.sanitizeDerivationName packageNameFinal; + + sourcePackage = mkCaminoSourcePackage { + inherit pkgs; + src = packageRoot; + name = sourceName; + }; + + exportsFor = attrs: + lib.concatStringsSep "\n" ( + lib.mapAttrsToList + (name: value: "export ${name}=${lib.escapeShellArg (toString value)}") + attrs + ); + + portalLinksFor = attrs: + lib.concatStringsSep "\n" ( + lib.mapAttrsToList + (target: source: "ln -sfn ${source} ${lib.escapeShellArg target}") + attrs + ); + + bundleConfig = if bundle == null then { } else bundle; + bundleOutfile = bundleConfig.outfile or "server.mjs"; + bundlePlatform = bundleConfig.platform or "node"; + bundleTarget = bundleConfig.target or "node24"; + bundleFormat = bundleConfig.format or "esm"; + bundleBanner = bundleConfig.banner or nodeRequireBanner; + nodeRequireBanner = "import { createRequire } from 'module';const require = createRequire(import.meta.url);"; + bundleCommand = + if bundle == null + then "" + else '' + esbuild ${lib.escapeShellArg bundleConfig.entry} \ + --bundle \ + --platform=${bundlePlatform} \ + --target=${bundleTarget} \ + --format=${bundleFormat} \ + ${lib.optionalString (bundleConfig.preserveSymlinks or true) "--preserve-symlinks \\"} + --banner:js=${lib.escapeShellArg bundleBanner} \ + --outfile=${lib.escapeShellArg bundleOutfile} + ''; + + installConfig = if installServer == null then { } else installServer; + serverBin = installConfig.binName or "server"; + serverLibexecName = + installConfig.libexecName or (lib.strings.sanitizeDerivationName packageNameFinal); + serverFile = installConfig.serverFile or bundleOutfile; + descriptorPath = installConfig.descriptorPath or "descriptor.quixos-package.txtpb"; + installServerPhase = + if installServer == null + then null + else '' + runHook preInstall + install -Dm755 ${lib.escapeShellArg serverFile} "$out/libexec/${serverLibexecName}/${serverFile}" + mkdir -p "$out/bin" + cat > "$out/bin/${serverBin}" <