Skip to content

Commit

Permalink
externalized commands impl into dedicated modules
Browse files Browse the repository at this point in the history
  • Loading branch information
fcamblor committed Jul 7, 2021
1 parent e7fe7f8 commit 7e3e503
Show file tree
Hide file tree
Showing 10 changed files with 257 additions and 100 deletions.
74 changes: 30 additions & 44 deletions build/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
import 'zx';
import { hideBin } from "yargs/helpers";
import yargs from "yargs";
import { CachePersistor } from "./CachePersistor.js";
import { cacheableCommand } from "./cacheableCommand.js";
import { auth } from "./commands/auth.js";
import { storeFS } from "./commands/store-fs.js";
import { loadFS } from "./commands/load-fs.js";
import { cachedFS } from "./commands/cached-fs.js";
const cacheCoordsOptions = {
'bucket-url': {
type: 'string',
Expand Down Expand Up @@ -44,49 +46,31 @@ yargs(hideBin(process.argv))
describe: 'url from where to download your account service key'
}
}), (argv) => __awaiter(void 0, void 0, void 0, function* () {
const tmpLocalFile = `/tmp/google-service-account.json`;
yield $ `curl -sSL ${argv["key-config"]} > ${tmpLocalFile}`;
yield $ `gcloud auth activate-service-account -q --key-file ${tmpLocalFile}`;
yield $ `rm -f ${tmpLocalFile}`;
yield auth({
keyConfig: argv["key-config"]
});
})).command("store-fs [directories..]", 'Stores directories into filesystem cache', (yargs) => yargs.options(Object.assign(Object.assign({}, cacheCoordsOptions), { 'skip-compress': {
type: 'boolean',
describe: 'avoids compressing files prior to sending it in store'
} })), (argv) => __awaiter(void 0, void 0, void 0, function* () {
const coords = coordsFromOpts(argv);
let compressed = !argv["skip-compress"];
const cachePersistor = CachePersistor.compressed(compressed);
const directories = (argv["directories"] || []);
const synchronizeAll = !directories.length;
const namedCachedPaths = synchronizeAll
? [{ pathName: "__all__", path: "." }]
: directories.map(dir => ({ pathName: dir, path: dir }));
yield Promise.all(namedCachedPaths.map(ncp => {
console.log(`Storing ${ncp.pathName} into cache:${coords.cacheName}`);
return cachePersistor.pushCache(coords, ncp.path, ncp.pathName);
}));
yield CachePersistor.storeCacheMetadata(coords, {
compressed,
// No need to provide any checksum when storing non-cacheable fs
checksum: undefined,
all: synchronizeAll
yield storeFS({
coords, compressed, directories
});
console.log(`Directories stored in cache !`);
})).command("load-fs [directories..]", 'Loads directories previously stored into filesystem cache', (yargs) => yargs.options(Object.assign({}, cacheCoordsOptions)), (argv) => __awaiter(void 0, void 0, void 0, function* () {
})).command("load-fs [directories..]", 'Loads directories previously stored into filesystem cache', (yargs) => yargs.options(Object.assign(Object.assign({}, cacheCoordsOptions), { 'on-inexistant-cache': {
type: 'string',
default: 'ignore',
describe: `allows to either ignore or fail the command when the cache doesn't exist`,
choices: ['ignore', 'warn', 'fail']
} })), (argv) => __awaiter(void 0, void 0, void 0, function* () {
const coords = coordsFromOpts(argv);
const cacheMetadata = yield CachePersistor.loadCacheMetadata(coords);
if (!cacheMetadata) {
throw new Error(`No cache metadata found for coordinates=${JSON.stringify(coords)}`);
}
const cachePersistor = CachePersistor.compressed(cacheMetadata.compressed);
const directories = (argv["directories"] || []);
const namedCachedPaths = cacheMetadata.all
? [{ pathName: "__all__", path: "" }]
: directories.map(dir => ({ pathName: dir, path: dir }));
yield Promise.all(namedCachedPaths.map(ncp => {
console.log(`Loading ${ncp.pathName} from cache:${coords.cacheName}`);
return cachePersistor.loadCache(coords, ncp.path, ncp.pathName);
}));
console.log(`Directories loaded from cache !`);
const onInexistantCache = argv['on-inexistant-cache'];
yield loadFS({
coords, directories, onInexistantCache
});
})).command("cached-fs [directories..]", 'Either loads cached filesystem or rebuild it from scratch based on a checksum', (yargs) => yargs.options(Object.assign(Object.assign({}, cacheCoordsOptions), { 'checksum-file': {
type: 'string',
demandOption: true,
Expand All @@ -98,16 +82,18 @@ yargs(hideBin(process.argv))
}, 'skip-compress': {
type: 'boolean',
describe: 'avoids compressing files prior to sending it in store'
} })), (argv) => __awaiter(void 0, void 0, void 0, function* () {
} })).check((argv, options) => {
if (!argv['directories'] || argv['directories'].length === 0) {
throw new Error("At least 1 directory must be provided !");
}
return true;
}), (argv) => __awaiter(void 0, void 0, void 0, function* () {
const coords = coordsFromOpts(argv);
const compressed = !argv["skip-compress"];
yield cacheableCommand(coords, {
compressContent: compressed,
checksumCommand: () => $ `md5 -q "${argv["checksum-file"]}"`,
cachedPaths: argv["directories"]
}, () => {
const [command, ...args] = argv["cacheable-command"].split(" ");
console.info(`Executing cacheable command: ${command} ${args}`);
return $ `${command} ${args}`;
const directories = (argv["directories"] || []);
yield cachedFS({
coords, compressed, directories,
checksumFile: argv["checksum-file"],
cacheableCommand: argv["cacheable-command"]
});
})).help().argv;
17 changes: 17 additions & 0 deletions build/commands/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
export function auth(opts) {
return __awaiter(this, void 0, void 0, function* () {
const tmpLocalFile = `/tmp/google-service-account.json`;
yield $ `curl -sSL ${opts.keyConfig} > ${tmpLocalFile}`;
yield $ `gcloud auth activate-service-account -q --key-file ${tmpLocalFile}`;
yield $ `rm -f ${tmpLocalFile}`;
});
}
23 changes: 23 additions & 0 deletions build/commands/cached-fs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { cacheableCommand } from "../cacheableCommand.js";
export function cachedFS(opts) {
return __awaiter(this, void 0, void 0, function* () {
yield cacheableCommand(opts.coords, {
compressContent: opts.compressed,
checksumCommand: () => $ `md5 -q "${opts.checksumFile}"`,
cachedPaths: opts.directories
}, () => {
const [command, ...args] = opts.cacheableCommand.split(" ");
console.info(`Executing cacheable command: ${command} ${args}`);
return $ `${command} ${args}`;
});
});
}
34 changes: 34 additions & 0 deletions build/commands/load-fs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { CachePersistor } from "../CachePersistor.js";
export function loadFS(opts) {
return __awaiter(this, void 0, void 0, function* () {
const cacheMetadata = yield CachePersistor.loadCacheMetadata(opts.coords);
if (!cacheMetadata) {
const message = `No cache metadata found for coordinates=${JSON.stringify(opts.coords)}`;
switch (opts.onInexistantCache) {
case 'fail': throw new Error(message);
case 'warn':
console.log(message);
return;
// default ('ignore'): do nothing
}
}
const cachePersistor = CachePersistor.compressed(cacheMetadata.compressed);
const namedCachedPaths = cacheMetadata.all
? [{ pathName: "__all__", path: "" }]
: opts.directories.map(dir => ({ pathName: dir, path: dir }));
yield Promise.all(namedCachedPaths.map(ncp => {
console.log(`Loading ${ncp.pathName} from cache:${opts.coords.cacheName}`);
return cachePersistor.loadCache(opts.coords, ncp.path, ncp.pathName);
}));
console.log(`Directories loaded from cache !`);
});
}
30 changes: 30 additions & 0 deletions build/commands/store-fs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { CachePersistor } from "../CachePersistor.js";
export function storeFS(opts) {
return __awaiter(this, void 0, void 0, function* () {
const cachePersistor = CachePersistor.compressed(opts.compressed);
const synchronizeAll = !opts.directories.length;
const namedCachedPaths = synchronizeAll
? [{ pathName: "__all__", path: "." }]
: opts.directories.map(dir => ({ pathName: dir, path: dir }));
yield Promise.all(namedCachedPaths.map(ncp => {
console.log(`Storing ${ncp.pathName} into cache:${opts.coords.cacheName}`);
return cachePersistor.pushCache(opts.coords, ncp.path, ncp.pathName);
}));
yield CachePersistor.storeCacheMetadata(opts.coords, {
compressed: opts.compressed,
// No need to provide any checksum when storing non-cacheable fs
checksum: undefined,
all: synchronizeAll
});
console.log(`Directories stored in cache !`);
});
}
81 changes: 25 additions & 56 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
import 'zx'
import {hideBin} from "yargs/helpers";
import yargs, {Options} from "yargs";
import {CacheCoordinates, CachePersistor} from "./CachePersistor.js";
import {cacheableCommand} from "./cacheableCommand.js";
import {CacheCoordinates} from "./CachePersistor.js";
import {auth} from "./commands/auth.js";
import {storeFS} from "./commands/store-fs.js";
import {loadFS} from "./commands/load-fs.js";
import {cachedFS} from "./commands/cached-fs.js";


type CoordsKeys = "bucket-url"|"branch"|"cache-name";
Expand Down Expand Up @@ -42,10 +45,9 @@ yargs(hideBin(process.argv))
describe: 'url from where to download your account service key'
}
}), async (argv) => {
const tmpLocalFile = `/tmp/google-service-account.json`;
await $`curl -sSL ${argv["key-config"]} > ${tmpLocalFile}`
await $`gcloud auth activate-service-account -q --key-file ${tmpLocalFile}`
await $`rm -f ${tmpLocalFile}`
await auth({
keyConfig: argv["key-config"]
});
}
).command("store-fs [directories..]", 'Stores directories into filesystem cache', (yargs) =>
yargs.options({
Expand All @@ -58,27 +60,11 @@ yargs(hideBin(process.argv))

const coords = coordsFromOpts(argv);
let compressed = !argv["skip-compress"];
const cachePersistor = CachePersistor.compressed(compressed);

const directories = (argv["directories"] || []) as string[];
const synchronizeAll = !directories.length;
const namedCachedPaths: {pathName: string, path: string}[] = synchronizeAll
?[{pathName: "__all__", path: "."}]
:directories.map(dir => ({pathName: dir, path: dir}));

await Promise.all(namedCachedPaths.map(ncp => {
console.log(`Storing ${ncp.pathName} into cache:${coords.cacheName}`)
return cachePersistor.pushCache(coords, ncp.path, ncp.pathName);
}));

await CachePersistor.storeCacheMetadata(coords, {
compressed,
// No need to provide any checksum when storing non-cacheable fs
checksum: undefined,
all: synchronizeAll
await storeFS({
coords, compressed, directories
});

console.log(`Directories stored in cache !`)
}
).command("load-fs [directories..]", 'Loads directories previously stored into filesystem cache', (yargs) =>
yargs.options({
Expand All @@ -92,31 +78,12 @@ yargs(hideBin(process.argv))
}), async (argv) => {

const coords = coordsFromOpts(argv);
const cacheMetadata = await CachePersistor.loadCacheMetadata(coords);

if(!cacheMetadata) {
const message = `No cache metadata found for coordinates=${JSON.stringify(coords)}`;
switch(argv['on-inexistant-cache']) {
case 'fail': throw new Error(message);
case 'warn': console.log(message); return;
// default ('ignore'): do nothing
}
}

const cachePersistor = CachePersistor.compressed(cacheMetadata!.compressed);

const directories = (argv["directories"] || []) as string[];
const namedCachedPaths: {pathName: string, path: string}[] = cacheMetadata!.all
?[{pathName: "__all__", path: ""}]
:directories.map(dir => ({pathName: dir, path: dir}));

const onInexistantCache = argv['on-inexistant-cache'] as "ignore"|"warn"|"fail";

await Promise.all(namedCachedPaths.map(ncp => {
console.log(`Loading ${ncp.pathName} from cache:${coords.cacheName}`)
return cachePersistor.loadCache(coords, ncp.path, ncp.pathName);
}));

console.log(`Directories loaded from cache !`)
await loadFS({
coords, directories, onInexistantCache
});
}
).command("cached-fs [directories..]", 'Either loads cached filesystem or rebuild it from scratch based on a checksum', (yargs) =>
yargs.options({
Expand All @@ -135,18 +102,20 @@ yargs(hideBin(process.argv))
type: 'boolean',
describe: 'avoids compressing files prior to sending it in store'
}
}).check((argv, options) => {
if(!argv['directories'] || (argv['directories'] as string[]).length===0) {
throw new Error("At least 1 directory must be provided !")
}
return true;
}), async (argv) => {
const coords = coordsFromOpts(argv);
const compressed = !argv["skip-compress"];
const directories = (argv["directories"] || []) as string[];

await cacheableCommand(coords, {
compressContent: compressed,
checksumCommand: () => $`md5 -q "${argv["checksum-file"]}"`,
cachedPaths: argv["directories"] as string[]
}, () => {
const [command, ...args] = argv["cacheable-command"].split(" ");
console.info(`Executing cacheable command: ${command} ${args}`)
return $`${command} ${args}`
})
await cachedFS({
coords, compressed, directories,
checksumFile: argv["checksum-file"],
cacheableCommand: argv["cacheable-command"]
});
}
).help().argv
11 changes: 11 additions & 0 deletions src/commands/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

export type AuthOptions = {
keyConfig: string;
};

export async function auth(opts: AuthOptions) {
const tmpLocalFile = `/tmp/google-service-account.json`;
await $`curl -sSL ${opts.keyConfig} > ${tmpLocalFile}`
await $`gcloud auth activate-service-account -q --key-file ${tmpLocalFile}`
await $`rm -f ${tmpLocalFile}`
}
23 changes: 23 additions & 0 deletions src/commands/cached-fs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {cacheableCommand} from "../cacheableCommand.js";
import {CacheCoordinates} from "../CachePersistor.js";


export type CachedFSOptions = {
coords: CacheCoordinates;
compressed: boolean;
checksumFile: string;
cacheableCommand: string;
directories: string[];
};

export async function cachedFS(opts: CachedFSOptions) {
await cacheableCommand(opts.coords, {
compressContent: opts.compressed,
checksumCommand: () => $`md5 -q "${opts.checksumFile}"`,
cachedPaths: opts.directories
}, () => {
const [command, ...args] = opts.cacheableCommand.split(" ");
console.info(`Executing cacheable command: ${command} ${args}`)
return $`${command} ${args}`
})
}
Loading

0 comments on commit 7e3e503

Please sign in to comment.