codify-plugin-lib 1.0.182-beta56 → 1.0.182-beta58

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.
@@ -21,6 +21,9 @@ export declare enum SpawnStatus {
21
21
  *
22
22
  * @property {boolean} [interactive] - Indicates whether the spawned process needs
23
23
  * to be interactive. Only works within apply (not plan). Defaults to true.
24
+ *
25
+ * @property {boolean} [disableWrapping] - Forces the terminal width to 10_000 to disable wrapping.
26
+ * In applys, this is off by default while it is on during plans.
24
27
  */
25
28
  export interface SpawnOptions {
26
29
  cwd?: string;
@@ -28,6 +31,7 @@ export interface SpawnOptions {
28
31
  interactive?: boolean;
29
32
  requiresRoot?: boolean;
30
33
  stdin?: boolean;
34
+ disableWrapping?: boolean;
31
35
  }
32
36
  export declare class SpawnError extends Error {
33
37
  data: string;
@@ -49,7 +49,8 @@ export class SequentialPty {
49
49
  ...historyIgnore
50
50
  };
51
51
  // Initial terminal dimensions
52
- const initialCols = 10_000; // Set to a really large value to prevent wrapping
52
+ // Set to a really large value to prevent wrapping
53
+ const initialCols = options?.disableWrapping ? 10_000 : process.stdout.columns ?? 80;
53
54
  const initialRows = process.stdout.rows ?? 24;
54
55
  const args = options?.interactive ? ['-i', '-c', cmd] : ['-c', cmd];
55
56
  // Run the command in a pty for interactivity
@@ -67,7 +68,7 @@ export class SequentialPty {
67
68
  });
68
69
  const resizeListener = () => {
69
70
  const { columns, rows } = process.stdout;
70
- mPty.resize(columns, rows);
71
+ mPty.resize(columns, options?.disableWrapping ? 10_000 : rows);
71
72
  };
72
73
  // Listen to resize events for the terminal window;
73
74
  process.stdout.on('resize', resizeListener);
@@ -27,4 +27,11 @@ export declare const Utils: {
27
27
  getPrimaryShellRc(): string;
28
28
  getShellRcFiles(): string[];
29
29
  isDirectoryOnPath(directory: string): Promise<boolean>;
30
+ assertBrewInstalled(): Promise<void>;
31
+ /**
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
34
+ */
35
+ installViaPkgMgr(packageName: string): Promise<boolean>;
36
+ linuxDistro(): Promise<"arch" | "centos" | "debian" | "fedora" | "rhel" | "ubuntu" | undefined>;
30
37
  };
@@ -1,6 +1,7 @@
1
+ import * as fs from 'node:fs/promises';
1
2
  import os from 'node:os';
2
3
  import path from 'node:path';
3
- import { getPty, SpawnStatus } from '../pty/index.js';
4
+ import { SpawnStatus, getPty } from '../pty/index.js';
4
5
  export function isDebug() {
5
6
  return process.env.DEBUG != null && process.env.DEBUG.includes('codify'); // TODO: replace with debug library
6
7
  }
@@ -138,4 +139,57 @@ export const Utils = {
138
139
  const lines = pathQuery.split(':');
139
140
  return lines.includes(directory);
140
141
  },
142
+ async assertBrewInstalled() {
143
+ const $ = getPty();
144
+ const brewCheck = await $.spawnSafe('which brew', { interactive: true });
145
+ if (brewCheck.status === SpawnStatus.ERROR) {
146
+ throw new Error(`Homebrew is not installed. Cannot install git-lfs without Homebrew installed.
147
+
148
+ Brew can be installed using Codify:
149
+ {
150
+ "type": "homebrew",
151
+ }`);
152
+ }
153
+ },
154
+ /**
155
+ * Installs a package via the system package manager. This will use Homebrew on macOS and apt on Ubuntu/Debian or dnf on Fedora.
156
+ * @param packageName
157
+ */
158
+ async installViaPkgMgr(packageName) {
159
+ const $ = getPty();
160
+ if (Utils.isMacOS()) {
161
+ await this.assertBrewInstalled();
162
+ const { status } = await $.spawnSafe(`brew install ${packageName}`, { interactive: true, env: { HOMEBREW_NO_AUTO_UPDATE: 1 } });
163
+ return status === SpawnStatus.SUCCESS;
164
+ }
165
+ if (Utils.isLinux()) {
166
+ const isAptInstalled = await $.spawnSafe('which apt');
167
+ if (isAptInstalled.status === SpawnStatus.SUCCESS) {
168
+ const { status } = await $.spawnSafe(`apt install ${packageName}`, { interactive: true, env: { DEBIAN_FRONTEND: 'noninteractive' } });
169
+ return status === SpawnStatus.SUCCESS;
170
+ }
171
+ const isDnfInstalled = await $.spawnSafe('which dnf');
172
+ if (isDnfInstalled.status === SpawnStatus.SUCCESS) {
173
+ const { status } = await $.spawnSafe(`dnf install ${packageName} -y`, { interactive: true });
174
+ return status === SpawnStatus.SUCCESS;
175
+ }
176
+ const isYumInstalled = await $.spawnSafe('which yum');
177
+ if (isYumInstalled.status === SpawnStatus.SUCCESS) {
178
+ const { status } = await $.spawnSafe(`yum install ${packageName} -y`, { interactive: true });
179
+ return status === SpawnStatus.SUCCESS;
180
+ }
181
+ return false;
182
+ }
183
+ return false;
184
+ },
185
+ async linuxDistro() {
186
+ const osRelease = await fs.readFile('/etc/os-release', 'utf8');
187
+ const lines = osRelease.split('\n');
188
+ for (const line of lines) {
189
+ if (line.startsWith('ID=')) {
190
+ return line.slice(3).trim();
191
+ }
192
+ }
193
+ return undefined;
194
+ }
141
195
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codify-plugin-lib",
3
- "version": "1.0.182-beta56",
3
+ "version": "1.0.182-beta58",
4
4
  "description": "Library plugin library",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
package/src/pty/index.ts CHANGED
@@ -25,6 +25,9 @@ export enum SpawnStatus {
25
25
  *
26
26
  * @property {boolean} [interactive] - Indicates whether the spawned process needs
27
27
  * to be interactive. Only works within apply (not plan). Defaults to true.
28
+ *
29
+ * @property {boolean} [disableWrapping] - Forces the terminal width to 10_000 to disable wrapping.
30
+ * In applys, this is off by default while it is on during plans.
28
31
  */
29
32
  export interface SpawnOptions {
30
33
  cwd?: string;
@@ -32,6 +35,7 @@ export interface SpawnOptions {
32
35
  interactive?: boolean;
33
36
  requiresRoot?: boolean;
34
37
  stdin?: boolean;
38
+ disableWrapping?: boolean;
35
39
  }
36
40
 
37
41
  export class SpawnError extends Error {
@@ -62,7 +62,8 @@ export class SequentialPty implements IPty {
62
62
  }
63
63
 
64
64
  // Initial terminal dimensions
65
- const initialCols = 10_000; // Set to a really large value to prevent wrapping
65
+ // Set to a really large value to prevent wrapping
66
+ const initialCols = options?.disableWrapping ? 10_000 : process.stdout.columns ?? 80
66
67
  const initialRows = process.stdout.rows ?? 24;
67
68
 
68
69
  const args = options?.interactive ? ['-i', '-c', cmd] : ['-c', cmd]
@@ -85,7 +86,7 @@ export class SequentialPty implements IPty {
85
86
 
86
87
  const resizeListener = () => {
87
88
  const { columns, rows } = process.stdout;
88
- mPty.resize(columns, rows);
89
+ mPty.resize(columns, options?.disableWrapping ? 10_000 : rows);
89
90
  }
90
91
 
91
92
  // Listen to resize events for the terminal window;
@@ -1,8 +1,9 @@
1
1
  import { OS } from 'codify-schemas';
2
+ import * as fs from 'node:fs/promises';
2
3
  import os from 'node:os';
3
4
  import path from 'node:path';
4
5
 
5
- import { getPty, SpawnStatus } from '../pty/index.js';
6
+ import { SpawnStatus, getPty } from '../pty/index.js';
6
7
 
7
8
  export function isDebug(): boolean {
8
9
  return process.env.DEBUG != null && process.env.DEBUG.includes('codify'); // TODO: replace with debug library
@@ -175,6 +176,71 @@ export const Utils = {
175
176
  const lines = pathQuery.split(':');
176
177
  return lines.includes(directory);
177
178
  },
179
+
180
+ async assertBrewInstalled(): Promise<void> {
181
+ const $ = getPty();
182
+ const brewCheck = await $.spawnSafe('which brew', { interactive: true });
183
+ if (brewCheck.status === SpawnStatus.ERROR) {
184
+ throw new Error(
185
+ `Homebrew is not installed. Cannot install git-lfs without Homebrew installed.
186
+
187
+ Brew can be installed using Codify:
188
+ {
189
+ "type": "homebrew",
190
+ }`
191
+ );
192
+ }
193
+ },
194
+
195
+ /**
196
+ * Installs a package via the system package manager. This will use Homebrew on macOS and apt on Ubuntu/Debian or dnf on Fedora.
197
+ * @param packageName
198
+ */
199
+ async installViaPkgMgr(packageName: string): Promise<boolean> {
200
+ const $ = getPty();
201
+
202
+ if (Utils.isMacOS()) {
203
+ await this.assertBrewInstalled();
204
+ const { status } = await $.spawnSafe(`brew install ${packageName}`, { interactive: true, env: { HOMEBREW_NO_AUTO_UPDATE: 1 } });
205
+ return status === SpawnStatus.SUCCESS;
206
+ }
207
+
208
+ if (Utils.isLinux()) {
209
+ const isAptInstalled = await $.spawnSafe('which apt');
210
+ if (isAptInstalled.status === SpawnStatus.SUCCESS) {
211
+ const { status } = await $.spawnSafe(`apt install ${packageName}`, { interactive: true, env: { DEBIAN_FRONTEND: 'noninteractive' } });
212
+ return status === SpawnStatus.SUCCESS;
213
+ }
214
+
215
+ const isDnfInstalled = await $.spawnSafe('which dnf');
216
+ if (isDnfInstalled.status === SpawnStatus.SUCCESS) {
217
+ const { status } = await $.spawnSafe(`dnf install ${packageName} -y`, { interactive: true });
218
+ return status === SpawnStatus.SUCCESS;
219
+ }
220
+
221
+ const isYumInstalled = await $.spawnSafe('which yum');
222
+ if (isYumInstalled.status === SpawnStatus.SUCCESS) {
223
+ const { status } = await $.spawnSafe(`yum install ${packageName} -y`, { interactive: true });
224
+ return status === SpawnStatus.SUCCESS;
225
+ }
226
+
227
+ return false;
228
+ }
229
+
230
+ return false;
231
+ },
232
+
233
+ async linuxDistro(): Promise<'arch' | 'centos' | 'debian' | 'fedora' | 'rhel' | 'ubuntu' | undefined> {
234
+ const osRelease = await fs.readFile('/etc/os-release', 'utf8');
235
+ const lines = osRelease.split('\n');
236
+ for (const line of lines) {
237
+ if (line.startsWith('ID=')) {
238
+ return line.slice(3).trim() as any;
239
+ }
240
+ }
241
+
242
+ return undefined;
243
+ }
178
244
  };
179
245
 
180
246