@codifycli/plugin-core 1.2.3-beta.2 → 1.2.5-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/build.js CHANGED
File without changes
@@ -110,6 +110,8 @@ export class BackgroundPty {
110
110
  return new Promise(resolve => {
111
111
  this.basePty.write(' unset PS1;\n');
112
112
  this.basePty.write(' unset PS0;\n');
113
+ // zsh autocorrect prompts (e.g. "zsh: correct 'config' to '.config' [nyae]?") will hang
114
+ // the pty waiting for interactive input. Can't be disabled via env var; must unset the options explicitly.
113
115
  this.basePty.write(' unsetopt CORRECT CORRECT_ALL 2>/dev/null; true;\n');
114
116
  this.basePty.write(' echo setup complete\\"\n');
115
117
  const listener = this.basePty.onData((data) => {
@@ -66,6 +66,8 @@ export class SequentialPty {
66
66
  // Set to a really large value to prevent wrapping
67
67
  const initialCols = options?.disableWrapping ? 10_000 : process.stdout.columns ?? 80;
68
68
  const initialRows = process.stdout.rows ?? 24;
69
+ // zsh autocorrect prompts (e.g. "zsh: correct 'config' to '.config' [nyae]?") will hang
70
+ // the pty waiting for interactive input. Can't be disabled via env var; must unset the options explicitly.
69
71
  const disableAutocorrect = Utils.getShell() === Shell.ZSH ? 'unsetopt CORRECT CORRECT_ALL 2>/dev/null; ' : '';
70
72
  const wrappedCmd = `${disableAutocorrect}${cmd}`;
71
73
  const args = options?.interactive ? ['-i', '-c', wrappedCmd] : ['-c', wrappedCmd];
@@ -12,6 +12,35 @@ export interface SystemInfo {
12
12
  os: OS;
13
13
  shell: Shell;
14
14
  }
15
+ export declare enum PackageManager {
16
+ BREW = "brew",
17
+ APT = "apt",
18
+ DNF = "dnf",
19
+ YUM = "yum",
20
+ PACMAN = "pacman"
21
+ }
22
+ export interface BasePkgMgrOptions {
23
+ flags?: string[];
24
+ }
25
+ export interface BrewOptions extends BasePkgMgrOptions {
26
+ cask?: boolean;
27
+ adopt?: boolean;
28
+ }
29
+ export interface AptOptions extends BasePkgMgrOptions {
30
+ }
31
+ export interface DnfOptions extends BasePkgMgrOptions {
32
+ }
33
+ export interface YumOptions extends BasePkgMgrOptions {
34
+ }
35
+ export interface PacmanOptions extends BasePkgMgrOptions {
36
+ }
37
+ export type PkgMgrOptionsMap = {
38
+ [PackageManager.BREW]?: BrewOptions;
39
+ [PackageManager.APT]?: AptOptions;
40
+ [PackageManager.DNF]?: DnfOptions;
41
+ [PackageManager.YUM]?: YumOptions;
42
+ [PackageManager.PACMAN]?: PacmanOptions;
43
+ };
15
44
  export declare const Utils: {
16
45
  getUser(): string;
17
46
  getSystemInfo(): {
@@ -29,11 +58,12 @@ export declare const Utils: {
29
58
  isDirectoryOnPath(directory: string): Promise<boolean>;
30
59
  assertBrewInstalled(): Promise<void>;
31
60
  /**
32
- * Installs a package via the system package manager. This will use Homebrew on macOS and apt on Ubuntu/Debian or dnf on Fedora.
33
- * @param packageName
61
+ * Installs a package via the system package manager. Auto-detects the PM from the OS unless
62
+ * forcePackageManager is specified. Per-PM options (flags, cask, etc.) can be passed via the
63
+ * options map.
34
64
  */
35
- installViaPkgMgr(packageName: string): Promise<void>;
36
- uninstallViaPkgMgr(packageName: string): Promise<boolean>;
65
+ installViaPkgMgr(packageName: string, options?: PkgMgrOptionsMap, forcePackageManager?: PackageManager): Promise<void>;
66
+ uninstallViaPkgMgr(packageName: string, options?: PkgMgrOptionsMap, forcePackageManager?: PackageManager): Promise<boolean>;
37
67
  getLinuxDistro(): Promise<LinuxDistro | undefined>;
38
68
  isUbuntu(): Promise<boolean>;
39
69
  isDebian(): Promise<boolean>;
@@ -16,6 +16,14 @@ export var Shell;
16
16
  Shell["CSH"] = "csh";
17
17
  Shell["FISH"] = "fish";
18
18
  })(Shell || (Shell = {}));
19
+ export var PackageManager;
20
+ (function (PackageManager) {
21
+ PackageManager["BREW"] = "brew";
22
+ PackageManager["APT"] = "apt";
23
+ PackageManager["DNF"] = "dnf";
24
+ PackageManager["YUM"] = "yum";
25
+ PackageManager["PACMAN"] = "pacman";
26
+ })(PackageManager || (PackageManager = {}));
19
27
  export const Utils = {
20
28
  getUser() {
21
29
  return os.userInfo().username;
@@ -154,26 +162,42 @@ Brew can be installed using Codify:
154
162
  }
155
163
  },
156
164
  /**
157
- * Installs a package via the system package manager. This will use Homebrew on macOS and apt on Ubuntu/Debian or dnf on Fedora.
158
- * @param packageName
165
+ * Installs a package via the system package manager. Auto-detects the PM from the OS unless
166
+ * forcePackageManager is specified. Per-PM options (flags, cask, etc.) can be passed via the
167
+ * options map.
159
168
  */
160
- async installViaPkgMgr(packageName) {
169
+ async installViaPkgMgr(packageName, options, forcePackageManager) {
161
170
  const $ = getPty();
162
- if (Utils.isMacOS()) {
171
+ const useBrew = forcePackageManager === PackageManager.BREW || (!forcePackageManager && Utils.isMacOS());
172
+ if (useBrew) {
163
173
  await this.assertBrewInstalled();
164
- await $.spawn(`brew install ${packageName}`, { interactive: true, env: { HOMEBREW_NO_AUTO_UPDATE: 1 } });
174
+ const brewOpts = options?.[PackageManager.BREW];
175
+ const flags = [];
176
+ if (brewOpts?.cask || brewOpts?.adopt)
177
+ flags.push('--cask');
178
+ if (brewOpts?.adopt)
179
+ flags.push('--adopt');
180
+ if (brewOpts?.flags)
181
+ flags.push(...brewOpts.flags);
182
+ const flagStr = flags.length > 0 ? `${flags.join(' ')} ` : '';
183
+ await $.spawn(`brew install ${flagStr}${packageName}`, { interactive: true, env: { HOMEBREW_NO_AUTO_UPDATE: 1, HOMEBREW_NO_REQUIRE_TAP_TRUST: 1 } });
184
+ return;
165
185
  }
166
- if (Utils.isLinux()) {
186
+ const useApt = forcePackageManager === PackageManager.APT || (!forcePackageManager && Utils.isLinux());
187
+ if (useApt) {
188
+ const aptOpts = options?.[PackageManager.APT];
189
+ const extraFlags = aptOpts?.flags ?? [];
167
190
  const isAptInstalled = await $.spawnSafe('which apt');
168
191
  if (isAptInstalled.status === SpawnStatus.SUCCESS) {
169
192
  await $.spawn('apt-get update', { requiresRoot: true });
170
- const { status, data } = await $.spawnSafe(`apt-get -y -qq install -o Dpkg::Use-Pty=0 -o Dpkg::Progress-Fancy=0 ${packageName}`, {
193
+ const flagStr = extraFlags.length > 0 ? `${extraFlags.join(' ')} ` : '';
194
+ const { status, data } = await $.spawnSafe(`apt-get -y -qq install -o Dpkg::Use-Pty=0 -o Dpkg::Progress-Fancy=0 ${flagStr}${packageName}`, {
171
195
  requiresRoot: true,
172
- env: { DEBIAN_FRONTEND: 'noninteractive', NEEDRESTART_MODE: 'a', }
196
+ env: { DEBIAN_FRONTEND: 'noninteractive', NEEDRESTART_MODE: 'a' }
173
197
  });
174
198
  if (status === SpawnStatus.ERROR && data.includes('E: dpkg was interrupted, you must manually run \'sudo dpkg --configure -a\' to correct the problem.')) {
175
199
  await $.spawn('dpkg --configure -a', { requiresRoot: true });
176
- await $.spawn(`apt-get -y install ${packageName}`, {
200
+ await $.spawn(`apt-get -y install ${flagStr}${packageName}`, {
177
201
  requiresRoot: true,
178
202
  env: { DEBIAN_FRONTEND: 'noninteractive', NEEDRESTART_MODE: 'a' }
179
203
  });
@@ -188,7 +212,7 @@ Brew can be installed using Codify:
188
212
  if (fixResult.status === SpawnStatus.ERROR) {
189
213
  throw new Error(`Failed to install package ${packageName} via apt: ${data}`);
190
214
  }
191
- const retryResult = await $.spawnSafe(`apt-get -y -qq install -o Dpkg::Use-Pty=0 -o Dpkg::Progress-Fancy=0 ${packageName}`, {
215
+ const retryResult = await $.spawnSafe(`apt-get -y -qq install -o Dpkg::Use-Pty=0 -o Dpkg::Progress-Fancy=0 ${flagStr}${packageName}`, {
192
216
  requiresRoot: true,
193
217
  env: { DEBIAN_FRONTEND: 'noninteractive', NEEDRESTART_MODE: 'a' }
194
218
  });
@@ -196,54 +220,95 @@ Brew can be installed using Codify:
196
220
  throw new Error(`Failed to install package ${packageName} via apt after fixing dependencies: ${retryResult.data}`);
197
221
  }
198
222
  }
223
+ return;
199
224
  }
225
+ }
226
+ if (forcePackageManager === PackageManager.DNF || !forcePackageManager) {
227
+ const dnfOpts = options?.[PackageManager.DNF];
228
+ const extraFlags = dnfOpts?.flags ?? [];
200
229
  const isDnfInstalled = await $.spawnSafe('which dnf');
201
230
  if (isDnfInstalled.status === SpawnStatus.SUCCESS) {
231
+ const flagStr = extraFlags.length > 0 ? `${extraFlags.join(' ')} ` : '';
202
232
  await $.spawn('dnf update', { requiresRoot: true });
203
- await $.spawn(`dnf install ${packageName} -y`, { requiresRoot: true });
233
+ await $.spawn(`dnf install ${flagStr}${packageName} -y`, { requiresRoot: true });
234
+ return;
204
235
  }
236
+ }
237
+ if (forcePackageManager === PackageManager.YUM || !forcePackageManager) {
238
+ const yumOpts = options?.[PackageManager.YUM];
239
+ const extraFlags = yumOpts?.flags ?? [];
205
240
  const isYumInstalled = await $.spawnSafe('which yum');
206
241
  if (isYumInstalled.status === SpawnStatus.SUCCESS) {
242
+ const flagStr = extraFlags.length > 0 ? `${extraFlags.join(' ')} ` : '';
207
243
  await $.spawn('yum update', { requiresRoot: true });
208
- await $.spawn(`yum install ${packageName} -y`, { requiresRoot: true });
244
+ await $.spawn(`yum install ${flagStr}${packageName} -y`, { requiresRoot: true });
245
+ return;
209
246
  }
247
+ }
248
+ if (forcePackageManager === PackageManager.PACMAN || !forcePackageManager) {
249
+ const pacmanOpts = options?.[PackageManager.PACMAN];
250
+ const extraFlags = pacmanOpts?.flags ?? [];
210
251
  const isPacmanInstalled = await $.spawnSafe('which pacman');
211
252
  if (isPacmanInstalled.status === SpawnStatus.SUCCESS) {
253
+ const flagStr = extraFlags.length > 0 ? `${extraFlags.join(' ')} ` : '';
212
254
  await $.spawn('pacman -Syu', { requiresRoot: true });
213
- await $.spawn(`pacman -S ${packageName} --noconfirm`, { requiresRoot: true });
255
+ await $.spawn(`pacman -S ${flagStr}${packageName} --noconfirm`, { requiresRoot: true });
256
+ return;
214
257
  }
215
258
  }
216
259
  },
217
- async uninstallViaPkgMgr(packageName) {
260
+ async uninstallViaPkgMgr(packageName, options, forcePackageManager) {
218
261
  const $ = getPty();
219
- if (Utils.isMacOS()) {
262
+ const useBrew = forcePackageManager === PackageManager.BREW || (!forcePackageManager && Utils.isMacOS());
263
+ if (useBrew) {
220
264
  await this.assertBrewInstalled();
221
- const { status } = await $.spawnSafe(`brew uninstall --zap ${packageName}`, {
265
+ const brewOpts = options?.[PackageManager.BREW];
266
+ const flags = [];
267
+ if (brewOpts?.cask || brewOpts?.adopt)
268
+ flags.push('--cask');
269
+ if (brewOpts?.flags)
270
+ flags.push(...brewOpts.flags);
271
+ flags.push('--zap');
272
+ const flagStr = flags.length > 0 ? `${flags.join(' ')} ` : '';
273
+ const { status } = await $.spawnSafe(`brew uninstall ${flagStr}${packageName}`, {
222
274
  interactive: true,
223
- env: { HOMEBREW_NO_AUTO_UPDATE: 1 }
275
+ env: { HOMEBREW_NO_AUTO_UPDATE: 1, HOMEBREW_NO_REQUIRE_TAP_TRUST: 1 }
224
276
  });
225
277
  return status === SpawnStatus.SUCCESS;
226
278
  }
227
- if (Utils.isLinux()) {
279
+ const useApt = forcePackageManager === PackageManager.APT || (!forcePackageManager && Utils.isLinux());
280
+ if (useApt) {
281
+ const aptOpts = options?.[PackageManager.APT];
282
+ const extraFlags = aptOpts?.flags ?? [];
228
283
  const isAptInstalled = await $.spawnSafe('which apt');
229
284
  if (isAptInstalled.status === SpawnStatus.SUCCESS) {
230
- const { status } = await $.spawnSafe(`apt-get -qq autoremove -y -o Dpkg::Use-Pty=0 -o Dpkg::Progress-Fancy=0 --purge ${packageName}`, {
285
+ const flagStr = extraFlags.length > 0 ? `${extraFlags.join(' ')} ` : '';
286
+ const { status } = await $.spawnSafe(`apt-get -qq autoremove -y -o Dpkg::Use-Pty=0 -o Dpkg::Progress-Fancy=0 --purge ${flagStr}${packageName}`, {
231
287
  requiresRoot: true,
232
288
  env: { DEBIAN_FRONTEND: 'noninteractive', NEEDRESTART_MODE: 'a' }
233
289
  });
234
290
  return status === SpawnStatus.SUCCESS;
235
291
  }
292
+ }
293
+ if (forcePackageManager === PackageManager.DNF || !forcePackageManager) {
294
+ const dnfOpts = options?.[PackageManager.DNF];
295
+ const extraFlags = dnfOpts?.flags ?? [];
236
296
  const isDnfInstalled = await $.spawnSafe('which dnf');
237
297
  if (isDnfInstalled.status === SpawnStatus.SUCCESS) {
238
- const { status } = await $.spawnSafe(`dnf autoremove ${packageName} -y`, { requiresRoot: true });
298
+ const flagStr = extraFlags.length > 0 ? `${extraFlags.join(' ')} ` : '';
299
+ const { status } = await $.spawnSafe(`dnf autoremove ${flagStr}${packageName} -y`, { requiresRoot: true });
239
300
  return status === SpawnStatus.SUCCESS;
240
301
  }
302
+ }
303
+ if (forcePackageManager === PackageManager.YUM || !forcePackageManager) {
304
+ const yumOpts = options?.[PackageManager.YUM];
305
+ const extraFlags = yumOpts?.flags ?? [];
241
306
  const isYumInstalled = await $.spawnSafe('which yum');
242
307
  if (isYumInstalled.status === SpawnStatus.SUCCESS) {
243
- const { status } = await $.spawnSafe(`yum autoremove ${packageName} -y`, { requiresRoot: true });
308
+ const flagStr = extraFlags.length > 0 ? `${extraFlags.join(' ')} ` : '';
309
+ const { status } = await $.spawnSafe(`yum autoremove ${flagStr}${packageName} -y`, { requiresRoot: true });
244
310
  return status === SpawnStatus.SUCCESS;
245
311
  }
246
- return false;
247
312
  }
248
313
  return false;
249
314
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codifycli/plugin-core",
3
- "version": "1.2.3-beta.2",
3
+ "version": "1.2.5-beta.1",
4
4
  "description": "TypeScript library for building Codify plugins to manage system resources (applications, CLI tools, settings) through infrastructure-as-code",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -135,6 +135,8 @@ export class BackgroundPty implements IPty {
135
135
  return new Promise(resolve => {
136
136
  this.basePty.write(' unset PS1;\n');
137
137
  this.basePty.write(' unset PS0;\n')
138
+ // zsh autocorrect prompts (e.g. "zsh: correct 'config' to '.config' [nyae]?") will hang
139
+ // the pty waiting for interactive input. Can't be disabled via env var; must unset the options explicitly.
138
140
  this.basePty.write(' unsetopt CORRECT CORRECT_ALL 2>/dev/null; true;\n')
139
141
  this.basePty.write(' echo setup complete\\"\n')
140
142
 
@@ -88,6 +88,8 @@ export class SequentialPty implements IPty {
88
88
  const initialCols = options?.disableWrapping ? 10_000 : process.stdout.columns ?? 80
89
89
  const initialRows = process.stdout.rows ?? 24;
90
90
 
91
+ // zsh autocorrect prompts (e.g. "zsh: correct 'config' to '.config' [nyae]?") will hang
92
+ // the pty waiting for interactive input. Can't be disabled via env var; must unset the options explicitly.
91
93
  const disableAutocorrect = Utils.getShell() === Shell.ZSH ? 'unsetopt CORRECT CORRECT_ALL 2>/dev/null; ' : '';
92
94
  const wrappedCmd = `${disableAutocorrect}${cmd}`;
93
95
  const args = options?.interactive ? ['-i', '-c', wrappedCmd] : ['-c', wrappedCmd]
@@ -24,6 +24,36 @@ export interface SystemInfo {
24
24
  shell: Shell;
25
25
  }
26
26
 
27
+ export enum PackageManager {
28
+ BREW = 'brew',
29
+ APT = 'apt',
30
+ DNF = 'dnf',
31
+ YUM = 'yum',
32
+ PACMAN = 'pacman',
33
+ }
34
+
35
+ export interface BasePkgMgrOptions {
36
+ flags?: string[];
37
+ }
38
+
39
+ export interface BrewOptions extends BasePkgMgrOptions {
40
+ cask?: boolean;
41
+ adopt?: boolean;
42
+ }
43
+
44
+ export interface AptOptions extends BasePkgMgrOptions {}
45
+ export interface DnfOptions extends BasePkgMgrOptions {}
46
+ export interface YumOptions extends BasePkgMgrOptions {}
47
+ export interface PacmanOptions extends BasePkgMgrOptions {}
48
+
49
+ export type PkgMgrOptionsMap = {
50
+ [PackageManager.BREW]?: BrewOptions;
51
+ [PackageManager.APT]?: AptOptions;
52
+ [PackageManager.DNF]?: DnfOptions;
53
+ [PackageManager.YUM]?: YumOptions;
54
+ [PackageManager.PACMAN]?: PacmanOptions;
55
+ };
56
+
27
57
  export const Utils = {
28
58
  getUser(): string {
29
59
  return os.userInfo().username;
@@ -194,33 +224,50 @@ Brew can be installed using Codify:
194
224
  },
195
225
 
196
226
  /**
197
- * Installs a package via the system package manager. This will use Homebrew on macOS and apt on Ubuntu/Debian or dnf on Fedora.
198
- * @param packageName
227
+ * Installs a package via the system package manager. Auto-detects the PM from the OS unless
228
+ * forcePackageManager is specified. Per-PM options (flags, cask, etc.) can be passed via the
229
+ * options map.
199
230
  */
200
- async installViaPkgMgr(packageName: string): Promise<void> {
231
+ async installViaPkgMgr(
232
+ packageName: string,
233
+ options?: PkgMgrOptionsMap,
234
+ forcePackageManager?: PackageManager,
235
+ ): Promise<void> {
201
236
  const $ = getPty();
202
237
 
203
- if (Utils.isMacOS()) {
238
+ const useBrew = forcePackageManager === PackageManager.BREW || (!forcePackageManager && Utils.isMacOS());
239
+ if (useBrew) {
204
240
  await this.assertBrewInstalled();
205
- await $.spawn(`brew install ${packageName}`, { interactive: true, env: { HOMEBREW_NO_AUTO_UPDATE: 1 } });
241
+ const brewOpts = options?.[PackageManager.BREW];
242
+ const flags: string[] = [];
243
+ if (brewOpts?.cask || brewOpts?.adopt) flags.push('--cask');
244
+ if (brewOpts?.adopt) flags.push('--adopt');
245
+ if (brewOpts?.flags) flags.push(...brewOpts.flags);
246
+ const flagStr = flags.length > 0 ? `${flags.join(' ')} ` : '';
247
+ await $.spawn(`brew install ${flagStr}${packageName}`, { interactive: true, env: { HOMEBREW_NO_AUTO_UPDATE: 1, HOMEBREW_NO_REQUIRE_TAP_TRUST: 1 } });
248
+ return;
206
249
  }
207
250
 
208
- if (Utils.isLinux()) {
251
+ const useApt = forcePackageManager === PackageManager.APT || (!forcePackageManager && Utils.isLinux());
252
+ if (useApt) {
253
+ const aptOpts = options?.[PackageManager.APT];
254
+ const extraFlags = aptOpts?.flags ?? [];
255
+
209
256
  const isAptInstalled = await $.spawnSafe('which apt');
210
257
  if (isAptInstalled.status === SpawnStatus.SUCCESS) {
211
258
  await $.spawn('apt-get update', { requiresRoot: true });
212
- const { status, data } = await $.spawnSafe(`apt-get -y -qq install -o Dpkg::Use-Pty=0 -o Dpkg::Progress-Fancy=0 ${packageName}`, {
259
+ const flagStr = extraFlags.length > 0 ? `${extraFlags.join(' ')} ` : '';
260
+ const { status, data } = await $.spawnSafe(`apt-get -y -qq install -o Dpkg::Use-Pty=0 -o Dpkg::Progress-Fancy=0 ${flagStr}${packageName}`, {
213
261
  requiresRoot: true,
214
- env: { DEBIAN_FRONTEND: 'noninteractive', NEEDRESTART_MODE: 'a', }
262
+ env: { DEBIAN_FRONTEND: 'noninteractive', NEEDRESTART_MODE: 'a' }
215
263
  });
216
264
 
217
265
  if (status === SpawnStatus.ERROR && data.includes('E: dpkg was interrupted, you must manually run \'sudo dpkg --configure -a\' to correct the problem.')) {
218
266
  await $.spawn('dpkg --configure -a', { requiresRoot: true });
219
- await $.spawn(`apt-get -y install ${packageName}`, {
267
+ await $.spawn(`apt-get -y install ${flagStr}${packageName}`, {
220
268
  requiresRoot: true,
221
269
  env: { DEBIAN_FRONTEND: 'noninteractive', NEEDRESTART_MODE: 'a' }
222
270
  });
223
-
224
271
  return;
225
272
  }
226
273
 
@@ -235,7 +282,7 @@ Brew can be installed using Codify:
235
282
  throw new Error(`Failed to install package ${packageName} via apt: ${data}`);
236
283
  }
237
284
 
238
- const retryResult = await $.spawnSafe(`apt-get -y -qq install -o Dpkg::Use-Pty=0 -o Dpkg::Progress-Fancy=0 ${packageName}`, {
285
+ const retryResult = await $.spawnSafe(`apt-get -y -qq install -o Dpkg::Use-Pty=0 -o Dpkg::Progress-Fancy=0 ${flagStr}${packageName}`, {
239
286
  requiresRoot: true,
240
287
  env: { DEBIAN_FRONTEND: 'noninteractive', NEEDRESTART_MODE: 'a' }
241
288
  });
@@ -244,64 +291,105 @@ Brew can be installed using Codify:
244
291
  throw new Error(`Failed to install package ${packageName} via apt after fixing dependencies: ${retryResult.data}`);
245
292
  }
246
293
  }
294
+ return;
247
295
  }
296
+ }
248
297
 
298
+ if (forcePackageManager === PackageManager.DNF || !forcePackageManager) {
299
+ const dnfOpts = options?.[PackageManager.DNF];
300
+ const extraFlags = dnfOpts?.flags ?? [];
249
301
  const isDnfInstalled = await $.spawnSafe('which dnf');
250
302
  if (isDnfInstalled.status === SpawnStatus.SUCCESS) {
303
+ const flagStr = extraFlags.length > 0 ? `${extraFlags.join(' ')} ` : '';
251
304
  await $.spawn('dnf update', { requiresRoot: true });
252
- await $.spawn(`dnf install ${packageName} -y`, { requiresRoot: true });
305
+ await $.spawn(`dnf install ${flagStr}${packageName} -y`, { requiresRoot: true });
306
+ return;
253
307
  }
308
+ }
254
309
 
310
+ if (forcePackageManager === PackageManager.YUM || !forcePackageManager) {
311
+ const yumOpts = options?.[PackageManager.YUM];
312
+ const extraFlags = yumOpts?.flags ?? [];
255
313
  const isYumInstalled = await $.spawnSafe('which yum');
256
314
  if (isYumInstalled.status === SpawnStatus.SUCCESS) {
315
+ const flagStr = extraFlags.length > 0 ? `${extraFlags.join(' ')} ` : '';
257
316
  await $.spawn('yum update', { requiresRoot: true });
258
- await $.spawn(`yum install ${packageName} -y`, { requiresRoot: true });
317
+ await $.spawn(`yum install ${flagStr}${packageName} -y`, { requiresRoot: true });
318
+ return;
259
319
  }
320
+ }
260
321
 
322
+ if (forcePackageManager === PackageManager.PACMAN || !forcePackageManager) {
323
+ const pacmanOpts = options?.[PackageManager.PACMAN];
324
+ const extraFlags = pacmanOpts?.flags ?? [];
261
325
  const isPacmanInstalled = await $.spawnSafe('which pacman');
262
326
  if (isPacmanInstalled.status === SpawnStatus.SUCCESS) {
327
+ const flagStr = extraFlags.length > 0 ? `${extraFlags.join(' ')} ` : '';
263
328
  await $.spawn('pacman -Syu', { requiresRoot: true });
264
- await $.spawn(`pacman -S ${packageName} --noconfirm`, { requiresRoot: true });
329
+ await $.spawn(`pacman -S ${flagStr}${packageName} --noconfirm`, { requiresRoot: true });
330
+ return;
265
331
  }
266
-
267
332
  }
268
333
  },
269
334
 
270
- async uninstallViaPkgMgr(packageName: string): Promise<boolean> {
335
+ async uninstallViaPkgMgr(
336
+ packageName: string,
337
+ options?: PkgMgrOptionsMap,
338
+ forcePackageManager?: PackageManager,
339
+ ): Promise<boolean> {
271
340
  const $ = getPty();
272
341
 
273
- if (Utils.isMacOS()) {
342
+ const useBrew = forcePackageManager === PackageManager.BREW || (!forcePackageManager && Utils.isMacOS());
343
+ if (useBrew) {
274
344
  await this.assertBrewInstalled();
275
- const { status } = await $.spawnSafe(`brew uninstall --zap ${packageName}`, {
345
+ const brewOpts = options?.[PackageManager.BREW];
346
+ const flags: string[] = [];
347
+ if (brewOpts?.cask || brewOpts?.adopt) flags.push('--cask');
348
+ if (brewOpts?.flags) flags.push(...brewOpts.flags);
349
+ flags.push('--zap');
350
+ const flagStr = flags.length > 0 ? `${flags.join(' ')} ` : '';
351
+ const { status } = await $.spawnSafe(`brew uninstall ${flagStr}${packageName}`, {
276
352
  interactive: true,
277
- env: { HOMEBREW_NO_AUTO_UPDATE: 1 }
353
+ env: { HOMEBREW_NO_AUTO_UPDATE: 1, HOMEBREW_NO_REQUIRE_TAP_TRUST: 1 }
278
354
  });
279
355
  return status === SpawnStatus.SUCCESS;
280
356
  }
281
357
 
282
- if (Utils.isLinux()) {
358
+ const useApt = forcePackageManager === PackageManager.APT || (!forcePackageManager && Utils.isLinux());
359
+ if (useApt) {
360
+ const aptOpts = options?.[PackageManager.APT];
361
+ const extraFlags = aptOpts?.flags ?? [];
283
362
  const isAptInstalled = await $.spawnSafe('which apt');
284
363
  if (isAptInstalled.status === SpawnStatus.SUCCESS) {
285
- const { status } = await $.spawnSafe(`apt-get -qq autoremove -y -o Dpkg::Use-Pty=0 -o Dpkg::Progress-Fancy=0 --purge ${packageName}`, {
364
+ const flagStr = extraFlags.length > 0 ? `${extraFlags.join(' ')} ` : '';
365
+ const { status } = await $.spawnSafe(`apt-get -qq autoremove -y -o Dpkg::Use-Pty=0 -o Dpkg::Progress-Fancy=0 --purge ${flagStr}${packageName}`, {
286
366
  requiresRoot: true,
287
367
  env: { DEBIAN_FRONTEND: 'noninteractive', NEEDRESTART_MODE: 'a' }
288
368
  });
289
369
  return status === SpawnStatus.SUCCESS;
290
370
  }
371
+ }
291
372
 
373
+ if (forcePackageManager === PackageManager.DNF || !forcePackageManager) {
374
+ const dnfOpts = options?.[PackageManager.DNF];
375
+ const extraFlags = dnfOpts?.flags ?? [];
292
376
  const isDnfInstalled = await $.spawnSafe('which dnf');
293
377
  if (isDnfInstalled.status === SpawnStatus.SUCCESS) {
294
- const { status } = await $.spawnSafe(`dnf autoremove ${packageName} -y`, { requiresRoot: true });
378
+ const flagStr = extraFlags.length > 0 ? `${extraFlags.join(' ')} ` : '';
379
+ const { status } = await $.spawnSafe(`dnf autoremove ${flagStr}${packageName} -y`, { requiresRoot: true });
295
380
  return status === SpawnStatus.SUCCESS;
296
381
  }
382
+ }
297
383
 
384
+ if (forcePackageManager === PackageManager.YUM || !forcePackageManager) {
385
+ const yumOpts = options?.[PackageManager.YUM];
386
+ const extraFlags = yumOpts?.flags ?? [];
298
387
  const isYumInstalled = await $.spawnSafe('which yum');
299
388
  if (isYumInstalled.status === SpawnStatus.SUCCESS) {
300
- const { status } = await $.spawnSafe(`yum autoremove ${packageName} -y`, { requiresRoot: true });
389
+ const flagStr = extraFlags.length > 0 ? `${extraFlags.join(' ')} ` : '';
390
+ const { status } = await $.spawnSafe(`yum autoremove ${flagStr}${packageName} -y`, { requiresRoot: true });
301
391
  return status === SpawnStatus.SUCCESS;
302
392
  }
303
-
304
- return false;
305
393
  }
306
394
 
307
395
  return false;