Skip to content

Commit b8cb876

Browse files
committed
feat: Added addiitonal utils
1 parent dce0de7 commit b8cb876

File tree

6 files changed

+119
-66
lines changed

6 files changed

+119
-66
lines changed

package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codify-plugin-lib",
3-
"version": "1.0.182-beta10",
3+
"version": "1.0.182-beta26",
44
"description": "Library plugin library",
55
"main": "dist/index.js",
66
"typings": "dist/index.d.ts",
@@ -22,7 +22,7 @@
2222
"ajv": "^8.12.0",
2323
"ajv-formats": "^2.1.1",
2424
"clean-deep": "^3.4.0",
25-
"codify-schemas": "1.0.86-beta5",
25+
"codify-schemas": "1.0.86-beta7",
2626
"lodash.isequal": "^4.5.0",
2727
"nanoid": "^5.0.9",
2828
"strip-ansi": "^7.1.0",

src/utils/file-utils.ts

Lines changed: 70 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export class FileUtils {
2525
console.log(`Finished downloading to ${destination}`);
2626
}
2727

28-
static async addToStartupFile(line: string): Promise<void> {
28+
static async addToShellRc(line: string): Promise<void> {
2929
const lineToInsert = addLeadingSpacer(
3030
addTrailingSpacer(line)
3131
);
@@ -45,7 +45,7 @@ export class FileUtils {
4545
}
4646
}
4747

48-
static async addAllToStartupFile(lines: string[]): Promise<void> {
48+
static async addAllToShellRc(lines: string[]): Promise<void> {
4949
const formattedLines = '\n' + lines.join('\n') + '\n';
5050
const shellRc = Utils.getPrimaryShellRc();
5151

@@ -55,7 +55,17 @@ ${lines.join('\n')}`)
5555
await fs.appendFile(shellRc, formattedLines)
5656
}
5757

58-
static async addPathToPrimaryShellRc(value: string, prepend: boolean): Promise<void> {
58+
/**
59+
* This method adds a directory path to the shell rc file if it doesn't already exist.
60+
*
61+
* @param value - The directory path to add.
62+
* @param prepend - Whether to prepend the path to the existing PATH variable.
63+
*/
64+
static async addPathToShellRc(value: string, prepend: boolean): Promise<void> {
65+
if (await Utils.isDirectoryOnPath(value)) {
66+
return;
67+
}
68+
5969
const shellRc = Utils.getPrimaryShellRc();
6070
console.log(`Saving path: ${value} to ${shellRc}`);
6171

@@ -67,64 +77,13 @@ ${lines.join('\n')}`)
6777
await fs.appendFile(shellRc, `\nexport PATH=${value}:$PATH;`, { encoding: 'utf8' });
6878
}
6979

70-
static async dirExists(path: string): Promise<boolean> {
71-
let stat;
72-
try {
73-
stat = await fs.stat(path);
74-
return stat.isDirectory();
75-
} catch {
76-
return false;
77-
}
78-
}
79-
80-
static async fileExists(path: string): Promise<boolean> {
81-
let stat;
82-
try {
83-
stat = await fs.stat(path);
84-
return stat.isFile();
85-
} catch {
86-
return false;
87-
}
88-
}
89-
90-
static async exists(path: string): Promise<boolean> {
91-
try {
92-
await fs.stat(path);
93-
return true;
94-
} catch {
95-
return false;
96-
}
97-
}
98-
99-
static async checkDirExistsOrThrowIfFile(path: string): Promise<boolean> {
100-
let stat;
101-
try {
102-
stat = await fs.stat(path);
103-
} catch {
104-
return false;
105-
}
106-
107-
if (stat.isDirectory()) {
108-
return true;
109-
}
110-
111-
throw new Error(`Directory ${path} already exists and is a file`);
112-
}
113-
114-
static async createDirIfNotExists(path: string): Promise<void> {
115-
if (!fsSync.existsSync(path)) {
116-
await fs.mkdir(path, { recursive: true });
117-
}
118-
}
119-
12080
static async removeFromFile(filePath: string, search: string): Promise<void> {
12181
const contents = await fs.readFile(filePath, 'utf8');
12282
const newContents = contents.replaceAll(search, '');
12383

12484
await fs.writeFile(filePath, newContents, 'utf8');
12585
}
12686

127-
12887
static async removeLineFromFile(filePath: string, search: RegExp | string): Promise<void> {
12988
const file = await fs.readFile(filePath, 'utf8')
13089
const lines = file.split('\n');
@@ -168,10 +127,16 @@ ${lines.join('\n')}`)
168127
console.log(`Removed line: ${search} from ${filePath}`)
169128
}
170129

171-
static async removeLineFromPrimaryShellRc(search: RegExp | string): Promise<void> {
130+
static async removeLineFromShellRc(search: RegExp | string): Promise<void> {
172131
return FileUtils.removeLineFromFile(Utils.getPrimaryShellRc(), search);
173132
}
174133

134+
static async removeAllLinesFromShellRc(searches: Array<RegExp | string>): Promise<void> {
135+
for (const search of searches) {
136+
await FileUtils.removeLineFromFile(Utils.getPrimaryShellRc(), search);
137+
}
138+
}
139+
175140
// Append the string to the end of a file ensuring at least 1 lines of space between.
176141
// Ex result:
177142
// something something;
@@ -190,6 +155,56 @@ ${lines.join('\n')}`)
190155
return lines.join('\n') + '\n'.repeat(numNewLines) + textToInsert
191156
}
192157

