From 6761bad26ec3834e3e7b99b70d79072a933d280c Mon Sep 17 00:00:00 2001 From: JOLIMAITRE Matthieu Date: Fri, 27 May 2022 03:47:38 +0300 Subject: [PATCH] initial commit --- complete.ts | 60 +++++++++++++++++++++++++ lib/context.ts | 36 +++++++++++++++ lib/deps.ts | 1 + lib/setup.ts | 15 +++++++ lib/utilities.ts | 105 +++++++++++++++++++++++++++++++++++++++++++ parts/bat.ts | 33 ++++++++++++++ parts/hello-world.ts | 13 ++++++ parts/kitty.ts | 0 parts/lvim.ts | 0 parts/n.ts | 0 parts/nano.ts | 0 parts/paru.ts | 0 parts/rc.ts | 7 +++ parts/rustup.ts | 0 parts/sudo.ts | 0 parts/tldr.ts | 0 parts/zsh.ts | 0 prelude.sh | 12 +++++ 18 files changed, 282 insertions(+) create mode 100644 complete.ts create mode 100644 lib/context.ts create mode 100644 lib/deps.ts create mode 100644 lib/setup.ts create mode 100644 lib/utilities.ts create mode 100644 parts/bat.ts create mode 100644 parts/hello-world.ts create mode 100644 parts/kitty.ts create mode 100644 parts/lvim.ts create mode 100644 parts/n.ts create mode 100644 parts/nano.ts create mode 100644 parts/paru.ts create mode 100644 parts/rc.ts create mode 100644 parts/rustup.ts create mode 100644 parts/sudo.ts create mode 100644 parts/tldr.ts create mode 100644 parts/zsh.ts create mode 100644 prelude.sh diff --git a/complete.ts b/complete.ts new file mode 100644 index 0000000..9891f59 --- /dev/null +++ b/complete.ts @@ -0,0 +1,60 @@ +import { success_format, value_format, process_format, prompt, failure_format } from "./lib/utilities.ts" +import { Context, Config } from "./lib/context.ts" + +// import { HelloWorldSetup } from "./parts/setup-hello-world.ts" +import { BatSetup } from "./parts/bat.ts" + +const config: Config = { + working_directory: "./barnulfizator-wd" +} +const all = [ + //new HelloWorldSetup(), + // nano + // sudo + // rustup + // paru + // zsh + // kitty + // lvim + // n + // tldr + new BatSetup(), + // rc +]; + +async function main() { + + console.log( + success_format("all components:\n") + + all + .map(s => `- '${value_format(s.name)}'`) + .join("\n") + + "\n" + ); + + const context = new Context(config); + + for (const setup of all) { + const input = await prompt(`Install '${setup.name}' ?`, ["y", "n"], "y"); + if (input == "y") context.push_to_install(setup); + } + + while (true) { + const setup = context.next_to_install(); + if (setup == undefined) break; + + console.log(process_format("Installing '") + value_format(setup.name) + process_format("' ...")) + const result = await setup.install(context); + + if (result == "Ok") { + console.log(success_format("Installed '") + value_format(setup.name) + success_format("' successfully.")); + context.set_installed(setup); + } + else { + console.log(failure_format("Failed to install '") + value_format(setup.name) + failure_format("'.")); + context.set_failed(setup); + } + } +} + +await main() \ No newline at end of file diff --git a/lib/context.ts b/lib/context.ts new file mode 100644 index 0000000..93e3a8f --- /dev/null +++ b/lib/context.ts @@ -0,0 +1,36 @@ +import { Setup } from "./setup.ts" + +export type Config = { + working_directory: string, +} + +export class Context { + installed_names: string[]; + to_install: Setup[]; + working_dir: string; + + constructor(config: Config) { + this.installed_names = []; + this.to_install = []; + this.working_dir = config.working_directory; + } + + push_to_install(setup: Setup) { + this.to_install.push(setup) + } + + set_installed(setup: Setup) { + const index = this.to_install.findIndex(e => e.name == setup.name); + if (index != -1) this.to_install.splice(index, 1); + this.installed_names.push(setup.name); + } + + set_failed(setup: Setup) { + const index = this.to_install.findIndex(e => e.name == setup.name); + if (index != -1) this.to_install.splice(index, 1); + } + + next_to_install(): Setup | undefined { + return this.to_install[0] + } +} \ No newline at end of file diff --git a/lib/deps.ts b/lib/deps.ts new file mode 100644 index 0000000..b5fe24b --- /dev/null +++ b/lib/deps.ts @@ -0,0 +1 @@ +export { styles } from "https://deno.land/x/ansi_styles@1.0.0/mod.ts"; diff --git a/lib/setup.ts b/lib/setup.ts new file mode 100644 index 0000000..3587d88 --- /dev/null +++ b/lib/setup.ts @@ -0,0 +1,15 @@ +import { Context } from "./context.ts" + +export type SetupResult = "Ok" | "Error"; + +export abstract class Setup { + name: string; + dependencies: string[]; + + constructor(options: { name: string, dependencies?: string[] }) { + this.dependencies = options.dependencies ?? []; + this.name = options.name; + } + + abstract install(context: Context): Promise; +} diff --git a/lib/utilities.ts b/lib/utilities.ts new file mode 100644 index 0000000..9a32f10 --- /dev/null +++ b/lib/utilities.ts @@ -0,0 +1,105 @@ +import { readLines } from "https://deno.land/std@0.140.0/io/mod.ts"; +import { writeAll } from "https://deno.land/std@0.140.0/streams/conversion.ts "; +import { styles } from "./deps.ts" + +export type CommandResult = { + status: "ok" +} | { + status: "Error", + stdout: string, + stderr: string +} + +/** Synthesize platform dependent shell command arguments. */ +function shArgs(command: string): string[] { + if (Deno.build.os === "windows") { + return ["PowerShell.exe", "-Command", command]; + } else { + const shellExe = Deno.env.get("SHELL") ?? "/bin/sh"; + return [shellExe, "-c", command]; + } +} + +/* +0x6a j ┘ +0x6b k ┐ +0x6c l ┌ +0x6d m └ +0x6e n ┼ +0x71 q ─ +0x74 t ├ +0x75 u ┤ +0x76 v ┴ +0x77 w ┬ +0x78 x │ + +*/ + + +export function value_format(text: string): string { + return `${styles.bold.open}${styles.white.open}${text}${styles.white.close}${styles.bold.close}`; +} + +export function process_format(text: string): string { + return `${styles.blue.open}${text}${styles.blue.close}`; +} + +export function prompt_format(text: string): string { + return `${styles.yellow.open}${text}${styles.yellow.close}`; +} + +export function success_format(text: string): string { + return `${styles.green.open}${text}${styles.green.close}`; +} + +export function failure_format(text: string): string { + return `${styles.red.open}${text}${styles.red.close}`; +} + +export async function run(command: string): Promise { + //throw "todo"; + + console.log(`${value_format("┌")} ${process_format("running '")}${value_format(command)}${process_format("'")}`); + + const cmd = shArgs(command); + const process = Deno.run({ + cmd: cmd, + stdin: "piped", + stdout: "piped", + stderr: "piped" + }); + + const [_o, _e, satus] = await Promise.all([pipe_out(process.stdout), pipe_out(process.stderr), process.status()]); + const code = satus.code; + return code; +} + +export async function pipe_out(out: Deno.Reader) { + const encoder = new TextEncoder(); + for await (const line of readLines(out)) + await writeAll(Deno.stdout, encoder.encode(`${value_format("│")} ${line}\n`)); +} + +// asks a question to the user +export async function prompt(line: string, options?: string[], default_?: string) { + + let options_part = ""; + if (options != undefined) options_part = `[${options.map(s => value_format(s)).join('/')}]`; + + let default_part = ""; + if (default_ != undefined) default_part = `(default: '${default_}')`; + + const text = `─> ${prompt_format(line)} ${options_part} ${default_part}`; + console.log(text); + + for await (const line of readLines(Deno.stdin)) { + if (default_ != undefined && line == "") return default_; + + if (options != undefined && !options.includes(line)) { + console.log(text); + continue; + } + + return line + } +} diff --git a/parts/bat.ts b/parts/bat.ts new file mode 100644 index 0000000..c09b4e6 --- /dev/null +++ b/parts/bat.ts @@ -0,0 +1,33 @@ +import { Setup, SetupResult } from "../lib/setup.ts" +import { Context } from "../lib/context.ts" +import { prompt, run, prompt_format } from "../lib/utilities.ts" + +export class BatSetup extends Setup { + constructor() { + super({ name: "bat" }) + } + + async install(context: Context): Promise { + const method = await prompt("Which method ?", ["pacman", "github", "cargo"], "pacman"); + + if (method == "pacman") { + await run("sudo pacman -S --noconfirm community/bat"); + } + + if (method == "github") { + await run(`mkdir -p ${context.working_dir}`); + await run(`wget "https://github.com/sharkdp/bat/releases/download/v0.21.0/bat-v0.21.0-i686-unknown-linux-gnu.tar.gz" -O "${context.working_dir}/bat-bin-linux.tar.gz"`); + await run(`tar xf "${context.working_dir}/bat-bin-linux.tar.gz" -C "${context.working_dir}"`); + await run(`mkdir -p "$HOME/.local/bin"`); + await run(`cp "${context.working_dir}/bat-v0.21.0-i686-unknown-linux-gnu/bat" "$HOME/.local/bin/"`); + await run(`rm -rf "${context.working_dir}/bat-v0.21.0-i686-unknown-linux-gnu" "${context.working_dir}/bat-bin-linux.tar.gz"`) + console.log(prompt_format("Don't forget to add '$HOME/.local/bin' to your path.")); + } + + if (method == "cargo") { + throw "TODO" + } + + return "Ok" + } +} diff --git a/parts/hello-world.ts b/parts/hello-world.ts new file mode 100644 index 0000000..673e4b3 --- /dev/null +++ b/parts/hello-world.ts @@ -0,0 +1,13 @@ +import { run } from "../lib/utilities.ts" +import { Setup, SetupResult } from "../lib/setup.ts" + +export class HelloWorldSetup extends Setup { + constructor() { + super({ name: "hello-world" }); + } + + async install(): Promise { + await run("echo hello yorld"); + return "Ok" + } +} diff --git a/parts/kitty.ts b/parts/kitty.ts new file mode 100644 index 0000000..e69de29 diff --git a/parts/lvim.ts b/parts/lvim.ts new file mode 100644 index 0000000..e69de29 diff --git a/parts/n.ts b/parts/n.ts new file mode 100644 index 0000000..e69de29 diff --git a/parts/nano.ts b/parts/nano.ts new file mode 100644 index 0000000..e69de29 diff --git a/parts/paru.ts b/parts/paru.ts new file mode 100644 index 0000000..e69de29 diff --git a/parts/rc.ts b/parts/rc.ts new file mode 100644 index 0000000..f50ee6d --- /dev/null +++ b/parts/rc.ts @@ -0,0 +1,7 @@ +import { Setup, SetupResult } from "../lib/setup.ts" + +export class RcSetup extends Setup { + async install(): Promise { + return "Ok"; + } +} diff --git a/parts/rustup.ts b/parts/rustup.ts new file mode 100644 index 0000000..e69de29 diff --git a/parts/sudo.ts b/parts/sudo.ts new file mode 100644 index 0000000..e69de29 diff --git a/parts/tldr.ts b/parts/tldr.ts new file mode 100644 index 0000000..e69de29 diff --git a/parts/zsh.ts b/parts/zsh.ts new file mode 100644 index 0000000..e69de29 diff --git a/prelude.sh b/prelude.sh new file mode 100644 index 0000000..1852510 --- /dev/null +++ b/prelude.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +# installing deno without sudo (necessary for continuation) +curl -fsSL https://deno.land/x/install/install.sh | sh + +# adding deno to the environment +export DENO_INSTALL="~/.deno" +export PATH="$DENO_INSTALL/bin:$PATH" + +# indications +echo "run with : +deno -A \"[URL]\"" \ No newline at end of file