Skip to content

Commit

Permalink
improve error handling on cli
Browse files Browse the repository at this point in the history
  • Loading branch information
tasshi-me committed Oct 27, 2024
1 parent 41cddc5 commit 2eb54d1
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 117 deletions.
12 changes: 10 additions & 2 deletions src/cli/plugin/info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import type { CommandModule } from "yargs";
import { emitExperimentalWarning } from "../../utils/stability";
import type { OutputFormat } from "../../plugin/info/";
import { run } from "../../plugin/info/";
import { logger } from "../../utils/log";
import { RunError } from "../../record/error";

const command = "info";

Expand Down Expand Up @@ -30,8 +32,14 @@ type Args = yargs.Arguments<
>;

const handler = async (args: Args) => {
emitExperimentalWarning("This feature is under early development");
await run(args.input, args.format);
try {
emitExperimentalWarning("This feature is under early development");
await run(args.input, args.format);
} catch (error) {
logger.error(new RunError(error));
// eslint-disable-next-line n/no-process-exit
process.exit(1);
}
};

export const infoCommand: CommandModule<{}, Args> = {
Expand Down
28 changes: 18 additions & 10 deletions src/cli/plugin/pack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import type yargs from "yargs";
import type { CommandModule } from "yargs";
import { emitExperimentalWarning } from "../../utils/stability";
import { run } from "../../plugin/packer/";
import { logger } from "../../utils/log";
import { RunError } from "../../record/error";

const command = "pack";

Expand Down Expand Up @@ -38,16 +40,22 @@ type Args = yargs.Arguments<
>;

const handler = async (args: Args) => {
emitExperimentalWarning("This feature is under early development");
const flags = {
ppk: args["private-key"],
out: args.output,
watch: args.watch,
};
if (process.env.NODE_ENV === "test") {
console.log(JSON.stringify({ pluginDir: args.input, flags: flags }));
} else {
await run(args.input, flags);
try {
emitExperimentalWarning("This feature is under early development");
const flags = {
ppk: args["private-key"],
out: args.output,
watch: args.watch,
};
if (process.env.NODE_ENV === "test") {
console.log(JSON.stringify({ pluginDir: args.input, flags: flags }));
} else {
await run(args.input, flags);
}
} catch (error) {
logger.error(new RunError(error));
// eslint-disable-next-line n/no-process-exit
process.exit(1);
}
};

Expand Down
205 changes: 100 additions & 105 deletions src/plugin/packer/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,110 +16,105 @@ type Options = Partial<{
export const run = async (pluginDir: string, options_?: Options) => {
const options = options_ || {};

try {
// 1. check if pluginDir is a directory
if (!(await fs.stat(pluginDir)).isDirectory()) {
throw new Error(`${pluginDir} should be a directory.`);
}

// 2. check pluginDir/manifest.json
const manifestJsonPath = path.join(pluginDir, "manifest.json");
if (!(await fs.stat(manifestJsonPath)).isFile()) {
throw new Error("Manifest file $PLUGIN_DIR/manifest.json not found.");
}

// 3. load manifest.json
const manifest = await ManifestFactory.loadJsonFile(manifestJsonPath);
if (manifest.manifestVersion === 2) {
logger.warn("Welcome to manifest v2 mode :)");
}

// 4. validate manifest.json
const result = await manifest.validate(new LocalFSDriver(pluginDir));

if (result.warnings.length > 0) {
result.warnings.forEach((warning) => {
logger.warn(warning);
});
}

if (!result.valid) {
logger.error("Invalid manifest.json:");
result.errors.forEach((msg) => {
logger.error(`- ${msg}`);
});
throw new Error("Invalid manifest.json");
}

// 5. generate new ppk if not specified
const ppkFile = options.ppk;
let privateKey: PrivateKey;
if (ppkFile) {
logger.debug(`loading an existing key: ${ppkFile}`);
const ppk = await fs.readFile(ppkFile, "utf8");
privateKey = PrivateKey.importKey(ppk);
} else {
logger.debug("generating a new key");
privateKey = PrivateKey.generateKey();
}

const id = privateKey.uuid();
logger.debug(`id: ${id}`);

// 6. prepare output directory
let outputDir = path.dirname(path.resolve(pluginDir));
let outputFile = path.join(outputDir, "plugin.zip");
if (options.out) {
outputFile = options.out;
outputDir = path.dirname(path.resolve(outputFile));
}
await fs.mkdir(outputDir, { recursive: true });
logger.debug(`outputDir: ${outputDir}`);
logger.debug(`outputFile: ${outputFile}`);

// 7. package plugin.zip
const pluginZip = await PluginZip.build(
manifest,
privateKey,
new LocalFSDriver(pluginDir),
);

const ppkFilePath = path.join(outputDir, `${id}.ppk`);
if (!ppkFile) {
await fs.writeFile(ppkFilePath, privateKey.exportPrivateKey(), "utf8");
}

if (options.watch) {
// change events are fired before chagned files are flushed on Windows,
// which generate an invalid plugin zip.
// in order to fix this, we use awaitWriteFinish option only on Windows.
const watchOptions =
os.platform() === "win32"
? {
awaitWriteFinish: {
stabilityThreshold: 1000,
pollInterval: 250,
},
}
: {};
const watcher = chokidar.watch(pluginDir, watchOptions);
watcher.on("change", () => {
run(
pluginDir,
Object.assign({}, options, {
watch: false,
ppk: options.ppk || ppkFilePath,
}),
);
});
}

await fs.writeFile(outputFile, pluginZip.buffer);

logger.info(`Succeeded: ${outputFile}`);
return outputFile;
} catch (error) {
logger.error(`Failed: ${error}`);
return Promise.reject(error);
// 1. check if pluginDir is a directory
if (!(await fs.stat(pluginDir)).isDirectory()) {
throw new Error(`${pluginDir} should be a directory.`);
}

// 2. check pluginDir/manifest.json
const manifestJsonPath = path.join(pluginDir, "manifest.json");
if (!(await fs.stat(manifestJsonPath)).isFile()) {
throw new Error("Manifest file $PLUGIN_DIR/manifest.json not found.");
}

// 3. load manifest.json
const manifest = await ManifestFactory.loadJsonFile(manifestJsonPath);
if (manifest.manifestVersion === 2) {
logger.warn("Welcome to manifest v2 mode :)");
}

// 4. validate manifest.json
const result = await manifest.validate(new LocalFSDriver(pluginDir));

if (result.warnings.length > 0) {
result.warnings.forEach((warning) => {
logger.warn(warning);
});
}

if (!result.valid) {
logger.error("Invalid manifest.json:");
result.errors.forEach((msg) => {
logger.error(`- ${msg}`);
});
throw new Error("Invalid manifest.json");
}

// 5. generate new ppk if not specified
const ppkFile = options.ppk;
let privateKey: PrivateKey;
if (ppkFile) {
logger.debug(`loading an existing key: ${ppkFile}`);
const ppk = await fs.readFile(ppkFile, "utf8");
privateKey = PrivateKey.importKey(ppk);
} else {
logger.debug("generating a new key");
privateKey = PrivateKey.generateKey();
}

const id = privateKey.uuid();
logger.debug(`id: ${id}`);

// 6. prepare output directory
let outputDir = path.dirname(path.resolve(pluginDir));
let outputFile = path.join(outputDir, "plugin.zip");
if (options.out) {
outputFile = options.out;
outputDir = path.dirname(path.resolve(outputFile));
}
await fs.mkdir(outputDir, { recursive: true });
logger.debug(`outputDir: ${outputDir}`);
logger.debug(`outputFile: ${outputFile}`);

// 7. package plugin.zip
const pluginZip = await PluginZip.build(
manifest,
privateKey,
new LocalFSDriver(pluginDir),
);

const ppkFilePath = path.join(outputDir, `${id}.ppk`);
if (!ppkFile) {
await fs.writeFile(ppkFilePath, privateKey.exportPrivateKey(), "utf8");
logger.info(`New private key generated: ${ppkFilePath}`);
}

if (options.watch) {
// change events are fired before chagned files are flushed on Windows,
// which generate an invalid plugin zip.
// in order to fix this, we use awaitWriteFinish option only on Windows.
const watchOptions =
os.platform() === "win32"
? {
awaitWriteFinish: {
stabilityThreshold: 1000,
pollInterval: 250,
},
}
: {};
const watcher = chokidar.watch(pluginDir, watchOptions);
watcher.on("change", () => {
run(
pluginDir,
Object.assign({}, options, {
watch: false,
ppk: options.ppk || ppkFilePath,
}),
);
});
}

await fs.writeFile(outputFile, pluginZip.buffer);

logger.info(`The plugin file generated: ${outputFile}`);
};

0 comments on commit 2eb54d1

Please sign in to comment.