1
- import { execRoot , execRootSync } from "admina"
1
+ import { defaultExecOptions , execRoot , execRootSync } from "admina"
2
2
import { GITHUB_ACTIONS } from "ci-info"
3
3
import { info , warning } from "ci-log"
4
4
import escapeRegex from "escape-string-regexp"
5
5
import { type ExecaError , execa } from "execa"
6
6
import { appendFile } from "fs/promises"
7
- import { addEnv , sourceRC } from "os-env"
7
+ import memoize from "micro-memoize"
8
+ import { sourceRC } from "os-env"
8
9
import { pathExists } from "path-exists"
9
10
import which from "which"
10
11
import { rcOptions } from "../../cli-options.js"
@@ -37,8 +38,6 @@ export async function setupAptPack(packages: AptPackage[], update = false): Prom
37
38
info ( `Installing ${ name } ${ version ?? "" } via ${ apt } ` )
38
39
}
39
40
40
- process . env . DEBIAN_FRONTEND = "noninteractive"
41
-
42
41
// Update the repos if needed
43
42
if ( update ) {
44
43
updateRepos ( apt )
@@ -63,13 +62,13 @@ export async function setupAptPack(packages: AptPackage[], update = false): Prom
63
62
64
63
// Install
65
64
try {
66
- execRootSync ( apt , [ "install" , "--fix-broken" , "-y" , ...needToInstall ] )
65
+ execRootSync ( apt , [ "install" , "--fix-broken" , "-y" , ...needToInstall ] , getAptExecOptions ( apt ) )
67
66
} catch ( err ) {
68
67
if ( "stderr" in ( err as ExecaError ) ) {
69
68
const stderr = ( err as ExecaError ) . stderr
70
69
if ( retryErrors . some ( ( error ) => stderr . includes ( error ) ) ) {
71
70
warning ( `Failed to install packages ${ needToInstall } . Retrying...` )
72
- execRootSync ( apt , [ "install" , "--fix-broken" , "-y" , "-o" , aptTimeout , ...needToInstall ] )
71
+ execRootSync ( apt , [ "install" , "--fix-broken" , "-y" , "-o" , aptTimeout , ...needToInstall ] , getAptExecOptions ( apt ) )
73
72
}
74
73
} else {
75
74
throw err
@@ -79,6 +78,42 @@ export async function setupAptPack(packages: AptPackage[], update = false): Prom
79
78
return { binDir : "/usr/bin/" }
80
79
}
81
80
81
+ export function hasNala ( ) {
82
+ return which . sync ( "nala" , { nothrow : true } ) !== null
83
+ }
84
+
85
+ export function getApt ( ) {
86
+ let apt : string
87
+ if ( hasNala ( ) ) {
88
+ apt = "nala"
89
+ } else {
90
+ apt = "apt-get"
91
+ }
92
+ return apt
93
+ }
94
+
95
+ function getEnv ( apt : string ) {
96
+ const env : NodeJS . ProcessEnv = { ...process . env , DEBIAN_FRONTEND : "noninteractive" }
97
+
98
+ if ( apt === "nala" ) {
99
+ // if LANG/LC_ALL is not set, enable utf8 otherwise nala fails because of ASCII encoding
100
+ if ( env . LANG === undefined ) {
101
+ env . LANG = "C.UTF-8"
102
+ }
103
+ if ( env . LC_ALL === undefined ) {
104
+ env . LC_ALL = "C.UTF-8"
105
+ }
106
+ }
107
+
108
+ return env
109
+ }
110
+
111
+ function getAptExecOptionsRaw ( apt : string = "apt-get" ) {
112
+ return { env : getEnv ( apt ) , ...defaultExecOptions }
113
+ }
114
+
115
+ const getAptExecOptions = memoize ( getAptExecOptionsRaw )
116
+
82
117
export enum AptPackageType {
83
118
NameDashVersion = 0 ,
84
119
NameEqualsVersion = 1 ,
@@ -111,7 +146,7 @@ async function addRepositories(apt: string, packages: AptPackage[]) {
111
146
await installAddAptRepo ( apt )
112
147
for ( const repo of allRepositories ) {
113
148
// eslint-disable-next-line no-await-in-loop
114
- execRootSync ( "add-apt-repository" , [ "-y" , "--no-update" , repo ] )
149
+ execRootSync ( "add-apt-repository" , [ "-y" , "--no-update" , repo ] , getAptExecOptions ( ) )
115
150
}
116
151
updateRepos ( apt )
117
152
didUpdate = true
@@ -124,15 +159,15 @@ export async function aptPackageType(name: string, version: string | undefined):
124
159
"search" ,
125
160
"--names-only" ,
126
161
`^${ escapeRegex ( name ) } -${ escapeRegex ( version ) } $` ,
127
- ] )
162
+ ] , getAptExecOptions ( ) )
128
163
if ( stdout . trim ( ) !== "" ) {
129
164
return AptPackageType . NameDashVersion
130
165
}
131
166
132
167
try {
133
168
// check if apt-get show can find the version
134
169
// eslint-disable-next-line @typescript-eslint/no-shadow
135
- const { stdout } = await execa ( "apt-cache" , [ "show" , `${ name } =${ version } ` ] )
170
+ const { stdout } = await execa ( "apt-cache" , [ "show" , `${ name } =${ version } ` ] , getAptExecOptions ( ) )
136
171
if ( stdout . trim ( ) === "" ) {
137
172
return AptPackageType . NameEqualsVersion
138
173
}
@@ -142,7 +177,7 @@ export async function aptPackageType(name: string, version: string | undefined):
142
177
}
143
178
144
179
try {
145
- const { stdout : showStdout } = await execa ( "apt-cache" , [ "show" , name ] )
180
+ const { stdout : showStdout } = await execa ( "apt-cache" , [ "show" , name ] , getAptExecOptions ( ) )
146
181
if ( showStdout . trim ( ) !== "" ) {
147
182
return AptPackageType . Name
148
183
}
@@ -174,29 +209,23 @@ async function getAptArg(name: string, version: string | undefined) {
174
209
}
175
210
}
176
211
177
- export function hasNala ( ) {
178
- return which . sync ( "nala" , { nothrow : true } ) !== null
179
- }
180
-
181
- export function getApt ( ) {
182
- let apt : string
183
- if ( hasNala ( ) ) {
184
- apt = "nala"
185
- } else {
186
- apt = "apt-get"
187
- }
188
- return apt
189
- }
190
-
191
212
function updateRepos ( apt : string ) {
192
- execRootSync ( apt , apt !== "nala" ? [ "update" , "-y" , "-o" , aptTimeout ] : [ "update" , "-o" , aptTimeout ] )
213
+ execRootSync (
214
+ apt ,
215
+ apt !== "nala" ? [ "update" , "-y" , "-o" , aptTimeout ] : [ "update" , "-o" , aptTimeout ] ,
216
+ getAptExecOptions ( apt ) ,
217
+ )
193
218
}
194
219
195
220
async function installAddAptRepo ( apt : string ) {
196
221
if ( await isPackageInstalled ( "software-properties-common" ) ) {
197
222
return
198
223
}
199
- execRootSync ( apt , [ "install" , "-y" , "--fix-broken" , "-o" , aptTimeout , "software-properties-common" ] )
224
+ execRootSync (
225
+ apt ,
226
+ [ "install" , "-y" , "--fix-broken" , "-o" , aptTimeout , "software-properties-common" ] ,
227
+ getAptExecOptions ( apt ) ,
228
+ )
200
229
}
201
230
202
231
/** Install gnupg and certificates (usually missing from docker containers) */
@@ -214,20 +243,13 @@ async function initApt(apt: string) {
214
243
] )
215
244
216
245
if ( toInstall . length !== 0 ) {
217
- execRootSync ( apt , [ "install" , "-y" , "--fix-broken" , "-o" , aptTimeout , ...toInstall ] )
246
+ execRootSync ( apt , [ "install" , "-y" , "--fix-broken" , "-o" , aptTimeout , ...toInstall ] , getAptExecOptions ( apt ) )
218
247
}
219
248
220
249
const promises : Promise < string | void > [ ] = [
221
250
addAptKeyViaServer ( [ "3B4FE6ACC0B21F32" , "40976EAF437D05B5" ] , "setup-cpp-ubuntu-archive.gpg" ) ,
222
251
addAptKeyViaServer ( [ "1E9377A2BA9EF27F" ] , "launchpad-toolchain.gpg" ) ,
223
252
]
224
- if ( apt === "nala" ) {
225
- // If LANGE/LC_ALL is not set, enable utf8 otherwise nala fails because of ASCII encoding
226
- promises . push (
227
- addEnv ( "LANG" , "C.UTF-8" , { overwrite : false , ...rcOptions } ) ,
228
- addEnv ( "LC_ALL" , "C.UTF-8" , { overwrite : false , ...rcOptions } ) ,
229
- )
230
- }
231
253
await Promise . all ( promises )
232
254
}
233
255
@@ -290,7 +312,7 @@ export async function updateAptAlternatives(name: string, path: string, rcPath:
290
312
export async function isPackageInstalled ( pack : string ) {
291
313
try {
292
314
// check if a package is installed
293
- const { stdout } = await execa ( "dpkg" , [ "-s" , pack ] )
315
+ const { stdout } = await execa ( "dpkg" , [ "-s" , pack ] , getAptExecOptions ( ) )
294
316
if ( typeof stdout !== "string" ) {
295
317
return false
296
318
}
@@ -305,7 +327,7 @@ export async function isPackageInstalled(pack: string) {
305
327
export async function isPackageRegexInstalled ( regexp : string ) {
306
328
try {
307
329
// check if a package matching the regexp is installed
308
- const { stdout } = await execa ( "dpkg" , [ "-l" , regexp ] )
330
+ const { stdout } = await execa ( "dpkg" , [ "-l" , regexp ] , getAptExecOptions ( ) )
309
331
if ( typeof stdout !== "string" ) {
310
332
return false
311
333
}
0 commit comments