initial commit
This commit is contained in:
21
node_modules/giget/LICENSE
generated
vendored
Normal file
21
node_modules/giget/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Pooya Parsa <pooya@pi0.io>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
219
node_modules/giget/README.md
generated
vendored
Normal file
219
node_modules/giget/README.md
generated
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
# ✨ giget
|
||||
|
||||
[![npm version][npm-version-src]][npm-version-href]
|
||||
[![npm downloads][npm-downloads-src]][npm-downloads-href]
|
||||
[![Github Actions][github-actions-src]][github-actions-href]
|
||||
[![Codecov][codecov-src]][codecov-href]
|
||||
|
||||
> Download templates and git repositories with pleasure!
|
||||
|
||||
## Features
|
||||
|
||||
✔ Support popular git providers (GitHub, GitLab, Bitbucket, Sourcehut) out of the box.
|
||||
|
||||
✔ Built-in and custom [template registry](#template-registry).
|
||||
|
||||
✔ Fast cloning using tarball gzip without depending on local `git` and `tar`.
|
||||
|
||||
✔ Works online and offline with disk cache support.
|
||||
|
||||
✔ Custom template provider support with programmatic usage.
|
||||
|
||||
✔ Support extracting with a subdir.
|
||||
|
||||
✔ Authorization support to download private templates
|
||||
|
||||
## Usage (CLI)
|
||||
|
||||
```bash
|
||||
npx giget@latest <template> [<dir>] [...options]
|
||||
```
|
||||
|
||||
### Arguments
|
||||
|
||||
- **template**: Template name or a a URI describing provider, repository, subdir, and branch/ref. (See [Examples](#examples))
|
||||
- **dir**: A relative or absolute path where to extract the template.
|
||||
|
||||
### Options
|
||||
|
||||
- `--force`: Clone to exsiting directory even if exists.
|
||||
- `--offline`: Do not attempt to download and use cached version.
|
||||
- `--prefer-offline`: Use cache if exists otherwise try to download.
|
||||
- `--force-clean`: ⚠️ Remove any existing directory or file recusively before cloning.
|
||||
- `--shell`: ⚠️ Open a new shell with current working directory in cloned dir. (Experimental).
|
||||
- `--registry`: URL to a custom registry. (Can be overriden with `GIGET_REGISTRY` environment variable).
|
||||
- `--no-registry`: Disable registry lookup and functionality.
|
||||
- `--verbose`: Show verbose debugging info.
|
||||
- `--cwd`: Set current working directory to resolve dirs relative to it.
|
||||
- `--auth`: Custom Authorization token to use for downloading template. (Can be overriden with `GIGET_AUTH` environment variable).
|
||||
|
||||
### Examples
|
||||
|
||||
```sh
|
||||
# Clone nuxt starter from giget template registry
|
||||
npx giget@latest nuxt
|
||||
|
||||
# Clone the main branch of github.com/unjs/template to unjs-template directory
|
||||
npx giget@latest gh:unjs/template
|
||||
|
||||
# Clone to myProject directory
|
||||
npx giget@latest gh:unjs/template myProject
|
||||
|
||||
# Clone dev branch
|
||||
npx giget@latest gh:unjs/template#dev
|
||||
|
||||
# Clone /test directory from main branch
|
||||
npx giget@latest gh:unjs/template/test
|
||||
|
||||
# Clone from gitlab
|
||||
npx giget@latest gitlab:unjs/template
|
||||
|
||||
# Clone from bitbucket
|
||||
npx giget@latest bitbucket:unjs/template
|
||||
|
||||
# Clone from sourcehut
|
||||
npx giget@latest sourcehut:pi0/unjs-template
|
||||
```
|
||||
|
||||
## Template Registry
|
||||
|
||||
Giget has a built-in HTTP registry system for resolving templates. This way you can support template name shortcuts and meta-data. Default registry is served from [unjs/giget/templates](./templates/).
|
||||
|
||||
If you want to add your template to the built-in registry, just drop a PR to add it to the [./templates](./templates) directory. Slugs are added on first-come first-served basis but this might change in the future.
|
||||
|
||||
### Custom Registry
|
||||
|
||||
A custom registry should provide an endpoint with dynamic path `/:template.json` that returns a JSON response with keys same as [custom providers](#custom-providers).
|
||||
|
||||
- `name`: (required) Name of the template.
|
||||
- `tar` (required) Link to the tar download link.
|
||||
- `defaultDir`: (optional) Default cloning directory.
|
||||
- `url`: (optional) Webpage of the template.
|
||||
- `subdir`: (optional) Directory inside the tar file.
|
||||
- `headers`: (optional) Custom headers to send while downloading template.
|
||||
|
||||
Because of the simplicity, you can even use a github repository as template registry but also you can build something more powerful by bringing your own API.
|
||||
|
||||
## Usage (Programmatic)
|
||||
|
||||
Install package:
|
||||
|
||||
```sh
|
||||
# npm
|
||||
npm install giget
|
||||
|
||||
# yarn
|
||||
yarn install giget
|
||||
|
||||
# pnpm
|
||||
pnpm install giget
|
||||
```
|
||||
|
||||
Import:
|
||||
|
||||
```js
|
||||
// ESM
|
||||
import { downloadTemplate } from 'giget'
|
||||
|
||||
// CommonJS
|
||||
const { downloadTemplate } = require('giget')
|
||||
```
|
||||
|
||||
### `downloadTemplate(source, options?)`
|
||||
|
||||
**Example:**
|
||||
|
||||
```js
|
||||
const { source, dir } = await downloadTemplate('github:unjs/template')
|
||||
```
|
||||
|
||||
**Options:**
|
||||
|
||||
- `source`: (string) Input source in format of `[provider]:repo[/subpath][#ref]`.
|
||||
- `dir`: (string) Destination directory to clone to. If not provided, `user-name` will be used relative to the current directory.
|
||||
- `options`: (object) Options are usually inferred from the input string. You can customize them.
|
||||
- `provider`: (string) Either `github`, `gitlab`, `bitbucket` or `sourcehut`. The default is `github`.
|
||||
- `repo`: (string) Name of repository in format of `{username}/{reponame}`.
|
||||
- `ref`: (string) Git ref (branch or commit or tag). The default value is `main`.
|
||||
- `subdir`: (string) Directory of the repo to clone from. The default value is none.
|
||||
- `force`: (boolean) Extract to the exisiting dir even if already exsists.
|
||||
- `forceClean`: (boolean) ⚠️ Clean ups any existing directory or file before cloning.
|
||||
- `offline`: (boolean) Do not attempt to download and use cached version.
|
||||
- `preferOffline`: (boolean) Use cache if exists otherwise try to download.
|
||||
- `providers`: (object) A map from provider name to custom providers. Can be used to override built-ins too.
|
||||
- `registry`: (string or false) Set to `false` to disable registry. Set to a URL string (without trailing slash) for custom registry. (Can be overriden with `GIGET_REGISTRY` environment variable).
|
||||
- `cwd`: (string) Current working directory to resolve dirs relative to it.
|
||||
- `auth`: (string) Custom Authorization token to use for downloading template. (Can be overriden with `GIGET_AUTH` environment variable).
|
||||
|
||||
**Return value:**
|
||||
|
||||
The return value is a promise that resolves to the resolved template.
|
||||
|
||||
- `dir`: (string) Path to extracted dir.
|
||||
- `source`: (string) Normalized version of the input source without provider.
|
||||
- [other provider template keys]
|
||||
- `url`: (string) URL of repostiroy that can be opened in browser. Useful for logging.
|
||||
|
||||
## Custom Providers
|
||||
|
||||
Using programmatic method, you can make your own custom template providers.
|
||||
|
||||
```ts
|
||||
import type { TemplateProvider } from 'giget'
|
||||
|
||||
const rainbow: TemplateProvider = async (input, { auth }) => {
|
||||
return {
|
||||
name: 'rainbow',
|
||||
version: input,
|
||||
headers: { Authorization: auth },
|
||||
url: `https://rainbow.template/?variant=${input}`,
|
||||
tar: `https://rainbow.template/dl/rainbow.${input}.tar.gz`
|
||||
}
|
||||
}
|
||||
|
||||
const { source, dir } = await downloadRepo('rainbow:one', { providers: { rainbow } })
|
||||
```
|
||||
|
||||
### Custom Registry Providers
|
||||
|
||||
You can define additional [custom registry](#custom-registry) providers using `registryProvider` utility and register to `providers`.
|
||||
|
||||
```ts
|
||||
import { registryProvider } from 'giget'
|
||||
|
||||
const themes = registryProvider('https://raw.githubusercontent.com/unjs/giget/main/templates')
|
||||
|
||||
const { source, dir } = await downloadRepo('themes:test', { providers: { themes } })
|
||||
```
|
||||
|
||||
## Related projects
|
||||
|
||||
Giget wouldn't be possible without inspering from former projects. In comparation giget does not depend on any local command which increases stability and performance, supports custom template providers, auth and many more features out of the box.
|
||||
|
||||
- https://github.com/samsonjs/gitter
|
||||
- https://github.com/tiged/tiged
|
||||
- https://github.com/Rich-Harris/degit
|
||||
|
||||
## 💻 Development
|
||||
|
||||
- Clone this repository
|
||||
- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable` (use `npm i -g corepack` for Node.js < 16.10)
|
||||
- Install dependencies using `pnpm install`
|
||||
- Run interactive tests using `pnpm dev`
|
||||
|
||||
## License
|
||||
|
||||
Made with 💛
|
||||
|
||||
Published under [MIT License](./LICENSE).
|
||||
|
||||
<!-- Badges -->
|
||||
|
||||
[npm-version-src]: https://img.shields.io/npm/v/giget?style=flat-square
|
||||
[npm-version-href]: https://npmjs.com/package/giget
|
||||
[npm-downloads-src]: https://img.shields.io/npm/dm/giget?style=flat-square
|
||||
[npm-downloads-href]: https://npmjs.com/package/giget
|
||||
[github-actions-src]: https://img.shields.io/github/workflow/status/unjs/giget/ci/main?style=flat-square
|
||||
[github-actions-href]: https://github.com/unjs/giget/actions?query=workflow%3Aci
|
||||
[codecov-src]: https://img.shields.io/codecov/c/gh/unjs/giget/main?style=flat-square
|
||||
[codecov-href]: https://codecov.io/gh/unjs/giget
|
||||
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 };
|
||||
57
node_modules/giget/package.json
generated
vendored
Normal file
57
node_modules/giget/package.json
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"name": "giget",
|
||||
"version": "1.0.0",
|
||||
"description": "Download templates and git repositories with pleasure!",
|
||||
"repository": "unjs/giget",
|
||||
"license": "MIT",
|
||||
"sideEffects": false,
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"giget": "./dist/cli.mjs"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"require": "./dist/index.cjs"
|
||||
}
|
||||
},
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "unbuild",
|
||||
"dev": "vitest dev",
|
||||
"giget": "jiti ./src/cli.ts",
|
||||
"lint": "eslint --ext .ts,.js,.mjs,.cjs .",
|
||||
"prepack": "unbuild",
|
||||
"play": "pnpm giget --force-clean --verbose unjs .tmp/clone",
|
||||
"release": "pnpm test && standard-version && git push --follow-tags && pnpm publish",
|
||||
"test": "pnpm lint && vitest run --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"colorette": "^2.0.19",
|
||||
"defu": "^6.1.1",
|
||||
"https-proxy-agent": "^5.0.1",
|
||||
"mri": "^1.2.0",
|
||||
"node-fetch-native": "^1.0.1",
|
||||
"pathe": "^1.0.0",
|
||||
"tar": "^6.1.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.11.9",
|
||||
"@types/tar": "^6.1.3",
|
||||
"@vitest/coverage-c8": "^0.25.2",
|
||||
"eslint": "^8.27.0",
|
||||
"eslint-config-unjs": "^0.0.2",
|
||||
"jiti": "^1.16.0",
|
||||
"standard-version": "^9.5.0",
|
||||
"typescript": "^4.8.4",
|
||||
"unbuild": "^0.9.4",
|
||||
"vitest": "^0.25.2"
|
||||
},
|
||||
"packageManager": "pnpm@7.16.0"
|
||||
}
|
||||
Reference in New Issue
Block a user