initial commit
This commit is contained in:
53
node_modules/giget/dist/cli.cjs
generated
vendored
Executable file
53
node_modules/giget/dist/cli.cjs
generated
vendored
Executable file
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
const node_path = require('node:path');
|
||||
const mri = require('mri');
|
||||
const colorette = require('colorette');
|
||||
const giget = require('./shared/giget.1028e17a.cjs');
|
||||
require('node:fs/promises');
|
||||
require('node:os');
|
||||
require('node:fs');
|
||||
require('tar');
|
||||
require('pathe');
|
||||
require('defu');
|
||||
require('node:stream');
|
||||
require('node:child_process');
|
||||
require('node:util');
|
||||
require('node-fetch-native');
|
||||
require('https-proxy-agent');
|
||||
|
||||
async function main() {
|
||||
const arguments_ = mri(process.argv.slice(2), {
|
||||
boolean: ["help", "force", "force-clean", "offline", "prefer-offline", "shell", "verbose"],
|
||||
string: ["registry", "cwd", "auth"]
|
||||
});
|
||||
const input = arguments_._[0];
|
||||
const dir = arguments_._[1];
|
||||
if (!input || arguments_.help || arguments_.h) {
|
||||
console.error("Usage: npx getgit@latest <input> [<dir>] [--force] [--force-clean] [--offline] [--prefer-offline] [--shell] [--registry] [--no-registry] [--verbose] [--cwd] [--auth]");
|
||||
process.exit(1);
|
||||
}
|
||||
if (arguments_.verbose) {
|
||||
process.env.DEBUG = process.env.DEBUG || "true";
|
||||
}
|
||||
const r = await giget.downloadTemplate(input, {
|
||||
dir,
|
||||
force: arguments_.force,
|
||||
forceClean: arguments_["force-clean"],
|
||||
offline: arguments_.offline,
|
||||
registry: arguments_.registry,
|
||||
cwd: arguments_.cwd,
|
||||
auth: arguments_.auth
|
||||
});
|
||||
console.log(`\u2728 Successfully cloned ${colorette.cyan(r.name || r.url)} to ${colorette.cyan(node_path.relative(process.cwd(), r.dir))}
|
||||
`);
|
||||
if (arguments_.shell) {
|
||||
giget.startShell(r.dir);
|
||||
}
|
||||
process.exit(0);
|
||||
}
|
||||
main().catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
1
node_modules/giget/dist/cli.d.ts
generated
vendored
Normal file
1
node_modules/giget/dist/cli.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
51
node_modules/giget/dist/cli.mjs
generated
vendored
Executable file
51
node_modules/giget/dist/cli.mjs
generated
vendored
Executable file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env node
|
||||
import { relative } from 'node:path';
|
||||
import mri from 'mri';
|
||||
import { cyan } from 'colorette';
|
||||
import { d as downloadTemplate, s as startShell } from './shared/giget.5e7ec864.mjs';
|
||||
import 'node:fs/promises';
|
||||
import 'node:os';
|
||||
import 'node:fs';
|
||||
import 'tar';
|
||||
import 'pathe';
|
||||
import 'defu';
|
||||
import 'node:stream';
|
||||
import 'node:child_process';
|
||||
import 'node:util';
|
||||
import 'node-fetch-native';
|
||||
import 'https-proxy-agent';
|
||||
|
||||
async function main() {
|
||||
const arguments_ = mri(process.argv.slice(2), {
|
||||
boolean: ["help", "force", "force-clean", "offline", "prefer-offline", "shell", "verbose"],
|
||||
string: ["registry", "cwd", "auth"]
|
||||
});
|
||||
const input = arguments_._[0];
|
||||
const dir = arguments_._[1];
|
||||
if (!input || arguments_.help || arguments_.h) {
|
||||
console.error("Usage: npx getgit@latest <input> [<dir>] [--force] [--force-clean] [--offline] [--prefer-offline] [--shell] [--registry] [--no-registry] [--verbose] [--cwd] [--auth]");
|
||||
process.exit(1);
|
||||
}
|
||||
if (arguments_.verbose) {
|
||||
process.env.DEBUG = process.env.DEBUG || "true";
|
||||
}
|
||||
const r = await downloadTemplate(input, {
|
||||
dir,
|
||||
force: arguments_.force,
|
||||
forceClean: arguments_["force-clean"],
|
||||
offline: arguments_.offline,
|
||||
registry: arguments_.registry,
|
||||
cwd: arguments_.cwd,
|
||||
auth: arguments_.auth
|
||||
});
|
||||
console.log(`\u2728 Successfully cloned ${cyan(r.name || r.url)} to ${cyan(relative(process.cwd(), r.dir))}
|
||||
`);
|
||||
if (arguments_.shell) {
|
||||
startShell(r.dir);
|
||||
}
|
||||
process.exit(0);
|
||||
}
|
||||
main().catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
20
node_modules/giget/dist/index.cjs
generated
vendored
Normal file
20
node_modules/giget/dist/index.cjs
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
const giget = require('./shared/giget.1028e17a.cjs');
|
||||
require('node:fs/promises');
|
||||
require('node:os');
|
||||
require('node:fs');
|
||||
require('tar');
|
||||
require('pathe');
|
||||
require('defu');
|
||||
require('node:stream');
|
||||
require('node:child_process');
|
||||
require('node:util');
|
||||
require('node-fetch-native');
|
||||
require('https-proxy-agent');
|
||||
|
||||
|
||||
|
||||
exports.downloadTemplate = giget.downloadTemplate;
|
||||
exports.registryProvider = giget.registryProvider;
|
||||
exports.startShell = giget.startShell;
|
||||
45
node_modules/giget/dist/index.d.ts
generated
vendored
Normal file
45
node_modules/giget/dist/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
interface GitInfo {
|
||||
provider: "github" | "gitlab" | "bitbucket" | "sourcehut";
|
||||
repo: string;
|
||||
subdir: string;
|
||||
ref: string;
|
||||
}
|
||||
interface TemplateInfo {
|
||||
name: string;
|
||||
tar: string;
|
||||
version?: string;
|
||||
subdir?: string;
|
||||
url?: string;
|
||||
defaultDir?: string;
|
||||
headers?: Record<string, string>;
|
||||
source?: never;
|
||||
dir?: never;
|
||||
[key: string]: any;
|
||||
}
|
||||
declare type TemplateProvider = (input: string, options: {
|
||||
auth?: string;
|
||||
}) => TemplateInfo | Promise<TemplateInfo> | null;
|
||||
|
||||
interface DownloadTemplateOptions {
|
||||
provider?: string;
|
||||
force?: boolean;
|
||||
forceClean?: boolean;
|
||||
offline?: boolean;
|
||||
preferOffline?: boolean;
|
||||
providers?: Record<string, TemplateProvider>;
|
||||
dir?: string;
|
||||
registry?: false | string;
|
||||
cwd?: string;
|
||||
auth?: string;
|
||||
}
|
||||
declare type DownloadTemplateResult = Omit<TemplateInfo, "dir" | "source"> & {
|
||||
dir: string;
|
||||
source: string;
|
||||
};
|
||||
declare function downloadTemplate(input: string, options?: DownloadTemplateOptions): Promise<DownloadTemplateResult>;
|
||||
|
||||
declare const registryProvider: (registryEndpoint?: string) => TemplateProvider;
|
||||
|
||||
declare function startShell(cwd: string): void;
|
||||
|
||||
export { DownloadTemplateOptions, DownloadTemplateResult, GitInfo, TemplateInfo, TemplateProvider, downloadTemplate, registryProvider, startShell };
|
||||
12
node_modules/giget/dist/index.mjs
generated
vendored
Normal file
12
node_modules/giget/dist/index.mjs
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
export { d as downloadTemplate, r as registryProvider, s as startShell } from './shared/giget.5e7ec864.mjs';
|
||||
import 'node:fs/promises';
|
||||
import 'node:os';
|
||||
import 'node:fs';
|
||||
import 'tar';
|
||||
import 'pathe';
|
||||
import 'defu';
|
||||
import 'node:stream';
|
||||
import 'node:child_process';
|
||||
import 'node:util';
|
||||
import 'node-fetch-native';
|
||||
import 'https-proxy-agent';
|
||||
219
node_modules/giget/dist/shared/giget.1028e17a.cjs
generated
vendored
Normal file
219
node_modules/giget/dist/shared/giget.1028e17a.cjs
generated
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
'use strict';
|
||||
|
||||
const promises = require('node:fs/promises');
|
||||
const node_os = require('node:os');
|
||||
const node_fs = require('node:fs');
|
||||
const tar = require('tar');
|
||||
const pathe = require('pathe');
|
||||
const defu = require('defu');
|
||||
const node_stream = require('node:stream');
|
||||
const node_child_process = require('node:child_process');
|
||||
const node_util = require('node:util');
|
||||
const nodeFetchNative = require('node-fetch-native');
|
||||
const createHttpsProxyAgent = require('https-proxy-agent');
|
||||
|
||||
async function download(url, filePath, options = {}) {
|
||||
const infoPath = filePath + ".json";
|
||||
const info = JSON.parse(await promises.readFile(infoPath, "utf8").catch(() => "{}"));
|
||||
const headResponse = await sendFetch(url, { method: "HEAD", headers: options.headers }).catch(() => void 0);
|
||||
const etag = headResponse?.headers.get("etag");
|
||||
if (info.etag === etag && node_fs.existsSync(filePath)) {
|
||||
return;
|
||||
}
|
||||
info.etag = etag;
|
||||
const response = await sendFetch(url, { headers: options.headers });
|
||||
if (response.status >= 400) {
|
||||
throw new Error(`Failed to download ${url}: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
const stream = node_fs.createWriteStream(filePath);
|
||||
await node_util.promisify(node_stream.pipeline)(response.body, stream);
|
||||
await promises.writeFile(infoPath, JSON.stringify(info), "utf8");
|
||||
}
|
||||
const inputRegex = /^(?<repo>[\w.-]+\/[\w.-]+)(?<subdir>[^#]+)?(?<ref>#[\w.-]+)?/;
|
||||
function parseGitURI(input) {
|
||||
const m = input.match(inputRegex)?.groups;
|
||||
return {
|
||||
repo: m.repo,
|
||||
subdir: m.subdir || "/",
|
||||
ref: m.ref ? m.ref.slice(1) : "main"
|
||||
};
|
||||
}
|
||||
function debug(...arguments_) {
|
||||
if (process.env.DEBUG) {
|
||||
console.debug("[giget]", ...arguments_);
|
||||
}
|
||||
}
|
||||
async function sendFetch(url, options) {
|
||||
const proxy = process.env.HTTPS_PROXY || process.env.https_proxy || process.env.HTTP_PROXY || process.env.http_proxy;
|
||||
const requestOptions = proxy ? { agent: createHttpsProxyAgent(proxy), ...options } : options;
|
||||
return await nodeFetchNative.fetch(url, requestOptions);
|
||||
}
|
||||
function currentShell() {
|
||||
if (process.env.SHELL) {
|
||||
return process.env.SHELL;
|
||||
}
|
||||
if (process.platform === "win32") {
|
||||
return "cmd.exe";
|
||||
}
|
||||
return "/bin/bash";
|
||||
}
|
||||
function startShell(cwd) {
|
||||
cwd = pathe.resolve(cwd);
|
||||
const shell = currentShell();
|
||||
console.info(`(experimental) Opening shell in ${pathe.relative(process.cwd(), cwd)}...`);
|
||||
node_child_process.spawnSync(shell, [], {
|
||||
cwd,
|
||||
shell: true,
|
||||
stdio: "inherit"
|
||||
});
|
||||
}
|
||||
|
||||
const github = (input, options) => {
|
||||
const parsed = parseGitURI(input);
|
||||
return {
|
||||
name: parsed.repo.replace("/", "-"),
|
||||
version: parsed.ref,
|
||||
subdir: parsed.subdir,
|
||||
headers: { Authorization: options.auth ? `Bearer ${options.auth}` : void 0 },
|
||||
url: `https://github.com/${parsed.repo}/tree/${parsed.ref}${parsed.subdir}`,
|
||||
tar: `https://github.com/${parsed.repo}/archive/${parsed.ref}.tar.gz`
|
||||
};
|
||||
};
|
||||
const gitlab = (input, options) => {
|
||||
const parsed = parseGitURI(input);
|
||||
return {
|
||||
name: parsed.repo.replace("/", "-"),
|
||||
version: parsed.ref,
|
||||
subdir: parsed.subdir,
|
||||
headers: { Authorization: options.auth ? `Bearer ${options.auth}` : void 0 },
|
||||
url: `https://gitlab.com/${parsed.repo}/tree/${parsed.ref}${parsed.subdir}`,
|
||||
tar: `https://gitlab.com/${parsed.repo}/-/archive/${parsed.ref}.tar.gz`
|
||||
};
|
||||
};
|
||||
const bitbucket = (input, options) => {
|
||||
const parsed = parseGitURI(input);
|
||||
return {
|
||||
name: parsed.repo.replace("/", "-"),
|
||||
version: parsed.ref,
|
||||
subdir: parsed.subdir,
|
||||
headers: { Authorization: options.auth ? `Bearer ${options.auth}` : void 0 },
|
||||
url: `https://bitbucket.com/${parsed.repo}/src/${parsed.ref}${parsed.subdir}`,
|
||||
tar: `https://bitbucket.org/${parsed.repo}/get/${parsed.ref}.tar.gz`
|
||||
};
|
||||
};
|
||||
const sourcehut = (input, options) => {
|
||||
const parsed = parseGitURI(input);
|
||||
return {
|
||||
name: parsed.repo.replace("/", "-"),
|
||||
version: parsed.ref,
|
||||
subdir: parsed.subdir,
|
||||
headers: { Authorization: options.auth ? `Bearer ${options.auth}` : void 0 },
|
||||
url: `https://git.sr.ht/~${parsed.repo}/tree/${parsed.ref}/item${parsed.subdir}`,
|
||||
tar: `https://git.sr.ht/~${parsed.repo}/archive/${parsed.ref}.tar.gz`
|
||||
};
|
||||
};
|
||||
const providers = {
|
||||
github,
|
||||
gh: github,
|
||||
gitlab,
|
||||
bitbucket,
|
||||
sourcehut
|
||||
};
|
||||
|
||||
const DEFAULT_REGISTRY = "https://raw.githubusercontent.com/unjs/giget/main/templates";
|
||||
const registryProvider = (registryEndpoint = DEFAULT_REGISTRY) => {
|
||||
return async (input) => {
|
||||
const start = Date.now();
|
||||
const registryURL = `${registryEndpoint}/${input}.json`;
|
||||
const result = await sendFetch(registryURL);
|
||||
if (result.status >= 400) {
|
||||
throw new Error(`Failed to download ${input} template info from ${registryURL}: ${result.status} ${result.statusText}`);
|
||||
}
|
||||
const info = await result.json();
|
||||
if (!info.tar || !info.name) {
|
||||
throw new Error(`Invalid template info from ${registryURL}. name or tar fields are missing!`);
|
||||
}
|
||||
debug(`Fetched ${input} template info from ${registryURL} in ${Date.now() - start}ms`);
|
||||
return info;
|
||||
};
|
||||
};
|
||||
|
||||
const sourceProtoRe = /^([\w-.]+):/;
|
||||
async function downloadTemplate(input, options = {}) {
|
||||
options = defu.defu({
|
||||
registry: process.env.GIGET_REGISTRY,
|
||||
auth: process.env.GIGET_AUTH
|
||||
}, options);
|
||||
const registry = options.registry !== false ? registryProvider(options.registry) : void 0;
|
||||
let providerName = options.provider || (registryProvider ? "registry" : "github");
|
||||
let source = input;
|
||||
const sourceProvierMatch = input.match(sourceProtoRe);
|
||||
if (sourceProvierMatch) {
|
||||
providerName = sourceProvierMatch[1];
|
||||
source = input.slice(sourceProvierMatch[0].length);
|
||||
}
|
||||
const provider = options.providers?.[providerName] || providers[providerName] || registry;
|
||||
if (!provider) {
|
||||
throw new Error(`Unsupported provider: ${providerName}`);
|
||||
}
|
||||
const template = await Promise.resolve().then(() => provider(source, { auth: options.auth })).catch((error) => {
|
||||
throw new Error(`Failed to download template from ${providerName}: ${error.message}`);
|
||||
});
|
||||
template.name = (template.name || "template").replace(/[^\da-z-]/gi, "-");
|
||||
template.defaultDir = (template.defaultDir || template.name).replace(/[^\da-z-]/gi, "-");
|
||||
const cwd = pathe.resolve(options.cwd || ".");
|
||||
const extractPath = pathe.resolve(cwd, options.dir || template.defaultDir);
|
||||
if (options.forceClean) {
|
||||
await promises.rm(extractPath, { recursive: true, force: true });
|
||||
}
|
||||
if (!options.force && node_fs.existsSync(extractPath) && node_fs.readdirSync(extractPath).length > 0) {
|
||||
throw new Error(`Destination ${extractPath} already exists.`);
|
||||
}
|
||||
await promises.mkdir(extractPath, { recursive: true });
|
||||
const temporaryDirectory = pathe.resolve(node_os.homedir(), ".giget", options.provider, template.name);
|
||||
const tarPath = pathe.resolve(temporaryDirectory, (template.version || template.name) + ".tar.gz");
|
||||
if (options.preferOffline && node_fs.existsSync(tarPath)) {
|
||||
options.offline = true;
|
||||
}
|
||||
if (!options.offline) {
|
||||
await promises.mkdir(pathe.dirname(tarPath), { recursive: true });
|
||||
const s2 = Date.now();
|
||||
await download(template.tar, tarPath, { headers: template.headers }).catch((error) => {
|
||||
if (!node_fs.existsSync(tarPath)) {
|
||||
throw error;
|
||||
}
|
||||
debug("Download error. Using cached version:", error);
|
||||
options.offline = true;
|
||||
});
|
||||
debug(`Downloaded ${template.tar} to ${tarPath} in ${Date.now() - s2}ms`);
|
||||
}
|
||||
if (!node_fs.existsSync(tarPath)) {
|
||||
throw new Error(`Tarball not found: ${tarPath} (offline: ${options.offline})`);
|
||||
}
|
||||
const s = Date.now();
|
||||
const subdir = template.subdir?.replace(/^\//, "") || "";
|
||||
await tar.extract({
|
||||
file: tarPath,
|
||||
cwd: extractPath,
|
||||
onentry(entry) {
|
||||
entry.path = entry.path.split("/").splice(1).join("/");
|
||||
if (subdir) {
|
||||
if (entry.path.startsWith(subdir + "/")) {
|
||||
entry.path = entry.path.slice(subdir.length);
|
||||
} else {
|
||||
entry.path = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
debug(`Extracted to ${extractPath} in ${Date.now() - s}ms`);
|
||||
return {
|
||||
...template,
|
||||
source,
|
||||
dir: extractPath
|
||||
};
|
||||
}
|
||||
|
||||
exports.downloadTemplate = downloadTemplate;
|
||||
exports.registryProvider = registryProvider;
|
||||
exports.startShell = startShell;
|
||||
215
node_modules/giget/dist/shared/giget.5e7ec864.mjs
generated
vendored
Normal file
215
node_modules/giget/dist/shared/giget.5e7ec864.mjs
generated
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
import { readFile, writeFile, rm, mkdir } from 'node:fs/promises';
|
||||
import { homedir } from 'node:os';
|
||||
import { existsSync, createWriteStream, readdirSync } from 'node:fs';
|
||||
import { extract } from 'tar';
|
||||
import { resolve, relative, dirname } from 'pathe';
|
||||
import { defu } from 'defu';
|
||||
import { pipeline } from 'node:stream';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { promisify } from 'node:util';
|
||||
import { fetch } from 'node-fetch-native';
|
||||
import createHttpsProxyAgent from 'https-proxy-agent';
|
||||
|
||||
async function download(url, filePath, options = {}) {
|
||||
const infoPath = filePath + ".json";
|
||||
const info = JSON.parse(await readFile(infoPath, "utf8").catch(() => "{}"));
|
||||
const headResponse = await sendFetch(url, { method: "HEAD", headers: options.headers }).catch(() => void 0);
|
||||
const etag = headResponse?.headers.get("etag");
|
||||
if (info.etag === etag && existsSync(filePath)) {
|
||||
return;
|
||||
}
|
||||
info.etag = etag;
|
||||
const response = await sendFetch(url, { headers: options.headers });
|
||||
if (response.status >= 400) {
|
||||
throw new Error(`Failed to download ${url}: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
const stream = createWriteStream(filePath);
|
||||
await promisify(pipeline)(response.body, stream);
|
||||
await writeFile(infoPath, JSON.stringify(info), "utf8");
|
||||
}
|
||||
const inputRegex = /^(?<repo>[\w.-]+\/[\w.-]+)(?<subdir>[^#]+)?(?<ref>#[\w.-]+)?/;
|
||||
function parseGitURI(input) {
|
||||
const m = input.match(inputRegex)?.groups;
|
||||
return {
|
||||
repo: m.repo,
|
||||
subdir: m.subdir || "/",
|
||||
ref: m.ref ? m.ref.slice(1) : "main"
|
||||
};
|
||||
}
|
||||
function debug(...arguments_) {
|
||||
if (process.env.DEBUG) {
|
||||
console.debug("[giget]", ...arguments_);
|
||||
}
|
||||
}
|
||||
async function sendFetch(url, options) {
|
||||
const proxy = process.env.HTTPS_PROXY || process.env.https_proxy || process.env.HTTP_PROXY || process.env.http_proxy;
|
||||
const requestOptions = proxy ? { agent: createHttpsProxyAgent(proxy), ...options } : options;
|
||||
return await fetch(url, requestOptions);
|
||||
}
|
||||
function currentShell() {
|
||||
if (process.env.SHELL) {
|
||||
return process.env.SHELL;
|
||||
}
|
||||
if (process.platform === "win32") {
|
||||
return "cmd.exe";
|
||||
}
|
||||
return "/bin/bash";
|
||||
}
|
||||
function startShell(cwd) {
|
||||
cwd = resolve(cwd);
|
||||
const shell = currentShell();
|
||||
console.info(`(experimental) Opening shell in ${relative(process.cwd(), cwd)}...`);
|
||||
spawnSync(shell, [], {
|
||||
cwd,
|
||||
shell: true,
|
||||
stdio: "inherit"
|
||||
});
|
||||
}
|
||||
|
||||
const github = (input, options) => {
|
||||
const parsed = parseGitURI(input);
|
||||
return {
|
||||
name: parsed.repo.replace("/", "-"),
|
||||
version: parsed.ref,
|
||||
subdir: parsed.subdir,
|
||||
headers: { Authorization: options.auth ? `Bearer ${options.auth}` : void 0 },
|
||||
url: `https://github.com/${parsed.repo}/tree/${parsed.ref}${parsed.subdir}`,
|
||||
tar: `https://github.com/${parsed.repo}/archive/${parsed.ref}.tar.gz`
|
||||
};
|
||||
};
|
||||
const gitlab = (input, options) => {
|
||||
const parsed = parseGitURI(input);
|
||||
return {
|
||||
name: parsed.repo.replace("/", "-"),
|
||||
version: parsed.ref,
|
||||
subdir: parsed.subdir,
|
||||
headers: { Authorization: options.auth ? `Bearer ${options.auth}` : void 0 },
|
||||
url: `https://gitlab.com/${parsed.repo}/tree/${parsed.ref}${parsed.subdir}`,
|
||||
tar: `https://gitlab.com/${parsed.repo}/-/archive/${parsed.ref}.tar.gz`
|
||||
};
|
||||
};
|
||||
const bitbucket = (input, options) => {
|
||||
const parsed = parseGitURI(input);
|
||||
return {
|
||||
name: parsed.repo.replace("/", "-"),
|
||||
version: parsed.ref,
|
||||
subdir: parsed.subdir,
|
||||
headers: { Authorization: options.auth ? `Bearer ${options.auth}` : void 0 },
|
||||
url: `https://bitbucket.com/${parsed.repo}/src/${parsed.ref}${parsed.subdir}`,
|
||||
tar: `https://bitbucket.org/${parsed.repo}/get/${parsed.ref}.tar.gz`
|
||||
};
|
||||
};
|
||||
const sourcehut = (input, options) => {
|
||||
const parsed = parseGitURI(input);
|
||||
return {
|
||||
name: parsed.repo.replace("/", "-"),
|
||||
version: parsed.ref,
|
||||
subdir: parsed.subdir,
|
||||
headers: { Authorization: options.auth ? `Bearer ${options.auth}` : void 0 },
|
||||
url: `https://git.sr.ht/~${parsed.repo}/tree/${parsed.ref}/item${parsed.subdir}`,
|
||||
tar: `https://git.sr.ht/~${parsed.repo}/archive/${parsed.ref}.tar.gz`
|
||||
};
|
||||
};
|
||||
const providers = {
|
||||
github,
|
||||
gh: github,
|
||||
gitlab,
|
||||
bitbucket,
|
||||
sourcehut
|
||||
};
|
||||
|
||||
const DEFAULT_REGISTRY = "https://raw.githubusercontent.com/unjs/giget/main/templates";
|
||||
const registryProvider = (registryEndpoint = DEFAULT_REGISTRY) => {
|
||||
return async (input) => {
|
||||
const start = Date.now();
|
||||
const registryURL = `${registryEndpoint}/${input}.json`;
|
||||
const result = await sendFetch(registryURL);
|
||||
if (result.status >= 400) {
|
||||
throw new Error(`Failed to download ${input} template info from ${registryURL}: ${result.status} ${result.statusText}`);
|
||||
}
|
||||
const info = await result.json();
|
||||
if (!info.tar || !info.name) {
|
||||
throw new Error(`Invalid template info from ${registryURL}. name or tar fields are missing!`);
|
||||
}
|
||||
debug(`Fetched ${input} template info from ${registryURL} in ${Date.now() - start}ms`);
|
||||
return info;
|
||||
};
|
||||
};
|
||||
|
||||
const sourceProtoRe = /^([\w-.]+):/;
|
||||
async function downloadTemplate(input, options = {}) {
|
||||
options = defu({
|
||||
registry: process.env.GIGET_REGISTRY,
|
||||
auth: process.env.GIGET_AUTH
|
||||
}, options);
|
||||
const registry = options.registry !== false ? registryProvider(options.registry) : void 0;
|
||||
let providerName = options.provider || (registryProvider ? "registry" : "github");
|
||||
let source = input;
|
||||
const sourceProvierMatch = input.match(sourceProtoRe);
|
||||
if (sourceProvierMatch) {
|
||||
providerName = sourceProvierMatch[1];
|
||||
source = input.slice(sourceProvierMatch[0].length);
|
||||
}
|
||||
const provider = options.providers?.[providerName] || providers[providerName] || registry;
|
||||
if (!provider) {
|
||||
throw new Error(`Unsupported provider: ${providerName}`);
|
||||
}
|
||||
const template = await Promise.resolve().then(() => provider(source, { auth: options.auth })).catch((error) => {
|
||||
throw new Error(`Failed to download template from ${providerName}: ${error.message}`);
|
||||
});
|
||||
template.name = (template.name || "template").replace(/[^\da-z-]/gi, "-");
|
||||
template.defaultDir = (template.defaultDir || template.name).replace(/[^\da-z-]/gi, "-");
|
||||
const cwd = resolve(options.cwd || ".");
|
||||
const extractPath = resolve(cwd, options.dir || template.defaultDir);
|
||||
if (options.forceClean) {
|
||||
await rm(extractPath, { recursive: true, force: true });
|
||||
}
|
||||
if (!options.force && existsSync(extractPath) && readdirSync(extractPath).length > 0) {
|
||||
throw new Error(`Destination ${extractPath} already exists.`);
|
||||
}
|
||||
await mkdir(extractPath, { recursive: true });
|
||||
const temporaryDirectory = resolve(homedir(), ".giget", options.provider, template.name);
|
||||
const tarPath = resolve(temporaryDirectory, (template.version || template.name) + ".tar.gz");
|
||||
if (options.preferOffline && existsSync(tarPath)) {
|
||||
options.offline = true;
|
||||
}
|
||||
if (!options.offline) {
|
||||
await mkdir(dirname(tarPath), { recursive: true });
|
||||
const s2 = Date.now();
|
||||
await download(template.tar, tarPath, { headers: template.headers }).catch((error) => {
|
||||
if (!existsSync(tarPath)) {
|
||||
throw error;
|
||||
}
|
||||
debug("Download error. Using cached version:", error);
|
||||
options.offline = true;
|
||||
});
|
||||
debug(`Downloaded ${template.tar} to ${tarPath} in ${Date.now() - s2}ms`);
|
||||
}
|
||||
if (!existsSync(tarPath)) {
|
||||
throw new Error(`Tarball not found: ${tarPath} (offline: ${options.offline})`);
|
||||
}
|
||||
const s = Date.now();
|
||||
const subdir = template.subdir?.replace(/^\//, "") || "";
|
||||
await extract({
|
||||
file: tarPath,
|
||||
cwd: extractPath,
|
||||
onentry(entry) {
|
||||
entry.path = entry.path.split("/").splice(1).join("/");
|
||||
if (subdir) {
|
||||
if (entry.path.startsWith(subdir + "/")) {
|
||||
entry.path = entry.path.slice(subdir.length);
|
||||
} else {
|
||||
entry.path = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
debug(`Extracted to ${extractPath} in ${Date.now() - s}ms`);
|
||||
return {
|
||||
...template,
|
||||
source,
|
||||
dir: extractPath
|
||||
};
|
||||
}
|
||||
|
||||
export { downloadTemplate as d, registryProvider as r, startShell as s };
|
||||
Reference in New Issue
Block a user