giget 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -22
- package/dist/cli.cjs +9 -5
- package/dist/cli.mjs +9 -5
- package/dist/index.cjs +4 -2
- package/dist/index.d.ts +12 -12
- package/dist/index.mjs +4 -2
- package/dist/shared/{giget.774476cb.cjs → giget.3522139c.cjs} +35 -13
- package/dist/shared/{giget.1430f5a2.mjs → giget.dd19862e.mjs} +35 -13
- package/package.json +9 -8
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
## Features
|
|
11
11
|
|
|
12
|
-
✔ Support popular git providers (GitHub, GitLab,
|
|
12
|
+
✔ Support popular git providers (GitHub, GitLab, Bitbucket, Sourcehut) out of the box.
|
|
13
13
|
|
|
14
14
|
✔ Built-in and custom [template registry](#template-registry).
|
|
15
15
|
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
|
|
22
22
|
✔ Support extracting with a subdir.
|
|
23
23
|
|
|
24
|
+
✔ Authorization support to download private templates
|
|
25
|
+
|
|
24
26
|
## Usage (CLI)
|
|
25
27
|
|
|
26
28
|
```bash
|
|
@@ -39,13 +41,18 @@ npx giget@latest <template> [<dir>] [...options]
|
|
|
39
41
|
- `--prefer-offline`: Use cache if exists otherwise try to download.
|
|
40
42
|
- `--force-clean`: ⚠️ Remove any existing directory or file recusively before cloning.
|
|
41
43
|
- `--shell`: ⚠️ Open a new shell with current working directory in cloned dir. (Experimental).
|
|
42
|
-
- `--registry`: URL to a custom registry.
|
|
44
|
+
- `--registry`: URL to a custom registry. (Can be overriden with `GIGET_REGISTRY` environment variable).
|
|
43
45
|
- `--no-registry`: Disable registry lookup and functionality.
|
|
44
46
|
- `--verbose`: Show verbose debugging info.
|
|
47
|
+
- `--cwd`: Set current working directory to resolve dirs relative to it.
|
|
48
|
+
- `--auth`: Custom Authorization token to use for downloading template. (Can be overriden with `GIGET_AUTH` environment variable).
|
|
45
49
|
|
|
46
50
|
### Examples
|
|
47
51
|
|
|
48
52
|
```sh
|
|
53
|
+
# Clone nuxt starter from giget template registry
|
|
54
|
+
npx giget@latest nuxt
|
|
55
|
+
|
|
49
56
|
# Clone the main branch of github.com/unjs/template to unjs-template directory
|
|
50
57
|
npx giget@latest gh:unjs/template
|
|
51
58
|
|
|
@@ -64,8 +71,8 @@ npx giget@latest gitlab:unjs/template
|
|
|
64
71
|
# Clone from bitbucket
|
|
65
72
|
npx giget@latest bitbucket:unjs/template
|
|
66
73
|
|
|
67
|
-
# Clone
|
|
68
|
-
npx giget@latest
|
|
74
|
+
# Clone from sourcehut
|
|
75
|
+
npx giget@latest sourcehut:pi0/unjs-template
|
|
69
76
|
```
|
|
70
77
|
|
|
71
78
|
## Template Registry
|
|
@@ -78,11 +85,12 @@ If you want to add your template to the built-in registry, just drop a PR to add
|
|
|
78
85
|
|
|
79
86
|
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).
|
|
80
87
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
88
|
+
- `name`: (required) Name of the template.
|
|
89
|
+
- `tar` (required) Link to the tar download link.
|
|
90
|
+
- `defaultDir`: (optional) Default cloning directory.
|
|
91
|
+
- `url`: (optional) Webpage of the template.
|
|
92
|
+
- `subpath`: (optional) Subpath inside the tar file.
|
|
93
|
+
- `headers`: (optional) Custom headers to send while downloading template.
|
|
86
94
|
|
|
87
95
|
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.
|
|
88
96
|
|
|
@@ -124,7 +132,7 @@ const { source, dir } = await downloadTemplate('github:unjs/template')
|
|
|
124
132
|
- `source`: (string) Input source in format of `[provider]:repo[/subpath][#ref]`.
|
|
125
133
|
- `dir`: (string) Destination directory to clone to. If not provided, `user-name` will be used relative to the current directory.
|
|
126
134
|
- `options`: (object) Options are usually inferred from the input string. You can customize them.
|
|
127
|
-
- `provider`: (string) Either `github`, `gitlab` or `
|
|
135
|
+
- `provider`: (string) Either `github`, `gitlab`, `bitbucket` or `sourcehut`. The default is `github`.
|
|
128
136
|
- `repo`: (string) Name of repository in format of `{username}/{reponame}`.
|
|
129
137
|
- `ref`: (string) Git ref (branch or commit or tag). The default value is `main`.
|
|
130
138
|
- `subdirpath`: (string) subdir of the repo to clone from. The default value is none.
|
|
@@ -133,7 +141,9 @@ const { source, dir } = await downloadTemplate('github:unjs/template')
|
|
|
133
141
|
- `offline`: (boolean) Do not attempt to download and use cached version.
|
|
134
142
|
- `preferOffline`: (boolean) Use cache if exists otherwise try to download.
|
|
135
143
|
- `providers`: (object) A map from provider name to custom providers. Can be used to override built-ins too.
|
|
136
|
-
- `registry`: (string or false) Set to `false` to disable registry. Set to a URL string (without trailing slash) for custom registry.
|
|
144
|
+
- `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).
|
|
145
|
+
- `cwd`: (string) Current working directory to resolve dirs relative to it.
|
|
146
|
+
- `auth`: (string) Custom Authorization token to use for downloading template. (Can be overriden with `GIGET_AUTH` environment variable).
|
|
137
147
|
|
|
138
148
|
**Return value:**
|
|
139
149
|
|
|
@@ -151,10 +161,11 @@ Using programmatic method, you can make your own custom template providers.
|
|
|
151
161
|
```ts
|
|
152
162
|
import type { TemplateProvider } from 'giget'
|
|
153
163
|
|
|
154
|
-
const rainbow: TemplateProvider = async (input) => {
|
|
164
|
+
const rainbow: TemplateProvider = async (input, { auth }) => {
|
|
155
165
|
return {
|
|
156
166
|
name: 'rainbow',
|
|
157
167
|
version: input,
|
|
168
|
+
headers: { Authorization: auth },
|
|
158
169
|
url: `https://rainbow.template/?variant=${input}`,
|
|
159
170
|
tar: `https://rainbow.template/dl/rainbow.${input}.tar.gz`
|
|
160
171
|
}
|
|
@@ -175,19 +186,20 @@ const themes = registryProvider('https://raw.githubusercontent.com/unjs/giget/ma
|
|
|
175
186
|
const { source, dir } = await downloadRepo('themes:test', { providers: { themes } })
|
|
176
187
|
```
|
|
177
188
|
|
|
178
|
-
## 💻 Development
|
|
179
|
-
|
|
180
|
-
- Clone this repository
|
|
181
|
-
- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable` (use `npm i -g corepack` for Node.js < 16.10)
|
|
182
|
-
- Install dependencies using `pnpm install`
|
|
183
|
-
- Run interactive tests using `pnpm dev`
|
|
184
|
-
|
|
185
189
|
## Related projects
|
|
186
190
|
|
|
191
|
+
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.
|
|
192
|
+
|
|
187
193
|
- https://github.com/samsonjs/gitter
|
|
188
194
|
- https://github.com/tiged/tiged
|
|
189
195
|
- https://github.com/Rich-Harris/degit
|
|
190
196
|
|
|
197
|
+
## 💻 Development
|
|
198
|
+
|
|
199
|
+
- Clone this repository
|
|
200
|
+
- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable` (use `npm i -g corepack` for Node.js < 16.10)
|
|
201
|
+
- Install dependencies using `pnpm install`
|
|
202
|
+
- Run interactive tests using `pnpm dev`
|
|
191
203
|
|
|
192
204
|
## License
|
|
193
205
|
|
|
@@ -196,14 +208,12 @@ Made with 💛
|
|
|
196
208
|
Published under [MIT License](./LICENSE).
|
|
197
209
|
|
|
198
210
|
<!-- Badges -->
|
|
211
|
+
|
|
199
212
|
[npm-version-src]: https://img.shields.io/npm/v/giget?style=flat-square
|
|
200
213
|
[npm-version-href]: https://npmjs.com/package/giget
|
|
201
|
-
|
|
202
214
|
[npm-downloads-src]: https://img.shields.io/npm/dm/giget?style=flat-square
|
|
203
215
|
[npm-downloads-href]: https://npmjs.com/package/giget
|
|
204
|
-
|
|
205
216
|
[github-actions-src]: https://img.shields.io/github/workflow/status/unjs/giget/ci/main?style=flat-square
|
|
206
217
|
[github-actions-href]: https://github.com/unjs/giget/actions?query=workflow%3Aci
|
|
207
|
-
|
|
208
218
|
[codecov-src]: https://img.shields.io/codecov/c/gh/unjs/giget/main?style=flat-square
|
|
209
219
|
[codecov-href]: https://codecov.io/gh/unjs/giget
|
package/dist/cli.cjs
CHANGED
|
@@ -4,14 +4,16 @@
|
|
|
4
4
|
const node_path = require('node:path');
|
|
5
5
|
const mri = require('mri');
|
|
6
6
|
const colorette = require('colorette');
|
|
7
|
-
const giget = require('./shared/giget.
|
|
7
|
+
const giget = require('./shared/giget.3522139c.cjs');
|
|
8
8
|
require('node:fs/promises');
|
|
9
9
|
require('node:os');
|
|
10
10
|
require('node:fs');
|
|
11
11
|
require('tar');
|
|
12
12
|
require('pathe');
|
|
13
|
-
require('
|
|
13
|
+
require('defu');
|
|
14
|
+
require('node:stream');
|
|
14
15
|
require('node:child_process');
|
|
16
|
+
require('node:util');
|
|
15
17
|
require('node-fetch-native');
|
|
16
18
|
|
|
17
19
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e["default"] : e; }
|
|
@@ -21,12 +23,12 @@ const mri__default = /*#__PURE__*/_interopDefaultLegacy(mri);
|
|
|
21
23
|
async function main() {
|
|
22
24
|
const args = mri__default(process.argv.slice(2), {
|
|
23
25
|
boolean: ["help", "force", "force-clean", "offline", "prefer-offline", "shell", "verbose"],
|
|
24
|
-
string: ["registry"]
|
|
26
|
+
string: ["registry", "cwd", "auth"]
|
|
25
27
|
});
|
|
26
28
|
const input = args._[0];
|
|
27
29
|
const dir = args._[1];
|
|
28
30
|
if (!input || args.help || args.h) {
|
|
29
|
-
console.error("Usage: npx getgit@latest <input> [<dir>] [--force] [--force-clean] [--offline] [--prefer-offline] [--shell] [--registry] [--no-registry] [--verbose]");
|
|
31
|
+
console.error("Usage: npx getgit@latest <input> [<dir>] [--force] [--force-clean] [--offline] [--prefer-offline] [--shell] [--registry] [--no-registry] [--verbose] [--cwd] [--auth]");
|
|
30
32
|
process.exit(1);
|
|
31
33
|
}
|
|
32
34
|
if (args.verbose) {
|
|
@@ -37,7 +39,9 @@ async function main() {
|
|
|
37
39
|
force: args.force,
|
|
38
40
|
forceClean: args["force-clean"],
|
|
39
41
|
offline: args.offline,
|
|
40
|
-
registry: args.registry
|
|
42
|
+
registry: args.registry,
|
|
43
|
+
cwd: args.cwd,
|
|
44
|
+
auth: args.auth
|
|
41
45
|
});
|
|
42
46
|
console.log(`\u2728 Successfully cloned ${colorette.cyan(r.name || r.url)} to ${colorette.cyan(node_path.relative(process.cwd(), r.dir))}
|
|
43
47
|
`);
|
package/dist/cli.mjs
CHANGED
|
@@ -2,25 +2,27 @@
|
|
|
2
2
|
import { relative } from 'node:path';
|
|
3
3
|
import mri from 'mri';
|
|
4
4
|
import { cyan } from 'colorette';
|
|
5
|
-
import { d as downloadTemplate, s as startShell } from './shared/giget.
|
|
5
|
+
import { d as downloadTemplate, s as startShell } from './shared/giget.dd19862e.mjs';
|
|
6
6
|
import 'node:fs/promises';
|
|
7
7
|
import 'node:os';
|
|
8
8
|
import 'node:fs';
|
|
9
9
|
import 'tar';
|
|
10
10
|
import 'pathe';
|
|
11
|
-
import '
|
|
11
|
+
import 'defu';
|
|
12
|
+
import 'node:stream';
|
|
12
13
|
import 'node:child_process';
|
|
14
|
+
import 'node:util';
|
|
13
15
|
import 'node-fetch-native';
|
|
14
16
|
|
|
15
17
|
async function main() {
|
|
16
18
|
const args = mri(process.argv.slice(2), {
|
|
17
19
|
boolean: ["help", "force", "force-clean", "offline", "prefer-offline", "shell", "verbose"],
|
|
18
|
-
string: ["registry"]
|
|
20
|
+
string: ["registry", "cwd", "auth"]
|
|
19
21
|
});
|
|
20
22
|
const input = args._[0];
|
|
21
23
|
const dir = args._[1];
|
|
22
24
|
if (!input || args.help || args.h) {
|
|
23
|
-
console.error("Usage: npx getgit@latest <input> [<dir>] [--force] [--force-clean] [--offline] [--prefer-offline] [--shell] [--registry] [--no-registry] [--verbose]");
|
|
25
|
+
console.error("Usage: npx getgit@latest <input> [<dir>] [--force] [--force-clean] [--offline] [--prefer-offline] [--shell] [--registry] [--no-registry] [--verbose] [--cwd] [--auth]");
|
|
24
26
|
process.exit(1);
|
|
25
27
|
}
|
|
26
28
|
if (args.verbose) {
|
|
@@ -31,7 +33,9 @@ async function main() {
|
|
|
31
33
|
force: args.force,
|
|
32
34
|
forceClean: args["force-clean"],
|
|
33
35
|
offline: args.offline,
|
|
34
|
-
registry: args.registry
|
|
36
|
+
registry: args.registry,
|
|
37
|
+
cwd: args.cwd,
|
|
38
|
+
auth: args.auth
|
|
35
39
|
});
|
|
36
40
|
console.log(`\u2728 Successfully cloned ${cyan(r.name || r.url)} to ${cyan(relative(process.cwd(), r.dir))}
|
|
37
41
|
`);
|
package/dist/index.cjs
CHANGED
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
const giget = require('./shared/giget.
|
|
5
|
+
const giget = require('./shared/giget.3522139c.cjs');
|
|
6
6
|
require('node:fs/promises');
|
|
7
7
|
require('node:os');
|
|
8
8
|
require('node:fs');
|
|
9
9
|
require('tar');
|
|
10
10
|
require('pathe');
|
|
11
|
-
require('
|
|
11
|
+
require('defu');
|
|
12
|
+
require('node:stream');
|
|
12
13
|
require('node:child_process');
|
|
14
|
+
require('node:util');
|
|
13
15
|
require('node-fetch-native');
|
|
14
16
|
|
|
15
17
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
interface GitInfo {
|
|
2
|
-
provider: 'github' | 'gitlab' | 'bitbucket';
|
|
2
|
+
provider: 'github' | 'gitlab' | 'bitbucket' | 'sourcehut';
|
|
3
3
|
repo: string;
|
|
4
4
|
subdir: string;
|
|
5
5
|
ref: string;
|
|
@@ -11,11 +11,14 @@ interface TemplateInfo {
|
|
|
11
11
|
subdir?: string;
|
|
12
12
|
url?: string;
|
|
13
13
|
defaultDir?: string;
|
|
14
|
+
headers?: Record<string, string>;
|
|
14
15
|
source?: never;
|
|
15
16
|
dir?: never;
|
|
16
17
|
[key: string]: any;
|
|
17
18
|
}
|
|
18
|
-
declare type TemplateProvider = (input: string
|
|
19
|
+
declare type TemplateProvider = (input: string, options: {
|
|
20
|
+
auth?: string;
|
|
21
|
+
}) => TemplateInfo | Promise<TemplateInfo> | null;
|
|
19
22
|
|
|
20
23
|
interface DownloadTemplateOptions {
|
|
21
24
|
provider?: string;
|
|
@@ -26,20 +29,17 @@ interface DownloadTemplateOptions {
|
|
|
26
29
|
providers?: Record<string, TemplateProvider>;
|
|
27
30
|
dir?: string;
|
|
28
31
|
registry?: false | string;
|
|
32
|
+
cwd?: string;
|
|
33
|
+
auth?: string;
|
|
29
34
|
}
|
|
30
|
-
declare
|
|
31
|
-
source: string;
|
|
35
|
+
declare type DownloadTemplateResult = Omit<TemplateInfo, 'dir' | 'source'> & {
|
|
32
36
|
dir: string;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
subdir?: string;
|
|
37
|
-
url?: string;
|
|
38
|
-
defaultDir?: string;
|
|
39
|
-
}>;
|
|
37
|
+
source: string;
|
|
38
|
+
};
|
|
39
|
+
declare function downloadTemplate(input: string, opts?: DownloadTemplateOptions): Promise<DownloadTemplateResult>;
|
|
40
40
|
|
|
41
41
|
declare const registryProvider: (registryEndpoint?: string) => TemplateProvider;
|
|
42
42
|
|
|
43
43
|
declare function startShell(cwd: string): void;
|
|
44
44
|
|
|
45
|
-
export { DownloadTemplateOptions, GitInfo, TemplateInfo, TemplateProvider, downloadTemplate, registryProvider, startShell };
|
|
45
|
+
export { DownloadTemplateOptions, DownloadTemplateResult, GitInfo, TemplateInfo, TemplateProvider, downloadTemplate, registryProvider, startShell };
|
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
export { d as downloadTemplate, r as registryProvider, s as startShell } from './shared/giget.
|
|
1
|
+
export { d as downloadTemplate, r as registryProvider, s as startShell } from './shared/giget.dd19862e.mjs';
|
|
2
2
|
import 'node:fs/promises';
|
|
3
3
|
import 'node:os';
|
|
4
4
|
import 'node:fs';
|
|
5
5
|
import 'tar';
|
|
6
6
|
import 'pathe';
|
|
7
|
-
import '
|
|
7
|
+
import 'defu';
|
|
8
|
+
import 'node:stream';
|
|
8
9
|
import 'node:child_process';
|
|
10
|
+
import 'node:util';
|
|
9
11
|
import 'node-fetch-native';
|
|
@@ -5,29 +5,31 @@ const node_os = require('node:os');
|
|
|
5
5
|
const node_fs = require('node:fs');
|
|
6
6
|
const tar = require('tar');
|
|
7
7
|
const pathe = require('pathe');
|
|
8
|
-
const
|
|
8
|
+
const defu = require('defu');
|
|
9
|
+
const node_stream = require('node:stream');
|
|
9
10
|
const node_child_process = require('node:child_process');
|
|
11
|
+
const node_util = require('node:util');
|
|
10
12
|
const fetch = require('node-fetch-native');
|
|
11
13
|
|
|
12
14
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e["default"] : e; }
|
|
13
15
|
|
|
14
16
|
const fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
|
|
15
17
|
|
|
16
|
-
async function download(url, filePath) {
|
|
18
|
+
async function download(url, filePath, opts = {}) {
|
|
17
19
|
const infoPath = filePath + ".json";
|
|
18
20
|
const info = JSON.parse(await promises.readFile(infoPath, "utf8").catch(() => "{}"));
|
|
19
|
-
const headRes = await fetch.fetch(url, { method: "HEAD" }).catch(() => null);
|
|
21
|
+
const headRes = await fetch.fetch(url, { method: "HEAD", headers: opts.headers }).catch(() => null);
|
|
20
22
|
const etag = headRes?.headers.get("etag");
|
|
21
23
|
if (info.etag === etag && node_fs.existsSync(filePath)) {
|
|
22
24
|
return;
|
|
23
25
|
}
|
|
24
26
|
info.etag = etag;
|
|
25
|
-
const res = await fetch.fetch(url);
|
|
27
|
+
const res = await fetch.fetch(url, { headers: opts.headers });
|
|
26
28
|
if (res.status >= 400) {
|
|
27
29
|
throw new Error(`Failed to download ${url}: ${res.status} ${res.statusText}`);
|
|
28
30
|
}
|
|
29
31
|
const stream = node_fs.createWriteStream(filePath);
|
|
30
|
-
await
|
|
32
|
+
await node_util.promisify(node_stream.pipeline)(res.body, stream);
|
|
31
33
|
await promises.writeFile(infoPath, JSON.stringify(info), "utf8");
|
|
32
34
|
}
|
|
33
35
|
const inputRegex = /^(?<repo>[\w.-]+\/[\w.-]+)(?<subdir>[^#]+)?(?<ref>#[\w.-]+)?/;
|
|
@@ -64,41 +66,56 @@ function startShell(cwd) {
|
|
|
64
66
|
});
|
|
65
67
|
}
|
|
66
68
|
|
|
67
|
-
const github = (input) => {
|
|
69
|
+
const github = (input, opts) => {
|
|
68
70
|
const parsed = parseGitURI(input);
|
|
69
71
|
return {
|
|
70
72
|
name: parsed.repo.replace("/", "-"),
|
|
71
73
|
version: parsed.ref,
|
|
72
74
|
subdir: parsed.subdir,
|
|
75
|
+
headers: { Authorization: opts.auth ? `Bearer ${opts.auth}` : void 0 },
|
|
73
76
|
url: `https://github.com/${parsed.repo}/tree/${parsed.ref}${parsed.subdir}`,
|
|
74
77
|
tar: `https://github.com/${parsed.repo}/archive/${parsed.ref}.tar.gz`
|
|
75
78
|
};
|
|
76
79
|
};
|
|
77
|
-
const gitlab = (input) => {
|
|
80
|
+
const gitlab = (input, opts) => {
|
|
78
81
|
const parsed = parseGitURI(input);
|
|
79
82
|
return {
|
|
80
83
|
name: parsed.repo.replace("/", "-"),
|
|
81
84
|
version: parsed.ref,
|
|
82
85
|
subdir: parsed.subdir,
|
|
86
|
+
headers: { Authorization: opts.auth ? `Bearer ${opts.auth}` : void 0 },
|
|
83
87
|
url: `https://gitlab.com/${parsed.repo}/tree/${parsed.ref}${parsed.subdir}`,
|
|
84
88
|
tar: `https://gitlab.com/${parsed.repo}/-/archive/${parsed.ref}.tar.gz`
|
|
85
89
|
};
|
|
86
90
|
};
|
|
87
|
-
const bitbucket = (input) => {
|
|
91
|
+
const bitbucket = (input, opts) => {
|
|
88
92
|
const parsed = parseGitURI(input);
|
|
89
93
|
return {
|
|
90
94
|
name: parsed.repo.replace("/", "-"),
|
|
91
95
|
version: parsed.ref,
|
|
92
96
|
subdir: parsed.subdir,
|
|
97
|
+
headers: { Authorization: opts.auth ? `Bearer ${opts.auth}` : void 0 },
|
|
93
98
|
url: `https://bitbucket.com/${parsed.repo}/src/${parsed.ref}${parsed.subdir}`,
|
|
94
99
|
tar: `https://bitbucket.org/${parsed.repo}/get/${parsed.ref}.tar.gz`
|
|
95
100
|
};
|
|
96
101
|
};
|
|
102
|
+
const sourcehut = (input, opts) => {
|
|
103
|
+
const parsed = parseGitURI(input);
|
|
104
|
+
return {
|
|
105
|
+
name: parsed.repo.replace("/", "-"),
|
|
106
|
+
version: parsed.ref,
|
|
107
|
+
subdir: parsed.subdir,
|
|
108
|
+
headers: { Authorization: opts.auth ? `Bearer ${opts.auth}` : void 0 },
|
|
109
|
+
url: `https://git.sr.ht/~${parsed.repo}/tree/${parsed.ref}/item${parsed.subdir}`,
|
|
110
|
+
tar: `https://git.sr.ht/~${parsed.repo}/archive/${parsed.ref}.tar.gz`
|
|
111
|
+
};
|
|
112
|
+
};
|
|
97
113
|
const providers = {
|
|
98
114
|
github,
|
|
99
115
|
gh: github,
|
|
100
116
|
gitlab,
|
|
101
|
-
bitbucket
|
|
117
|
+
bitbucket,
|
|
118
|
+
sourcehut
|
|
102
119
|
};
|
|
103
120
|
|
|
104
121
|
const DEFAULT_REGISTRY = "https://raw.githubusercontent.com/unjs/giget/main/templates";
|
|
@@ -121,6 +138,10 @@ const registryProvider = (registryEndpoint = DEFAULT_REGISTRY) => {
|
|
|
121
138
|
|
|
122
139
|
const sourceProtoRe = /^([\w-.]+):/;
|
|
123
140
|
async function downloadTemplate(input, opts = {}) {
|
|
141
|
+
opts = defu.defu({
|
|
142
|
+
registry: process.env.GIGET_REGISTRY,
|
|
143
|
+
auth: process.env.GIGET_AUTH
|
|
144
|
+
}, opts);
|
|
124
145
|
const registry = opts.registry !== false ? registryProvider(opts.registry) : null;
|
|
125
146
|
let providerName = opts.provider || (registryProvider ? "registry" : "github");
|
|
126
147
|
let source = input;
|
|
@@ -133,12 +154,13 @@ async function downloadTemplate(input, opts = {}) {
|
|
|
133
154
|
if (!provider) {
|
|
134
155
|
throw new Error(`Unsupported provider: ${providerName}`);
|
|
135
156
|
}
|
|
136
|
-
const template = await Promise.resolve().then(() => provider(source)).catch((err) => {
|
|
157
|
+
const template = await Promise.resolve().then(() => provider(source, { auth: opts.auth })).catch((err) => {
|
|
137
158
|
throw new Error(`Failed to download template from ${providerName}: ${err.message}`);
|
|
138
159
|
});
|
|
139
160
|
template.name = (template.name || "template").replace(/[^a-z0-9-]/gi, "-");
|
|
140
161
|
template.defaultDir = (template.defaultDir || template.name).replace(/[^a-z0-9-]/gi, "-");
|
|
141
|
-
const
|
|
162
|
+
const cwd = pathe.resolve(opts.cwd || ".");
|
|
163
|
+
const extractPath = pathe.resolve(cwd, opts.dir || template.defaultDir);
|
|
142
164
|
if (opts.forceClean) {
|
|
143
165
|
await promises.rm(extractPath, { recursive: true, force: true });
|
|
144
166
|
}
|
|
@@ -154,7 +176,7 @@ async function downloadTemplate(input, opts = {}) {
|
|
|
154
176
|
if (!opts.offline) {
|
|
155
177
|
await promises.mkdir(pathe.dirname(tarPath), { recursive: true });
|
|
156
178
|
const s2 = Date.now();
|
|
157
|
-
await download(template.tar, tarPath).catch((err) => {
|
|
179
|
+
await download(template.tar, tarPath, { headers: template.headers }).catch((err) => {
|
|
158
180
|
if (!node_fs.existsSync(tarPath)) {
|
|
159
181
|
throw err;
|
|
160
182
|
}
|
|
@@ -174,7 +196,7 @@ async function downloadTemplate(input, opts = {}) {
|
|
|
174
196
|
onentry(entry) {
|
|
175
197
|
entry.path = entry.path.split("/").splice(1).join("/");
|
|
176
198
|
if (subdir) {
|
|
177
|
-
if (entry.path.startsWith(subdir)) {
|
|
199
|
+
if (entry.path.startsWith(subdir + "/")) {
|
|
178
200
|
entry.path = entry.path.substring(subdir.length);
|
|
179
201
|
} else {
|
|
180
202
|
entry.path = "";
|
|
@@ -3,25 +3,27 @@ import { homedir } from 'node:os';
|
|
|
3
3
|
import { existsSync, createWriteStream, readdirSync } from 'node:fs';
|
|
4
4
|
import { extract } from 'tar';
|
|
5
5
|
import { resolve, relative, dirname } from 'pathe';
|
|
6
|
-
import {
|
|
6
|
+
import { defu } from 'defu';
|
|
7
|
+
import { pipeline } from 'node:stream';
|
|
7
8
|
import { spawnSync } from 'node:child_process';
|
|
9
|
+
import { promisify } from 'node:util';
|
|
8
10
|
import fetch$1, { fetch } from 'node-fetch-native';
|
|
9
11
|
|
|
10
|
-
async function download(url, filePath) {
|
|
12
|
+
async function download(url, filePath, opts = {}) {
|
|
11
13
|
const infoPath = filePath + ".json";
|
|
12
14
|
const info = JSON.parse(await readFile(infoPath, "utf8").catch(() => "{}"));
|
|
13
|
-
const headRes = await fetch(url, { method: "HEAD" }).catch(() => null);
|
|
15
|
+
const headRes = await fetch(url, { method: "HEAD", headers: opts.headers }).catch(() => null);
|
|
14
16
|
const etag = headRes?.headers.get("etag");
|
|
15
17
|
if (info.etag === etag && existsSync(filePath)) {
|
|
16
18
|
return;
|
|
17
19
|
}
|
|
18
20
|
info.etag = etag;
|
|
19
|
-
const res = await fetch(url);
|
|
21
|
+
const res = await fetch(url, { headers: opts.headers });
|
|
20
22
|
if (res.status >= 400) {
|
|
21
23
|
throw new Error(`Failed to download ${url}: ${res.status} ${res.statusText}`);
|
|
22
24
|
}
|
|
23
25
|
const stream = createWriteStream(filePath);
|
|
24
|
-
await pipeline(res.body, stream);
|
|
26
|
+
await promisify(pipeline)(res.body, stream);
|
|
25
27
|
await writeFile(infoPath, JSON.stringify(info), "utf8");
|
|
26
28
|
}
|
|
27
29
|
const inputRegex = /^(?<repo>[\w.-]+\/[\w.-]+)(?<subdir>[^#]+)?(?<ref>#[\w.-]+)?/;
|
|
@@ -58,41 +60,56 @@ function startShell(cwd) {
|
|
|
58
60
|
});
|
|
59
61
|
}
|
|
60
62
|
|
|
61
|
-
const github = (input) => {
|
|
63
|
+
const github = (input, opts) => {
|
|
62
64
|
const parsed = parseGitURI(input);
|
|
63
65
|
return {
|
|
64
66
|
name: parsed.repo.replace("/", "-"),
|
|
65
67
|
version: parsed.ref,
|
|
66
68
|
subdir: parsed.subdir,
|
|
69
|
+
headers: { Authorization: opts.auth ? `Bearer ${opts.auth}` : void 0 },
|
|
67
70
|
url: `https://github.com/${parsed.repo}/tree/${parsed.ref}${parsed.subdir}`,
|
|
68
71
|
tar: `https://github.com/${parsed.repo}/archive/${parsed.ref}.tar.gz`
|
|
69
72
|
};
|
|
70
73
|
};
|
|
71
|
-
const gitlab = (input) => {
|
|
74
|
+
const gitlab = (input, opts) => {
|
|
72
75
|
const parsed = parseGitURI(input);
|
|
73
76
|
return {
|
|
74
77
|
name: parsed.repo.replace("/", "-"),
|
|
75
78
|
version: parsed.ref,
|
|
76
79
|
subdir: parsed.subdir,
|
|
80
|
+
headers: { Authorization: opts.auth ? `Bearer ${opts.auth}` : void 0 },
|
|
77
81
|
url: `https://gitlab.com/${parsed.repo}/tree/${parsed.ref}${parsed.subdir}`,
|
|
78
82
|
tar: `https://gitlab.com/${parsed.repo}/-/archive/${parsed.ref}.tar.gz`
|
|
79
83
|
};
|
|
80
84
|
};
|
|
81
|
-
const bitbucket = (input) => {
|
|
85
|
+
const bitbucket = (input, opts) => {
|
|
82
86
|
const parsed = parseGitURI(input);
|
|
83
87
|
return {
|
|
84
88
|
name: parsed.repo.replace("/", "-"),
|
|
85
89
|
version: parsed.ref,
|
|
86
90
|
subdir: parsed.subdir,
|
|
91
|
+
headers: { Authorization: opts.auth ? `Bearer ${opts.auth}` : void 0 },
|
|
87
92
|
url: `https://bitbucket.com/${parsed.repo}/src/${parsed.ref}${parsed.subdir}`,
|
|
88
93
|
tar: `https://bitbucket.org/${parsed.repo}/get/${parsed.ref}.tar.gz`
|
|
89
94
|
};
|
|
90
95
|
};
|
|
96
|
+
const sourcehut = (input, opts) => {
|
|
97
|
+
const parsed = parseGitURI(input);
|
|
98
|
+
return {
|
|
99
|
+
name: parsed.repo.replace("/", "-"),
|
|
100
|
+
version: parsed.ref,
|
|
101
|
+
subdir: parsed.subdir,
|
|
102
|
+
headers: { Authorization: opts.auth ? `Bearer ${opts.auth}` : void 0 },
|
|
103
|
+
url: `https://git.sr.ht/~${parsed.repo}/tree/${parsed.ref}/item${parsed.subdir}`,
|
|
104
|
+
tar: `https://git.sr.ht/~${parsed.repo}/archive/${parsed.ref}.tar.gz`
|
|
105
|
+
};
|
|
106
|
+
};
|
|
91
107
|
const providers = {
|
|
92
108
|
github,
|
|
93
109
|
gh: github,
|
|
94
110
|
gitlab,
|
|
95
|
-
bitbucket
|
|
111
|
+
bitbucket,
|
|
112
|
+
sourcehut
|
|
96
113
|
};
|
|
97
114
|
|
|
98
115
|
const DEFAULT_REGISTRY = "https://raw.githubusercontent.com/unjs/giget/main/templates";
|
|
@@ -115,6 +132,10 @@ const registryProvider = (registryEndpoint = DEFAULT_REGISTRY) => {
|
|
|
115
132
|
|
|
116
133
|
const sourceProtoRe = /^([\w-.]+):/;
|
|
117
134
|
async function downloadTemplate(input, opts = {}) {
|
|
135
|
+
opts = defu({
|
|
136
|
+
registry: process.env.GIGET_REGISTRY,
|
|
137
|
+
auth: process.env.GIGET_AUTH
|
|
138
|
+
}, opts);
|
|
118
139
|
const registry = opts.registry !== false ? registryProvider(opts.registry) : null;
|
|
119
140
|
let providerName = opts.provider || (registryProvider ? "registry" : "github");
|
|
120
141
|
let source = input;
|
|
@@ -127,12 +148,13 @@ async function downloadTemplate(input, opts = {}) {
|
|
|
127
148
|
if (!provider) {
|
|
128
149
|
throw new Error(`Unsupported provider: ${providerName}`);
|
|
129
150
|
}
|
|
130
|
-
const template = await Promise.resolve().then(() => provider(source)).catch((err) => {
|
|
151
|
+
const template = await Promise.resolve().then(() => provider(source, { auth: opts.auth })).catch((err) => {
|
|
131
152
|
throw new Error(`Failed to download template from ${providerName}: ${err.message}`);
|
|
132
153
|
});
|
|
133
154
|
template.name = (template.name || "template").replace(/[^a-z0-9-]/gi, "-");
|
|
134
155
|
template.defaultDir = (template.defaultDir || template.name).replace(/[^a-z0-9-]/gi, "-");
|
|
135
|
-
const
|
|
156
|
+
const cwd = resolve(opts.cwd || ".");
|
|
157
|
+
const extractPath = resolve(cwd, opts.dir || template.defaultDir);
|
|
136
158
|
if (opts.forceClean) {
|
|
137
159
|
await rm(extractPath, { recursive: true, force: true });
|
|
138
160
|
}
|
|
@@ -148,7 +170,7 @@ async function downloadTemplate(input, opts = {}) {
|
|
|
148
170
|
if (!opts.offline) {
|
|
149
171
|
await mkdir(dirname(tarPath), { recursive: true });
|
|
150
172
|
const s2 = Date.now();
|
|
151
|
-
await download(template.tar, tarPath).catch((err) => {
|
|
173
|
+
await download(template.tar, tarPath, { headers: template.headers }).catch((err) => {
|
|
152
174
|
if (!existsSync(tarPath)) {
|
|
153
175
|
throw err;
|
|
154
176
|
}
|
|
@@ -168,7 +190,7 @@ async function downloadTemplate(input, opts = {}) {
|
|
|
168
190
|
onentry(entry) {
|
|
169
191
|
entry.path = entry.path.split("/").splice(1).join("/");
|
|
170
192
|
if (subdir) {
|
|
171
|
-
if (entry.path.startsWith(subdir)) {
|
|
193
|
+
if (entry.path.startsWith(subdir + "/")) {
|
|
172
194
|
entry.path = entry.path.substring(subdir.length);
|
|
173
195
|
} else {
|
|
174
196
|
entry.path = "";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "giget",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Download templates and git repositories with pleasure!",
|
|
5
5
|
"repository": "unjs/giget",
|
|
6
6
|
"license": "MIT",
|
|
@@ -23,24 +23,25 @@
|
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"colorette": "^2.0.19",
|
|
26
|
+
"defu": "^6.1.0",
|
|
26
27
|
"mri": "^1.2.0",
|
|
27
28
|
"node-fetch-native": "^0.1.4",
|
|
28
|
-
"pathe": "^0.3.
|
|
29
|
+
"pathe": "^0.3.8",
|
|
29
30
|
"tar": "^6.1.11"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
32
33
|
"@nuxtjs/eslint-config-typescript": "^11.0.0",
|
|
33
34
|
"@types/node": "^18.7.16",
|
|
34
35
|
"@types/tar": "^6.1.2",
|
|
35
|
-
"@vitest/coverage-c8": "^0.23.
|
|
36
|
-
"eslint": "^8.23.
|
|
37
|
-
"jiti": "^1.
|
|
36
|
+
"@vitest/coverage-c8": "^0.23.4",
|
|
37
|
+
"eslint": "^8.23.1",
|
|
38
|
+
"jiti": "^1.16.0",
|
|
38
39
|
"standard-version": "^9.5.0",
|
|
39
40
|
"typescript": "^4.8.3",
|
|
40
|
-
"unbuild": "^0.8.
|
|
41
|
-
"vitest": "^0.23.
|
|
41
|
+
"unbuild": "^0.8.11",
|
|
42
|
+
"vitest": "^0.23.4"
|
|
42
43
|
},
|
|
43
|
-
"packageManager": "pnpm@7.
|
|
44
|
+
"packageManager": "pnpm@7.12.0",
|
|
44
45
|
"scripts": {
|
|
45
46
|
"build": "unbuild",
|
|
46
47
|
"dev": "vitest dev",
|