@hurshb50/setup-ubuntu 0.0.1 → 0.0.3

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.
@@ -1,8 +1,641 @@
1
1
  #!/usr/bin/env node
2
2
  import { program } from "@commander-js/extra-typings";
3
+ import os from "os";
4
+ import path from "path";
5
+ import styles from "ansi-styles";
6
+ import escapes from "ansi-escapes";
7
+ import { setTimeout } from "timers/promises";
8
+ import { stdout } from "process";
9
+ import fs from "fs/promises";
10
+ import { execa } from "execa";
11
+ //#region package.json
12
+ var name = "@hurshb50/setup-ubuntu";
13
+ var version = "0.0.2";
14
+ //#endregion
15
+ //#region source/modules/logger/logger.ts
16
+ var Logger = class Logger {
17
+ status;
18
+ tasks;
19
+ tick;
20
+ static check = "✔";
21
+ static dots = [
22
+ "⠋",
23
+ "⠙",
24
+ "⠹",
25
+ "⠸",
26
+ "⠼",
27
+ "⠴",
28
+ "⠦",
29
+ "⠧",
30
+ "⠇",
31
+ "⠏"
32
+ ];
33
+ static defaultColumns = 150;
34
+ constructor() {
35
+ this.status = "idle";
36
+ this.tasks = [];
37
+ this.tick = 0;
38
+ }
39
+ add(task) {
40
+ this.tasks.push(task);
41
+ }
42
+ start() {
43
+ if (this.status !== "idle") throw new Error(`Cannot start task logger when status is '${this.status}'.`);
44
+ this.status = "in-progress";
45
+ this.loop();
46
+ }
47
+ stop() {
48
+ if (this.status !== "in-progress") throw new Error(`Cannot start task logger when status is '${this.status}'.`);
49
+ this.status = "done";
50
+ }
51
+ async loop() {
52
+ const minimumIntervalMilliSeconds = 80;
53
+ this.newline();
54
+ this.banner("Ubuntu Setup");
55
+ this.newline();
56
+ while (this.status === "in-progress") {
57
+ const start = performance.now();
58
+ this.write();
59
+ const remainingTime = minimumIntervalMilliSeconds - (performance.now() - start);
60
+ await setTimeout(remainingTime);
61
+ this.tick += 1;
62
+ }
63
+ this.write();
64
+ this.newline(this.tasks.length + 1);
65
+ this.log(styles.reset.close);
66
+ }
67
+ write() {
68
+ if (this.status === "idle") throw new Error("Cannot write to stdout if status is 'idle'.");
69
+ const columns = stdout.columns ?? Logger.defaultColumns;
70
+ for (const [taskIndex, task] of this.tasks.entries()) {
71
+ const width = columns - 1;
72
+ const { left, right } = this.render(task, width);
73
+ this.reset(task);
74
+ this.icon(task);
75
+ this.padding(2);
76
+ this.log(left);
77
+ const centerPadding = Math.max(1, width - (4 + left.length + right.length));
78
+ this.padding(centerPadding);
79
+ this.log(right);
80
+ if (taskIndex !== this.tasks.length - 1) this.down(1);
81
+ }
82
+ if (this.tasks.length > 1) this.up(this.tasks.length - 1);
83
+ }
84
+ dot() {
85
+ const dotIndex = this.tick % Logger.dots.length;
86
+ const dot = Logger.dots[dotIndex];
87
+ if (dot === void 0) throw new Error(`Invalid index '${dotIndex}' to access dots of length '${Logger.dots.length}'.`);
88
+ this.log(dot);
89
+ }
90
+ log(message) {
91
+ stdout.write(message);
92
+ }
93
+ truncate(text, maxWidth) {
94
+ if (text.length <= maxWidth) return text;
95
+ if (maxWidth < 1) return "";
96
+ return `${text.slice(0, maxWidth - 1)}…`;
97
+ }
98
+ render(task, width) {
99
+ const rightText = this.truncate(task.step ?? "", Math.max(0, width - 5 - task.name.length));
100
+ return {
101
+ left: this.truncate(task.name, Math.max(0, width - 4 - rightText.length)),
102
+ right: rightText
103
+ };
104
+ }
105
+ reset(task) {
106
+ let color = styles.yellow.open;
107
+ if (task.status === "done") color = styles.green.open;
108
+ this.log(escapes.cursorLeft);
109
+ this.log(escapes.eraseLine);
110
+ this.log(color);
111
+ }
112
+ icon(task) {
113
+ if (task.status === "idle") this.padding(2);
114
+ else if (task.status === "in-progress") this.dot();
115
+ else this.log(Logger.check);
116
+ }
117
+ padding(count = 1) {
118
+ this.log(" ".repeat(count));
119
+ }
120
+ newline(count = 1) {
121
+ this.log("\n".repeat(count));
122
+ }
123
+ up(count = 1) {
124
+ this.log(escapes.cursorUp(count));
125
+ }
126
+ down(count = 1) {
127
+ this.log(escapes.cursorDown(count));
128
+ }
129
+ banner(title) {
130
+ const columns = stdout.columns ?? Logger.defaultColumns;
131
+ const width = Math.max(4, columns - 2);
132
+ const text = ` ${title} `;
133
+ const remaining = Math.max(0, width - text.length);
134
+ const leftPadding = Math.floor(remaining / 2);
135
+ const rightPadding = remaining - leftPadding;
136
+ const leftText = " ".repeat(leftPadding) + text + " ".repeat(rightPadding);
137
+ const top = `╭${"─".repeat(width)}╮`;
138
+ const middle = `│${styles.bold.open}${styles.white.open}${leftText}${styles.white.close}${styles.bold.close}${styles.blue.open}│`;
139
+ const bottom = `╰${"─".repeat(width)}╯`;
140
+ this.log(styles.blue.open);
141
+ this.log(escapes.cursorLeft);
142
+ this.log(escapes.eraseLine);
143
+ this.log(top);
144
+ this.newline();
145
+ this.log(escapes.cursorLeft);
146
+ this.log(middle);
147
+ this.newline();
148
+ this.log(escapes.cursorLeft);
149
+ this.log(bottom);
150
+ this.log(styles.blue.close);
151
+ this.newline();
152
+ }
153
+ };
154
+ //#endregion
155
+ //#region source/modules/dependency-manager/dependency-manager.ts
156
+ var DependencyManager = class {
157
+ queue;
158
+ constructor() {
159
+ this.queue = Promise.resolve();
160
+ }
161
+ async commandExists(command) {
162
+ try {
163
+ await execa("command", ["-v", command], {
164
+ shell: true,
165
+ stdin: "ignore"
166
+ });
167
+ return true;
168
+ } catch {
169
+ const commandFilePath = path.join(os.homedir(), ".local", "bin", command);
170
+ return await fs.stat(commandFilePath, { throwIfNoEntry: false }) !== void 0;
171
+ }
172
+ }
173
+ async isInstalled(dependencies) {
174
+ return (await Promise.all(dependencies.map(async (dependency) => {
175
+ try {
176
+ const { stdout } = await execa("dpkg-query", [
177
+ "--show",
178
+ "--showformat=${Status}",
179
+ dependency
180
+ ]);
181
+ return stdout.includes("install ok installed");
182
+ } catch {
183
+ return false;
184
+ }
185
+ }))).every((installation) => installation === true);
186
+ }
187
+ async install(dependencies, task) {
188
+ await this.enqueue([
189
+ "install",
190
+ "-y",
191
+ "--no-install-recommends",
192
+ ...dependencies
193
+ ], task);
194
+ }
195
+ async update(task) {
196
+ await this.enqueue(["update"], task);
197
+ }
198
+ enqueue(managerArguments, task) {
199
+ const operation = this.queue.then(async () => {
200
+ const subprocess = execa("sudo", [
201
+ "env",
202
+ ...["DEBIAN_FRONTEND=noninteractive", "NEEDRESTART_SUSPEND=1"],
203
+ "apt-get",
204
+ ...managerArguments
205
+ ], { stdin: "ignore" });
206
+ let partial = "";
207
+ subprocess.stdout?.on("data", (chunk) => {
208
+ partial += chunk.toString();
209
+ const lines = partial.split(/\r\n|\r|\n/);
210
+ partial = lines.pop() ?? "";
211
+ const line = lines.at(-1)?.trim();
212
+ if (line) task.continue(line);
213
+ });
214
+ await subprocess;
215
+ });
216
+ this.queue = operation.catch(() => {});
217
+ return operation;
218
+ }
219
+ };
220
+ //#endregion
221
+ //#region source/modules/task/task.ts
222
+ var Task = class {
223
+ name;
224
+ status;
225
+ step;
226
+ constructor(name) {
227
+ this.name = name;
228
+ this.status = "idle";
229
+ this.step = void 0;
230
+ }
231
+ start() {
232
+ if (this.status !== "idle") throw new Error(`Cannot start task '${this.name}' when status is '${this.status}'.`);
233
+ this.status = "in-progress";
234
+ }
235
+ continue(step) {
236
+ if (this.status !== "in-progress") throw new Error(`Cannot update task '${this.name}' step when status is '${this.status}'.`);
237
+ this.step = step;
238
+ }
239
+ finish() {
240
+ if (this.status !== "in-progress") throw new Error(`Cannot finish task '${this.name}' when status is '${this.status}'.`);
241
+ this.step = void 0;
242
+ this.status = "done";
243
+ }
244
+ };
245
+ //#endregion
246
+ //#region source/modules/agent-rules/agent-rules.ts
247
+ var AgentRules = class {
248
+ async install(context) {
249
+ const task = new Task("Agent Rules");
250
+ context.logger.add(task);
251
+ task.start();
252
+ const destinationDirectoryPath = path.join(context.directories.home, ".config", "zed");
253
+ const destinationFilePath = path.join(destinationDirectoryPath, "AGENTS.md");
254
+ const sourceFilePath = path.join(context.directories.assets, "AGENTS.md");
255
+ task.continue("Create global rules directory");
256
+ await fs.mkdir(destinationDirectoryPath, { recursive: true });
257
+ task.continue("Copy agent rules");
258
+ await fs.copyFile(sourceFilePath, destinationFilePath);
259
+ task.finish();
260
+ }
261
+ };
262
+ //#endregion
263
+ //#region source/modules/agent-skills/agent-skills.ts
264
+ var AgentSkills = class {
265
+ async install(context) {
266
+ const task = new Task("Agent Skills");
267
+ context.logger.add(task);
268
+ task.start();
269
+ const destinationDirectoryPath = path.join(context.directories.home, ".agents", "skills");
270
+ const sourceDirectoryPath = path.join(context.directories.assets, "skills");
271
+ task.continue("Create global skills directory");
272
+ await fs.mkdir(destinationDirectoryPath, { recursive: true });
273
+ task.continue("Copy agent skills");
274
+ await fs.cp(sourceDirectoryPath, destinationDirectoryPath, { recursive: true });
275
+ task.finish();
276
+ }
277
+ };
278
+ //#endregion
279
+ //#region source/modules/auto-suggestion/auto-suggestion.ts
280
+ var AutoSuggestion = class {
281
+ async install(context) {
282
+ const task = new Task("Auto Suggestion");
283
+ context.logger.add(task);
284
+ task.start();
285
+ const destinationDirectoryPath = path.join(context.directories.home, ".local", "share");
286
+ const installedFilePath = path.join(destinationDirectoryPath, "blesh", "ble.sh");
287
+ const sourceFilePath = path.join(context.directories.assets, ".blerc");
288
+ const destinationFilePath = path.join(context.directories.home, ".blerc");
289
+ if (!(await fs.stat(installedFilePath, { throwIfNoEntry: false }) !== void 0)) {
290
+ task.continue("Update package manager");
291
+ await context.dependencyManager.update(task);
292
+ const dependencies = ["xz-utils"];
293
+ task.continue(`Installing dependencies: ${dependencies.join(", ")}`);
294
+ await context.dependencyManager.install(dependencies, task);
295
+ const temporaryDirectoryPath = await fs.mkdtemp(path.join(os.tmpdir(), "ble.sh"));
296
+ const installationFilePath = path.join(temporaryDirectoryPath, "ble-nightly", "ble.sh");
297
+ task.continue("Download ble.sh");
298
+ await execa(`curl -L https://github.com/akinomyoga/ble.sh/releases/download/nightly/ble-nightly.tar.xz | tar xJf - -C ${temporaryDirectoryPath}`, { shell: true });
299
+ task.continue("Install ble.sh");
300
+ await execa(`bash ${installationFilePath} --install ${destinationDirectoryPath}`, { shell: true });
301
+ task.continue("Remove temporary directory");
302
+ await fs.rm(temporaryDirectoryPath, { recursive: true });
303
+ }
304
+ task.continue("Copy configuration");
305
+ await fs.copyFile(sourceFilePath, destinationFilePath);
306
+ task.finish();
307
+ }
308
+ };
309
+ //#endregion
310
+ //#region source/modules/browser/browser.ts
311
+ var Browser = class {
312
+ async install(context) {
313
+ const task = new Task("Browser");
314
+ context.logger.add(task);
315
+ task.start();
316
+ const dependencies = ["google-chrome-stable"];
317
+ if (await context.dependencyManager.isInstalled(dependencies)) {
318
+ task.finish();
319
+ return;
320
+ }
321
+ task.continue("Update package manager");
322
+ await context.dependencyManager.update(task);
323
+ const systemDependencies = ["gnupg"];
324
+ task.continue(`Installing dependencies: ${systemDependencies.join(", ")}`);
325
+ await context.dependencyManager.install(systemDependencies, task);
326
+ const keyringFilePath = path.join("/", "usr", "share", "keyrings", "google-chrome.gpg");
327
+ const sourceFilePath = path.join("/", "etc", "apt", "sources.list.d", "google-chrome.list");
328
+ task.continue("Set up google chrome sources");
329
+ await execa(`curl -fsSL https://dl.google.com/linux/linux_signing_key.pub | sudo gpg --dearmor --yes -o ${keyringFilePath}`, { shell: true });
330
+ await execa(`echo 'deb [arch=amd64 signed-by=${keyringFilePath}] http://dl.google.com/linux/chrome/deb/ stable main' | sudo tee ${sourceFilePath} > /dev/null`, { shell: true });
331
+ task.continue("Update package manager");
332
+ await context.dependencyManager.update(task);
333
+ task.continue(`Installing dependencies: ${dependencies.join(", ")}`);
334
+ await context.dependencyManager.install(dependencies, task);
335
+ task.finish();
336
+ }
337
+ };
338
+ //#endregion
339
+ //#region source/modules/code-editor/code-editor.ts
340
+ var CodeEditor = class {
341
+ async install(context) {
342
+ const task = new Task("Code Editor");
343
+ context.logger.add(task);
344
+ task.start();
345
+ const sourceDirectoryPath = path.join(context.directories.assets, "zed");
346
+ const destinationDirectoryPath = path.join(context.directories.home, ".config", "zed");
347
+ task.continue("Install Zed");
348
+ if (!await context.dependencyManager.commandExists("zed")) await execa("curl -f https://zed.dev/install.sh | sh", { shell: true });
349
+ task.continue("Copy configuration");
350
+ await fs.cp(sourceDirectoryPath, destinationDirectoryPath, { recursive: true });
351
+ task.finish();
352
+ }
353
+ };
354
+ //#endregion
355
+ //#region source/modules/code-host/code-host.ts
356
+ var CodeHost = class {
357
+ async install(context) {
358
+ const task = new Task("Code Host");
359
+ context.logger.add(task);
360
+ task.start();
361
+ const dependencies = ["gh"];
362
+ if (await context.dependencyManager.isInstalled(dependencies)) {
363
+ task.finish();
364
+ return;
365
+ }
366
+ task.continue("Update package manager");
367
+ await context.dependencyManager.update(task);
368
+ const systemDependencies = ["gnupg"];
369
+ task.continue(`Installing dependencies: ${systemDependencies.join(", ")}`);
370
+ await context.dependencyManager.install(systemDependencies, task);
371
+ const keyringFilePath = path.join("/", "usr", "share", "keyrings", "github-cli.gpg");
372
+ const sourceFilePath = path.join("/", "etc", "apt", "sources.list.d", "github-cli.list");
373
+ task.continue("Set up github cli sources");
374
+ await execa(`curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.asc | sudo gpg --dearmor --yes -o ${keyringFilePath}`, { shell: true });
375
+ await execa(`echo "deb [arch=$(dpkg --print-architecture) signed-by=${keyringFilePath}] https://cli.github.com/packages stable main" | sudo tee ${sourceFilePath} > /dev/null`, { shell: true });
376
+ task.continue("Update package manager");
377
+ await context.dependencyManager.update(task);
378
+ task.continue(`Installing dependencies: ${dependencies.join(", ")}`);
379
+ await context.dependencyManager.install(dependencies, task);
380
+ task.finish();
381
+ }
382
+ };
383
+ //#endregion
384
+ //#region source/modules/container-engine/container-engine.ts
385
+ var ContainerEngine = class {
386
+ async install(context) {
387
+ const task = new Task("Container Engine");
388
+ context.logger.add(task);
389
+ task.start();
390
+ const dependencies = [
391
+ "docker-ce",
392
+ "docker-ce-cli",
393
+ "containerd.io",
394
+ "docker-buildx-plugin",
395
+ "docker-compose-plugin"
396
+ ];
397
+ if (await context.dependencyManager.isInstalled(dependencies)) {
398
+ task.finish();
399
+ return;
400
+ }
401
+ task.continue("Update package manager");
402
+ await context.dependencyManager.update(task);
403
+ const systemDependencies = ["gnupg"];
404
+ task.continue(`Installing dependencies: ${systemDependencies.join(", ")}`);
405
+ await context.dependencyManager.install(systemDependencies, task);
406
+ const keyringFilePath = path.join("/", "usr", "share", "keyrings", "docker.gpg");
407
+ const sourceFilePath = path.join("/", "etc", "apt", "sources.list.d", "docker.list");
408
+ task.continue("Set up docker sources");
409
+ await execa(`curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor --yes -o ${keyringFilePath}`, { shell: true });
410
+ await execa(`echo "deb [arch=$(dpkg --print-architecture) signed-by=${keyringFilePath}] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | sudo tee ${sourceFilePath} > /dev/null`, { shell: true });
411
+ task.continue("Update package manager");
412
+ await context.dependencyManager.update(task);
413
+ task.continue(`Installing dependencies: ${dependencies.join(", ")}`);
414
+ await context.dependencyManager.install(dependencies, task);
415
+ task.continue("Add user to docker group");
416
+ await execa(`sudo usermod --append --groups docker ${os.userInfo().username}`, { shell: true });
417
+ task.finish();
418
+ }
419
+ };
420
+ //#endregion
421
+ //#region source/modules/fonts/fonts.ts
422
+ var Fonts = class {
423
+ async install(context) {
424
+ const task = new Task("Fonts");
425
+ context.logger.add(task);
426
+ task.start();
427
+ const dependencies = ["fontconfig"];
428
+ if (!await context.dependencyManager.isInstalled(dependencies)) {
429
+ task.continue("Update package manager");
430
+ await context.dependencyManager.update(task);
431
+ task.continue(`Installing dependencies: ${dependencies.join(", ")}`);
432
+ await context.dependencyManager.install(dependencies, task);
433
+ }
434
+ const sourceDirectoryPath = path.join(context.directories.assets, "fonts");
435
+ const destinationDirectoryPath = path.join(context.directories.home, ".local", "share", "fonts");
436
+ task.continue("Create fonts directory");
437
+ await fs.mkdir(destinationDirectoryPath, { recursive: true });
438
+ task.continue("Copy fonts");
439
+ await fs.cp(sourceDirectoryPath, destinationDirectoryPath, { recursive: true });
440
+ task.finish();
441
+ }
442
+ };
443
+ //#endregion
444
+ //#region source/modules/fuzzy-finder/fuzzy-finder.ts
445
+ var FuzzyFinder = class {
446
+ async install(context) {
447
+ const task = new Task("Fuzzy Finder");
448
+ context.logger.add(task);
449
+ task.start();
450
+ const dependencies = ["fzf"];
451
+ if (await context.dependencyManager.isInstalled(dependencies)) {
452
+ task.finish();
453
+ return;
454
+ }
455
+ task.continue("Update package manager");
456
+ await context.dependencyManager.update(task);
457
+ task.continue(`Installing dependencies: ${dependencies.join(", ")}`);
458
+ await context.dependencyManager.install(dependencies, task);
459
+ task.finish();
460
+ }
461
+ };
462
+ //#endregion
463
+ //#region source/modules/password-manager/password-manager.ts
464
+ var PasswordManager = class {
465
+ async install(context) {
466
+ const task = new Task("Password Manager");
467
+ context.logger.add(task);
468
+ task.start();
469
+ const dependencies = ["libasound2t64", "1password"];
470
+ if (await context.dependencyManager.isInstalled(dependencies)) {
471
+ task.finish();
472
+ return;
473
+ }
474
+ task.continue("Update package manager");
475
+ await context.dependencyManager.update(task);
476
+ const systemDependencies = ["gnupg"];
477
+ task.continue(`Installing dependencies: ${systemDependencies.join(", ")}`);
478
+ await context.dependencyManager.install(systemDependencies, task);
479
+ const keyringFilePath = path.join("/", "usr", "share", "keyrings", "1password-archive-keyring.gpg");
480
+ const sourceFilePath = path.join("/", "etc", "apt", "sources.list.d", "1password.list");
481
+ const policyDirectoryPath = path.join("/", "etc", "debsig", "policies", "AC2D62742012EA22");
482
+ const policyFilePath = path.join(policyDirectoryPath, "1password.pol");
483
+ const debsigKeyringDirectoryPath = path.join("/", "usr", "share", "debsig", "keyrings", "AC2D62742012EA22");
484
+ const debsigKeyringFilePath = path.join(debsigKeyringDirectoryPath, "debsig.gpg");
485
+ task.continue("Set up 1password sources");
486
+ await execa(`curl -sS https://downloads.1password.com/linux/keys/1password.asc | sudo gpg --dearmor --yes --output ${keyringFilePath}`, { shell: true });
487
+ await execa(`echo 'deb [arch=amd64 signed-by=${keyringFilePath}] https://downloads.1password.com/linux/debian/amd64 stable main' | sudo tee ${sourceFilePath}`, { shell: true });
488
+ await execa(`sudo mkdir -p ${policyDirectoryPath}`, { shell: true });
489
+ await execa(`curl -sS https://downloads.1password.com/linux/debian/debsig/1password.pol | sudo tee ${policyFilePath}`, { shell: true });
490
+ await execa(`sudo mkdir -p ${debsigKeyringDirectoryPath}`, { shell: true });
491
+ await execa(`curl -sS https://downloads.1password.com/linux/keys/1password.asc | sudo gpg --dearmor --yes --output ${debsigKeyringFilePath}`, { shell: true });
492
+ task.continue("Update package manager");
493
+ await context.dependencyManager.update(task);
494
+ task.continue(`Installing dependencies: ${dependencies.join(", ")}`);
495
+ await context.dependencyManager.install(dependencies, task);
496
+ task.finish();
497
+ }
498
+ };
499
+ //#endregion
500
+ //#region source/modules/shell-configuration/shell-configuration.ts
501
+ var ShellConfiguration = class {
502
+ async install(context) {
503
+ const task = new Task("Shell Configuration");
504
+ context.logger.add(task);
505
+ task.start();
506
+ const sourceFilePath = path.join(context.directories.assets, ".bashrc");
507
+ const destinationFilePath = path.join(context.directories.home, ".bashrc");
508
+ task.continue("Copy shell configuration");
509
+ await fs.copyFile(sourceFilePath, destinationFilePath);
510
+ task.finish();
511
+ }
512
+ };
513
+ //#endregion
514
+ //#region source/modules/smart-change-directory/smart-change-directory.ts
515
+ var SmartChangeDirectory = class {
516
+ async install(context) {
517
+ const task = new Task("Smart Change Directory");
518
+ context.logger.add(task);
519
+ task.start();
520
+ const dependencies = ["zoxide"];
521
+ if (await context.dependencyManager.isInstalled(dependencies)) {
522
+ task.finish();
523
+ return;
524
+ }
525
+ task.continue("Update package manager");
526
+ await context.dependencyManager.update(task);
527
+ task.continue(`Installing dependencies: ${dependencies.join(", ")}`);
528
+ await context.dependencyManager.install(dependencies, task);
529
+ task.finish();
530
+ }
531
+ };
532
+ //#endregion
533
+ //#region source/modules/terminal-view/terminal-view.ts
534
+ var TerminalView = class {
535
+ async install(context) {
536
+ const task = new Task("Terminal View");
537
+ context.logger.add(task);
538
+ task.start();
539
+ if (!await context.dependencyManager.commandExists("oh-my-posh")) {
540
+ task.continue("Update package manager");
541
+ await context.dependencyManager.update(task);
542
+ const dependencies = ["unzip"];
543
+ task.continue(`Installing dependencies: ${dependencies.join(", ")}`);
544
+ await context.dependencyManager.install(dependencies, task);
545
+ task.continue("Install oh-my-posh");
546
+ await execa("curl -s https://ohmyposh.dev/install.sh | bash -s", { shell: true });
547
+ }
548
+ const sourceFilePath = path.join(context.directories.assets, "oh-my-posh.toml");
549
+ const destinationDirectoryPath = path.join(context.directories.home, ".config", "oh-my-posh");
550
+ const destinationFilePath = path.join(destinationDirectoryPath, "oh-my-posh.toml");
551
+ task.continue("Create configuration directory");
552
+ await fs.mkdir(destinationDirectoryPath, { recursive: true });
553
+ task.continue("Copy configuration");
554
+ await fs.copyFile(sourceFilePath, destinationFilePath);
555
+ task.finish();
556
+ }
557
+ };
558
+ //#endregion
559
+ //#region source/modules/version-control-system/version-control-system.ts
560
+ var VersionControlSystem = class {
561
+ async install(context) {
562
+ const task = new Task("Version Control System");
563
+ context.logger.add(task);
564
+ task.start();
565
+ const dependencies = ["git", "build-essential"];
566
+ if (await context.dependencyManager.isInstalled(dependencies)) {
567
+ task.finish();
568
+ return;
569
+ }
570
+ task.continue("Update package manager");
571
+ await context.dependencyManager.update(task);
572
+ task.continue(`Installing dependencies: ${dependencies.join(", ")}`);
573
+ await context.dependencyManager.install(dependencies, task);
574
+ task.finish();
575
+ }
576
+ };
577
+ //#endregion
578
+ //#region source/modules/wallpapers/wallpapers.ts
579
+ var Wallpapers = class {
580
+ async install(context) {
581
+ const task = new Task("Wallpapers");
582
+ context.logger.add(task);
583
+ task.start();
584
+ const dependencies = ["hydrapaper"];
585
+ if (!await context.dependencyManager.isInstalled(dependencies)) {
586
+ task.continue("Update package manager");
587
+ await context.dependencyManager.update(task);
588
+ task.continue(`Installing dependencies: ${dependencies.join(", ")}`);
589
+ await context.dependencyManager.install(dependencies, task);
590
+ }
591
+ const sourceDirectoryPath = path.join(context.directories.assets, "wallpapers");
592
+ const destinationDirectoryPath = path.join(context.directories.home, ".local", "share", "backgrounds");
593
+ task.continue("Create backgrounds directory");
594
+ await fs.mkdir(destinationDirectoryPath, { recursive: true });
595
+ task.continue("Copy wallpapers");
596
+ await fs.cp(sourceDirectoryPath, destinationDirectoryPath, { recursive: true });
597
+ task.finish();
598
+ }
599
+ };
3
600
  //#endregion
