sindri
Version:
The Sindri Labs JavaScript SDK and CLI tool.
105 lines (96 loc) • 3.52 kB
text/typescript
import assert from "assert";
import fs from "fs";
import path from "path";
import process from "process";
import { Command } from "@commander-js/extra-typings";
import tar from "tar";
import sindri from "lib";
import { ApiError } from "lib/api";
export const cloneCommand = new Command()
.name("clone")
.description("Clone a circuit into a local directory.")
.argument("<circuit>", "The circuit to clone.")
.argument("[directory]", "The directory to clone the circuit into.")
.action(async (circuit, directory) => {
// Validate the circuit identifier.
const circuitIdentifierRegex =
/^(?:([-a-zA-Z0-9_]+)\/)?([-a-zA-Z0-9_]+)(?::([-a-zA-Z0-9_.]+))?$/;
const match = circuitIdentifierRegex.exec(circuit);
if (!match) {
sindri.logger.error(`"${circuit}" is not a valid circuit identifier.`);
return process.exit(1);
}
assert(match[2], "The circuit name must be provided.");
const circuitName: string = match[2];
const outputDirectory: string = path.resolve(directory ?? circuitName);
// Check that the output directory does not exist.
if (fs.existsSync(outputDirectory)) {
sindri.logger.error(
`The directory "${outputDirectory}" already exists. Aborting.`,
);
return process.exit(1);
}
// Check that the API client is authorized.
if (!sindri.apiKey || !sindri.baseUrl) {
sindri.logger.warn("You must login first with `sindri login`.");
return process.exit(1);
}
// Request the circuit tarball from the server.
let responseStream: NodeJS.ReadableStream;
sindri.logger.info(
`Cloning the circuit "${circuit}" into "${outputDirectory}".`,
);
try {
responseStream = (await sindri._client.internal.circuitDownload(
circuit,
)) as unknown as NodeJS.ReadableStream;
} catch (error) {
if (error instanceof ApiError && error.status === 401) {
sindri.logger.error(
"Your credentials are invalid. Please log in again with `sindri login`.",
);
return process.exit(1);
} else if (error instanceof ApiError && error.status === 404) {
sindri.logger.error(
`The circuit "${circuit}" does not exist or you lack permission to access it.`,
);
return process.exit(1);
} else {
sindri.logger.fatal("An unknown error occurred.");
sindri.logger.error(error);
return process.exit(1);
}
}
// Make the output directory.
try {
fs.mkdirSync(outputDirectory, { recursive: true });
} catch (error) {
sindri.logger.fatal(
`Failed to create the directory "${outputDirectory}". Aborting.`,
);
sindri.logger.error(error);
return process.exit(1);
}
// Extract the tarball into the output directory.
await new Promise((resolve, reject) => {
responseStream.on("end", resolve);
responseStream.on("error", reject);
responseStream.pipe(
tar.x({
cwd: outputDirectory,
noChmod: true,
noMtime: true,
onwarn: (code: string, message: string) => {
sindri.logger.warn(
`While extracting tarball: ${code} - ${message}`,
);
},
preserveOwner: false,
// @ts-expect-error - `preservePaths` is missing from the library's type definitions.
preservePaths: false,
strip: 1,
}),
);
});
sindri.logger.info("Circuit cloned successfully.");
});