@@ -2,7 +2,7 @@ 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
- import { type ExecaError , execa } from "execa"
5
+ import { type ExecaError , type SyncOptions , execa } from "execa"
6
6
import { appendFile } from "fs/promises"
7
7
import memoize from "micro-memoize"
8
8
import { sourceRC } from "os-env"
@@ -47,7 +47,7 @@ export async function setupAptPack(packages: AptPackage[], update = false): Prom
47
47
// Add the repos if needed
48
48
await addRepositories ( apt , packages )
49
49
50
- const needToInstall = await filterAndQualifyAptPackages ( packages )
50
+ const needToInstall = await filterAndQualifyAptPackages ( apt , packages )
51
51
52
52
if ( needToInstall . length === 0 ) {
53
53
info ( "All packages are already installed" )
@@ -62,13 +62,17 @@ export async function setupAptPack(packages: AptPackage[], update = false): Prom
62
62
63
63
// Install
64
64
try {
65
- execRootSync ( apt , [ "install" , "--fix-broken" , "-y" , ...needToInstall ] , getAptExecOptions ( apt ) )
65
+ execRootSync ( apt , [ "install" , "--fix-broken" , "-y" , ...needToInstall ] , getAptExecOptions ( { apt } ) )
66
66
} catch ( err ) {
67
67
if ( "stderr" in ( err as ExecaError ) ) {
68
68
const stderr = ( err as ExecaError ) . stderr
69
69
if ( retryErrors . some ( ( error ) => stderr . includes ( error ) ) ) {
70
70
warning ( `Failed to install packages ${ needToInstall } . Retrying...` )
71
- execRootSync ( apt , [ "install" , "--fix-broken" , "-y" , "-o" , aptTimeout , ...needToInstall ] , getAptExecOptions ( apt ) )
71
+ execRootSync (
72
+ apt ,
73
+ [ "install" , "--fix-broken" , "-y" , "-o" , aptTimeout , ...needToInstall ] ,
74
+ getAptExecOptions ( { apt } ) ,
75
+ )
72
76
}
73
77
} else {
74
78
throw err
@@ -108,8 +112,14 @@ function getEnv(apt: string) {
108
112
return env
109
113
}
110
114
111
- function getAptExecOptionsRaw ( apt : string = "apt-get" ) {
112
- return { env : getEnv ( apt ) , ...defaultExecOptions }
115
+ function getAptExecOptionsRaw ( givenOpts : { apt ?: string ; pipe ?: boolean } = { } ) : SyncOptions {
116
+ const opts = {
117
+ apt : "apt-get" ,
118
+ pipe : false ,
119
+ ...givenOpts ,
120
+ }
121
+
122
+ return { env : getEnv ( opts . apt ) , ...defaultExecOptions , stdio : opts . pipe ? "pipe" : "inherit" }
113
123
}
114
124
115
125
const getAptExecOptions = memoize ( getAptExecOptionsRaw )
@@ -124,14 +134,14 @@ export enum AptPackageType {
124
134
/**
125
135
* Filter out the packages that are already installed and qualify the packages into a full package name/version
126
136
*/
127
- async function filterAndQualifyAptPackages ( packages : AptPackage [ ] ) {
128
- return ( await Promise . all ( packages . map ( qualifiedNeededAptPackage ) ) )
137
+ async function filterAndQualifyAptPackages ( apt : string , packages : AptPackage [ ] ) {
138
+ return ( await Promise . all ( packages . map ( ( pack ) => qualifiedNeededAptPackage ( apt , pack ) ) ) )
129
139
. filter ( ( pack ) => pack !== undefined )
130
140
}
131
141
132
- async function qualifiedNeededAptPackage ( pack : AptPackage ) {
142
+ async function qualifiedNeededAptPackage ( apt : string , pack : AptPackage ) {
133
143
// Qualify the packages into full package name/version
134
- const qualified = await getAptArg ( pack . name , pack . version )
144
+ const qualified = await getAptArg ( apt , pack . name , pack . version )
135
145
// filter out the packages that are already installed
136
146
return ( await isPackageInstalled ( qualified ) ) ? undefined : qualified
137
147
}
@@ -153,13 +163,13 @@ async function addRepositories(apt: string, packages: AptPackage[]) {
153
163
}
154
164
}
155
165
156
- export async function aptPackageType ( name : string , version : string | undefined ) : Promise < AptPackageType > {
166
+ async function aptPackageType ( apt : string , name : string , version : string | undefined ) : Promise < AptPackageType > {
157
167
if ( version !== undefined && version !== "" ) {
158
168
const { stdout } = await execa ( "apt-cache" , [
159
169
"search" ,
160
170
"--names-only" ,
161
171
`^${ escapeRegex ( name ) } -${ escapeRegex ( version ) } $` ,
162
- ] , getAptExecOptions ( ) )
172
+ ] , getAptExecOptions ( { apt , pipe : true } ) )
163
173
if ( stdout . trim ( ) !== "" ) {
164
174
return AptPackageType . NameDashVersion
165
175
}
@@ -189,14 +199,14 @@ export async function aptPackageType(name: string, version: string | undefined):
189
199
if ( ! didUpdate ) {
190
200
updateRepos ( getApt ( ) )
191
201
didUpdate = true
192
- return aptPackageType ( name , version )
202
+ return aptPackageType ( apt , name , version )
193
203
}
194
204
195
205
return AptPackageType . None
196
206
}
197
207
198
- async function getAptArg ( name : string , version : string | undefined ) {
199
- const package_type = await aptPackageType ( name , version )
208
+ async function getAptArg ( apt : string , name : string , version : string | undefined ) {
209
+ const package_type = await aptPackageType ( apt , name , version )
200
210
switch ( package_type ) {
201
211
case AptPackageType . NameDashVersion :
202
212
return `${ name } -${ version } `
@@ -213,7 +223,7 @@ function updateRepos(apt: string) {
213
223
execRootSync (
214
224
apt ,
215
225
apt !== "nala" ? [ "update" , "-y" , "-o" , aptTimeout ] : [ "update" , "-o" , aptTimeout ] ,
216
- getAptExecOptions ( apt ) ,
226
+ getAptExecOptions ( { apt } ) ,
217
227
)
218
228
}
219
229
@@ -224,7 +234,7 @@ async function installAddAptRepo(apt: string) {
224
234
execRootSync (
225
235
apt ,
226
236
[ "install" , "-y" , "--fix-broken" , "-o" , aptTimeout , "software-properties-common" ] ,
227
- getAptExecOptions ( apt ) ,
237
+ getAptExecOptions ( { apt } ) ,
228
238
)
229
239
}
230
240
@@ -236,14 +246,14 @@ async function initApt(apt: string) {
236
246
didUpdate = true
237
247
}
238
248
239
- const toInstall = await filterAndQualifyAptPackages ( [
249
+ const toInstall = await filterAndQualifyAptPackages ( apt , [
240
250
{ name : "ca-certificates" } ,
241
251
{ name : "gnupg" } ,
242
252
{ name : "apt-utils" } ,
243
253
] )
244
254
245
255
if ( toInstall . length !== 0 ) {
246
- execRootSync ( apt , [ "install" , "-y" , "--fix-broken" , "-o" , aptTimeout , ...toInstall ] , getAptExecOptions ( apt ) )
256
+ execRootSync ( apt , [ "install" , "-y" , "--fix-broken" , "-o" , aptTimeout , ...toInstall ] , getAptExecOptions ( { apt } ) )
247
257
}
248
258
249
259
const promises : Promise < string | void > [ ] = [
@@ -312,7 +322,7 @@ export async function updateAptAlternatives(name: string, path: string, rcPath:
312
322
export async function isPackageInstalled ( pack : string ) {
313
323
try {
314
324
// check if a package is installed
315
- const { stdout } = await execa ( "dpkg" , [ "-s" , pack ] , getAptExecOptions ( ) )
325
+ const { stdout } = await execa ( "dpkg" , [ "-s" , pack ] , getAptExecOptions ( { pipe : true } ) )
316
326
if ( typeof stdout !== "string" ) {
317
327
return false
318
328
}
@@ -327,7 +337,7 @@ export async function isPackageInstalled(pack: string) {
327
337
export async function isPackageRegexInstalled ( regexp : string ) {
328
338
try {
329
339
// check if a package matching the regexp is installed
330
- const { stdout } = await execa ( "dpkg" , [ "-l" , regexp ] , getAptExecOptions ( ) )
340
+ const { stdout } = await execa ( "dpkg" , [ "-l" , regexp ] , getAptExecOptions ( { pipe : true } ) )
331
341
if ( typeof stdout !== "string" ) {
332
342
return false
333
343
}
0 commit comments