From bd4baeb047f42e981ee7283252bc93c0a5f9ce84 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Mon, 21 Feb 2022 15:04:54 +0100 Subject: [PATCH 01/34] Clean up code --- lib/ConfigSchema.ts | 25 ++++++ lib/ConfigType.ts | 13 +++ lib/deletePackages.ts | 37 ++++++++ lib/installPackages.ts | 52 +++++++++++ lib/main.ts | 193 +++++------------------------------------ lib/parseConfig.ts | 60 +++++++++++++ lib/runCommand.ts | 28 ++++++ lib/styles.ts | 21 +++++ 8 files changed, 257 insertions(+), 172 deletions(-) create mode 100644 lib/ConfigSchema.ts create mode 100644 lib/ConfigType.ts create mode 100644 lib/deletePackages.ts create mode 100644 lib/installPackages.ts create mode 100644 lib/parseConfig.ts create mode 100644 lib/runCommand.ts create mode 100644 lib/styles.ts diff --git a/lib/ConfigSchema.ts b/lib/ConfigSchema.ts new file mode 100644 index 0000000..56118f8 --- /dev/null +++ b/lib/ConfigSchema.ts @@ -0,0 +1,25 @@ +/** + * @copyright Copyright (c) 2022 Adam Josefus + */ + + +type VariablesType = Record | string; + + +type PackageType = { + name?: string, + destination?: string, + tag?: string, + variables?: VariablesType, +} | boolean; + + +type PackageMapType = Record; + + +export type ConfigSchema = { + variables?: VariablesType, + packages?: PackageMapType, +}; diff --git a/lib/ConfigType.ts b/lib/ConfigType.ts new file mode 100644 index 0000000..4c869d5 --- /dev/null +++ b/lib/ConfigType.ts @@ -0,0 +1,13 @@ +/** + * @copyright Copyright (c) 2022 Adam Josefus + */ + + +export type ConfigType = { + readonly reference: string; + readonly displayReference: string; + readonly tag: string | null; + readonly name: string, + readonly destinationDir: string, + readonly separatedGitDir: string, +}[]; diff --git a/lib/deletePackages.ts b/lib/deletePackages.ts new file mode 100644 index 0000000..c2dcb22 --- /dev/null +++ b/lib/deletePackages.ts @@ -0,0 +1,37 @@ +import { ConfigType } from "./ConfigType.ts"; +import * as styles from "./styles.ts"; + + +function print(name: string, columnLength: number, success: boolean, message: string) { + console.log( + `> ${name.padEnd(columnLength)}`, + success + ? styles.success('delete OK') + : styles.error('delete FAILED'), + ); + + if (message.trim() !== '') { + console.log(styles.note(`>> ${message}`)); + } +} + + +export async function deletePackages(config: ConfigType): Promise { + const length = config.map(x => x.reference).reduce((a, b) => Math.max(a, b.length), 0); + + for (const item of config) { + let success: boolean; + let message: string; + + try { + await Deno.remove(item.destinationDir, { recursive: true }); + success = true; + message = ''; + } catch (error) { + success = false; + message = error.toString(); + } + + print(item.reference, length + 5, success, message); + } +} diff --git a/lib/installPackages.ts b/lib/installPackages.ts new file mode 100644 index 0000000..118c93a --- /dev/null +++ b/lib/installPackages.ts @@ -0,0 +1,52 @@ +import { ConfigType } from "./ConfigType.ts"; +import { runCommand } from "./runCommand.ts"; +import * as styles from "./styles.ts"; + + +function createTask(reference: string, tag: string | null, destinationDir: string, separatedGitDir: string): readonly string[] { + const task: string[] = []; + + task.push('git', 'clone'); + task.push('--depth', '1'); + + if (tag) task.push('--branch', tag); + + task.push('--separate-git-dir', separatedGitDir); + + task.push(reference); + task.push(destinationDir); + task.push('--single-branch'); + + return task; +} + + +function print(name: string, columnLength: number, success: boolean, message: string) { + console.log( + `> ${name.padEnd(columnLength)}`, + success + ? styles.success('install OK') + : styles.error('install FAILED'), + ); + + if (message.trim() !== '') { + console.log(styles.note(`>> ${message}`)); + } +} + + +export async function installPackages(config: ConfigType, separateGitRoot: string): Promise { + // TODO: Change to temp directory + Deno.mkdirSync(separateGitRoot); + + const length = config.map(x => x.reference).reduce((a, b) => Math.max(a, b.length), 0); + + for (const item of config) { + const cmd = createTask(item.reference, item.tag, item.destinationDir, item.separatedGitDir); + const p = await runCommand(...cmd); + + print(item.reference, length + 5, p.success, p.message); + } + + Deno.removeSync(separateGitRoot, { recursive: true }); +} diff --git a/lib/main.ts b/lib/main.ts index 9109050..f2da896 100644 --- a/lib/main.ts +++ b/lib/main.ts @@ -3,32 +3,12 @@ */ -import { join, basename, dirname, isAbsolute } from "https://deno.land/std@0.126.0/path/mod.ts"; -import { green, red, gray, bold } from "https://deno.land/std@0.126.0/fmt/colors.ts"; +import { join, dirname } from "https://deno.land/std@0.126.0/path/mod.ts"; import { Arguments, ValueException } from "https://deno.land/x/allo_arguments@v4.0.1/mod.ts"; import { existsSync } from "./exists.ts"; - - -const successStyle = (s: string) => green(bold(s)); -const errorStyle = (s: string) => red(bold(s)); - - -type ConfigFileType = { - [repository: string]: { - name?: string, - dest?: string, - branch?: string, - } | boolean, -} - - -type PackageListType = Array<{ - git: string, - name: string, - path: string, - repository: string, - branch: string | null, -}> +import { parseConfig } from "./parseConfig.ts"; +import { installPackages } from "./installPackages.ts"; +import { deletePackages } from "./deletePackages.ts"; const getArguments = () => { @@ -65,159 +45,24 @@ const getArguments = () => { description: `Deletes packages according to the configuration file.`, convertor: (v: string | boolean) => v === true || v === 'true', default: false + }, + { + name: 'force', + description: `If true, the script will not ask for confirmation.`, + convertor: (v: string | boolean) => v === true || v === 'true', + default: false } ); - if (args.shouldHelp()) { args.triggerHelpException(); } return { + config: args.get('config'), delete: args.get('delete'), install: args.get('install'), - config: args.get('config'), - } -} - - -const parseConfig = (json: string, root: string, separateGitRoot: string): PackageListType => { - const list: PackageListType = []; - const data = JSON.parse(json) as ConfigFileType; - - for (const repository in data) { - const value = data[repository]; - if (value === false) break; - const options = value === true ? {} : value; - - const originalName = basename(repository, '.git'); - const name = options.name ?? originalName; - - const path = (d => { - const p = join(d, name); - - return isAbsolute(p) ? p : join(root, p); - })(options.dest ?? './'); - - const branch = options.branch ?? null; - - list.push({ - git: join(separateGitRoot, originalName), - name, - path, - repository, - branch, - }); - } - - return list; -} - - -// deno-lint-ignore no-explicit-any -const runCommand = async (...cmd: any[]) => { - const process = Deno.run({ - cmd, - stdout: "piped", - stderr: "piped", - }); - - const status = await process.status(); - - const output = await (async (ok) => { - if (ok) return await process.output() - else return await process.stderrOutput() - })(status.success); - - const decoder = new TextDecoder(); - - return { - success: status.success, - message: decoder.decode(output) - } -} - - -function padRight(s: string, all: string[]): string { - const length = all.reduce((a, b) => Math.max(a, b.length), 0) + 5; - - return s.padEnd(length, '.'); -} - - -const installPackage = async (list: PackageListType, separateGitRoot: string) => { - function createTask(git: string, path: string, reference: string, branch: string | null) { - const task: string[] = []; - - task.push('git', 'clone'); - task.push('--depth', '1'); - - if (branch) { - task.push('--branch', branch); - } - - task.push('--separate-git-dir', git); - - task.push(reference); - task.push(path); - task.push('--single-branch'); - - return task; - } - - - function printTask(name: string, names: string[], success: boolean, message: string) { - console.log([ - `> ${padRight(name, names)}`, - success ? successStyle('install OK') : errorStyle('install FAILED'), - ].join('')); - - if (message.trim() !== '') { - console.log(gray(`>> ${message}`)); - } - } - - Deno.mkdirSync(separateGitRoot); - - // Run tasks - for (const item of list) { - const cmd = createTask(item.git, item.path, item.repository, item.branch); - const p = await runCommand(...cmd); - - printTask(item.repository, list.map(x => x.repository), p.success, p.message); - } - - Deno.removeSync(separateGitRoot, { recursive: true }); -} - - -const deletePackage = (list: PackageListType) => { - function printTask(name: string, names: string[], success: boolean, message: string) { - console.log([ - `> ${padRight(name, names)}`, - success ? successStyle('delete OK') : errorStyle('delete FAILED'), - ].join('')); - - if (message.trim() !== '') { - console.log(gray(`>> ${message}`)); - } - } - - // Run tasks - for (const item of list) { - let success: boolean; - let message: string; - - try { - Deno.removeSync(item.path, { recursive: true }); - success = true; - message = ''; - } catch (error) { - success = false; - message = error.toString(); - } - - printTask(item.repository, list.map(x => x.repository), success, message); + force: args.get('force'), } } @@ -234,11 +79,15 @@ const run = async () => { if (args.delete) { console.log('\n'); - const yes = 'y'; - const no = 'n'; - const decision = prompt(`Are you sure you want to delete? (${yes}/${no})`, 'n'); + let confirmation = false; + if (!args.force) { + const yes = 'y'; + const no = 'n'; + + confirmation = prompt(`Are you sure you want to delete? (${yes}/${no})`, 'n') === yes; + } - if (decision === yes) await deletePackage(config); + if (confirmation || args.force) await deletePackages(config); console.log('\n'); } @@ -246,7 +95,7 @@ const run = async () => { if (args.install) { console.log('\n'); - await installPackage(config, separateGitRoot); + await installPackages(config, separateGitRoot); console.log('\n'); } } diff --git a/lib/parseConfig.ts b/lib/parseConfig.ts new file mode 100644 index 0000000..7f173df --- /dev/null +++ b/lib/parseConfig.ts @@ -0,0 +1,60 @@ +/** + * @copyright Copyright (c) 2022 Adam Josefus + */ + + +import { join, basename, isAbsolute } from "https://deno.land/std@0.126.0/path/mod.ts"; +import { ConfigSchema } from "./ConfigSchema.ts"; +import { ConfigType } from "./ConfigType.ts"; + + +export function parseConfig(json: string, destinationRoot: string, separateGitRoot: string): ConfigType { + const config: ConfigType = []; + + const data = JSON.parse(json) as ConfigSchema; + + const packages = data.packages ?? {}; + + for (const reference in packages) { + const options = (v => { + if (typeof v === "boolean") { + return v ? {} : null + } else { + return v; + } + })(packages[reference]); + + if (options === null) break; + + + const remoteName = basename(reference, '.git'); + + const localName = options.name ?? remoteName; + + const destinationDir = (d => { + const p = join(d, localName); + return isAbsolute(p) ? p : join(destinationRoot, p); + })(options.destination ?? './'); + + const separatedGitDir = join(separateGitRoot, remoteName); + + const tag = options.tag ?? null; + + config.push({ + reference, + displayReference: createDisplayReference(reference), + tag, + name: localName, + destinationDir, + separatedGitDir, + }); + } + + return config; +} + + +function createDisplayReference(s: string): string { + // TODO: Hide auth credentials + return s; +} diff --git a/lib/runCommand.ts b/lib/runCommand.ts new file mode 100644 index 0000000..952c69a --- /dev/null +++ b/lib/runCommand.ts @@ -0,0 +1,28 @@ +/** + * @copyright Copyright (c) 2022 Adam Josefus + */ + + +export async function runCommand(...cmd: string[]) { + const process = Deno.run({ + cmd, + stdout: "piped", + stderr: "piped", + }); + + const status = await process.status(); + + const output = await (async (ok) => { + if (ok) return await process.output() + else return await process.stderrOutput() + })(status.success); + + process.close(); + + const decoder = new TextDecoder(); + + return { + success: status.success, + message: decoder.decode(output) + } +} diff --git a/lib/styles.ts b/lib/styles.ts new file mode 100644 index 0000000..3cd9610 --- /dev/null +++ b/lib/styles.ts @@ -0,0 +1,21 @@ +/** + * @copyright Copyright (c) 2022 Adam Josefus + */ + + +import { green, red, gray, bold } from "https://deno.land/std@0.126.0/fmt/colors.ts"; + + +export function success(s: string) { + return green(bold(s)); +} + + +export function error(s: string) { + return red(bold(s)); +} + + +export function note(s: string) { + return gray(s); +} From e7c577b9fb0f6d32641c002a487702297dde22b9 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Mon, 21 Feb 2022 15:04:59 +0100 Subject: [PATCH 02/34] Add demo --- demo/config.json | 5 +++++ demo/demo.sh | 2 ++ 2 files changed, 7 insertions(+) create mode 100644 demo/config.json create mode 100644 demo/demo.sh diff --git a/demo/config.json b/demo/config.json new file mode 100644 index 0000000..c5db371 --- /dev/null +++ b/demo/config.json @@ -0,0 +1,5 @@ +{ + "packages": { + "https://github.com/adamjosefus/allo_responses.git": {} + } +} \ No newline at end of file diff --git a/demo/demo.sh b/demo/demo.sh new file mode 100644 index 0000000..4c5703a --- /dev/null +++ b/demo/demo.sh @@ -0,0 +1,2 @@ +#!/bin/bash +deno run -A ../pkg.ts --config=./config.json --delete \ No newline at end of file From 90b439af601976dce5175b273c5fdd63dc7da54f Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Mon, 21 Feb 2022 15:09:40 +0100 Subject: [PATCH 03/34] Better file structure --- .DS_Store | Bin 0 -> 6148 bytes libs/.DS_Store | Bin 0 -> 6148 bytes {lib => libs/helpers}/exists.ts | 0 {lib => libs/helpers}/runCommand.ts | 0 {lib => libs/helpers}/styles.ts | 0 {lib => libs}/main.ts | 8 ++++---- {lib => libs/model}/deletePackages.ts | 9 +++++++-- {lib => libs/model}/installPackages.ts | 11 ++++++++--- {lib => libs/model}/parseConfig.ts | 4 ++-- {lib => libs/types}/ConfigSchema.ts | 0 {lib => libs/types}/ConfigType.ts | 0 pkg.ts | 2 +- 12 files changed, 22 insertions(+), 12 deletions(-) create mode 100644 .DS_Store create mode 100644 libs/.DS_Store rename {lib => libs/helpers}/exists.ts (100%) rename {lib => libs/helpers}/runCommand.ts (100%) rename {lib => libs/helpers}/styles.ts (100%) rename {lib => libs}/main.ts (93%) rename {lib => libs/model}/deletePackages.ts (85%) rename {lib => libs/model}/installPackages.ts (86%) rename {lib => libs/model}/parseConfig.ts (92%) rename {lib => libs/types}/ConfigSchema.ts (100%) rename {lib => libs/types}/ConfigType.ts (100%) diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..09ca51ae20534b411b25f8f6c6593d47a57ae1c2 GIT binary patch literal 6148 zcmeHKOHRWu6dbn^v>>4_*&yWvk+?yq+647wQnT@@*j*INy;M0* z6f41;tO6^=dse(7Jm8*BnvuKV^On?2S!cM@+RjXA`;B&i8~^lbHHbSeEqC@B#ad_g z`)qUjxWt$lMz|nmSfEsUkv+E+>{^%u=72fyV-E1lmgpS@wAvgn2h4%S0r@_pEP{E& zI-vh_u<};`V!~k`Z2Mn-Vk!f~JYpS?BMcX$#2|I?is9nT!38hJ6KmPvyzb&$!IbaU_D+gRMx*83+rFgdPY);PF tl;xU5LU?t+M#6?aipiCu_?X29$5Uw#^N4jojxg*;z}sMzIq<6vd;lDQfMWmv literal 0 HcmV?d00001 diff --git a/libs/.DS_Store b/libs/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..acb4aa025bc4574f1f33696f41b2627ea7501ab9 GIT binary patch literal 6148 zcmeHKy-veG4EB{Gf?&vqnC=xiA+}J3fw?bGl~xofQ6hc@w!9n9z`#aF#7pq`Y=ujc zN-Q9RY{~ase0F^Ka*AUja?{7X8(z>hG1n$40N3EF537z4&Y%K(2LJd`n0Yy`un14C#5fMb}0V9vb+$9Tm| zu@S@y#7QVnLY=l4PQqdL>X#`tf)Y+nn-8a%opvZLWXJt|a3_}u+Gq?I16>C8 { diff --git a/lib/deletePackages.ts b/libs/model/deletePackages.ts similarity index 85% rename from lib/deletePackages.ts rename to libs/model/deletePackages.ts index c2dcb22..dbe4ae2 100644 --- a/lib/deletePackages.ts +++ b/libs/model/deletePackages.ts @@ -1,5 +1,10 @@ -import { ConfigType } from "./ConfigType.ts"; -import * as styles from "./styles.ts"; +/** + * @copyright Copyright (c) 2022 Adam Josefus + */ + + +import { ConfigType } from "../types/ConfigType.ts"; +import * as styles from "../helpers/styles.ts"; function print(name: string, columnLength: number, success: boolean, message: string) { diff --git a/lib/installPackages.ts b/libs/model/installPackages.ts similarity index 86% rename from lib/installPackages.ts rename to libs/model/installPackages.ts index 118c93a..984b5e6 100644 --- a/lib/installPackages.ts +++ b/libs/model/installPackages.ts @@ -1,6 +1,11 @@ -import { ConfigType } from "./ConfigType.ts"; -import { runCommand } from "./runCommand.ts"; -import * as styles from "./styles.ts"; +/** + * @copyright Copyright (c) 2022 Adam Josefus + */ + + +import { ConfigType } from "../types/ConfigType.ts"; +import { runCommand } from "../helpers/runCommand.ts"; +import * as styles from "../helpers/styles.ts"; function createTask(reference: string, tag: string | null, destinationDir: string, separatedGitDir: string): readonly string[] { diff --git a/lib/parseConfig.ts b/libs/model/parseConfig.ts similarity index 92% rename from lib/parseConfig.ts rename to libs/model/parseConfig.ts index 7f173df..9d4e27c 100644 --- a/lib/parseConfig.ts +++ b/libs/model/parseConfig.ts @@ -4,8 +4,8 @@ import { join, basename, isAbsolute } from "https://deno.land/std@0.126.0/path/mod.ts"; -import { ConfigSchema } from "./ConfigSchema.ts"; -import { ConfigType } from "./ConfigType.ts"; +import { ConfigSchema } from "../types/ConfigSchema.ts"; +import { ConfigType } from "../types/ConfigType.ts"; export function parseConfig(json: string, destinationRoot: string, separateGitRoot: string): ConfigType { diff --git a/lib/ConfigSchema.ts b/libs/types/ConfigSchema.ts similarity index 100% rename from lib/ConfigSchema.ts rename to libs/types/ConfigSchema.ts diff --git a/lib/ConfigType.ts b/libs/types/ConfigType.ts similarity index 100% rename from lib/ConfigType.ts rename to libs/types/ConfigType.ts diff --git a/pkg.ts b/pkg.ts index 5233802..3a80bfc 100644 --- a/pkg.ts +++ b/pkg.ts @@ -1,3 +1,3 @@ -import { pkg } from "./lib/main.ts"; +import { pkg } from "./libs/main.ts"; pkg(); \ No newline at end of file From 793a7486bc3f59a2e77fdd0768a262a02ee5ce7b Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Mon, 21 Feb 2022 15:45:36 +0100 Subject: [PATCH 04/34] Update `createDisplayReference` --- libs/model/deletePackages.ts | 2 +- libs/model/installPackages.ts | 2 +- libs/model/parseConfig.ts | 7 +++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/libs/model/deletePackages.ts b/libs/model/deletePackages.ts index dbe4ae2..060a273 100644 --- a/libs/model/deletePackages.ts +++ b/libs/model/deletePackages.ts @@ -37,6 +37,6 @@ export async function deletePackages(config: ConfigType): Promise { message = error.toString(); } - print(item.reference, length + 5, success, message); + print(item.displayReference, length + 5, success, message); } } diff --git a/libs/model/installPackages.ts b/libs/model/installPackages.ts index 984b5e6..75f816c 100644 --- a/libs/model/installPackages.ts +++ b/libs/model/installPackages.ts @@ -50,7 +50,7 @@ export async function installPackages(config: ConfigType, separateGitRoot: strin const cmd = createTask(item.reference, item.tag, item.destinationDir, item.separatedGitDir); const p = await runCommand(...cmd); - print(item.reference, length + 5, p.success, p.message); + print(item.displayReference, length + 5, p.success, p.message); } Deno.removeSync(separateGitRoot, { recursive: true }); diff --git a/libs/model/parseConfig.ts b/libs/model/parseConfig.ts index 9d4e27c..335247e 100644 --- a/libs/model/parseConfig.ts +++ b/libs/model/parseConfig.ts @@ -55,6 +55,9 @@ export function parseConfig(json: string, destinationRoot: string, separateGitRo function createDisplayReference(s: string): string { - // TODO: Hide auth credentials - return s; + const authenticationReplacer = /^(?https?:\/\/)(?.+?)\:(?.+?)@/i; + + return s.replace(authenticationReplacer, (_match, protocol, username, _password) => { + return `${protocol}${username}:●●●●●@`; + }); } From 840cb22cb5c467989540a221807fe611cdc5935a Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Mon, 21 Feb 2022 15:45:45 +0100 Subject: [PATCH 05/34] Update config schema --- demo/config.json | 4 +++- demo/demo.sh | 2 +- demo/packages/.gitignore | 2 ++ libs/main.ts | 4 ++++ libs/model/parseConfig.ts | 6 +++--- libs/types/ConfigSchema.ts | 3 ++- 6 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 demo/packages/.gitignore diff --git a/demo/config.json b/demo/config.json index c5db371..ca808b5 100644 --- a/demo/config.json +++ b/demo/config.json @@ -1,5 +1,7 @@ { + "destination": "./packages", "packages": { - "https://github.com/adamjosefus/allo_responses.git": {} + "https://username:password@github.com/adamjosefus/allo_responses.git": { + } } } \ No newline at end of file diff --git a/demo/demo.sh b/demo/demo.sh index 4c5703a..8ca241e 100644 --- a/demo/demo.sh +++ b/demo/demo.sh @@ -1,2 +1,2 @@ #!/bin/bash -deno run -A ../pkg.ts --config=./config.json --delete \ No newline at end of file +deno run -A ./pkg.ts --config=./demo/config.json --delete \ No newline at end of file diff --git a/demo/packages/.gitignore b/demo/packages/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/demo/packages/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/libs/main.ts b/libs/main.ts index 7b4784f..e670e80 100644 --- a/libs/main.ts +++ b/libs/main.ts @@ -76,6 +76,10 @@ const run = async () => { const configJson = Deno.readTextFileSync(args.config); const config = parseConfig(configJson, root, separateGitRoot); + + // console.log(config); + + if (args.delete) { console.log('\n'); diff --git a/libs/model/parseConfig.ts b/libs/model/parseConfig.ts index 335247e..37fefda 100644 --- a/libs/model/parseConfig.ts +++ b/libs/model/parseConfig.ts @@ -17,7 +17,7 @@ export function parseConfig(json: string, destinationRoot: string, separateGitRo for (const reference in packages) { const options = (v => { - if (typeof v === "boolean") { + if (typeof v === "boolean") { return v ? {} : null } else { return v; @@ -28,13 +28,13 @@ export function parseConfig(json: string, destinationRoot: string, separateGitRo const remoteName = basename(reference, '.git'); - + const localName = options.name ?? remoteName; const destinationDir = (d => { const p = join(d, localName); return isAbsolute(p) ? p : join(destinationRoot, p); - })(options.destination ?? './'); + })(options.destination ?? data.destination ?? './'); const separatedGitDir = join(separateGitRoot, remoteName); diff --git a/libs/types/ConfigSchema.ts b/libs/types/ConfigSchema.ts index 56118f8..76b2682 100644 --- a/libs/types/ConfigSchema.ts +++ b/libs/types/ConfigSchema.ts @@ -9,8 +9,8 @@ type VariablesType = Record; export type ConfigSchema = { + destination?: string, variables?: VariablesType, packages?: PackageMapType, }; From 4ff13e4ffc71f3dafdd424a7806465f648b86774 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Mon, 21 Feb 2022 18:04:12 +0100 Subject: [PATCH 06/34] Update demo --- demo/bar.token | 1 + demo/config.json | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 demo/bar.token diff --git a/demo/bar.token b/demo/bar.token new file mode 100644 index 0000000..e8093c4 --- /dev/null +++ b/demo/bar.token @@ -0,0 +1 @@ +My token for BAR :-) \ No newline at end of file diff --git a/demo/config.json b/demo/config.json index ca808b5..e84f8d5 100644 --- a/demo/config.json +++ b/demo/config.json @@ -1,7 +1,18 @@ { "destination": "./packages", + "variables": { + "FOO": "my-foo", + "BAR": { + "from": "./bar.token" + } + }, + "variables2": { + "FOO": "my-foo", + "BAR": "my-bar" + }, "packages": { - "https://username:password@github.com/adamjosefus/allo_responses.git": { + "https://${FOO}:password@github.com/adamjosefus/allo_responses.git": { + "tag": "${BAR|encodeURIComponent}" } } } \ No newline at end of file From 0e53246ab8fa7e981be9ef5fc8ffc00667ec3cd8 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Mon, 21 Feb 2022 18:04:16 +0100 Subject: [PATCH 07/34] Update ConfigSchema.ts --- libs/types/ConfigSchema.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/types/ConfigSchema.ts b/libs/types/ConfigSchema.ts index 76b2682..8a07da2 100644 --- a/libs/types/ConfigSchema.ts +++ b/libs/types/ConfigSchema.ts @@ -3,9 +3,9 @@ */ -type VariablesType = Record | string; +}>; type PackageType = { From 9fb05d563220234ccb1b6c1a7237886b15642b39 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Mon, 21 Feb 2022 18:04:21 +0100 Subject: [PATCH 08/34] Update parseConfig.ts --- libs/model/parseConfig.ts | 90 +++++++++++++++++++++++++++++++++------ 1 file changed, 77 insertions(+), 13 deletions(-) diff --git a/libs/model/parseConfig.ts b/libs/model/parseConfig.ts index 37fefda..13eed8f 100644 --- a/libs/model/parseConfig.ts +++ b/libs/model/parseConfig.ts @@ -3,16 +3,29 @@ */ -import { join, basename, isAbsolute } from "https://deno.land/std@0.126.0/path/mod.ts"; -import { ConfigSchema } from "../types/ConfigSchema.ts"; -import { ConfigType } from "../types/ConfigType.ts"; +import { join, basename } from "https://deno.land/std@0.126.0/path/mod.ts"; +import { type ConfigSchema, type VariablesType } from "../types/ConfigSchema.ts"; +import { type ConfigType } from "../types/ConfigType.ts"; +import { makeAbsolute } from "../helpers/makeAbsolute.ts"; +import * as styles from "../helpers/styles.ts"; -export function parseConfig(json: string, destinationRoot: string, separateGitRoot: string): ConfigType { + +const regex = { + variable: /\$\{(?[A-Z_][A-Z0-9_]*)(\|(?.+?))?\}/g, +} + + +export function parseConfig(json: string, configRoot: string, separateGitRoot: string): ConfigType { const config: ConfigType = []; const data = JSON.parse(json) as ConfigSchema; + const variables = parseVariables(configRoot, data.variables ?? {}); + console.log(variables); + + const getVariable = createVariableGetter(variables); + const packages = data.packages ?? {}; for (const reference in packages) { @@ -26,14 +39,11 @@ export function parseConfig(json: string, destinationRoot: string, separateGitRo if (options === null) break; - const remoteName = basename(reference, '.git'); - const localName = options.name ?? remoteName; const destinationDir = (d => { - const p = join(d, localName); - return isAbsolute(p) ? p : join(destinationRoot, p); + return makeAbsolute(configRoot, join(d, localName)); })(options.destination ?? data.destination ?? './'); const separatedGitDir = join(separateGitRoot, remoteName); @@ -41,15 +51,17 @@ export function parseConfig(json: string, destinationRoot: string, separateGitRo const tag = options.tag ?? null; config.push({ - reference, - displayReference: createDisplayReference(reference), - tag, + reference: apllyVariables(reference, getVariable), + displayReference: createDisplayReference(apllyVariables(reference, getVariable)), + tag: tag ? apllyVariables(tag, getVariable) : null, name: localName, - destinationDir, - separatedGitDir, + destinationDir: apllyVariables(destinationDir, getVariable), + separatedGitDir: apllyVariables(separatedGitDir, getVariable), }); } + console.log(config); + return config; } @@ -61,3 +73,55 @@ function createDisplayReference(s: string): string { return `${protocol}${username}:●●●●●@`; }); } + + +function parseVariables(root: string, list: VariablesType): Map { + const variables = new Map(); + + for (const [name, value] of Object.entries(list)) { + // TODO: Check if name is valid + + if (typeof value === "string") { + variables.set(name, value); + } else { + const path = makeAbsolute(root, value.from); + const content = Deno.readTextFileSync(path); + + variables.set(name, content); + } + } + + return variables; +} + + +function createVariableGetter(store: Map, useEnv = true): (name: string) => string | undefined { + return (name: string) => { + if (store.has(name)) return store.get(name); + if (useEnv) return Deno.env.get(name); + + return undefined; + } +} + + +function apllyVariables(s: string, getVariable: (name: string) => string | undefined): string { + regex.variable.lastIndex = 0; + return s.replace(regex.variable, (_match, _g1, _g2, _g3, _g4, _g5, groups) => { + const { name, filter } = groups; + + const value = getVariable(name); + + if (value === undefined) return `\$${name}`; + if (filter === undefined) return value; + + switch (filter.toLowerCase()) { + case 'encodeURIComponent'.toLowerCase(): return encodeURIComponent(value); + case 'encodeURI'.toLowerCase(): return encodeURI(value); + + default: + console.log(styles.warning(`> Unknown filter: ${filter}`)); + return value; + } + }); +} From 1722cd691dfa550de612a5abb0501712045b2368 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Mon, 21 Feb 2022 18:04:24 +0100 Subject: [PATCH 09/34] Update styles.ts --- libs/helpers/styles.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libs/helpers/styles.ts b/libs/helpers/styles.ts index 3cd9610..7220726 100644 --- a/libs/helpers/styles.ts +++ b/libs/helpers/styles.ts @@ -3,7 +3,7 @@ */ -import { green, red, gray, bold } from "https://deno.land/std@0.126.0/fmt/colors.ts"; +import { green, red, yellow, gray, bold } from "https://deno.land/std@0.126.0/fmt/colors.ts"; export function success(s: string) { @@ -16,6 +16,11 @@ export function error(s: string) { } +export function warning(s: string) { + return yellow(bold(s)); +} + + export function note(s: string) { return gray(s); } From 4a23258ab7d7a72d57b530805395af28a995380c Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Mon, 21 Feb 2022 18:04:26 +0100 Subject: [PATCH 10/34] Create makeAbsolute.ts --- libs/helpers/makeAbsolute.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 libs/helpers/makeAbsolute.ts diff --git a/libs/helpers/makeAbsolute.ts b/libs/helpers/makeAbsolute.ts new file mode 100644 index 0000000..8ad8cb3 --- /dev/null +++ b/libs/helpers/makeAbsolute.ts @@ -0,0 +1,15 @@ +/** + * @copyright Copyright (c) 2022 Adam Josefus + */ + + +import { join, isAbsolute } from "https://deno.land/std@0.126.0/path/mod.ts"; + + +export function makeAbsolute(root: string, path: string): string { + if (isAbsolute(path)) { + return path; + } + + return join(root, path); +} \ No newline at end of file From 3fa8b5b9337c4dbaa5e24978c79c7f8a78728726 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Mon, 21 Feb 2022 18:04:29 +0100 Subject: [PATCH 11/34] Update main.ts --- libs/main.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/main.ts b/libs/main.ts index e670e80..481cb4c 100644 --- a/libs/main.ts +++ b/libs/main.ts @@ -70,11 +70,11 @@ const getArguments = () => { const run = async () => { const args = getArguments(); - const root = dirname(args.config); - const separateGitRoot = join(root, './.pkg'); + const configRoot = dirname(args.config); + const separateGitRoot = join(configRoot, './.pkg'); const configJson = Deno.readTextFileSync(args.config); - const config = parseConfig(configJson, root, separateGitRoot); + const config = parseConfig(configJson, configRoot, separateGitRoot); // console.log(config); From ff8190ea6eeadcdcd95ff739712958c57a23e753 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Mon, 21 Feb 2022 22:10:35 +0100 Subject: [PATCH 12/34] Clean up code --- libs/model/parseConfig.ts | 12 ++++++------ libs/model/variableFilters.ts | 6 ++++++ 2 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 libs/model/variableFilters.ts diff --git a/libs/model/parseConfig.ts b/libs/model/parseConfig.ts index 13eed8f..4d1da81 100644 --- a/libs/model/parseConfig.ts +++ b/libs/model/parseConfig.ts @@ -8,6 +8,7 @@ import { type ConfigSchema, type VariablesType } from "../types/ConfigSchema.ts" import { type ConfigType } from "../types/ConfigType.ts"; import { makeAbsolute } from "../helpers/makeAbsolute.ts"; import * as styles from "../helpers/styles.ts"; +import { variableFilters } from "./variableFilters.ts"; @@ -115,13 +116,12 @@ function apllyVariables(s: string, getVariable: (name: string) => string | undef if (value === undefined) return `\$${name}`; if (filter === undefined) return value; - switch (filter.toLowerCase()) { - case 'encodeURIComponent'.toLowerCase(): return encodeURIComponent(value); - case 'encodeURI'.toLowerCase(): return encodeURI(value); + const filterFunc = variableFilters.get(filter); - default: - console.log(styles.warning(`> Unknown filter: ${filter}`)); - return value; + if (filterFunc) { + return filterFunc(value); } + + return value; }); } diff --git a/libs/model/variableFilters.ts b/libs/model/variableFilters.ts new file mode 100644 index 0000000..f78d387 --- /dev/null +++ b/libs/model/variableFilters.ts @@ -0,0 +1,6 @@ + +export const variableFilters: Map string> = new Map(); + +variableFilters.set("encodeUri", (s: string) => encodeURI(s)); + +variableFilters.set("encodeUriComponent", (s: string) => encodeURIComponent(s)); From 2b92ceef7729ac27c42d5711e259e5c76eecf4ab Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Mon, 21 Feb 2022 22:24:45 +0100 Subject: [PATCH 13/34] Update --- libs/main.ts | 4 ---- libs/model/parseConfig.ts | 6 ------ 2 files changed, 10 deletions(-) diff --git a/libs/main.ts b/libs/main.ts index 481cb4c..e74c2a2 100644 --- a/libs/main.ts +++ b/libs/main.ts @@ -76,10 +76,6 @@ const run = async () => { const configJson = Deno.readTextFileSync(args.config); const config = parseConfig(configJson, configRoot, separateGitRoot); - - // console.log(config); - - if (args.delete) { console.log('\n'); diff --git a/libs/model/parseConfig.ts b/libs/model/parseConfig.ts index 4d1da81..89404f4 100644 --- a/libs/model/parseConfig.ts +++ b/libs/model/parseConfig.ts @@ -7,11 +7,9 @@ import { join, basename } from "https://deno.land/std@0.126.0/path/mod.ts"; import { type ConfigSchema, type VariablesType } from "../types/ConfigSchema.ts"; import { type ConfigType } from "../types/ConfigType.ts"; import { makeAbsolute } from "../helpers/makeAbsolute.ts"; -import * as styles from "../helpers/styles.ts"; import { variableFilters } from "./variableFilters.ts"; - const regex = { variable: /\$\{(?[A-Z_][A-Z0-9_]*)(\|(?.+?))?\}/g, } @@ -42,13 +40,11 @@ export function parseConfig(json: string, configRoot: string, separateGitRoot: s const remoteName = basename(reference, '.git'); const localName = options.name ?? remoteName; - const destinationDir = (d => { return makeAbsolute(configRoot, join(d, localName)); })(options.destination ?? data.destination ?? './'); const separatedGitDir = join(separateGitRoot, remoteName); - const tag = options.tag ?? null; config.push({ @@ -61,8 +57,6 @@ export function parseConfig(json: string, configRoot: string, separateGitRoot: s }); } - console.log(config); - return config; } From 55dfa64e5819e8d1dbf67b51166979a20447bf22 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Mon, 21 Feb 2022 22:25:30 +0100 Subject: [PATCH 14/34] Update --- libs/model/parseConfig.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libs/model/parseConfig.ts b/libs/model/parseConfig.ts index 89404f4..1dff038 100644 --- a/libs/model/parseConfig.ts +++ b/libs/model/parseConfig.ts @@ -17,14 +17,9 @@ const regex = { export function parseConfig(json: string, configRoot: string, separateGitRoot: string): ConfigType { const config: ConfigType = []; - const data = JSON.parse(json) as ConfigSchema; - const variables = parseVariables(configRoot, data.variables ?? {}); - console.log(variables); - const getVariable = createVariableGetter(variables); - const packages = data.packages ?? {}; for (const reference in packages) { From 3edb506dba9991b2b1c9bd2280282c54e480e089 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Tue, 22 Feb 2022 08:10:17 +0100 Subject: [PATCH 15/34] Add local variables --- libs/model/parseConfig.ts | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/libs/model/parseConfig.ts b/libs/model/parseConfig.ts index 1dff038..148503c 100644 --- a/libs/model/parseConfig.ts +++ b/libs/model/parseConfig.ts @@ -18,8 +18,7 @@ const regex = { export function parseConfig(json: string, configRoot: string, separateGitRoot: string): ConfigType { const config: ConfigType = []; const data = JSON.parse(json) as ConfigSchema; - const variables = parseVariables(configRoot, data.variables ?? {}); - const getVariable = createVariableGetter(variables); + const commonVariables = parseVariables(configRoot, data.variables ?? {}); const packages = data.packages ?? {}; for (const reference in packages) { @@ -33,6 +32,9 @@ export function parseConfig(json: string, configRoot: string, separateGitRoot: s if (options === null) break; + const variables = parseVariables(configRoot, options.variables ?? {}); + const getVariable = createVariableGetter(variables, commonVariables); + const remoteName = basename(reference, '.git'); const localName = options.name ?? remoteName; const destinationDir = (d => { @@ -46,7 +48,7 @@ export function parseConfig(json: string, configRoot: string, separateGitRoot: s reference: apllyVariables(reference, getVariable), displayReference: createDisplayReference(apllyVariables(reference, getVariable)), tag: tag ? apllyVariables(tag, getVariable) : null, - name: localName, + name: apllyVariables(localName, getVariable), destinationDir: apllyVariables(destinationDir, getVariable), separatedGitDir: apllyVariables(separatedGitDir, getVariable), }); @@ -85,12 +87,13 @@ function parseVariables(root: string, list: VariablesType): Map } -function createVariableGetter(store: Map, useEnv = true): (name: string) => string | undefined { +function createVariableGetter(...lists: Map[]): (name: string) => string | undefined { return (name: string) => { - if (store.has(name)) return store.get(name); - if (useEnv) return Deno.env.get(name); - - return undefined; + for (const list of lists) { + if (list.has(name)) return list.get(name); + } + + return Deno.env.get(name); } } @@ -110,7 +113,7 @@ function apllyVariables(s: string, getVariable: (name: string) => string | undef if (filterFunc) { return filterFunc(value); } - + return value; }); } From 1bb836cac91dbd6e0e7f27dddcdaa773dffb1669 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Tue, 22 Feb 2022 09:16:35 +0100 Subject: [PATCH 16/34] Create VariableStoreType.ts --- libs/types/VariableStoreType.ts | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 libs/types/VariableStoreType.ts diff --git a/libs/types/VariableStoreType.ts b/libs/types/VariableStoreType.ts new file mode 100644 index 0000000..466b608 --- /dev/null +++ b/libs/types/VariableStoreType.ts @@ -0,0 +1,6 @@ +/** + * @copyright Copyright (c) 2022 Adam Josefus + */ + + +export type VariableStoreType = (name: string) => string | undefined; From d5359fc5d99a7b561448680742c0a1cb649bb7ed Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Tue, 22 Feb 2022 09:17:01 +0100 Subject: [PATCH 17/34] Update ConfigSchema.ts --- libs/types/ConfigSchema.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/types/ConfigSchema.ts b/libs/types/ConfigSchema.ts index 8a07da2..27dff88 100644 --- a/libs/types/ConfigSchema.ts +++ b/libs/types/ConfigSchema.ts @@ -3,7 +3,7 @@ */ -export type VariablesType = Record; @@ -12,7 +12,7 @@ type PackageType = { destination?: string, name?: string, tag?: string, - variables?: VariablesType, + variables?: VariableDeclarationsType, } | boolean; @@ -21,6 +21,6 @@ type PackageMapType = Record; export type ConfigSchema = { destination?: string, - variables?: VariablesType, + variables?: VariableDeclarationsType, packages?: PackageMapType, }; From ee3615b288ca32b1b6b3d1c23dc7fc3f0f8904f6 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Tue, 22 Feb 2022 09:17:16 +0100 Subject: [PATCH 18/34] Add doc comments --- libs/model/parseConfig.ts | 55 ++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/libs/model/parseConfig.ts b/libs/model/parseConfig.ts index 148503c..8af5910 100644 --- a/libs/model/parseConfig.ts +++ b/libs/model/parseConfig.ts @@ -4,21 +4,31 @@ import { join, basename } from "https://deno.land/std@0.126.0/path/mod.ts"; -import { type ConfigSchema, type VariablesType } from "../types/ConfigSchema.ts"; +import { type ConfigSchema, type VariableDeclarationsType } from "../types/ConfigSchema.ts"; import { type ConfigType } from "../types/ConfigType.ts"; import { makeAbsolute } from "../helpers/makeAbsolute.ts"; import { variableFilters } from "./variableFilters.ts"; +import { VariableStoreType } from "../types/VariableStoreType.ts"; const regex = { - variable: /\$\{(?[A-Z_][A-Z0-9_]*)(\|(?.+?))?\}/g, + variableReplacer: /\$\{(?[A-Z_][A-Z0-9_]*)(\|(?.+?))?\}/g, + authenticationReplacer: /^(?https?:\/\/)(?.+?)\:(?.+?)@/i } +/** + * Parse config file and return a config object. + * + * @param json Content of the config file. + * @param configRoot Folder where the config file is located. + * @param separateGitRoot Meta folder where the git repository is located. + * @returns + */ export function parseConfig(json: string, configRoot: string, separateGitRoot: string): ConfigType { const config: ConfigType = []; const data = JSON.parse(json) as ConfigSchema; - const commonVariables = parseVariables(configRoot, data.variables ?? {}); + const commonVariables = crateVariables(configRoot, data.variables ?? {}); const packages = data.packages ?? {}; for (const reference in packages) { @@ -32,8 +42,8 @@ export function parseConfig(json: string, configRoot: string, separateGitRoot: s if (options === null) break; - const variables = parseVariables(configRoot, options.variables ?? {}); - const getVariable = createVariableGetter(variables, commonVariables); + const variables = crateVariables(configRoot, options.variables ?? {}); + const getVariable = createVariableStore(variables, commonVariables); const remoteName = basename(reference, '.git'); const localName = options.name ?? remoteName; @@ -58,6 +68,9 @@ export function parseConfig(json: string, configRoot: string, separateGitRoot: s } +/** + * Transform a reference to a displayable reference. This is useful for hiding authentication information. + */ function createDisplayReference(s: string): string { const authenticationReplacer = /^(?https?:\/\/)(?.+?)\:(?.+?)@/i; @@ -67,10 +80,16 @@ function createDisplayReference(s: string): string { } -function parseVariables(root: string, list: VariablesType): Map { +/** + * Create a map of variables from config declarations. + * @param root Folder for relative paths. + * @param declarations + * @returns + */ +function crateVariables(root: string, declarations: VariableDeclarationsType): Map { const variables = new Map(); - for (const [name, value] of Object.entries(list)) { + for (const [name, value] of Object.entries(declarations)) { // TODO: Check if name is valid if (typeof value === "string") { @@ -87,10 +106,10 @@ function parseVariables(root: string, list: VariablesType): Map } -function createVariableGetter(...lists: Map[]): (name: string) => string | undefined { +function createVariableStore(...declarations: Map[]): VariableStoreType { return (name: string) => { - for (const list of lists) { - if (list.has(name)) return list.get(name); + for (const declaration of declarations) { + if (declaration.has(name)) return declaration.get(name); } return Deno.env.get(name); @@ -98,21 +117,21 @@ function createVariableGetter(...lists: Map[]): (name: string) = } -function apllyVariables(s: string, getVariable: (name: string) => string | undefined): string { - regex.variable.lastIndex = 0; - return s.replace(regex.variable, (_match, _g1, _g2, _g3, _g4, _g5, groups) => { +/** + * Apply variables to a string. + */ +function apllyVariables(s: string, variableStore: VariableStoreType): string { + regex.variableReplacer.lastIndex = 0; + return s.replace(regex.variableReplacer, (_match, _g1, _g2, _g3, _g4, _g5, groups) => { const { name, filter } = groups; - const value = getVariable(name); + const value = variableStore(name); if (value === undefined) return `\$${name}`; if (filter === undefined) return value; const filterFunc = variableFilters.get(filter); - - if (filterFunc) { - return filterFunc(value); - } + if (filterFunc) return filterFunc(value); return value; }); From f89f9ad3e1386a3178220e3f00148cb02bd22bbe Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Tue, 22 Feb 2022 09:31:20 +0100 Subject: [PATCH 19/34] Update config type --- libs/types/ConfigSchema.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/types/ConfigSchema.ts b/libs/types/ConfigSchema.ts index 27dff88..0ee655c 100644 --- a/libs/types/ConfigSchema.ts +++ b/libs/types/ConfigSchema.ts @@ -13,10 +13,10 @@ type PackageType = { name?: string, tag?: string, variables?: VariableDeclarationsType, -} | boolean; +}; -type PackageMapType = Record; +type PackageMapType = Record; export type ConfigSchema = { From 1f8b8b98ffa90d1ca35cbe72fac7d290ba99cddf Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Tue, 22 Feb 2022 09:31:31 +0100 Subject: [PATCH 20/34] Update parseConfig.ts --- libs/model/parseConfig.ts | 63 ++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/libs/model/parseConfig.ts b/libs/model/parseConfig.ts index 8af5910..41657c8 100644 --- a/libs/model/parseConfig.ts +++ b/libs/model/parseConfig.ts @@ -28,40 +28,43 @@ const regex = { export function parseConfig(json: string, configRoot: string, separateGitRoot: string): ConfigType { const config: ConfigType = []; const data = JSON.parse(json) as ConfigSchema; - const commonVariables = crateVariables(configRoot, data.variables ?? {}); + const commonVars = crateVariables(configRoot, data.variables ?? {}); const packages = data.packages ?? {}; for (const reference in packages) { - const options = (v => { - if (typeof v === "boolean") { - return v ? {} : null - } else { - return v; - } - })(packages[reference]); - - if (options === null) break; - - const variables = crateVariables(configRoot, options.variables ?? {}); - const getVariable = createVariableStore(variables, commonVariables); - - const remoteName = basename(reference, '.git'); - const localName = options.name ?? remoteName; - const destinationDir = (d => { - return makeAbsolute(configRoot, join(d, localName)); - })(options.destination ?? data.destination ?? './'); + // Normalize reference + const settingsArr = (v => { + if (v === true || v === null) return [{}]; + if (v === false) return null; - const separatedGitDir = join(separateGitRoot, remoteName); - const tag = options.tag ?? null; + return Array.isArray(v) ? v : [v]; + })(packages[reference]); - config.push({ - reference: apllyVariables(reference, getVariable), - displayReference: createDisplayReference(apllyVariables(reference, getVariable)), - tag: tag ? apllyVariables(tag, getVariable) : null, - name: apllyVariables(localName, getVariable), - destinationDir: apllyVariables(destinationDir, getVariable), - separatedGitDir: apllyVariables(separatedGitDir, getVariable), - }); + // Skip if no settings + if (settingsArr === null) break; + + for (const settings of settingsArr) { + const localVars = crateVariables(configRoot, settings.variables ?? {}); + const getVariable = createVariableStore(localVars, commonVars); + + const remoteName = basename(reference, '.git'); + const localName = settings.name ?? remoteName; + const destinationDir = (d => { + return makeAbsolute(configRoot, join(d, localName)); + })(settings.destination ?? data.destination ?? './'); + + const separatedGitDir = join(separateGitRoot, remoteName); + const tag = settings.tag ?? null; + + config.push({ + reference: apllyVariables(reference, getVariable), + displayReference: createDisplayReference(apllyVariables(reference, getVariable)), + tag: tag ? apllyVariables(tag, getVariable) : null, + name: apllyVariables(localName, getVariable), + destinationDir: apllyVariables(destinationDir, getVariable), + separatedGitDir: apllyVariables(separatedGitDir, getVariable), + }); + } } return config; @@ -111,7 +114,7 @@ function createVariableStore(...declarations: Map[]): VariableSt for (const declaration of declarations) { if (declaration.has(name)) return declaration.get(name); } - + return Deno.env.get(name); } } From 5048c87a8c42ff25681708a00d6269c5c2725e1f Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Tue, 22 Feb 2022 11:35:19 +0100 Subject: [PATCH 21/34] Update README.md --- README.md | 75 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 4156ad2..f0ec590 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,9 @@ A tool for managing the packages (repositories) on which your application depend # Run directly deno run pkg.ts --config=config.json +# Run directly from remote +deno run https://raw.githubusercontent.com/adamjosefus/pkg/main/pkg.ts --config=config.json + # Run bundled deno run pkg.bundled.js --config=config.json @@ -24,22 +27,6 @@ deno run pkg.bundled.js --config=config.json ``` -## Config - -```json -{ - "https://github.com/adamjosefus/pkg.git": { - "dest": "../packages", - }, - "": { - "dest": "", - "branch": "" - } -} -``` - ---- - ## Help @@ -67,6 +54,62 @@ deno run pkg.ts --help ``` +## Config + +### Schema + +```js +{ + "destination": , // Optional + "variables": { + : , + : { + "from": + } + }, // Optional + "packages": { + : { + "destination": // Optional + "name": // Optional + "tag": // Optional + "variables": { + : , + : { + "from": + } + } // Optional + } + } +} +``` + +### Example +```json +{ + "destination": "./packages", + "variables": { + "ACCESS_TOKEN": { + "from": "./sercet.txt" + } + }, + "packages": { + "https://github.com/foo.git": [ + { + "name": "Foo_v1", + "tag": "v1.0.0" + }, + { + "name": "Foo_v2", + "tag": "v2.1.1" + } + ], + "https://username:${ACCESS_TOKEN}@dev.azure.com/bar": { + "name": "Bar" + } + } +} +``` + --- From 8387aac4b59e3751c86a3f482c167778bf9a0d1f Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Tue, 22 Feb 2022 11:37:09 +0100 Subject: [PATCH 22/34] Update README.md --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index f0ec590..e934d51 100644 --- a/README.md +++ b/README.md @@ -62,20 +62,20 @@ deno run pkg.ts --help { "destination": , // Optional "variables": { - : , - : { + "": "", + "": { "from": } }, // Optional "packages": { - : { - "destination": // Optional - "name": // Optional - "tag": // Optional + "": { + "destination": "" // Optional + "name": "" // Optional + "tag": "" // Optional "variables": { - : , - : { - "from": + "": "", + "": { + "from": "" } } // Optional } From 1add096af1377ebc8b1474e029e1d77f26a11ccf Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Tue, 22 Feb 2022 11:38:27 +0100 Subject: [PATCH 23/34] Update README.md --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e934d51..8cd653c 100644 --- a/README.md +++ b/README.md @@ -60,24 +60,24 @@ deno run pkg.ts --help ```js { - "destination": , // Optional + "destination": , // optional "variables": { "": "", "": { "from": } - }, // Optional + }, // optional "packages": { "": { - "destination": "" // Optional - "name": "" // Optional - "tag": "" // Optional + "destination": "" // optional + "name": "" // optional + "tag": "" // optional "variables": { "": "", "": { "from": "" } - } // Optional + } // optional } } } From d1c9f10e8f29123d69dee527075f7b765ba1a049 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Tue, 22 Feb 2022 11:38:51 +0100 Subject: [PATCH 24/34] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8cd653c..02ce179 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ deno run pkg.ts --help ```js { - "destination": , // optional + "destination": "", // optional "variables": { "": "", "": { From 87d3775c93d9850448de5ed381ef95080257f8c1 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Tue, 22 Feb 2022 11:40:08 +0100 Subject: [PATCH 25/34] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 02ce179..9e6c8cc 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ deno run pkg.ts --help "variables": { "": "", "": { - "from": + "from": "" } }, // optional "packages": { From 46aab7e5ce4fe08390cd0059403c7c946bf62783 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Tue, 22 Feb 2022 13:14:48 +0100 Subject: [PATCH 26/34] Update variableFilters.ts --- libs/model/variableFilters.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/libs/model/variableFilters.ts b/libs/model/variableFilters.ts index f78d387..80b34d5 100644 --- a/libs/model/variableFilters.ts +++ b/libs/model/variableFilters.ts @@ -1,6 +1,4 @@ - export const variableFilters: Map string> = new Map(); variableFilters.set("encodeUri", (s: string) => encodeURI(s)); - variableFilters.set("encodeUriComponent", (s: string) => encodeURIComponent(s)); From a61cf113ad9ede08e00759b2844c5a241e3c9629 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Tue, 22 Feb 2022 13:15:14 +0100 Subject: [PATCH 27/34] Remove Demo --- demo/bar.token | 1 - demo/config.json | 18 ------------------ demo/demo.sh | 2 -- demo/packages/.gitignore | 2 -- 4 files changed, 23 deletions(-) delete mode 100644 demo/bar.token delete mode 100644 demo/config.json delete mode 100644 demo/demo.sh delete mode 100644 demo/packages/.gitignore diff --git a/demo/bar.token b/demo/bar.token deleted file mode 100644 index e8093c4..0000000 --- a/demo/bar.token +++ /dev/null @@ -1 +0,0 @@ -My token for BAR :-) \ No newline at end of file diff --git a/demo/config.json b/demo/config.json deleted file mode 100644 index e84f8d5..0000000 --- a/demo/config.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "destination": "./packages", - "variables": { - "FOO": "my-foo", - "BAR": { - "from": "./bar.token" - } - }, - "variables2": { - "FOO": "my-foo", - "BAR": "my-bar" - }, - "packages": { - "https://${FOO}:password@github.com/adamjosefus/allo_responses.git": { - "tag": "${BAR|encodeURIComponent}" - } - } -} \ No newline at end of file diff --git a/demo/demo.sh b/demo/demo.sh deleted file mode 100644 index 8ca241e..0000000 --- a/demo/demo.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -deno run -A ./pkg.ts --config=./demo/config.json --delete \ No newline at end of file diff --git a/demo/packages/.gitignore b/demo/packages/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/demo/packages/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file From bc8aadfc298cb1232fd68b75f9bcb0591095fe1c Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Tue, 22 Feb 2022 13:29:15 +0100 Subject: [PATCH 28/34] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 5d91d99..b78fa67 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.DS_Store pkg.macos pkg.exe pkg.linux From df5b36201fd5ccf784d30e818be05bdc806f2960 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Tue, 22 Feb 2022 13:29:43 +0100 Subject: [PATCH 29/34] Update COnfigSchema --- README.md | 4 ++-- libs/model/parseConfig.ts | 6 +++--- libs/types/ConfigSchema.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 9e6c8cc..cf75b5e 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ deno run pkg.ts --help "from": "" } }, // optional - "packages": { + "repositories": { "": { "destination": "" // optional "name": "" // optional @@ -92,7 +92,7 @@ deno run pkg.ts --help "from": "./sercet.txt" } }, - "packages": { + "repositories": { "https://github.com/foo.git": [ { "name": "Foo_v1", diff --git a/libs/model/parseConfig.ts b/libs/model/parseConfig.ts index 41657c8..ea076de 100644 --- a/libs/model/parseConfig.ts +++ b/libs/model/parseConfig.ts @@ -29,16 +29,16 @@ export function parseConfig(json: string, configRoot: string, separateGitRoot: s const config: ConfigType = []; const data = JSON.parse(json) as ConfigSchema; const commonVars = crateVariables(configRoot, data.variables ?? {}); - const packages = data.packages ?? {}; + const repositories = data.repositories ?? {}; - for (const reference in packages) { + for (const reference in repositories) { // Normalize reference const settingsArr = (v => { if (v === true || v === null) return [{}]; if (v === false) return null; return Array.isArray(v) ? v : [v]; - })(packages[reference]); + })(repositories[reference]); // Skip if no settings if (settingsArr === null) break; diff --git a/libs/types/ConfigSchema.ts b/libs/types/ConfigSchema.ts index 0ee655c..62dc4f6 100644 --- a/libs/types/ConfigSchema.ts +++ b/libs/types/ConfigSchema.ts @@ -22,5 +22,5 @@ type PackageMapType = Record Date: Tue, 22 Feb 2022 13:38:27 +0100 Subject: [PATCH 30/34] Create parseConfig.test.ts --- tests/parseConfig.test.ts | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tests/parseConfig.test.ts diff --git a/tests/parseConfig.test.ts b/tests/parseConfig.test.ts new file mode 100644 index 0000000..a45275b --- /dev/null +++ b/tests/parseConfig.test.ts @@ -0,0 +1,36 @@ +import { assertEquals } from "https://deno.land/std@0.126.0/testing/asserts.ts"; +import { parseConfig } from "../libs/model/parseConfig.ts"; + + +Deno.test("parseConfig", () => { + const configRoot = '/packages'; + const separateGitRoot = '/meta'; + + + const exercises = [ + { + json: `{ + "repositories": { + "https://github.com/my-repo.git": { + + } + } + }`, + expected: [ + { + destinationDir: "/packages/my-repo", + displayReference: "https://github.com/my-repo.git", + name: "my-repo", + reference: "https://github.com/my-repo.git", + separatedGitDir: "/meta/my-repo", + tag: null, + }, + ], + }, + ]; + + exercises.forEach((exercise) => { + const config = parseConfig(exercise.json, configRoot, separateGitRoot); + assertEquals(config, exercise.expected); + }); +}); \ No newline at end of file From 41c84278b7f1c12147e22b9b2fc519ecac780674 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Tue, 22 Feb 2022 13:40:33 +0100 Subject: [PATCH 31/34] Update parseConfig.ts --- libs/model/parseConfig.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/model/parseConfig.ts b/libs/model/parseConfig.ts index ea076de..05e7ae0 100644 --- a/libs/model/parseConfig.ts +++ b/libs/model/parseConfig.ts @@ -34,8 +34,8 @@ export function parseConfig(json: string, configRoot: string, separateGitRoot: s for (const reference in repositories) { // Normalize reference const settingsArr = (v => { - if (v === true || v === null) return [{}]; - if (v === false) return null; + if (v === false || v === null) return null; + if (v === true) return [{}]; return Array.isArray(v) ? v : [v]; })(repositories[reference]); From cdab4eb3a22c2a14ccfddd2dee2cf0835593cdb4 Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Tue, 22 Feb 2022 13:40:35 +0100 Subject: [PATCH 32/34] Update parseConfig.test.ts --- tests/parseConfig.test.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/parseConfig.test.ts b/tests/parseConfig.test.ts index a45275b..e4a1869 100644 --- a/tests/parseConfig.test.ts +++ b/tests/parseConfig.test.ts @@ -8,6 +8,10 @@ Deno.test("parseConfig", () => { const exercises = [ + { + json: `{}`, + expected: [], + }, { json: `{ "repositories": { @@ -27,6 +31,22 @@ Deno.test("parseConfig", () => { }, ], }, + { + json: `{ + "repositories": { + "https://github.com/my-repo.git": false + } + }`, + expected: [], + }, + { + json: `{ + "repositories": { + "https://github.com/my-repo.git": null + } + }`, + expected: [], + }, ]; exercises.forEach((exercise) => { From 82bceb7082af33276387666ab03a68ae2275cd4a Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Tue, 22 Feb 2022 13:47:21 +0100 Subject: [PATCH 33/34] Update parseConfig.test.ts --- tests/parseConfig.test.ts | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/tests/parseConfig.test.ts b/tests/parseConfig.test.ts index e4a1869..c27e85f 100644 --- a/tests/parseConfig.test.ts +++ b/tests/parseConfig.test.ts @@ -7,12 +7,18 @@ Deno.test("parseConfig", () => { const separateGitRoot = '/meta'; - const exercises = [ + const exercises: { + label: string, + json: string, + expected: unknown, + }[] = [ { + label: "Test 1", json: `{}`, expected: [], }, { + label: "Test 2", json: `{ "repositories": { "https://github.com/my-repo.git": { @@ -32,6 +38,7 @@ Deno.test("parseConfig", () => { ], }, { + label: "Test 3", json: `{ "repositories": { "https://github.com/my-repo.git": false @@ -40,6 +47,7 @@ Deno.test("parseConfig", () => { expected: [], }, { + label: "Test 4", json: `{ "repositories": { "https://github.com/my-repo.git": null @@ -47,10 +55,28 @@ Deno.test("parseConfig", () => { }`, expected: [], }, + { + label: "Test 5", + json: `{ + "repositories": { + "https://github.com/my-repo.git": true + } + }`, + expected: [ + { + destinationDir: "/packages/my-repo", + displayReference: "https://github.com/my-repo.git", + name: "my-repo", + reference: "https://github.com/my-repo.git", + separatedGitDir: "/meta/my-repo", + tag: null, + }, + ], + }, ]; - exercises.forEach((exercise) => { - const config = parseConfig(exercise.json, configRoot, separateGitRoot); - assertEquals(config, exercise.expected); + exercises.forEach(({ json, expected, label }) => { + const config = parseConfig(json, configRoot, separateGitRoot); + assertEquals(config, expected, label); }); }); \ No newline at end of file From f9db6d4abaddbeae6b3f791c28234dfddf3935da Mon Sep 17 00:00:00 2001 From: Adam Josefus <1031370+adamjosefus@users.noreply.github.com> Date: Tue, 22 Feb 2022 14:05:52 +0100 Subject: [PATCH 34/34] Update parseConfig.test.ts --- tests/parseConfig.test.ts | 66 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/tests/parseConfig.test.ts b/tests/parseConfig.test.ts index c27e85f..55cad66 100644 --- a/tests/parseConfig.test.ts +++ b/tests/parseConfig.test.ts @@ -73,10 +73,76 @@ Deno.test("parseConfig", () => { }, ], }, + { + label: "Test 6", + json: `{ + "destination": "./subdir", + "repositories": { + "https://github.com/my-repo.git": true + } + }`, + expected: [ + { + destinationDir: "/packages/subdir/my-repo", + displayReference: "https://github.com/my-repo.git", + name: "my-repo", + reference: "https://github.com/my-repo.git", + separatedGitDir: "/meta/my-repo", + tag: null, + }, + ], + }, + { + label: "Test 7", + json: `{ + "destination": "./subdir", + "repositories": { + "https://github.com/my-repo.git": { + "destination": "./subdir2" + } + } + }`, + expected: [ + { + destinationDir: "/packages/subdir2/my-repo", + displayReference: "https://github.com/my-repo.git", + name: "my-repo", + reference: "https://github.com/my-repo.git", + separatedGitDir: "/meta/my-repo", + tag: null, + }, + ], + }, + { + label: "Test 8", + json: `{ + "destination": "./subdir", + "variables": { + "MY_VAR": "my-value" + }, + "repositories": { + "https://github.com/my-repo.git": { + "destination": "./subdir2/${"${MY_VAR}"}" + } + } + }`, + expected: [ + { + destinationDir: "/packages/subdir2/my-value/my-repo", + displayReference: "https://github.com/my-repo.git", + name: "my-repo", + reference: "https://github.com/my-repo.git", + separatedGitDir: "/meta/my-repo", + tag: null, + }, + ], + }, ]; + exercises.forEach(({ json, expected, label }) => { const config = parseConfig(json, configRoot, separateGitRoot); + assertEquals(config, expected, label); }); }); \ No newline at end of file