initial commit

This commit is contained in:
JOLIMAITRE Matthieu 2022-05-27 03:47:38 +03:00
commit 6761bad26e
18 changed files with 282 additions and 0 deletions

60
complete.ts Normal file
View file

@ -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()

36
lib/context.ts Normal file
View file

@ -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]
}
}

1
lib/deps.ts Normal file
View file

@ -0,0 +1 @@
export { styles } from "https://deno.land/x/ansi_styles@1.0.0/mod.ts";

15
lib/setup.ts Normal file
View file

@ -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<SetupResult>;
}

105
lib/utilities.ts Normal file
View file

@ -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<number> {
//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
}
}

33
parts/bat.ts Normal file
View file

@ -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<SetupResult> {
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"
}
}

13
parts/hello-world.ts Normal file
View file

@ -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<SetupResult> {
await run("echo hello yorld");
return "Ok"
}
}

0
parts/kitty.ts Normal file
View file

0
parts/lvim.ts Normal file
View file

0
parts/n.ts Normal file
View file

0
parts/nano.ts Normal file
View file

0
parts/paru.ts Normal file
View file

7
parts/rc.ts Normal file
View file

@ -0,0 +1,7 @@
import { Setup, SetupResult } from "../lib/setup.ts"
export class RcSetup extends Setup {
async install(): Promise<SetupResult> {
return "Ok";
}
}

0
parts/rustup.ts Normal file
View file

0
parts/sudo.ts Normal file
View file

0
parts/tldr.ts Normal file
View file

0
parts/zsh.ts Normal file
View file

12
prelude.sh Normal file
View file

@ -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]\""