2024-04-15 19:23:29 -03:00
import * as actionsCore from "@actions/core" ;
2023-10-04 15:31:05 -04:00
import * as github from "@actions/github" ;
2024-04-15 19:23:29 -03:00
import * as actionsExec from "@actions/exec" ;
2024-04-11 11:58:56 -04:00
import { access , writeFile , readFile } from "node:fs/promises" ;
2023-07-13 10:11:00 -07:00
import { join } from "node:path" ;
import fs from "node:fs" ;
2023-12-04 14:17:47 -05:00
import { userInfo } from "node:os" ;
2023-07-13 10:11:00 -07:00
import stringArgv from "string-argv" ;
2024-05-15 16:45:00 -04:00
import * as path from "path" ;
2024-04-15 19:23:29 -03:00
import { IdsToolbox , inputs , platform } from "detsys-ts" ;
2024-04-11 11:58:56 -04:00
import { randomUUID } from "node:crypto" ;
2023-07-11 10:34:16 -07:00
2024-04-15 19:34:51 -03:00
// Nix installation events
const EVENT_INSTALL_NIX_FAILURE = "install_nix_failure" ;
const EVENT_INSTALL_NIX_START = "install_nix_start" ;
const EVENT_INSTALL_NIX_SUCCESS = "install_nix_start" ;
const EVENT_SETUP_KVM = "setup_kvm" ;
const EVENT_UNINSTALL_NIX = "uninstall" ;
// Docker events
const EVENT_CLEAN_UP_DOCKER_SHIM = "clean_up_docker_shim" ;
const EVENT_START_DOCKER_SHIM = "start_docker_shim" ;
// FlakeHub events
const EVENT_LOGIN_TO_FLAKEHUB = "login_to_flakehub" ;
// Other events
const EVENT_CONCLUDE_WORKFLOW = "conclude_workflow" ;
// Facts
const FACT_HAS_DOCKER = "has_docker" ;
const FACT_HAS_SYSTEMD = "has_systemd" ;
const FACT_IN_GITHUB_ACTIONS = "in_act" ;
const FACT_IN_NAMESPACE_SO = "in_namespace_so" ;
const FACT_NIX_INSTALLER_PLANNER = "nix_installer_planner" ;
2023-07-11 10:34:16 -07:00
class NixInstallerAction {
2024-04-11 11:58:56 -04:00
idslib : IdsToolbox ;
2023-07-13 10:11:00 -07:00
platform : string ;
2024-04-15 19:23:29 -03:00
nixPackageUrl : string | null ;
2023-07-13 10:11:00 -07:00
backtrace : string | null ;
2024-04-15 19:23:29 -03:00
extraArgs : string | null ;
extraConf : string [ ] | null ;
2023-10-04 17:35:16 -04:00
flakehub : boolean ;
2023-11-21 14:06:06 -05:00
kvm : boolean ;
2024-04-15 19:23:29 -03:00
githubServerUrl : string | null ;
githubToken : string | null ;
forceDockerShim : boolean | null ;
2023-07-13 10:11:00 -07:00
init : string | null ;
2024-04-15 19:23:29 -03:00
localRoot : string | null ;
logDirectives : string | null ;
2023-07-13 10:11:00 -07:00
logger : string | null ;
2024-04-15 19:23:29 -03:00
sslCertFile : string | null ;
2023-07-13 10:11:00 -07:00
proxy : string | null ;
2024-04-15 19:23:29 -03:00
macCaseSensitive : string | null ;
macEncrypt : string | null ;
macRootDisk : string | null ;
macVolumeLabel : string | null ;
modifyProfile : boolean ;
nixBuildGroupId : number | null ;
nixBuildGroupName : string | null ;
nixBuildUserBase : number | null ;
nixBuildUserCount : number | null ;
nixBuildUserPrefix : string | null ;
2023-07-13 10:11:00 -07:00
planner : string | null ;
reinstall : boolean ;
2024-04-15 19:23:29 -03:00
startDaemon : boolean ;
trustRunnerUser : boolean | null ;
2023-07-11 10:34:16 -07:00
2024-04-11 11:58:56 -04:00
constructor ( ) {
this . idslib = new IdsToolbox ( {
name : "nix-installer" ,
fetchStyle : "nix-style" ,
legacySourcePrefix : "nix-installer" ,
2024-05-02 10:52:54 -03:00
requireNix : "ignore" ,
2024-04-11 11:58:56 -04:00
} ) ;
2023-10-04 15:31:05 -04:00
2024-04-15 19:23:29 -03:00
this . platform = platform . getNixPlatform ( platform . getArchOs ( ) ) ;
this . nixPackageUrl = inputs . getStringOrNull ( "nix-package-url" ) ;
2024-04-15 19:09:42 -03:00
this . backtrace = inputs . getStringOrNull ( "backtrace" ) ;
2024-04-15 19:23:29 -03:00
this . extraArgs = inputs . getStringOrNull ( "extra-args" ) ;
this . extraConf = inputs . getMultilineStringOrNull ( "extra-conf" ) ;
2024-04-15 19:09:42 -03:00
this . flakehub = inputs . getBool ( "flakehub" ) ;
this . kvm = inputs . getBool ( "kvm" ) ;
2024-04-15 19:23:29 -03:00
this . forceDockerShim = inputs . getBool ( "force-docker-shim" ) ;
this . githubToken = inputs . getStringOrNull ( "github-token" ) ;
this . githubServerUrl = inputs . getStringOrNull ( "github-server-url" ) ;
2024-04-15 19:09:42 -03:00
this . init = inputs . getStringOrNull ( "init" ) ;
2024-04-15 19:23:29 -03:00
this . localRoot = inputs . getStringOrNull ( "local-root" ) ;
this . logDirectives = inputs . getStringOrNull ( "log-directives" ) ;
2024-04-15 19:09:42 -03:00
this . logger = inputs . getStringOrNull ( "logger" ) ;
2024-04-15 19:23:29 -03:00
this . sslCertFile = inputs . getStringOrNull ( "ssl-cert-file" ) ;
2024-04-15 19:09:42 -03:00
this . proxy = inputs . getStringOrNull ( "proxy" ) ;
2024-04-15 19:23:29 -03:00
this . macCaseSensitive = inputs . getStringOrNull ( "mac-case-sensitive" ) ;
this . macEncrypt = inputs . getStringOrNull ( "mac-encrypt" ) ;
this . macRootDisk = inputs . getStringOrNull ( "mac-root-disk" ) ;
this . macVolumeLabel = inputs . getStringOrNull ( "mac-volume-label" ) ;
this . modifyProfile = inputs . getBool ( "modify-profile" ) ;
this . nixBuildGroupId = inputs . getNumberOrNull ( "nix-build-group-id" ) ;
this . nixBuildGroupName = inputs . getStringOrNull ( "nix-build-group-name" ) ;
this . nixBuildUserBase = inputs . getNumberOrNull ( "nix-build-user-base" ) ;
this . nixBuildUserCount = inputs . getNumberOrNull ( "nix-build-user-count" ) ;
this . nixBuildUserPrefix = inputs . getStringOrNull ( "nix-build-user-prefix" ) ;
2024-04-15 19:09:42 -03:00
this . planner = inputs . getStringOrNull ( "planner" ) ;
this . reinstall = inputs . getBool ( "reinstall" ) ;
2024-04-15 19:23:29 -03:00
this . startDaemon = inputs . getBool ( "start-daemon" ) ;
this . trustRunnerUser = inputs . getBool ( "trust-runner-user" ) ;
2023-07-11 10:34:16 -07:00
}
2023-12-04 14:17:47 -05:00
async detectAndForceDockerShim ( ) : Promise < void > {
2024-04-15 19:42:44 -03:00
const runnerOs = process . env [ "RUNNER_OS" ] ;
2023-12-04 14:17:47 -05:00
// Detect if we're in a GHA runner which is Linux, doesn't have Systemd, and does have Docker.
// This is a common case in self-hosted runners, providers like [Namespace](https://namespace.so/),
// and especially GitHub Enterprise Server.
2024-04-15 19:42:44 -03:00
if ( runnerOs !== "Linux" ) {
2024-04-15 19:23:29 -03:00
if ( this . forceDockerShim ) {
actionsCore . warning (
2023-12-04 14:17:47 -05:00
"Ignoring force-docker-shim which is set to true, as it is only supported on Linux." ,
) ;
2024-04-15 19:23:29 -03:00
this . forceDockerShim = false ;
2023-12-04 14:17:47 -05:00
}
return ;
}
const systemdCheck = fs . statSync ( "/run/systemd/system" , {
throwIfNoEntry : false ,
} ) ;
if ( systemdCheck ? . isDirectory ( ) ) {
2024-04-15 19:23:29 -03:00
if ( this . forceDockerShim ) {
actionsCore . warning (
2023-12-04 14:17:47 -05:00
"Systemd is detected, but ignoring it since force-docker-shim is enabled." ,
) ;
} else {
2024-04-15 19:34:51 -03:00
this . idslib . addFact ( FACT_HAS_SYSTEMD , true ) ;
2023-12-04 14:17:47 -05:00
return ;
}
}
2024-04-15 19:34:51 -03:00
this . idslib . addFact ( FACT_HAS_SYSTEMD , false ) ;
2023-12-04 14:17:47 -05:00
2024-04-15 19:23:29 -03:00
actionsCore . debug (
2023-12-04 14:17:47 -05:00
"Linux detected without systemd, testing for Docker with `docker info` as an alternative daemon supervisor." ,
) ;
2024-01-09 10:36:54 -08:00
2024-04-15 19:34:51 -03:00
this . idslib . addFact ( FACT_HAS_DOCKER , false ) ; // Set to false here, and only in the success case do we set it to true
2024-04-15 19:23:29 -03:00
let exitCode ;
2024-01-09 10:36:54 -08:00
try {
2024-04-15 19:23:29 -03:00
exitCode = await actionsExec . exec ( "docker" , [ "info" ] , {
2024-01-09 10:36:54 -08:00
silent : true ,
listeners : {
stdout : ( data : Buffer ) = > {
const trimmed = data . toString ( "utf-8" ) . trimEnd ( ) ;
if ( trimmed . length >= 0 ) {
2024-04-15 19:23:29 -03:00
actionsCore . debug ( trimmed ) ;
2024-01-09 10:36:54 -08:00
}
} ,
stderr : ( data : Buffer ) = > {
const trimmed = data . toString ( "utf-8" ) . trimEnd ( ) ;
if ( trimmed . length >= 0 ) {
2024-04-15 19:23:29 -03:00
actionsCore . debug ( trimmed ) ;
2024-01-09 10:36:54 -08:00
}
} ,
2023-12-04 14:17:47 -05:00
} ,
2024-01-09 10:36:54 -08:00
} ) ;
2024-05-02 13:03:12 -03:00
} catch {
2024-04-15 19:23:29 -03:00
actionsCore . debug ( "Docker not detected, not enabling docker shim." ) ;
2024-01-09 10:36:54 -08:00
return ;
}
2023-12-04 14:17:47 -05:00
2024-04-15 19:23:29 -03:00
if ( exitCode !== 0 ) {
if ( this . forceDockerShim ) {
actionsCore . warning (
2023-12-04 14:17:47 -05:00
"docker info check failed, but trying anyway since force-docker-shim is enabled." ,
) ;
} else {
return ;
}
}
2024-04-15 19:34:51 -03:00
this . idslib . addFact ( FACT_HAS_DOCKER , true ) ;
2023-12-04 14:17:47 -05:00
2024-01-10 11:45:04 -08:00
if (
2024-04-15 19:23:29 -03:00
! this . forceDockerShim &&
2024-01-10 11:45:04 -08:00
( await this . detectDockerWithMountedDockerSocket ( ) )
) {
2024-04-15 19:23:29 -03:00
actionsCore . debug (
2024-01-10 11:45:04 -08:00
"Detected a Docker container with a Docker socket mounted, not enabling docker shim." ,
) ;
return ;
}
2024-04-15 19:23:29 -03:00
actionsCore . startGroup (
2023-12-04 14:17:47 -05:00
"Enabling the Docker shim for running Nix on Linux in CI without Systemd." ,
) ;
if ( this . init !== "none" ) {
2024-04-15 19:23:29 -03:00
actionsCore . info ( ` Changing init from ' ${ this . init } ' to 'none' ` ) ;
2023-12-04 14:17:47 -05:00
this . init = "none" ;
}
if ( this . planner !== "linux" ) {
2024-04-15 19:23:29 -03:00
actionsCore . info ( ` Changing planner from ' ${ this . planner } ' to 'linux' ` ) ;
2023-12-04 14:17:47 -05:00
this . planner = "linux" ;
}
2024-04-15 19:23:29 -03:00
this . forceDockerShim = true ;
2023-12-04 14:17:47 -05:00
2024-04-15 19:23:29 -03:00
actionsCore . endGroup ( ) ;
2023-12-04 14:17:47 -05:00
}
2024-01-10 11:45:04 -08:00
// Detect if we are running under `act` or some other system which is not using docker-in-docker,
// and instead using a mounted docker socket.
// In the case of the socket mount solution, the shim will cause issues since the given mount paths will
// equate to mount paths on the host, not mount paths to the docker container in question.
async detectDockerWithMountedDockerSocket ( ) : Promise < boolean > {
2024-04-15 19:23:29 -03:00
let cgroupsBuffer ;
2024-01-10 11:45:04 -08:00
try {
// If we are inside a docker container, the last line of `/proc/self/cgroup` should be
// 0::/docker/$SOME_ID
//
// If we are not, the line will likely be `0::/`
2024-04-15 19:23:29 -03:00
cgroupsBuffer = await readFile ( "/proc/self/cgroup" , {
2024-01-10 11:45:04 -08:00
encoding : "utf-8" ,
} ) ;
} catch ( e ) {
2024-04-15 19:23:29 -03:00
actionsCore . debug (
2024-01-10 11:45:04 -08:00
` Did not detect \` /proc/self/cgroup \` existence, bailing on docker container ID detection: \ n ${ e } ` ,
) ;
return false ;
}
2024-04-15 19:23:29 -03:00
const cgroups = cgroupsBuffer . trim ( ) . split ( "\n" ) ;
const lastCgroup = cgroups [ cgroups . length - 1 ] ;
const lastCgroupParts = lastCgroup . split ( ":" ) ;
const lastCgroupPath = lastCgroupParts [ lastCgroupParts . length - 1 ] ;
if ( ! lastCgroupPath . includes ( "/docker/" ) ) {
actionsCore . debug (
2024-01-10 11:45:04 -08:00
"Did not detect a container ID, bailing on docker.sock detection" ,
) ;
return false ;
}
// We are in a docker container, now to determine if this container is visible from
// the `docker` command, and if so, if there is a `docker.socket` mounted.
2024-04-15 19:23:29 -03:00
const lastCgroupPathParts = lastCgroupPath . split ( "/" ) ;
const containerId = lastCgroupPathParts [ lastCgroupPathParts . length - 1 ] ;
2024-01-10 11:45:04 -08:00
// If we cannot `docker inspect` this discovered container ID, we'll fall through to the `catch` below.
2024-04-15 19:23:29 -03:00
let stdoutBuffer = "" ;
let stderrBuffer = "" ;
let exitCode ;
2024-01-10 11:45:04 -08:00
try {
2024-04-15 19:23:29 -03:00
exitCode = await actionsExec . exec ( "docker" , [ "inspect" , containerId ] , {
2024-01-10 11:45:04 -08:00
silent : true ,
listeners : {
stdout : ( data : Buffer ) = > {
2024-04-15 19:23:29 -03:00
stdoutBuffer += data . toString ( "utf-8" ) ;
2024-01-10 11:45:04 -08:00
} ,
stderr : ( data : Buffer ) = > {
2024-04-15 19:23:29 -03:00
stderrBuffer += data . toString ( "utf-8" ) ;
2024-01-10 11:45:04 -08:00
} ,
} ,
} ) ;
} catch ( e ) {
2024-04-15 19:23:29 -03:00
actionsCore . debug (
` Could not execute \` docker inspect ${ containerId } \` , bailing on docker container inspection: \ n ${ e } ` ,
2024-01-10 11:45:04 -08:00
) ;
return false ;
}
2024-04-15 19:23:29 -03:00
if ( exitCode !== 0 ) {
actionsCore . debug (
` Unable to inspect detected docker container with id \` ${ containerId } \` , bailing on container inspection (exit ${ exitCode } ): \ n ${ stderrBuffer } ` ,
2024-01-10 11:45:04 -08:00
) ;
return false ;
}
2024-04-15 19:23:29 -03:00
const output = JSON . parse ( stdoutBuffer ) ;
2024-01-10 11:45:04 -08:00
// `docker inspect $ID` prints an array containing objects.
// In our use case, we should only see 1 item in the array.
if ( output . length !== 1 ) {
2024-04-15 19:23:29 -03:00
actionsCore . debug (
` Got \` docker inspect ${ containerId } \` output which was not one item (was ${ output . length } ), bailing on docker.sock detection. ` ,
2024-01-10 11:45:04 -08:00
) ;
return false ;
}
const item = output [ 0 ] ;
// On this array item we want the `Mounts` field, which is an array
// containing `{ Type, Source, Destination, Mode}`.
// We are looking for a `Destination` ending with `docker.sock`.
const mounts = item [ "Mounts" ] ;
if ( typeof mounts !== "object" ) {
2024-04-15 19:23:29 -03:00
actionsCore . debug (
` Got non-object in \` Mounts \` field of \` docker inspect ${ containerId } \` output, bailing on docker.sock detection. ` ,
2024-01-10 11:45:04 -08:00
) ;
return false ;
}
2024-04-15 19:23:29 -03:00
let foundDockerSockMount = false ;
2024-01-10 11:45:04 -08:00
for ( const mount of mounts ) {
const destination = mount [ "Destination" ] ;
if ( typeof destination === "string" ) {
if ( destination . endsWith ( "docker.sock" ) ) {
2024-04-15 19:23:29 -03:00
foundDockerSockMount = true ;
2024-01-10 11:45:04 -08:00
break ;
}
}
}
2024-04-15 19:23:29 -03:00
return foundDockerSockMount ;
2024-01-10 11:45:04 -08:00
}
2023-10-04 17:35:16 -04:00
private async executionEnvironment ( ) : Promise < ExecuteEnvironment > {
2024-04-15 19:23:29 -03:00
const executionEnv : ExecuteEnvironment = { } ;
2024-04-15 19:42:44 -03:00
const runnerOs = process . env [ "RUNNER_OS" ] ;
2023-07-12 10:24:35 -07:00
2024-04-15 19:23:29 -03:00
executionEnv . NIX_INSTALLER_NO_CONFIRM = "true" ;
executionEnv . NIX_INSTALLER_DIAGNOSTIC_ATTRIBUTION = JSON . stringify (
2024-04-11 11:58:56 -04:00
this . idslib . getCorrelationHashes ( ) ,
) ;
2023-07-11 10:34:16 -07:00
if ( this . backtrace !== null ) {
2024-04-15 19:23:29 -03:00
executionEnv . RUST_BACKTRACE = this . backtrace ;
2023-07-11 10:34:16 -07:00
}
2024-04-15 19:23:29 -03:00
if ( this . modifyProfile !== null ) {
if ( this . modifyProfile ) {
executionEnv . NIX_INSTALLER_MODIFY_PROFILE = "true" ;
2023-07-11 10:34:16 -07:00
} else {
2024-04-15 19:23:29 -03:00
executionEnv . NIX_INSTALLER_MODIFY_PROFILE = "false" ;
2023-07-11 10:34:16 -07:00
}
}
2024-04-15 19:23:29 -03:00
if ( this . nixBuildGroupId !== null ) {
executionEnv . NIX_INSTALLER_NIX_BUILD_GROUP_ID = ` ${ this . nixBuildGroupId } ` ;
2023-07-11 10:34:16 -07:00
}
2024-04-15 19:23:29 -03:00
if ( this . nixBuildGroupName !== null ) {
executionEnv . NIX_INSTALLER_NIX_BUILD_GROUP_NAME = this . nixBuildGroupName ;
2023-07-11 10:34:16 -07:00
}
2024-04-15 19:23:29 -03:00
if ( this . nixBuildUserPrefix !== null ) {
executionEnv . NIX_INSTALLER_NIX_BUILD_USER_PREFIX =
this . nixBuildUserPrefix ;
2023-07-11 10:34:16 -07:00
}
2024-04-15 19:23:29 -03:00
if ( this . nixBuildUserCount !== null ) {
executionEnv . NIX_INSTALLER_NIX_BUILD_USER_COUNT = ` ${ this . nixBuildUserCount } ` ;
2023-07-11 10:34:16 -07:00
}
2024-04-15 19:23:29 -03:00
if ( this . nixBuildUserBase !== null ) {
executionEnv . NIX_INSTALLER_NIX_BUILD_USER_ID_BASE = ` ${ this . nixBuildUserCount } ` ;
2023-07-11 10:34:16 -07:00
}
2024-04-15 19:23:29 -03:00
if ( this . nixPackageUrl !== null ) {
executionEnv . NIX_INSTALLER_NIX_PACKAGE_URL = ` ${ this . nixPackageUrl } ` ;
2023-07-11 10:34:16 -07:00
}
if ( this . proxy !== null ) {
2024-04-15 19:23:29 -03:00
executionEnv . NIX_INSTALLER_PROXY = this . proxy ;
2023-07-11 10:34:16 -07:00
}
2024-04-15 19:23:29 -03:00
if ( this . sslCertFile !== null ) {
executionEnv . NIX_INSTALLER_SSL_CERT_FILE = this . sslCertFile ;
2023-07-11 10:34:16 -07:00
}
2024-04-15 19:23:29 -03:00
executionEnv . NIX_INSTALLER_DIAGNOSTIC_ENDPOINT =
2024-04-24 11:13:40 -03:00
this . idslib . getDiagnosticsUrl ( ) ? . toString ( ) ? ? "" ;
2023-07-11 10:34:16 -07:00
// TODO: Error if the user uses these on not-MacOS
2024-04-15 19:23:29 -03:00
if ( this . macEncrypt !== null ) {
2024-04-15 19:42:44 -03:00
if ( runnerOs !== "macOS" ) {
2023-07-13 11:03:55 -07:00
throw new Error ( "`mac-encrypt` while `$RUNNER_OS` was not `macOS`" ) ;
}
2024-04-15 19:23:29 -03:00
executionEnv . NIX_INSTALLER_ENCRYPT = this . macEncrypt ;
2023-07-11 10:34:16 -07:00
}
2024-04-15 19:23:29 -03:00
if ( this . macCaseSensitive !== null ) {
2024-04-15 19:42:44 -03:00
if ( runnerOs !== "macOS" ) {
2023-07-13 11:03:55 -07:00
throw new Error (
"`mac-case-sensitive` while `$RUNNER_OS` was not `macOS`" ,
) ;
}
2024-04-15 19:23:29 -03:00
executionEnv . NIX_INSTALLER_CASE_SENSITIVE = this . macCaseSensitive ;
2023-07-11 10:34:16 -07:00
}
2024-04-15 19:23:29 -03:00
if ( this . macVolumeLabel !== null ) {
2024-04-15 19:42:44 -03:00
if ( runnerOs !== "macOS" ) {
2023-07-13 11:03:55 -07:00
throw new Error (
"`mac-volume-label` while `$RUNNER_OS` was not `macOS`" ,
) ;
}
2024-04-15 19:23:29 -03:00
executionEnv . NIX_INSTALLER_VOLUME_LABEL = this . macVolumeLabel ;
2023-07-11 10:34:16 -07:00
}
2024-04-15 19:23:29 -03:00
if ( this . macRootDisk !== null ) {
2024-04-15 19:42:44 -03:00
if ( runnerOs !== "macOS" ) {
2023-07-13 11:03:55 -07:00
throw new Error ( "`mac-root-disk` while `$RUNNER_OS` was not `macOS`" ) ;
}
2024-04-15 19:23:29 -03:00
executionEnv . NIX_INSTALLER_ROOT_DISK = this . macRootDisk ;
2023-07-11 10:34:16 -07:00
}
2023-07-12 13:17:46 -07:00
if ( this . logger !== null ) {
2024-04-15 19:23:29 -03:00
executionEnv . NIX_INSTALLER_LOGGER = this . logger ;
2023-07-12 13:17:46 -07:00
}
2024-04-15 19:23:29 -03:00
if ( this . logDirectives !== null ) {
executionEnv . NIX_INSTALLER_LOG_DIRECTIVES = this . logDirectives ;
2023-07-12 13:17:46 -07:00
}
2023-07-11 10:34:16 -07:00
// TODO: Error if the user uses these on MacOS
if ( this . init !== null ) {
2024-04-15 19:42:44 -03:00
if ( runnerOs === "macOS" ) {
2023-07-13 11:03:55 -07:00
throw new Error (
"`init` is not a valid option when `$RUNNER_OS` is `macOS`" ,
) ;
}
2024-04-15 19:23:29 -03:00
executionEnv . NIX_INSTALLER_INIT = this . init ;
2023-07-11 10:34:16 -07:00
}
2024-04-15 19:23:29 -03:00
if ( this . startDaemon !== null ) {
if ( this . startDaemon ) {
executionEnv . NIX_INSTALLER_START_DAEMON = "true" ;
2023-07-11 10:34:16 -07:00
} else {
2024-04-15 19:23:29 -03:00
executionEnv . NIX_INSTALLER_START_DAEMON = "false" ;
2023-07-11 10:34:16 -07:00
}
}
2024-04-15 19:23:29 -03:00
let extraConf = "" ;
if ( this . githubServerUrl !== null && this . githubToken !== null ) {
const serverUrl = this . githubServerUrl . replace ( "https://" , "" ) ;
extraConf += ` access-tokens = ${ serverUrl } = ${ this . githubToken } ` ;
extraConf += "\n" ;
2023-07-12 10:24:35 -07:00
}
2024-04-15 19:23:29 -03:00
if ( this . trustRunnerUser !== null ) {
2023-12-04 14:17:47 -05:00
const user = userInfo ( ) . username ;
if ( user ) {
2024-04-15 19:23:29 -03:00
extraConf += ` trusted-users = root ${ user } ` ;
2023-12-04 14:17:47 -05:00
} else {
2024-04-15 19:23:29 -03:00
extraConf += ` trusted-users = root ` ;
2023-12-04 14:17:47 -05:00
}
2024-04-15 19:23:29 -03:00
extraConf += "\n" ;
2023-07-12 10:24:35 -07:00
}
2023-10-04 17:35:16 -04:00
if ( this . flakehub ) {
2024-04-23 09:55:39 -07:00
try {
2024-05-02 13:03:12 -03:00
const flakeHubNetrcFile = await this . flakehubLogin ( ) ;
extraConf += ` netrc-file = ${ flakeHubNetrcFile } ` ;
extraConf += "\n" ;
2024-04-23 09:55:39 -07:00
} catch ( e ) {
2024-05-02 13:03:12 -03:00
actionsCore . warning ( ` Failed to set up FlakeHub: ${ e } ` ) ;
2024-04-23 09:55:39 -07:00
}
2023-10-04 17:35:16 -04:00
}
2024-04-15 19:23:29 -03:00
if ( this . extraConf !== null && this . extraConf . length !== 0 ) {
extraConf += this . extraConf . join ( "\n" ) ;
extraConf += "\n" ;
2023-07-12 10:24:35 -07:00
}
2024-04-15 19:23:29 -03:00
executionEnv . NIX_INSTALLER_EXTRA_CONF = extraConf ;
2023-07-12 10:24:35 -07:00
2024-04-15 19:42:44 -03:00
if ( process . env [ "ACT" ] && ! process . env [ "NOT_ACT" ] ) {
2024-04-15 19:34:51 -03:00
this . idslib . addFact ( FACT_IN_GITHUB_ACTIONS , true ) ;
2024-04-15 19:23:29 -03:00
actionsCore . info (
2023-07-13 11:10:08 -07:00
"Detected `$ACT` environment, assuming this is a https://github.com/nektos/act created container, set `NOT_ACT=true` to override this. This will change the setting of the `init` to be compatible with `act`" ,
2023-07-13 10:11:00 -07:00
) ;
2024-04-15 19:23:29 -03:00
executionEnv . NIX_INSTALLER_INIT = "none" ;
2023-11-02 16:58:37 +01:00
}
2024-04-15 19:42:44 -03:00
if ( process . env [ "NSC_VM_ID" ] && ! process . env [ "NOT_NAMESPACE" ] ) {
2024-04-15 19:34:51 -03:00
this . idslib . addFact ( FACT_IN_NAMESPACE_SO , true ) ;
2024-04-15 19:23:29 -03:00
actionsCore . info (
2023-11-02 16:58:37 +01:00
"Detected Namespace runner, assuming this is a https://namespace.so created container, set `NOT_NAMESPACE=true` to override this. This will change the setting of the `init` to be compatible with Namespace" ,
) ;
2024-04-15 19:23:29 -03:00
executionEnv . NIX_INSTALLER_INIT = "none" ;
2023-07-12 10:24:35 -07:00
}
2024-04-15 19:23:29 -03:00
return executionEnv ;
2023-07-11 10:34:16 -07:00
}
2024-04-15 19:23:29 -03:00
private async executeInstall ( binaryPath : string ) : Promise < number > {
const executionEnv = await this . executionEnvironment ( ) ;
actionsCore . debug (
` Execution environment: ${ JSON . stringify ( executionEnv , null , 4 ) } ` ,
2023-07-13 10:11:00 -07:00
) ;
2023-07-12 10:24:35 -07:00
2023-07-13 10:11:00 -07:00
const args = [ "install" ] ;
2023-07-12 10:24:35 -07:00
if ( this . planner ) {
2024-04-15 19:34:51 -03:00
this . idslib . addFact ( FACT_NIX_INSTALLER_PLANNER , this . planner ) ;
2023-07-13 10:11:00 -07:00
args . push ( this . planner ) ;
2023-07-12 10:24:35 -07:00
} else {
2024-04-15 19:34:51 -03:00
this . idslib . addFact ( FACT_NIX_INSTALLER_PLANNER , getDefaultPlanner ( ) ) ;
2024-04-15 19:23:29 -03:00
args . push ( getDefaultPlanner ( ) ) ;
2023-07-12 10:24:35 -07:00
}
2024-04-15 19:23:29 -03:00
if ( this . extraArgs ) {
const extraArgs = stringArgv ( this . extraArgs ) ;
args . concat ( extraArgs ) ;
2023-07-12 10:24:35 -07:00
}
2024-04-15 19:34:51 -03:00
this . idslib . recordEvent ( EVENT_INSTALL_NIX_START ) ;
2024-04-15 19:23:29 -03:00
const exitCode = await actionsExec . exec ( binaryPath , args , {
2023-11-02 10:48:10 -07:00
env : {
2024-04-15 19:23:29 -03:00
. . . executionEnv ,
2023-11-02 10:48:10 -07:00
. . . process . env , // To get $PATH, etc
} ,
2023-07-13 10:11:00 -07:00
} ) ;
2023-07-11 10:34:16 -07:00
2024-04-15 19:23:29 -03:00
if ( exitCode !== 0 ) {
2024-04-15 19:34:51 -03:00
this . idslib . recordEvent ( EVENT_INSTALL_NIX_FAILURE , {
2024-04-15 19:23:29 -03:00
exitCode ,
2024-04-11 11:58:56 -04:00
} ) ;
2024-04-15 19:23:29 -03:00
throw new Error ( ` Non-zero exit code of \` ${ exitCode } \` detected ` ) ;
2023-07-11 10:34:16 -07:00
}
2024-04-15 19:34:51 -03:00
this . idslib . recordEvent ( EVENT_INSTALL_NIX_SUCCESS ) ;
2024-04-11 11:58:56 -04:00
2024-04-15 19:23:29 -03:00
return exitCode ;
2023-07-11 10:34:16 -07:00
}
async install ( ) : Promise < void > {
2024-04-15 19:23:29 -03:00
const existingInstall = await this . detectExisting ( ) ;
if ( existingInstall ) {
2023-07-12 10:24:35 -07:00
if ( this . reinstall ) {
// We need to uninstall, then reinstall
2024-04-15 19:23:29 -03:00
actionsCore . info (
2023-07-13 10:11:00 -07:00
"Nix was already installed, `reinstall` is set, uninstalling for a reinstall" ,
) ;
2024-04-15 19:23:29 -03:00
await this . executeUninstall ( ) ;
2023-07-12 10:24:35 -07:00
} else {
// We're already installed, and not reinstalling, just set GITHUB_PATH and finish early
2024-04-15 19:23:29 -03:00
await this . setGithubPath ( ) ;
actionsCore . info ( "Nix was already installed, using existing install" ) ;
2023-07-13 10:11:00 -07:00
return ;
2023-07-12 10:24:35 -07:00
}
}
2023-11-21 14:06:06 -05:00
if ( this . kvm ) {
2024-04-15 19:23:29 -03:00
actionsCore . startGroup ( "Configuring KVM" ) ;
if ( await this . setupKvm ( ) ) {
actionsCore . endGroup ( ) ;
actionsCore . info ( "\u001b[32m Accelerated KVM is enabled \u001b[33m⚡️ " ) ;
actionsCore . exportVariable ( "DETERMINATE_NIX_KVM" , "1" ) ;
2023-11-21 14:06:06 -05:00
} else {
2024-04-15 19:23:29 -03:00
actionsCore . endGroup ( ) ;
actionsCore . info ( "KVM is not available." ) ;
actionsCore . exportVariable ( "DETERMINATE_NIX_KVM" , "0" ) ;
2023-11-21 14:06:06 -05:00
}
}
2023-07-12 10:24:35 -07:00
// Normal just doing of the install
2024-04-15 19:23:29 -03:00
actionsCore . startGroup ( "Installing Nix" ) ;
const binaryPath = await this . fetchBinary ( ) ;
await this . executeInstall ( binaryPath ) ;
actionsCore . endGroup ( ) ;
2023-12-04 14:17:47 -05:00
2024-04-15 19:23:29 -03:00
if ( this . forceDockerShim ) {
2023-12-04 14:17:47 -05:00
await this . spawnDockerShim ( ) ;
}
2024-04-15 19:23:29 -03:00
await this . setGithubPath ( ) ;
2023-07-12 10:24:35 -07:00
}
2023-12-04 14:17:47 -05:00
async spawnDockerShim ( ) : Promise < void > {
2024-04-15 19:23:29 -03:00
actionsCore . startGroup (
2023-12-04 14:17:47 -05:00
"Configuring the Docker shim as the Nix Daemon's process supervisor" ,
) ;
const images : { [ key : string ] : string } = {
2024-05-15 16:45:00 -04:00
X64 : path.join ( __dirname , "/../docker-shim/amd64.tar.gz" ) ,
ARM64 : path.join ( __dirname , "/../docker-shim/arm64.tar.gz" ) ,
2023-12-04 14:17:47 -05:00
} ;
2024-04-15 19:42:44 -03:00
const runnerArch = process . env [ "RUNNER_ARCH" ] ;
2023-12-04 14:17:47 -05:00
let arch ;
2024-04-15 19:42:44 -03:00
if ( runnerArch === "X64" ) {
2023-12-04 14:17:47 -05:00
arch = "X64" ;
2024-04-15 19:42:44 -03:00
} else if ( runnerArch === "ARM64" ) {
2023-12-04 14:17:47 -05:00
arch = "ARM64" ;
} else {
throw Error ( "Architecture not supported in Docker shim mode." ) ;
}
2024-04-15 19:23:29 -03:00
actionsCore . debug ( "Loading image: determinate-nix-shim:latest..." ) ;
2023-12-04 14:17:47 -05:00
{
2024-04-15 19:23:29 -03:00
const exitCode = await actionsExec . exec (
2023-12-04 14:17:47 -05:00
"docker" ,
[ "image" , "load" , "--input" , images [ arch ] ] ,
{
silent : true ,
listeners : {
stdout : ( data : Buffer ) = > {
const trimmed = data . toString ( "utf-8" ) . trimEnd ( ) ;
if ( trimmed . length >= 0 ) {
2024-04-15 19:23:29 -03:00
actionsCore . debug ( trimmed ) ;
2023-12-04 14:17:47 -05:00
}
} ,
stderr : ( data : Buffer ) = > {
const trimmed = data . toString ( "utf-8" ) . trimEnd ( ) ;
if ( trimmed . length >= 0 ) {
2024-04-15 19:23:29 -03:00
actionsCore . debug ( trimmed ) ;
2023-12-04 14:17:47 -05:00
}
} ,
} ,
} ,
) ;
2024-04-15 19:23:29 -03:00
if ( exitCode !== 0 ) {
2023-12-04 14:17:47 -05:00
throw new Error (
2024-04-15 19:23:29 -03:00
` Failed to build the shim image, exit code: \` ${ exitCode } \` ` ,
2023-12-04 14:17:47 -05:00
) ;
}
}
{
2024-04-15 19:23:29 -03:00
actionsCore . debug ( "Starting the Nix daemon through Docker..." ) ;
2024-04-15 19:34:51 -03:00
this . idslib . recordEvent ( EVENT_START_DOCKER_SHIM ) ;
2024-04-15 19:23:29 -03:00
const exitCode = await actionsExec . exec (
2023-12-04 14:17:47 -05:00
"docker" ,
[
"--log-level=debug" ,
"run" ,
"--detach" ,
"--privileged" ,
2024-03-11 19:53:25 -04:00
"--network=host" ,
2023-12-04 14:17:47 -05:00
"--userns=host" ,
"--pid=host" ,
"--mount" ,
2024-03-11 19:53:25 -04:00
"type=bind,src=/bin,dst=/bin,readonly" ,
"--mount" ,
"type=bind,src=/lib,dst=/lib,readonly" ,
"--mount" ,
"type=bind,src=/home,dst=/home,readonly" ,
"--mount" ,
2023-12-04 14:17:47 -05:00
"type=bind,src=/tmp,dst=/tmp" ,
"--mount" ,
"type=bind,src=/nix,dst=/nix" ,
"--mount" ,
"type=bind,src=/etc,dst=/etc,readonly" ,
"--restart" ,
"always" ,
"--init" ,
"--name" ,
2024-04-11 11:58:56 -04:00
` determinate-nix-shim- ${ this . idslib . getUniqueId ( ) } - ${ randomUUID ( ) } ` ,
2023-12-04 14:17:47 -05:00
"determinate-nix-shim:latest" ,
] ,
{
silent : true ,
listeners : {
stdline : ( data : string ) = > {
2024-04-15 19:23:29 -03:00
actionsCore . saveState ( "docker_shim_container_id" , data . trimEnd ( ) ) ;
2023-12-04 14:17:47 -05:00
} ,
stdout : ( data : Buffer ) = > {
const trimmed = data . toString ( "utf-8" ) . trimEnd ( ) ;
if ( trimmed . length >= 0 ) {
2024-04-15 19:23:29 -03:00
actionsCore . debug ( trimmed ) ;
2023-12-04 14:17:47 -05:00
}
} ,
stderr : ( data : Buffer ) = > {
const trimmed = data . toString ( "utf-8" ) . trimEnd ( ) ;
if ( trimmed . length >= 0 ) {
2024-04-15 19:23:29 -03:00
actionsCore . debug ( trimmed ) ;
2023-12-04 14:17:47 -05:00
}
} ,
} ,
} ,
) ;
2024-04-15 19:23:29 -03:00
if ( exitCode !== 0 ) {
2023-12-04 14:17:47 -05:00
throw new Error (
2024-04-15 19:23:29 -03:00
` Failed to start the Nix daemon through Docker, exit code: \` ${ exitCode } \` ` ,
2023-12-04 14:17:47 -05:00
) ;
}
}
2024-04-15 19:23:29 -03:00
actionsCore . endGroup ( ) ;
2023-12-04 14:17:47 -05:00
return ;
}
async cleanupDockerShim ( ) : Promise < void > {
2024-04-15 19:23:29 -03:00
const containerId = actionsCore . getState ( "docker_shim_container_id" ) ;
2023-12-19 10:01:56 -06:00
2024-04-15 19:23:29 -03:00
if ( containerId !== "" ) {
actionsCore . startGroup ( "Cleaning up the Nix daemon's Docker shim" ) ;
2023-12-04 14:17:47 -05:00
2023-12-19 10:01:56 -06:00
let cleaned = false ;
try {
2024-04-15 19:23:29 -03:00
await actionsExec . exec ( "docker" , [ "rm" , "--force" , containerId ] ) ;
2023-12-19 10:01:56 -06:00
cleaned = true ;
} catch {
2024-04-15 19:23:29 -03:00
actionsCore . warning ( "failed to cleanup nix daemon container" ) ;
2023-12-19 10:01:56 -06:00
}
if ( ! cleaned ) {
2024-04-15 19:23:29 -03:00
actionsCore . info ( "trying to pkill the container's shim process" ) ;
2023-12-19 10:01:56 -06:00
try {
2024-04-15 19:23:29 -03:00
await actionsExec . exec ( "pkill" , [ containerId ] ) ;
2023-12-19 10:01:56 -06:00
cleaned = true ;
} catch {
2024-04-15 19:23:29 -03:00
actionsCore . warning (
2023-12-19 10:01:56 -06:00
"failed to forcibly kill the container's shim process" ,
) ;
}
}
2024-04-11 11:58:56 -04:00
if ( cleaned ) {
2024-04-15 19:34:51 -03:00
this . idslib . recordEvent ( EVENT_CLEAN_UP_DOCKER_SHIM ) ;
2024-04-11 11:58:56 -04:00
} else {
2024-04-15 19:23:29 -03:00
actionsCore . warning (
2023-12-19 10:01:56 -06:00
"Giving up on cleaning up the nix daemon container" ,
) ;
}
2023-12-04 14:17:47 -05:00
2024-04-15 19:23:29 -03:00
actionsCore . endGroup ( ) ;
2023-12-04 14:17:47 -05:00
}
}
2024-04-15 19:23:29 -03:00
async setGithubPath ( ) : Promise < void > {
2023-07-14 07:58:00 -07:00
// Interim versions of the `nix-installer` crate may have already manipulated `$GITHUB_PATH`, as root even! Accessing that will be an error.
2023-07-14 08:03:38 -07:00
try {
2024-04-15 19:23:29 -03:00
const nixVarNixProfilePath = "/nix/var/nix/profiles/default/bin" ;
2024-04-15 19:42:44 -03:00
const homeNixProfilePath = ` ${ process . env [ "HOME" ] } /.nix-profile/bin ` ;
2024-04-15 19:23:29 -03:00
actionsCore . addPath ( nixVarNixProfilePath ) ;
actionsCore . addPath ( homeNixProfilePath ) ;
actionsCore . info (
` Added \` ${ nixVarNixProfilePath } \` and \` ${ homeNixProfilePath } \` to \` $ GITHUB_PATH \` ` ,
2023-07-14 09:07:56 -07:00
) ;
2024-05-02 13:03:12 -03:00
} catch {
2024-04-15 19:23:29 -03:00
actionsCore . info (
2023-07-17 10:56:49 -07:00
"Skipping setting $GITHUB_PATH in action, the `nix-installer` crate seems to have done this already. From `nix-installer` version 0.11.0 and up, this step is done in the action. Prior to 0.11.0, this was only done in the `nix-installer` binary." ,
2023-07-14 08:03:38 -07:00
) ;
}
2023-07-12 10:24:35 -07:00
}
2024-04-15 19:23:29 -03:00
async flakehubLogin ( ) : Promise < string > {
2024-04-15 19:34:51 -03:00
this . idslib . recordEvent ( EVENT_LOGIN_TO_FLAKEHUB ) ;
2024-04-15 19:23:29 -03:00
const netrcPath = ` ${ process . env [ "RUNNER_TEMP" ] } /determinate-nix-installer-netrc ` ;
2023-10-04 17:35:16 -04:00
2024-04-15 19:23:29 -03:00
const jwt = await actionsCore . getIDToken ( "api.flakehub.com" ) ;
2023-10-04 17:35:16 -04:00
await writeFile (
2024-04-15 19:23:29 -03:00
netrcPath ,
2023-10-04 17:35:16 -04:00
[
` machine api.flakehub.com login flakehub password ${ jwt } ` ,
` machine flakehub.com login flakehub password ${ jwt } ` ,
] . join ( "\n" ) ,
) ;
2024-04-15 19:23:29 -03:00
actionsCore . info ( "Logging in to FlakeHub." ) ;
2023-10-04 17:35:16 -04:00
// the join followed by a match on ^... looks silly, but extra_config
// could contain multi-line values
2024-04-15 19:23:29 -03:00
if ( this . extraConf ? . join ( "\n" ) . match ( /^netrc-file/m ) ) {
actionsCore . warning (
2023-10-04 17:35:16 -04:00
"Logging in to FlakeHub conflicts with the Nix option `netrc-file`." ,
) ;
}
2024-04-15 19:23:29 -03:00
return netrcPath ;
2023-10-04 17:35:16 -04:00
}
2024-04-15 19:23:29 -03:00
async executeUninstall ( ) : Promise < number > {
2024-04-15 19:34:51 -03:00
this . idslib . recordEvent ( EVENT_UNINSTALL_NIX ) ;
2024-04-15 19:23:29 -03:00
const exitCode = await actionsExec . exec (
2023-11-02 10:48:10 -07:00
` /nix/nix-installer ` ,
[ "uninstall" ] ,
{
env : {
NIX_INSTALLER_NO_CONFIRM : "true" ,
. . . process . env , // To get $PATH, etc
} ,
2023-07-13 10:11:00 -07:00
} ,
2023-11-02 10:48:10 -07:00
) ;
2023-07-12 10:24:35 -07:00
2024-04-15 19:23:29 -03:00
if ( exitCode !== 0 ) {
throw new Error ( ` Non-zero exit code of \` ${ exitCode } \` detected ` ) ;
2023-07-12 10:24:35 -07:00
}
2024-04-15 19:23:29 -03:00
return exitCode ;
2023-07-12 10:24:35 -07:00
}
2024-04-15 19:23:29 -03:00
async detectExisting ( ) : Promise < boolean > {
const receiptPath = "/nix/receipt.json" ;
2023-07-12 10:24:35 -07:00
try {
2024-04-15 19:23:29 -03:00
await access ( receiptPath ) ;
2023-07-12 10:24:35 -07:00
// There is a /nix/receipt.json
2023-07-13 10:11:00 -07:00
return true ;
2023-07-12 10:24:35 -07:00
} catch {
// No /nix/receipt.json
2023-07-13 10:11:00 -07:00
return false ;
2023-07-12 10:24:35 -07:00
}
2023-07-11 10:34:16 -07:00
}
2024-04-15 19:23:29 -03:00
private async setupKvm ( ) : Promise < boolean > {
2024-04-15 19:34:51 -03:00
this . idslib . recordEvent ( EVENT_SETUP_KVM ) ;
2024-04-15 19:23:29 -03:00
const currentUser = userInfo ( ) ;
const isRoot = currentUser . uid === 0 ;
const maybeSudo = isRoot ? "" : "sudo" ;
2024-01-08 10:50:02 -08:00
2024-04-15 19:23:29 -03:00
const kvmRules = "/etc/udev/rules.d/99-determinate-nix-installer-kvm.rules" ;
2023-11-21 14:06:06 -05:00
try {
2024-04-15 19:23:29 -03:00
const writeFileExitCode = await actionsExec . exec (
2023-11-21 14:06:06 -05:00
"sh" ,
[
"-c" ,
2024-04-15 19:23:29 -03:00
` echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | ${ maybeSudo } tee ${ kvmRules } > /dev/null ` ,
2023-11-21 14:06:06 -05:00
] ,
{
2023-12-04 14:17:47 -05:00
silent : true ,
2023-11-21 14:06:06 -05:00
listeners : {
2023-12-04 14:17:47 -05:00
stdout : ( data : Buffer ) = > {
const trimmed = data . toString ( "utf-8" ) . trimEnd ( ) ;
if ( trimmed . length >= 0 ) {
2024-04-15 19:23:29 -03:00
actionsCore . debug ( trimmed ) ;
2023-12-04 14:17:47 -05:00
}
} ,
2023-11-21 14:06:06 -05:00
stderr : ( data : Buffer ) = > {
const trimmed = data . toString ( "utf-8" ) . trimEnd ( ) ;
if ( trimmed . length >= 0 ) {
2024-04-15 19:23:29 -03:00
actionsCore . debug ( trimmed ) ;
2023-11-21 14:06:06 -05:00
}
} ,
} ,
} ,
) ;
2024-04-15 19:23:29 -03:00
if ( writeFileExitCode !== 0 ) {
2023-11-21 14:06:06 -05:00
throw new Error (
2024-04-15 19:23:29 -03:00
` Non-zero exit code of \` ${ writeFileExitCode } \` detected while writing ' ${ kvmRules } ' ` ,
2023-11-21 14:06:06 -05:00
) ;
}
2024-04-15 19:23:29 -03:00
const debugRootRunThrow = async (
2023-11-21 14:06:06 -05:00
action : string ,
command : string ,
args : string [ ] ,
) : Promise < void > = > {
2024-04-15 19:23:29 -03:00
if ( ! isRoot ) {
2024-01-08 10:50:02 -08:00
args = [ command , . . . args ] ;
command = "sudo" ;
}
2024-04-15 19:23:29 -03:00
const reloadExitCode = await actionsExec . exec ( command , args , {
2023-12-04 14:17:47 -05:00
silent : true ,
2023-11-21 14:06:06 -05:00
listeners : {
stdout : ( data : Buffer ) = > {
const trimmed = data . toString ( "utf-8" ) . trimEnd ( ) ;
if ( trimmed . length >= 0 ) {
2024-04-15 19:23:29 -03:00
actionsCore . debug ( trimmed ) ;
2023-11-21 14:06:06 -05:00
}
} ,
stderr : ( data : Buffer ) = > {
const trimmed = data . toString ( "utf-8" ) . trimEnd ( ) ;
if ( trimmed . length >= 0 ) {
2024-04-15 19:23:29 -03:00
actionsCore . debug ( trimmed ) ;
2023-11-21 14:06:06 -05:00
}
} ,
} ,
} ) ;
2024-04-15 19:23:29 -03:00
if ( reloadExitCode !== 0 ) {
2023-11-21 14:06:06 -05:00
throw new Error (
2024-04-15 19:23:29 -03:00
` Non-zero exit code of \` ${ reloadExitCode } \` detected while ${ action } . ` ,
2023-11-21 14:06:06 -05:00
) ;
}
} ;
2024-04-15 19:23:29 -03:00
await debugRootRunThrow ( "reloading udev rules" , "udevadm" , [
2023-11-21 14:06:06 -05:00
"control" ,
"--reload-rules" ,
] ) ;
2024-04-15 19:23:29 -03:00
await debugRootRunThrow ( "triggering udev against kvm" , "udevadm" , [
2023-11-21 14:06:06 -05:00
"trigger" ,
"--name-match=kvm" ,
] ) ;
return true ;
2024-05-02 13:03:12 -03:00
} catch {
2024-04-15 19:23:29 -03:00
if ( isRoot ) {
await actionsExec . exec ( "rm" , [ "-f" , kvmRules ] ) ;
2024-01-08 10:50:02 -08:00
} else {
2024-04-15 19:23:29 -03:00
await actionsExec . exec ( "sudo" , [ "rm" , "-f" , kvmRules ] ) ;
2024-01-08 10:50:02 -08:00
}
2023-11-21 14:06:06 -05:00
return false ;
}
}
2024-04-15 19:23:29 -03:00
private async fetchBinary ( ) : Promise < string > {
if ( ! this . localRoot ) {
2024-04-11 11:58:56 -04:00
return await this . idslib . fetchExecutable ( ) ;
2023-07-11 10:34:16 -07:00
} else {
2024-04-15 19:23:29 -03:00
const localPath = join ( this . localRoot , ` nix-installer- ${ this . platform } ` ) ;
actionsCore . info ( ` Using binary ${ localPath } ` ) ;
return localPath ;
2023-07-11 10:34:16 -07:00
}
}
2023-10-04 15:31:05 -04:00
2024-04-15 19:23:29 -03:00
async reportOverall ( ) : Promise < void > {
2023-10-04 15:31:05 -04:00
try {
2024-04-15 19:34:51 -03:00
this . idslib . recordEvent ( EVENT_CONCLUDE_WORKFLOW , {
2024-04-15 19:23:29 -03:00
conclusion : await this . getWorkflowConclusion ( ) ,
2023-10-04 15:31:05 -04:00
} ) ;
2024-05-02 13:03:12 -03:00
} catch ( e ) {
actionsCore . debug ( ` Error submitting post-run diagnostics report: ${ e } ` ) ;
2023-10-04 15:31:05 -04:00
}
}
2024-04-15 19:23:29 -03:00
private async getWorkflowConclusion ( ) : Promise <
2023-10-04 15:31:05 -04:00
undefined | "success" | "failure" | "cancelled" | "unavailable" | "no-jobs"
> {
2024-04-15 19:23:29 -03:00
if ( this . githubToken == null ) {
2023-10-04 15:31:05 -04:00
return undefined ;
}
try {
2024-04-15 19:23:29 -03:00
const octokit = github . getOctokit ( this . githubToken ) ;
2023-10-04 15:31:05 -04:00
const jobs = await octokit . paginate (
octokit . rest . actions . listJobsForWorkflowRun ,
{
owner : github.context.repo.owner ,
repo : github.context.repo.repo ,
2024-04-24 11:09:48 -03:00
/* eslint-disable camelcase */
2023-10-04 15:31:05 -04:00
run_id : github.context.runId ,
} ,
) ;
2024-04-15 19:23:29 -03:00
actionsCore . debug ( ` awaited jobs: ${ jobs } ` ) ;
2023-10-04 15:31:05 -04:00
const job = jobs
. filter ( ( candidate ) = > candidate . name === github . context . job )
. at ( 0 ) ;
if ( job === undefined ) {
return "no-jobs" ;
}
2024-04-24 11:13:40 -03:00
const outcomes = ( job . steps ? ? [ ] ) . map ( ( j ) = > j . conclusion ? ? "unknown" ) ;
2023-10-04 15:31:05 -04:00
// Possible values: success, failure, cancelled, or skipped
// from: https://docs.github.com/en/actions/learn-github-actions/contexts
if ( outcomes . includes ( "failure" ) ) {
// Any failures fails the job
return "failure" ;
}
if ( outcomes . includes ( "cancelled" ) ) {
// Any cancellations cancels the job
return "cancelled" ;
}
// Assume success if no jobs failed or were canceled
return "success" ;
2024-05-02 13:03:12 -03:00
} catch ( e ) {
actionsCore . debug ( ` Error determining final disposition: ${ e } ` ) ;
2023-10-04 15:31:05 -04:00
return "unavailable" ;
}
}
2023-07-11 10:34:16 -07:00
}
type ExecuteEnvironment = {
// All env vars are strings, no fanciness here.
2023-07-13 10:11:00 -07:00
RUST_BACKTRACE? : string ;
NIX_INSTALLER_MODIFY_PROFILE? : string ;
NIX_INSTALLER_NIX_BUILD_GROUP_NAME? : string ;
NIX_INSTALLER_NIX_BUILD_GROUP_ID? : string ;
NIX_INSTALLER_NIX_BUILD_USER_PREFIX? : string ;
NIX_INSTALLER_NIX_BUILD_USER_COUNT? : string ;
NIX_INSTALLER_NIX_BUILD_USER_ID_BASE? : string ;
NIX_INSTALLER_NIX_PACKAGE_URL? : string ;
NIX_INSTALLER_PROXY? : string ;
NIX_INSTALLER_SSL_CERT_FILE? : string ;
NIX_INSTALLER_DIAGNOSTIC_ENDPOINT? : string ;
2023-10-04 15:31:05 -04:00
NIX_INSTALLER_DIAGNOSTIC_ATTRIBUTION? : string ;
2023-07-13 10:11:00 -07:00
NIX_INSTALLER_ENCRYPT? : string ;
NIX_INSTALLER_CASE_SENSITIVE? : string ;
NIX_INSTALLER_VOLUME_LABEL? : string ;
NIX_INSTALLER_ROOT_DISK? : string ;
NIX_INSTALLER_INIT? : string ;
NIX_INSTALLER_START_DAEMON? : string ;
NIX_INSTALLER_NO_CONFIRM? : string ;
NIX_INSTALLER_EXTRA_CONF? : string ;
NIX_INSTALLER_LOG_DIRECTIVES? : string ;
NIX_INSTALLER_LOGGER? : string ;
} ;
2023-07-11 10:34:16 -07:00
2024-04-15 19:23:29 -03:00
function getDefaultPlanner ( ) : string {
2024-04-15 19:42:44 -03:00
const envOs = process . env [ "RUNNER_OS" ] ;
2023-07-12 10:24:35 -07:00
2024-04-15 19:23:29 -03:00
if ( envOs === "macOS" ) {
2023-07-13 10:11:00 -07:00
return "macos" ;
2024-04-15 19:23:29 -03:00
} else if ( envOs === "Linux" ) {
2023-07-13 10:11:00 -07:00
return "linux" ;
2023-07-12 10:24:35 -07:00
} else {
2024-04-15 19:23:29 -03:00
throw new Error ( ` Unsupported \` RUNNER_OS \` (currently \` ${ envOs } \` ) ` ) ;
2023-07-12 10:24:35 -07:00
}
}
2024-04-11 11:58:56 -04:00
function main ( ) : void {
const installer = new NixInstallerAction ( ) ;
2023-07-12 10:24:35 -07:00
2024-04-11 11:58:56 -04:00
installer . idslib . onMain ( async ( ) = > {
await installer . detectAndForceDockerShim ( ) ;
await installer . install ( ) ;
} ) ;
2023-12-04 14:17:47 -05:00
2024-04-11 11:58:56 -04:00
installer . idslib . onPost ( async ( ) = > {
await installer . cleanupDockerShim ( ) ;
2024-04-15 19:23:29 -03:00
await installer . reportOverall ( ) ;
2024-04-11 11:58:56 -04:00
} ) ;
installer . idslib . execute ( ) ;
2023-07-11 10:34:16 -07:00
}
2024-04-11 11:58:56 -04:00
main ( ) ;