codify-plugin-lib 1.0.181 → 1.0.182-beta10
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/dist/index.d.ts +4 -1
- package/dist/index.js +4 -1
- package/dist/plugin/plugin.js +5 -2
- package/dist/pty/background-pty.d.ts +1 -0
- package/dist/pty/background-pty.js +17 -6
- package/dist/pty/index.d.ts +19 -1
- package/dist/pty/seqeuntial-pty.d.ts +17 -0
- package/dist/pty/seqeuntial-pty.js +117 -0
- package/dist/resource/parsed-resource-settings.d.ts +3 -1
- package/dist/resource/parsed-resource-settings.js +4 -6
- package/dist/resource/resource-settings.d.ts +5 -1
- package/dist/resource/resource-settings.js +1 -1
- package/dist/test.d.ts +1 -0
- package/dist/test.js +5 -0
- package/dist/utils/file-utils.d.ts +16 -0
- package/dist/utils/file-utils.js +172 -0
- package/dist/utils/functions.d.ts +12 -0
- package/dist/utils/functions.js +74 -0
- package/dist/utils/index.d.ts +26 -0
- package/dist/utils/index.js +111 -0
- package/dist/utils/internal-utils.d.ts +12 -0
- package/dist/utils/internal-utils.js +74 -0
- package/dist/utils/verbosity-level.d.ts +5 -0
- package/dist/utils/verbosity-level.js +9 -0
- package/package.json +2 -2
- package/src/index.ts +4 -1
- package/src/plan/plan.test.ts +6 -1
- package/src/plugin/plugin.test.ts +11 -2
- package/src/plugin/plugin.ts +5 -2
- package/src/pty/background-pty.ts +18 -6
- package/src/pty/index.test.ts +7 -4
- package/src/pty/index.ts +20 -2
- package/src/pty/seqeuntial-pty.ts +148 -0
- package/src/pty/sequential-pty.test.ts +179 -0
- package/src/resource/parsed-resource-settings.ts +8 -7
- package/src/resource/resource-controller-stateful-mode.test.ts +2 -1
- package/src/resource/resource-controller.test.ts +22 -4
- package/src/resource/resource-settings.test.ts +29 -2
- package/src/resource/resource-settings.ts +13 -2
- package/src/utils/file-utils.test.ts +7 -0
- package/src/utils/file-utils.ts +216 -0
- package/src/utils/{utils.ts → functions.ts} +0 -16
- package/src/utils/index.ts +144 -0
- package/src/utils/{utils.test.ts → internal-utils.test.ts} +1 -1
- package/src/utils/test-utils.test.ts +5 -2
- package/src/utils/verbosity-level.ts +11 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
2
|
import { Plan } from '../plan/plan.js';
|
|
3
3
|
import { spy } from 'sinon';
|
|
4
|
-
import { ParameterOperation, ResourceOperation } from 'codify-schemas';
|
|
4
|
+
import { OS, ParameterOperation, ResourceOperation } from 'codify-schemas';
|
|
5
5
|
import {
|
|
6
6
|
TestArrayStatefulParameter,
|
|
7
7
|
TestConfig,
|
|
@@ -26,6 +26,7 @@ describe('Resource parameter tests', () => {
|
|
|
26
26
|
getSettings(): ResourceSettings<TestConfig> {
|
|
27
27
|
return {
|
|
28
28
|
id: 'type',
|
|
29
|
+
operatingSystems: [OS.Darwin],
|
|
29
30
|
parameterSettings: {
|
|
30
31
|
propA: { type: 'stateful', definition: statefulParameter }
|
|
31
32
|
},
|
|
@@ -71,6 +72,7 @@ describe('Resource parameter tests', () => {
|
|
|
71
72
|
getSettings(): ResourceSettings<TestConfig> {
|
|
72
73
|
return {
|
|
73
74
|
id: 'type',
|
|
75
|
+
operatingSystems: [OS.Darwin],
|
|
74
76
|
parameterSettings: {
|
|
75
77
|
propA: { type: 'stateful', definition: statefulParameterSpy }
|
|
76
78
|
},
|
|
@@ -105,6 +107,7 @@ describe('Resource parameter tests', () => {
|
|
|
105
107
|
getSettings(): ResourceSettings<TestConfig> {
|
|
106
108
|
return {
|
|
107
109
|
id: 'type',
|
|
110
|
+
operatingSystems: [OS.Darwin],
|
|
108
111
|
parameterSettings: {
|
|
109
112
|
propA: { type: 'stateful', definition: statefulParameterSpy },
|
|
110
113
|
propB: { canModify: true },
|
|
@@ -137,7 +140,8 @@ describe('Resource parameter tests', () => {
|
|
|
137
140
|
const statefulParameter = spy(new class extends TestStatefulParameter {
|
|
138
141
|
getSettings(): ParameterSetting {
|
|
139
142
|
return {
|
|
140
|
-
default: 'abc'
|
|
143
|
+
default: 'abc',
|
|
144
|
+
operatingSystems: [OS.Darwin],
|
|
141
145
|
};
|
|
142
146
|
}
|
|
143
147
|
|
|
@@ -150,6 +154,7 @@ describe('Resource parameter tests', () => {
|
|
|
150
154
|
getSettings(): ResourceSettings<TestConfig> {
|
|
151
155
|
return {
|
|
152
156
|
id: 'type',
|
|
157
|
+
operatingSystems: [OS.Darwin],
|
|
153
158
|
parameterSettings: {
|
|
154
159
|
propA: { type: 'stateful', definition: statefulParameter }
|
|
155
160
|
},
|
|
@@ -191,6 +196,7 @@ describe('Resource parameter tests', () => {
|
|
|
191
196
|
getSettings(): ResourceSettings<TestConfig> {
|
|
192
197
|
return {
|
|
193
198
|
id: 'type',
|
|
199
|
+
operatingSystems: [OS.Darwin],
|
|
194
200
|
parameterSettings: {
|
|
195
201
|
propA: { type: 'stateful', definition: statefulParameterSpy },
|
|
196
202
|
},
|
|
@@ -225,6 +231,7 @@ describe('Resource parameter tests', () => {
|
|
|
225
231
|
getSettings(): ResourceSettings<TestConfig> {
|
|
226
232
|
return {
|
|
227
233
|
id: 'type',
|
|
234
|
+
operatingSystems: [OS.Darwin],
|
|
228
235
|
parameterSettings: {
|
|
229
236
|
propA: { type: 'stateful', definition: statefulParameterSpy }
|
|
230
237
|
},
|
|
@@ -251,6 +258,7 @@ describe('Resource parameter tests', () => {
|
|
|
251
258
|
getSettings(): ResourceSettings<TestConfig> {
|
|
252
259
|
return {
|
|
253
260
|
id: 'type',
|
|
261
|
+
operatingSystems: [OS.Darwin],
|
|
254
262
|
parameterSettings: {
|
|
255
263
|
hosts: {
|
|
256
264
|
type: 'array',
|
|
@@ -360,6 +368,7 @@ describe('Resource parameter tests', () => {
|
|
|
360
368
|
getSettings(): ResourceSettings<TestConfig> {
|
|
361
369
|
return {
|
|
362
370
|
id: 'type',
|
|
371
|
+
operatingSystems: [OS.Darwin],
|
|
363
372
|
parameterSettings: {
|
|
364
373
|
propA: { type: 'stateful', definition: statefulParameterSpy }
|
|
365
374
|
},
|
|
@@ -416,6 +425,7 @@ describe('Resource parameter tests', () => {
|
|
|
416
425
|
getSettings(): ResourceSettings<TestConfig> {
|
|
417
426
|
return {
|
|
418
427
|
id: 'resourceType',
|
|
428
|
+
operatingSystems: [OS.Darwin],
|
|
419
429
|
parameterSettings: {
|
|
420
430
|
propA: { type: 'stateful', definition: statefulParameterA, order: 3 },
|
|
421
431
|
propB: { type: 'stateful', definition: statefulParameterB, order: 1 },
|
|
@@ -494,6 +504,7 @@ describe('Resource parameter tests', () => {
|
|
|
494
504
|
getSettings(): ResourceSettings<TestConfig> {
|
|
495
505
|
return {
|
|
496
506
|
id: 'resourceType',
|
|
507
|
+
operatingSystems: [OS.Darwin],
|
|
497
508
|
parameterSettings: {
|
|
498
509
|
propA: { type: 'stateful', definition: statefulParameterA, order: 3 },
|
|
499
510
|
propB: { type: 'stateful', definition: statefulParameterB, order: 1 },
|
|
@@ -569,6 +580,7 @@ describe('Resource parameter tests', () => {
|
|
|
569
580
|
getSettings(): ResourceSettings<TestConfig> {
|
|
570
581
|
return {
|
|
571
582
|
id: 'resourceType',
|
|
583
|
+
operatingSystems: [OS.Darwin],
|
|
572
584
|
transformation: {
|
|
573
585
|
to: (desired) => ({
|
|
574
586
|
propA: 'propA',
|
|
@@ -610,6 +622,7 @@ describe('Resource parameter tests', () => {
|
|
|
610
622
|
getSettings(): ResourceSettings<TestConfig> {
|
|
611
623
|
return {
|
|
612
624
|
id: 'resourceType',
|
|
625
|
+
operatingSystems: [OS.Darwin],
|
|
613
626
|
transformation: {
|
|
614
627
|
to: (desired) => ({
|
|
615
628
|
propA: 'propA',
|
|
@@ -649,6 +662,7 @@ describe('Resource parameter tests', () => {
|
|
|
649
662
|
getSettings(): ResourceSettings<TestConfig> {
|
|
650
663
|
return {
|
|
651
664
|
id: 'resourceType',
|
|
665
|
+
operatingSystems: [OS.Darwin],
|
|
652
666
|
importAndDestroy: {
|
|
653
667
|
requiredParameters: [
|
|
654
668
|
'propA',
|
|
@@ -668,6 +682,7 @@ describe('Resource parameter tests', () => {
|
|
|
668
682
|
getSettings(): ResourceSettings<TestConfig> {
|
|
669
683
|
return {
|
|
670
684
|
id: 'resourceType',
|
|
685
|
+
operatingSystems: [OS.Darwin],
|
|
671
686
|
parameterSettings: {
|
|
672
687
|
propA: { type: 'directory' }
|
|
673
688
|
}
|
|
@@ -695,6 +710,7 @@ describe('Resource parameter tests', () => {
|
|
|
695
710
|
getSettings(): ResourceSettings<TestConfig> {
|
|
696
711
|
return {
|
|
697
712
|
id: 'resourceType',
|
|
713
|
+
operatingSystems: [OS.Darwin],
|
|
698
714
|
parameterSettings: {
|
|
699
715
|
propA: { type: 'string', setting: true },
|
|
700
716
|
propB: { type: 'number' }
|
|
@@ -737,6 +753,7 @@ describe('Resource parameter tests', () => {
|
|
|
737
753
|
getSettings(): ResourceSettings<TestConfig> {
|
|
738
754
|
return {
|
|
739
755
|
id: 'resourceType',
|
|
756
|
+
operatingSystems: [OS.Darwin],
|
|
740
757
|
importAndDestroy: {
|
|
741
758
|
requiredParameters: ['propA'],
|
|
742
759
|
refreshKeys: ['propB', 'propA'],
|
|
@@ -754,6 +771,7 @@ describe('Resource parameter tests', () => {
|
|
|
754
771
|
getSettings(): ResourceSettings<TestConfig> {
|
|
755
772
|
return {
|
|
756
773
|
id: 'resourceType',
|
|
774
|
+
operatingSystems: [OS.Darwin],
|
|
757
775
|
parameterSettings: {
|
|
758
776
|
propA: { type: 'string', isEqual: 'version' }
|
|
759
777
|
}
|
|
@@ -780,6 +798,7 @@ describe('Resource parameter tests', () => {
|
|
|
780
798
|
getSettings(): ResourceSettings<TestConfig> {
|
|
781
799
|
return {
|
|
782
800
|
id: 'resourceType',
|
|
801
|
+
operatingSystems: [OS.Darwin],
|
|
783
802
|
parameterSettings: {
|
|
784
803
|
propD: { type: 'object' }
|
|
785
804
|
}
|
|
@@ -822,6 +841,7 @@ describe('Resource parameter tests', () => {
|
|
|
822
841
|
getSettings(): ResourceSettings<TestConfig> {
|
|
823
842
|
return {
|
|
824
843
|
id: 'resourceType',
|
|
844
|
+
operatingSystems: [OS.Darwin],
|
|
825
845
|
parameterSettings: {
|
|
826
846
|
propD: { type: 'object' }
|
|
827
847
|
}
|
|
@@ -863,6 +883,7 @@ describe('Resource parameter tests', () => {
|
|
|
863
883
|
getSettings(): ResourceSettings<TestConfig> {
|
|
864
884
|
return {
|
|
865
885
|
id: 'resourceType',
|
|
886
|
+
operatingSystems: [OS.Darwin],
|
|
866
887
|
parameterSettings: {
|
|
867
888
|
propD: {
|
|
868
889
|
type: 'array',
|
|
@@ -968,6 +989,7 @@ describe('Resource parameter tests', () => {
|
|
|
968
989
|
getSettings(): ResourceSettings<TestConfig> {
|
|
969
990
|
return {
|
|
970
991
|
id: 'resourceType',
|
|
992
|
+
operatingSystems: [OS.Darwin],
|
|
971
993
|
parameterSettings: {
|
|
972
994
|
propD: { type: 'stateful', definition: sp }
|
|
973
995
|
}
|
|
@@ -1007,6 +1029,7 @@ describe('Resource parameter tests', () => {
|
|
|
1007
1029
|
getSettings(): ResourceSettings<TestConfig> {
|
|
1008
1030
|
return {
|
|
1009
1031
|
id: 'resourceType',
|
|
1032
|
+
operatingSystems: [OS.Darwin],
|
|
1010
1033
|
parameterSettings: {
|
|
1011
1034
|
propA: { type: 'array', itemType: 'version' }
|
|
1012
1035
|
}
|
|
@@ -1036,6 +1059,7 @@ describe('Resource parameter tests', () => {
|
|
|
1036
1059
|
getSettings(): ResourceSettings<TestConfig> {
|
|
1037
1060
|
return {
|
|
1038
1061
|
id: 'resourceType',
|
|
1062
|
+
operatingSystems: [OS.Darwin],
|
|
1039
1063
|
parameterSettings: {
|
|
1040
1064
|
propA: { type: 'array', itemType: 'directory' }
|
|
1041
1065
|
}
|
|
@@ -1065,6 +1089,7 @@ describe('Resource parameter tests', () => {
|
|
|
1065
1089
|
getSettings(): ResourceSettings<TestConfig> {
|
|
1066
1090
|
return {
|
|
1067
1091
|
id: 'resourceType',
|
|
1092
|
+
operatingSystems: [OS.Darwin],
|
|
1068
1093
|
parameterSettings: {
|
|
1069
1094
|
propA: { type: 'array', itemType: 'directory' }
|
|
1070
1095
|
},
|
|
@@ -1101,6 +1126,7 @@ describe('Resource parameter tests', () => {
|
|
|
1101
1126
|
getSettings(): ResourceSettings<TestConfig> {
|
|
1102
1127
|
return {
|
|
1103
1128
|
id: 'resourceType',
|
|
1129
|
+
operatingSystems: [OS.Darwin],
|
|
1104
1130
|
parameterSettings: {
|
|
1105
1131
|
propA: { type: 'array', itemType: 'directory' }
|
|
1106
1132
|
},
|
|
@@ -1127,6 +1153,7 @@ describe('Resource parameter tests', () => {
|
|
|
1127
1153
|
getSettings(): ResourceSettings<TestConfig> {
|
|
1128
1154
|
return {
|
|
1129
1155
|
id: 'resourceType',
|
|
1156
|
+
operatingSystems: [OS.Darwin],
|
|
1130
1157
|
parameterSettings: {
|
|
1131
1158
|
propA: { type: 'directory' }
|
|
1132
1159
|
},
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { JSONSchemaType } from 'ajv';
|
|
2
|
-
import { StringIndexedObject } from 'codify-schemas';
|
|
2
|
+
import { OS, StringIndexedObject } from 'codify-schemas';
|
|
3
3
|
import isObjectsEqual from 'lodash.isequal'
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
|
|
6
6
|
import { ArrayStatefulParameter, StatefulParameter } from '../stateful-parameter/stateful-parameter.js';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
addVariablesToPath,
|
|
9
|
+
areArraysEqual,
|
|
10
|
+
resolvePathWithVariables,
|
|
11
|
+
tildify,
|
|
12
|
+
untildify
|
|
13
|
+
} from '../utils/functions.js';
|
|
8
14
|
import { RefreshContext } from './resource.js';
|
|
9
15
|
|
|
10
16
|
export interface InputTransformation {
|
|
@@ -22,6 +28,11 @@ export interface ResourceSettings<T extends StringIndexedObject> {
|
|
|
22
28
|
*/
|
|
23
29
|
id: string;
|
|
24
30
|
|
|
31
|
+
/**
|
|
32
|
+
* List of supported operating systems
|
|
33
|
+
*/
|
|
34
|
+
operatingSystems: Array<OS>;
|
|
35
|
+
|
|
25
36
|
/**
|
|
26
37
|
* Schema to validate user configs with. Must be in the format JSON Schema draft07
|
|
27
38
|
*/
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { describe, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
describe('File utils tests', { timeout: 100_000_000 }, () => {
|
|
4
|
+
it('Can download a file', async () => {
|
|
5
|
+
// await FileUtils.downloadFile('https://download.jetbrains.com/webstorm/WebStorm-2025.3.1-aarch64.dmg?_gl=1*1huoi7o*_gcl_aw*R0NMLjE3NjU3NDAwMTcuQ2p3S0NBaUEzZm5KQmhBZ0Vpd0F5cW1ZNVhLVENlbHJOcTk2YXdjZVlfMS1wdE91MXc0WDk2bFJkVDM3QURhUFNJMUtwNVVSVUhxWTJob0NuZ0FRQXZEX0J3RQ..*_gcl_au*MjA0MDQ0MjE2My4xNzYzNjQzNzMz*FPAU*MjA0MDQ0MjE2My4xNzYzNjQzNzMz*_ga*MTYxMDg4MTkzMi4xNzYzNjQzNzMz*_ga_9J976DJZ68*czE3NjYzNjI5ODAkbzEyJGcxJHQxNzY2MzYzMDQwJGo2MCRsMCRoMA..', path.join(process.cwd(), 'google.html'));
|
|
6
|
+
})
|
|
7
|
+
})
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import * as fsSync from 'node:fs';
|
|
2
|
+
import * as fs from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { Readable } from 'node:stream';
|
|
5
|
+
import { finished } from 'node:stream/promises';
|
|
6
|
+
|
|
7
|
+
import { Utils } from './index.js';
|
|
8
|
+
|
|
9
|
+
const SPACE_REGEX = /^\s*$/
|
|
10
|
+
|
|
11
|
+
export class FileUtils {
|
|
12
|
+
static async downloadFile(url: string, destination: string): Promise<void> {
|
|
13
|
+
console.log(`Downloading file from ${url} to ${destination}`);
|
|
14
|
+
const { body } = await fetch(url)
|
|
15
|
+
|
|
16
|
+
const dirname = path.dirname(destination);
|
|
17
|
+
if (!await fs.stat(dirname).then((s) => s.isDirectory()).catch(() => false)) {
|
|
18
|
+
await fs.mkdir(dirname, { recursive: true });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const ws = fsSync.createWriteStream(destination)
|
|
22
|
+
// Different type definitions here for readable stream (NodeJS vs DOM). Small hack to fix that
|
|
23
|
+
await finished(Readable.fromWeb(body as never).pipe(ws));
|
|
24
|
+
|
|
25
|
+
console.log(`Finished downloading to ${destination}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static async addToStartupFile(line: string): Promise<void> {
|
|
29
|
+
const lineToInsert = addLeadingSpacer(
|
|
30
|
+
addTrailingSpacer(line)
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
await fs.appendFile(Utils.getPrimaryShellRc(), lineToInsert)
|
|
34
|
+
|
|
35
|
+
function addLeadingSpacer(line: string): string {
|
|
36
|
+
return line.startsWith('\n')
|
|
37
|
+
? line
|
|
38
|
+
: '\n' + line;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function addTrailingSpacer(line: string): string {
|
|
42
|
+
return line.endsWith('\n')
|
|
43
|
+
? line
|
|
44
|
+
: line + '\n';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static async addAllToStartupFile(lines: string[]): Promise<void> {
|
|
49
|
+
const formattedLines = '\n' + lines.join('\n') + '\n';
|
|
50
|
+
const shellRc = Utils.getPrimaryShellRc();
|
|
51
|
+
|
|
52
|
+
console.log(`Adding to ${path.basename(shellRc)}:
|
|
53
|
+
${lines.join('\n')}`)
|
|
54
|
+
|
|
55
|
+
await fs.appendFile(shellRc, formattedLines)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static async addPathToPrimaryShellRc(value: string, prepend: boolean): Promise<void> {
|
|
59
|
+
const shellRc = Utils.getPrimaryShellRc();
|
|
60
|
+
console.log(`Saving path: ${value} to ${shellRc}`);
|
|
61
|
+
|
|
62
|
+
if (prepend) {
|
|
63
|
+
await fs.appendFile(shellRc, `\nexport PATH=$PATH:${value};`, { encoding: 'utf8' });
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
await fs.appendFile(shellRc, `\nexport PATH=${value}:$PATH;`, { encoding: 'utf8' });
|
|
68
|
+
}
|
|
69
|
+
|
|
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
|
+
|
|
120
|
+
static async removeFromFile(filePath: string, search: string): Promise<void> {
|
|
121
|
+
const contents = await fs.readFile(filePath, 'utf8');
|
|
122
|
+
const newContents = contents.replaceAll(search, '');
|
|
123
|
+
|
|
124
|
+
await fs.writeFile(filePath, newContents, 'utf8');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
static async removeLineFromFile(filePath: string, search: RegExp | string): Promise<void> {
|
|
129
|
+
const file = await fs.readFile(filePath, 'utf8')
|
|
130
|
+
const lines = file.split('\n');
|
|
131
|
+
|
|
132
|
+
let searchRegex;
|
|
133
|
+
let searchString;
|
|
134
|
+
|
|
135
|
+
if (typeof search === 'object') {
|
|
136
|
+
const startRegex = /^([\t ]*)?/;
|
|
137
|
+
const endRegex = /([\t ]*)?/;
|
|
138
|
+
|
|
139
|
+
// Augment regex with spaces criteria to make sure this function is not deleting lines that are comments or has other content.
|
|
140
|
+
searchRegex = search
|
|
141
|
+
? new RegExp(
|
|
142
|
+
startRegex.source + search.source + endRegex.source,
|
|
143
|
+
search.flags
|
|
144
|
+
)
|
|
145
|
+
: search;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (typeof search === 'string') {
|
|
149
|
+
searchString = search;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
for (let counter = lines.length; counter >= 0; counter--) {
|
|
153
|
+
if (!lines[counter]) {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (searchString && lines[counter].includes(searchString)) {
|
|
158
|
+
lines.splice(counter, 1);
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (searchRegex && lines[counter].search(searchRegex) !== -1) {
|
|
163
|
+
lines.splice(counter, 1);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
await fs.writeFile(filePath, lines.join('\n'));
|
|
168
|
+
console.log(`Removed line: ${search} from ${filePath}`)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
static async removeLineFromPrimaryShellRc(search: RegExp | string): Promise<void> {
|
|
172
|
+
return FileUtils.removeLineFromFile(Utils.getPrimaryShellRc(), search);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Append the string to the end of a file ensuring at least 1 lines of space between.
|
|
176
|
+
// Ex result:
|
|
177
|
+
// something something;
|
|
178
|
+
//
|
|
179
|
+
// newline;
|
|
180
|
+
static appendToFileWithSpacing(file: string, textToInsert: string): string {
|
|
181
|
+
const lines = file.trimEnd().split(/\n/);
|
|
182
|
+
if (lines.length === 0) {
|
|
183
|
+
return textToInsert;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const endingNewLines = FileUtils.calculateEndingNewLines(lines);
|
|
187
|
+
const numNewLines = endingNewLines === -1
|
|
188
|
+
? 0
|
|
189
|
+
: Math.max(0, 2 - endingNewLines);
|
|
190
|
+
return lines.join('\n') + '\n'.repeat(numNewLines) + textToInsert
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// This is overly complicated but it can be used to insert into any
|
|
194
|
+
// position in the future
|
|
195
|
+
private static calculateEndingNewLines(lines: string[]): number {
|
|
196
|
+
let counter = 0;
|
|
197
|
+
while (true) {
|
|
198
|
+
const line = lines.at(-counter - 1);
|
|
199
|
+
|
|
200
|
+
if (!line) {
|
|
201
|
+
return -1
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (!SPACE_REGEX.test(line)) {
|
|
205
|
+
return counter;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
counter++;
|
|
209
|
+
|
|
210
|
+
// Short circuit here because we don't need to check over 2;
|
|
211
|
+
if (counter > 2) {
|
|
212
|
+
return counter;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
@@ -2,22 +2,6 @@ import { ResourceConfig, StringIndexedObject } from 'codify-schemas';
|
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
|
|
5
|
-
export const VerbosityLevel = new class {
|
|
6
|
-
level = 0;
|
|
7
|
-
|
|
8
|
-
get() {
|
|
9
|
-
return this.level;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
set(level: number) {
|
|
13
|
-
this.level = level;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function isDebug(): boolean {
|
|
18
|
-
return process.env.DEBUG != null && process.env.DEBUG.includes('codify'); // TODO: replace with debug library
|
|
19
|
-
}
|
|
20
|
-
|
|
21
5
|
export function splitUserConfig<T extends StringIndexedObject>(
|
|
22
6
|
config: ResourceConfig & T
|
|
23
7
|
): { parameters: T; coreParameters: ResourceConfig } {
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { OS } from 'codify-schemas';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
export function isDebug(): boolean {
|
|
6
|
+
return process.env.DEBUG != null && process.env.DEBUG.includes('codify'); // TODO: replace with debug library
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export enum Shell {
|
|
10
|
+
ZSH = 'zsh',
|
|
11
|
+
BASH = 'bash',
|
|
12
|
+
SH = 'sh',
|
|
13
|
+
KSH = 'ksh',
|
|
14
|
+
CSH = 'csh',
|
|
15
|
+
FISH = 'fish',
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface SystemInfo {
|
|
19
|
+
os: OS;
|
|
20
|
+
shell: Shell;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const Utils = {
|
|
24
|
+
getUser(): string {
|
|
25
|
+
return os.userInfo().username;
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
getSystemInfo() {
|
|
29
|
+
return {
|
|
30
|
+
os: os.type(),
|
|
31
|
+
shell: this.getShell(),
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
isMacOS(): boolean {
|
|
36
|
+
return os.platform() === 'darwin';
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
isLinux(): boolean {
|
|
40
|
+
return os.platform() === 'linux';
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
getShell(): Shell | undefined {
|
|
44
|
+
const shell = process.env.SHELL || '';
|
|
45
|
+
|
|
46
|
+
if (shell.endsWith('bash')) {
|
|
47
|
+
return Shell.BASH
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (shell.endsWith('zsh')) {
|
|
51
|
+
return Shell.ZSH
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (shell.endsWith('sh')) {
|
|
55
|
+
return Shell.SH
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (shell.endsWith('csh')) {
|
|
59
|
+
return Shell.CSH
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (shell.endsWith('ksh')) {
|
|
63
|
+
return Shell.KSH
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (shell.endsWith('fish')) {
|
|
67
|
+
return Shell.FISH
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return undefined;
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
getPrimaryShellRc(): string {
|
|
75
|
+
return this.getShellRcFiles()[0];
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
getShellRcFiles(): string[] {
|
|
79
|
+
const shell = process.env.SHELL || '';
|
|
80
|
+
const homeDir = os.homedir();
|
|
81
|
+
|
|
82
|
+
if (shell.endsWith('bash')) {
|
|
83
|
+
// Linux typically uses .bashrc, macOS uses .bash_profile
|
|
84
|
+
if (Utils.isLinux()) {
|
|
85
|
+
return [
|
|
86
|
+
path.join(homeDir, '.bashrc'),
|
|
87
|
+
path.join(homeDir, '.bash_profile'),
|
|
88
|
+
path.join(homeDir, '.profile'),
|
|
89
|
+
];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return [
|
|
93
|
+
path.join(homeDir, '.bash_profile'),
|
|
94
|
+
path.join(homeDir, '.bashrc'),
|
|
95
|
+
path.join(homeDir, '.profile'),
|
|
96
|
+
];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (shell.endsWith('zsh')) {
|
|
100
|
+
return [
|
|
101
|
+
path.join(homeDir, '.zshrc'),
|
|
102
|
+
path.join(homeDir, '.zprofile'),
|
|
103
|
+
path.join(homeDir, '.zshenv'),
|
|
104
|
+
];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (shell.endsWith('sh')) {
|
|
108
|
+
return [
|
|
109
|
+
path.join(homeDir, '.profile'),
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (shell.endsWith('ksh')) {
|
|
114
|
+
return [
|
|
115
|
+
path.join(homeDir, '.profile'),
|
|
116
|
+
path.join(homeDir, '.kshrc'),
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (shell.endsWith('csh')) {
|
|
121
|
+
return [
|
|
122
|
+
path.join(homeDir, '.cshrc'),
|
|
123
|
+
path.join(homeDir, '.login'),
|
|
124
|
+
path.join(homeDir, '.logout'),
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (shell.endsWith('fish')) {
|
|
129
|
+
return [
|
|
130
|
+
path.join(homeDir, '.config/fish/config.fish'),
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Default to bash-style files
|
|
135
|
+
return [
|
|
136
|
+
path.join(homeDir, '.bashrc'),
|
|
137
|
+
path.join(homeDir, '.bash_profile'),
|
|
138
|
+
path.join(homeDir, '.profile'),
|
|
139
|
+
];
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { addVariablesToPath, resolvePathWithVariables, splitUserConfig } from './
|
|
2
|
+
import { addVariablesToPath, resolvePathWithVariables, splitUserConfig } from './functions.js';
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
|
|
5
5
|
describe('Utils tests', () => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ResourceConfig, StringIndexedObject } from 'codify-schemas';
|
|
1
|
+
import { OS, ResourceConfig, StringIndexedObject } from 'codify-schemas';
|
|
2
2
|
import { ResourceSettings } from '../resource/resource-settings.js';
|
|
3
3
|
import { Plan } from '../plan/plan.js';
|
|
4
4
|
import { Resource } from '../resource/resource.js';
|
|
@@ -35,7 +35,10 @@ export interface TestConfig extends StringIndexedObject {
|
|
|
35
35
|
|
|
36
36
|
export class TestResource extends Resource<TestConfig> {
|
|
37
37
|
getSettings(): ResourceSettings<TestConfig> {
|
|
38
|
-
return {
|
|
38
|
+
return {
|
|
39
|
+
id: 'type',
|
|
40
|
+
operatingSystems: [OS.Darwin]
|
|
41
|
+
}
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
create(plan: CreatePlan<TestConfig>): Promise<void> {
|