4
601
  //#region source/setup-ubuntu.ts
5
- program.name("@hurshb50/setup-ubuntu").version("0.0.0").description("TODO");
602
+ program.name(name).version(version).description("TODO").action(async () => {
603
+ const logger = new Logger();
604
+ const dependencyManager = new DependencyManager();
605
+ logger.start();
606
+ const packages = [
607
+ new AgentRules(),
608
+ new AgentSkills(),
609
+ new AutoSuggestion(),
610
+ new Browser(),
611
+ new CodeEditor(),
612
+ new CodeHost(),
613
+ new ContainerEngine(),
614
+ new Fonts(),
615
+ new FuzzyFinder(),
616
+ new PasswordManager(),
617
+ new ShellConfiguration(),
618
+ new SmartChangeDirectory(),
619
+ new TerminalView(),
620
+ new VersionControlSystem(),
621
+ new Wallpapers()
622
+ ];
623
+ try {
624
+ const directories = {
625
+ current: import.meta.dirname,
626
+ assets: path.join(import.meta.dirname, "assets"),
627
+ home: os.homedir()
628
+ };
629
+ const installations = packages.map(({ install }) => install({
630
+ dependencyManager,
631
+ directories,
632
+ logger
633
+ }));
634
+ await Promise.all(installations);
635
+ } finally {
636
+ logger.stop();
637
+ }
638
+ });
6
639
  program.parse();
