Skip to content

Commit

Permalink
chore: add cache
Browse files Browse the repository at this point in the history
  • Loading branch information
hunghg255 committed Feb 2, 2024
1 parent 615699b commit b09ac4f
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 2 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@
"scripts": {
"build": "unbuild",
"dev": "unbuild --stub",
"test:cli": "node ./dist/cli.mjs",
"test:cli": "node ./dist/nr.cjs",
"lint": "tsc --noEmit",
"lint-es": "eslint --ext .ts,.tsx src --color",
"start": "esno src/nu.ts react",
"start": "esno src/nr.ts",
"test": "vitest",
"verify-commit": "verify-commit-msg",
"prepare": "git-scm-hooks",
Expand Down
11 changes: 11 additions & 0 deletions src/nr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ import c from 'kleur';
import { cancel, isCancel, select, intro } from 'unprompts';

import { getPackageJSON } from './fs';
import { dump, load } from './storage';
import { limitText } from './utils';

export const niCli = async (cwd: string = process.cwd(), argv = process.argv) => {
try {
const storage = await load();

const pkg = getPackageJSON(cwd);
const scripts = pkg.scripts || {};
const scriptsInfo = pkg['scripts-info'] || {};
Expand Down Expand Up @@ -42,12 +45,15 @@ export const niCli = async (cwd: string = process.cwd(), argv = process.argv) =>
if (argv?.length > 2) {
scriptValue = argv.slice(2).join(' ');
} else {
const initialValue = storage.lastRunCommand;

scriptValue = (await select({
message: c.bgCyan(' Run script '),
options: raw.map((scriptItem) => ({
label: `${c.green(scriptItem.key)}: ${c.dim(limitText(scriptItem.description, 50))}`,
value: scriptItem.key,
})),
initialValue,
})) as string;

if (isCancel(scriptValue)) {
Expand All @@ -56,6 +62,11 @@ export const niCli = async (cwd: string = process.cwd(), argv = process.argv) =>
}
}

if (storage.lastRunCommand !== scriptValue) {
storage.lastRunCommand = scriptValue;
dump();
}

if (agent.name === 'bun') {
intro(c.bold(c.green(`bun run ${scriptValue}\n`)));

Expand Down
95 changes: 95 additions & 0 deletions src/storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/* eslint-disable import/export */
import type { Buffer } from 'node:buffer';
import { existsSync, promises as fs } from 'node:fs';
import os from 'node:os';
import { dirname, join, resolve } from 'node:path';
import process from 'node:process';

const CLI_TEMP_DIR = join(os.tmpdir(), 'run-script-cli');
const storagePath = resolve(CLI_TEMP_DIR, '_storage.json');

export interface Storage {
lastRunCommand?: string;
}

let storage: Storage | undefined;

interface TempFile {
path: string;
fd: fs.FileHandle;
cleanup: () => void;
}

let counter = 0;

async function openTemp(): Promise<TempFile | undefined> {
if (!existsSync(CLI_TEMP_DIR)) {
await fs.mkdir(CLI_TEMP_DIR, { recursive: true });
}

const competitivePath = join(CLI_TEMP_DIR, `.${process.pid}.${counter}`);
counter++;

return fs
.open(competitivePath, 'wx')
.then((fd) => ({
fd,
path: competitivePath,
cleanup() {
fd.close().then(() => {
if (existsSync(competitivePath)) {
fs.unlink(competitivePath);
}
});
},
}))
.catch((error: any) => {
return error && error.code === 'EEXIST' ? openTemp() : undefined;
});
}

/**
* Write file safely avoiding conflicts
*/
export async function writeFileSafe(path: string, data: string | Buffer = ''): Promise<boolean> {
const temp = await openTemp();

if (temp) {
fs.writeFile(temp.path, data)
.then(() => {
const directory = dirname(path);
if (!existsSync(directory)) {
fs.mkdir(directory, { recursive: true });
}

return fs
.rename(temp.path, path)
.then(() => true)
.catch(() => false);
})
.catch(() => false)
.finally(temp.cleanup);
}

return false;
}

export async function load(fn?: (storage: Storage) => Promise<boolean> | boolean) {
if (!storage) {
storage = existsSync(storagePath)
? JSON.parse((await fs.readFile(storagePath, 'utf8')) || '{}') || {}
: {};
}

if (fn && (await fn(storage!))) {
await dump();
}

return storage!;
}

export async function dump() {
if (storage) {
await writeFileSafe(storagePath, JSON.stringify(storage));
}
}

0 comments on commit b09ac4f

Please sign in to comment.