158+
static async dirExists(path: string): Promise<boolean> {
159+
let stat;
160+
try {
161+
stat = await fs.stat(path);
162+
return stat.isDirectory();
163+
} catch {
164+
return false;
165+
}
166+
}
167+
168+
static async fileExists(path: string): Promise<boolean> {
169+
let stat;
170+
try {
171+
stat = await fs.stat(path);
172+
return stat.isFile();
173+
} catch {
174+
return false;
175+
}
176+
}
177+
178+
static async exists(path: string): Promise<boolean> {
179+
try {
180+
await fs.stat(path);
181+
return true;
182+
} catch {
183+
return false;
184+
}
185+
}
186+
187+
static async checkDirExistsOrThrowIfFile(path: string): Promise<boolean> {
188+
let stat;
189+
try {
190+
stat = await fs.stat(path);
191+
} catch {
192+
return false;
193+
}
194+
195+
if (stat.isDirectory()) {
196+
return true;
197+
}
198+
199+
throw new Error(`Directory ${path} already exists and is a file`);
200+
}
201+
202+
static async createDirIfNotExists(path: string): Promise<void> {
203+
if (!fsSync.existsSync(path)) {
204+
await fs.mkdir(path, { recursive: true });
205+
}
206+
}
207+
193208
// This is overly complicated but it can be used to insert into any
194209
// position in the future
195210
private static calculateEndingNewLines(lines: string[]): number {

src/utils/functions.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ export function splitUserConfig<T extends StringIndexedObject>(
99
type: config.type,
1010
...(config.name ? { name: config.name } : {}),
1111
...(config.dependsOn ? { dependsOn: config.dependsOn } : {}),
12+
...(config.os ? { os: config.os } : {}),
1213
};
1314

1415
// eslint-disable-next-line @typescript-eslint/no-unused-vars
15-
const { type, name, dependsOn, ...parameters } = config;
16+
const { type, name, dependsOn, os, ...parameters } = config;
1617

1718
return {
1819
parameters: parameters as T,
@@ -35,8 +36,7 @@ export function tildify(pathWithTilde: string) {
3536
}
3637

3738
export function resolvePathWithVariables(pathWithVariables: string) {
38-
// @ts-expect-error Ignore this for now
39-
return pathWithVariables.replace(/\$([A-Z_]+[A-Z0-9_]*)|\${([A-Z0-9_]*)}/ig, (_, a, b) => process.env[a || b])
39+
return pathWithVariables.replaceAll(/\$([A-Z_]+[A-Z0-9_]*)|\${([A-Z0-9_]*)}/ig, (_, a, b) => process.env[a || b])
4040
}
4141

4242
export function addVariablesToPath(pathWithoutVariables: string) {

src/utils/index.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { OS } from 'codify-schemas';
22
import os from 'node:os';
33
import path from 'node:path';
44

5+
import { getPty, SpawnStatus } from '../pty/index.js';
6+
57
export function isDebug(): boolean {
68
return process.env.DEBUG != null && process.env.DEBUG.includes('codify'); // TODO: replace with debug library
79
}
@@ -40,6 +42,34 @@ export const Utils = {
4042
return os.platform() === 'linux';
4143
},
4244

45+
async isArmArch(): Promise<boolean> {
46+
const $ = getPty();
47+
if (!Utils.isMacOS()) {
48+
// On Linux, check uname -m
49+
const query = await $.spawn('uname -m');
50+
return query.data.trim() === 'aarch64' || query.data.trim() === 'arm64';
51+
}
52+
53+
const query = await $.spawn('sysctl -n machdep.cpu.brand_string');
54+
return /M(\d)/.test(query.data);
55+
},
56+
57+
async isHomebrewInstalled(): Promise<boolean> {
58+
const $ = getPty();
59+
const query = await $.spawnSafe('which brew', { interactive: true });
60+
return query.status === SpawnStatus.SUCCESS;
61+
},
62+
63+
async isRosetta2Installed(): Promise<boolean> {
64+
if (!Utils.isMacOS()) {
65+
return false;
66+
}
67+
68+
const $ = getPty();
69+
const query = await $.spawnSafe('arch -x86_64 /usr/bin/true 2> /dev/null', { interactive: true });
70+
return query.status === SpawnStatus.SUCCESS;
71+
},
72+
4373
getShell(): Shell | undefined {
4474
const shell = process.env.SHELL || '';
4575

@@ -138,6 +168,13 @@ export const Utils = {
138168
path.join(homeDir, '.profile'),
139169
];
140170
},
171+
172+
async isDirectoryOnPath(directory: string): Promise<boolean> {
173+
const $ = getPty();
174+
const { data: pathQuery } = await $.spawn('echo $PATH', { interactive: true });
175+
const lines = pathQuery.split(':');
176+
return lines.includes(directory);
177+
},
141178
};
142179

143180

src/utils/internal-utils.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ describe('Utils tests', () => {
88
type: 'type',
99
name: 'name',
1010
dependsOn: ['a', 'b', 'c'],
11+
os: ['linux'],
1112
propA: 'propA',
1213
propB: 'propB',
1314
propC: 'propC',

0 commit comments

Comments
 (0)