7
640
  //#endregion
8
641
  export {};
package/package.json CHANGED
@@ -1,22 +1,27 @@
1
1
  {
2
2
  "name": "@hurshb50/setup-ubuntu",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "distribution"
7
7
  ],
8
- "bin": "./distribution/setup-ubuntu.js",
8
+ "bin": "./distribution/setup-ubuntu.mjs",
9
9
  "scripts": {
10
10
  "build": "vp pack",
11
11
  "check": "vp check",
12
- "check-fix": "vp check --fix",
13
- "test": "vp test",
14
- "test-watch": "vp test --watch"
12
+ "fix": "vp check --fix",
13
+ "unit-test": "vp test --project unit",
14
+ "integration-test": "node scripts/integration.ts",
15
+ "end-to-end-test": "docker build -t setup-ubuntu:end-to-end -f ./docker/end-to-end.dockerfile . && docker run --rm setup-ubuntu:end-to-end"
15
16
  },
16
17
  "dependencies": {
17
18
  "@commander-js/extra-typings": "^15.0.0",
18
- "@types/bun": "latest",
19
- "bumpp": "^11.1.0",
19
+ "ansi-escapes": "^7.3.0",
20
+ "ansi-styles": "^7.0.0",
21
+ "execa": "^10.0.1"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "latest",
20
25
  "typescript": "^7.0.2",
21
26
  "vite": "npm:@voidzero-dev/vite-plus-core@0.3.1",
22
27
  "vite-plus": "^0.2.4"