gitpick 4.20.0-canary.0 ā 4.20.0-canary.10
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 +77 -2
- package/dist/index.mjs +13 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,13 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
**Clone exactly what you need aka straightforward project scaffolding!**
|
|
6
6
|
|
|
7
|
-
š¦ `Zero dependencies` / `Un/packed (~25/10kb)` / `Faster and more features` yet drop-in replacement for `degit`
|
|
8
|
-
|
|
9
7
|
[](https://twitter.com/nrjdalal_dev)
|
|
10
8
|
[](https://www.npmjs.com/package/gitpick)
|
|
11
9
|
[](https://www.npmjs.com/package/gitpick)
|
|
12
10
|
[](https://github.com/nrjdalal/gitpick)
|
|
13
11
|
|
|
12
|
+
**Now with Interactive Mode.** Browse any repo right in your terminal. See every file, pick what you want, skip what you don't. Just `gitpick owner/repo -i` and you're in. No more guessing paths.
|
|
13
|
+
|
|
14
|
+
š¦ `Zero dependencies` / `Un/packed (~37/14kb)` / `Faster and more features` yet drop-in replacement for `degit`
|
|
15
|
+
|
|
14
16
|
> #### Just `copy-and-paste` any GitHub, GitLab or Bitbucket URL - no editing required (shorthands work too) - to clone individual files, folders, branches, commits, raw content or even entire repositories without the `.git` directory.
|
|
15
17
|
|
|
16
18
|
Unlike other tools that force you to tweak URLs or follow strict formats to clone files, folders, branches or commits GitPick works seamlessly with any URL.
|
|
@@ -19,11 +21,30 @@ Unlike other tools that force you to tweak URLs or follow strict formats to clon
|
|
|
19
21
|
|
|
20
22
|
---
|
|
21
23
|
|
|
24
|
+
### Table of Contents
|
|
25
|
+
|
|
26
|
+
- [Some Examples](#-some-examples)
|
|
27
|
+
- [Features](#-features)
|
|
28
|
+
- [Quick Usage](#-quick-usage)
|
|
29
|
+
- [Options](#-options)
|
|
30
|
+
- [Interactive Mode](#-interactive-mode)
|
|
31
|
+
- [Private Repos](#-private-repos)
|
|
32
|
+
- [Config File](#-config-file)
|
|
33
|
+
- [Install Globally](#-install-globally-optional)
|
|
34
|
+
- [Used By](#-used-by)
|
|
35
|
+
- [Related Projects](#-related-projects)
|
|
36
|
+
- [Contributing](#-contributing)
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
22
40
|
## š Some Examples
|
|
23
41
|
|
|
24
42
|
### See [Quick Usage](#-quick-usage) for to learn more.
|
|
25
43
|
|
|
26
44
|
```sh
|
|
45
|
+
# interactive mode - browse and pick files/folders
|
|
46
|
+
npx gitpick owner/repo -i
|
|
47
|
+
npx gitpick https://github.com/owner/repo -i
|
|
27
48
|
# clone a repo without .git
|
|
28
49
|
npx gitpick owner/repo
|
|
29
50
|
npx gitpick https://github.com/owner/repo
|
|
@@ -54,6 +75,7 @@ npx gitpick https://bitbucket.org/owner/repo
|
|
|
54
75
|
npx gitpick https://bitbucket.org/owner/repo/src/main/path/to/folder
|
|
55
76
|
# dry run (preview without cloning)
|
|
56
77
|
npx gitpick owner/repo --dry-run
|
|
78
|
+
npx gitpick owner/repo -i --dry-run
|
|
57
79
|
```
|
|
58
80
|
|
|
59
81
|
---
|
|
@@ -63,6 +85,7 @@ npx gitpick owner/repo --dry-run
|
|
|
63
85
|
- š Clone individual files or folders from GitHub, GitLab and Bitbucket
|
|
64
86
|
- š§ Use shorthands `TanStack/router` or full URL's `https://github.com/TanStack/router`
|
|
65
87
|
- āļø Auto-detects branches and target directory (if not specified) like `git clone`
|
|
88
|
+
- **š„ Interactive mode** - browse and cherry-pick files/folders with `-i` | `--interactive`
|
|
66
89
|
- š Seamlessly works with both public and private repositories using a PAT
|
|
67
90
|
- š¦ Can easily clone all submodules with `-r` | `--recursive`
|
|
68
91
|
- š Preview what would be cloned with `--dry-run` before cloning
|
|
@@ -109,6 +132,7 @@ npx gitpick https://bitbucket.org/owner/repo # Bitbucket
|
|
|
109
132
|
|
|
110
133
|
```
|
|
111
134
|
-b, --branch Branch/SHA to clone
|
|
135
|
+
-i, --interactive Browse and pick files/folders interactively
|
|
112
136
|
-n, --dry-run Show what would be cloned without cloning
|
|
113
137
|
-o, --overwrite Skip overwrite prompt
|
|
114
138
|
-r, --recursive Clone submodules
|
|
@@ -123,6 +147,57 @@ npx gitpick https://bitbucket.org/owner/repo # Bitbucket
|
|
|
123
147
|
|
|
124
148
|
---
|
|
125
149
|
|
|
150
|
+
## š„ Interactive Mode
|
|
151
|
+
|
|
152
|
+
> **New in v5.0.** Browse any repository's file tree in your terminal and cherry-pick exactly the files and folders you want.
|
|
153
|
+
|
|
154
|
+
```sh
|
|
155
|
+
npx gitpick owner/repo -i
|
|
156
|
+
npx gitpick owner/repo -i -b canary
|
|
157
|
+
npx gitpick https://github.com/owner/repo -i
|
|
158
|
+
npx gitpick https://gitlab.com/owner/repo -i
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**How it works:**
|
|
162
|
+
|
|
163
|
+
1. GitPick fetches the repository
|
|
164
|
+
2. An interactive file tree appears in your terminal
|
|
165
|
+
3. Navigate with arrow keys, select with space, expand/collapse folders with enter
|
|
166
|
+
4. Press `c` to confirm - only your selected files get copied
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
nrjdalal/gitpick repository:main > gitpick
|
|
170
|
+
|
|
171
|
+
> ā .
|
|
172
|
+
ā āāā ā¾ bin/
|
|
173
|
+
ā ā āāā āø external/
|
|
174
|
+
ā ā āāā āø utils/
|
|
175
|
+
ā ā āāā index.ts
|
|
176
|
+
ā āāā āø tests/
|
|
177
|
+
ā āāā package.json
|
|
178
|
+
ā āāā README.md
|
|
179
|
+
|
|
180
|
+
2 folders 3 files ⢠12.4 KB
|
|
181
|
+
|
|
182
|
+
āā:navigate enter:expand space:select c:confirm q:quit
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Controls:**
|
|
186
|
+
|
|
187
|
+
| Key | Action |
|
|
188
|
+
| ----------------- | -------------------------- |
|
|
189
|
+
| `ā` `ā` / `j` `k` | Navigate up/down |
|
|
190
|
+
| `ā` `ā` / `h` `l` | Collapse/expand folder |
|
|
191
|
+
| `Enter` | Toggle expand/collapse |
|
|
192
|
+
| `Space` | Toggle selection |
|
|
193
|
+
| `.` (first row) | Select/deselect all |
|
|
194
|
+
| `c` | Confirm and clone selected |
|
|
195
|
+
| `q` / `Ctrl+C` | Quit without cloning |
|
|
196
|
+
|
|
197
|
+
Works with GitHub, GitLab, Bitbucket, public and private repos.
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
126
201
|
## š Private Repos
|
|
127
202
|
|
|
128
203
|
Use a personal access token with read-only contents permission. Works with GitHub, GitLab and Bitbucket:
|
package/dist/index.mjs
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import e from"node:fs";import t from"node:os";import n from"node:path";import{parseArgs as r,stripVTControlCharacters as i}from"node:util";import{spawn as a}from"node:child_process";import{once as o}from"node:events";import s from"node:fs/promises";import c from"node:process";import{fileURLToPath as l}from"node:url";import u from"node:tty";import d from"node:https";var f=class extends Error{constructor(...e){super(...e),this.name=`SubprocessError`,this.stdout=``,this.stderr=``}};const p=[`.exe`,`.com`],m={},h=e=>(...t)=>m[t.join(`\0`)]??=e(...t),g=h(async(...e)=>{try{return await s.access(e[0]),!0}catch{return!1}}),_=h(async(e,t,r)=>{let i=r.split(n.delimiter).filter(Boolean).map(e=>e.replace(/^"(.*)"$/,`$1`));try{await Promise.any([t,...i].flatMap(t=>p.map(r=>g(`${n.resolve(t,e)}${r}`))))}catch{return!1}return!0}),v=async(e,t)=>c.platform===`win32`&&!t.shell&&!p.some(t=>e.toLowerCase().endsWith(t))&&!await _(e,t.cwd??`.`,(c.env.PATH||c.env.Path)??``),y=e=>e.replaceAll(/([()\][%!^"`<>&|;, *?])/g,`^$1`),b=e=>y(y(`"${e.replaceAll(/(\\*)"/g,`$1$1\\"`).replace(/(\\*)$/,`$1$1`)}"`)),x=e=>/[^\w./-]/.test(e)?`'${e.replaceAll(`'`,`'\\''`)}'`:e;async function S(e,t=[],r={}){let{stdin:s,stdout:u,stderr:d,stdio:p,cwd:m=`.`,env:h,...g}=r,_=m instanceof URL?l(m):n.resolve(m),S=h?{...c.env,...h}:void 0,C=p??[s,u,d],w=[e,...t].map(e=>x(i(e))).join(` `);[`node`,`node.exe`].includes(e.toLowerCase())&&(e=c.execPath,t=[...c.execArgv.filter(e=>!e.startsWith(`--inspect`)),...t]);let T={...g,stdio:C,env:S,cwd:_};await v(e,T)&&(t=t.map(e=>b(e)),e=y(e),T={...T,shell:!0}),T.shell&&t.length>0&&(e=[e,...t].join(` `),t=[]);let E=a(e,t,T),D=``,O=``;E.stdout&&(E.stdout.setEncoding(`utf8`),E.stdout.on(`data`,e=>D+=e)),E.stderr&&(E.stderr.setEncoding(`utf8`),E.stderr.on(`data`,e=>O+=e)),E.once(`error`,()=>{});try{await o(E,`spawn`)}catch(e){throw Object.assign(new f(`Command failed: ${w}`,{cause:e}),{stdout:D,stderr:O})}await o(E,`close`);let k=e=>e.at(-1)===`
|
|
3
|
-
`?e.slice(0,e.at(-2)===`\r`?-2:-1):e;if(E.exitCode&&E.exitCode>0)throw Object.assign(new f(`Command failed with exit code ${E.exitCode}: ${w}`),{stdout:k(D),stderr:k(O),exitCode:E.exitCode});if(E.signalCode)throw Object.assign(new f(`Command was terminated with ${E.signalCode}: ${w}`),{stdout:k(D),stderr:k(O)});return{stdout:k(D),stderr:k(O)}}const C=u?.WriteStream?.prototype?.hasColors?.()??!1,w=(e,t)=>{if(!C)return e=>e;let n=`\u001B[${e}m`,r=`\u001B[${t}m`;return e=>{let i=e+``,a=i.indexOf(r);if(a===-1)return n+i+r;let o=n,s=0,c=(t===22?r:``)+n;for(;a!==-1;)o+=i.slice(s,a)+c,s=a+r.length,a=i.indexOf(r,s);return o+=i.slice(s)+r,o}},T=w(1,22),E=w(2,22),D=w(31,39),O=w(32,39),k=w(33,39),A=w(36,39),
|
|
4
|
-
`),r=0;for(let e of n)r+=Math.max(1,Math.ceil(e.length/t));return r},m=()=>{if(!o)return;let e=Date.now();(t===-1||e-l>=80)&&(t=++t%
|
|
5
|
-
`;for(let e=0;e<u.length;e++){let t=u[e],r=o+e+1===a,i=t.node.selected?O(
|
|
3
|
+
`?e.slice(0,e.at(-2)===`\r`?-2:-1):e;if(E.exitCode&&E.exitCode>0)throw Object.assign(new f(`Command failed with exit code ${E.exitCode}: ${w}`),{stdout:k(D),stderr:k(O),exitCode:E.exitCode});if(E.signalCode)throw Object.assign(new f(`Command was terminated with ${E.signalCode}: ${w}`),{stdout:k(D),stderr:k(O)});return{stdout:k(D),stderr:k(O)}}const C=u?.WriteStream?.prototype?.hasColors?.()??!1,w=(e,t)=>{if(!C)return e=>e;let n=`\u001B[${e}m`,r=`\u001B[${t}m`;return e=>{let i=e+``,a=i.indexOf(r);if(a===-1)return n+i+r;let o=n,s=0,c=(t===22?r:``)+n;for(;a!==-1;)o+=i.slice(s,a)+c,s=a+r.length,a=i.indexOf(r,s);return o+=i.slice(s)+r,o}},T=w(1,22),E=w(2,22),D=w(31,39),O=w(32,39),k=w(33,39),A=w(36,39),j=c.platform!==`win32`||!!c.env.WT_SESSION||c.env.TERM_PROGRAM===`vscode`,ee=e=>!!(e.isTTY&&c.env.TERM!==`dumb`&&!(`CI`in c.env)),te=O(j?`ā`:`ā`),M=j?[`ā `,`ā `,`ā ¹`,`ā ø`,`ā ¼`,`ā “`,`ā ¦`,`ā §`,`ā `,`ā `]:[`-`,`\\`,`|`,`/`],N=(e={})=>{let t=-1,n,r=e.text??``,a=e.stream??c.stderr,o=ee(a),s=0,l=0,u=!1,d=e=>a.write(e),f=()=>{if(!(!o||s===0)){a.cursorTo(0);for(let e=0;e<s;e++)e>0&&a.moveCursor(0,-1),a.clearLine(1);s=0}},p=e=>{let t=a.columns??80,n=i(e).split(`
|
|
4
|
+
`),r=0;for(let e of n)r+=Math.max(1,Math.ceil(e.length/t));return r},m=()=>{if(!o)return;let e=Date.now();(t===-1||e-l>=80)&&(t=++t%M.length,l=e);let n=M[t],i=`${A(n)} ${r}`;f(),d(i),s=p(i)};return{start(e){return r=e,u=!0,o&&d(`\x1B[?25l`),m(),o&&(n=setInterval(m,80)),this},success(e){return u?(u=!1,n&&=(clearInterval(n),void 0),f(),o&&d(`\x1B[?25h`),d(`${te} ${e??r}\n`),this):this}}},P=async(t,r,i)=>{let a=i??r,o=await e.promises.readdir(t,{withFileTypes:!0});await e.promises.mkdir(r,{recursive:!0});let s=[];for(let i of o){if(i.name===`.git`)continue;let o=n.join(t,i.name),c=n.join(r,i.name);if(i.isDirectory())s.push(...await P(o,c,a));else if(i.isSymbolicLink()){let t=await e.promises.readlink(o);await e.promises.symlink(t,c),s.push(n.relative(a,c))}else await e.promises.copyFile(o,c),s.push(n.relative(a,c))}return s},F=new Set;function I(){for(let t of F)try{e.rmSync(t,{recursive:!0,force:!0})}catch{}process.exit(1)}process.on(`SIGINT`,I),process.on(`SIGTERM`,I);const ne=e=>e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`,L=async(r,i,a)=>{let o=i.tree||i.quiet,s=i.verbose&&!o;process.platform===`win32`&&await S(`git`,[`config`,`--global`,`core.longpaths`,`true`]);let c=`https://${r.token?r.token+`@`:r.token}${r.host}/${r.owner}/${r.repository}.git`,l=`https://${r.host}/${r.owner}/${r.repository}.git`,u=n.resolve(t.tmpdir(),`${r.repository}-${Date.now()}${Math.random().toString(16).slice(2,6)}`);F.add(u);let d=N(),f=performance.now();!i.watch&&!o&&d.start(`Picking ${r.type}${r.type===`repository`?` without .git`:` from repository`}...`);let p=`shallow`,m=performance.now();try{await S(`git`,[`clone`,c,u,`--branch`,r.branch,`--depth`,`1`,`--single-branch`,...i.recursive?[`--recursive`]:[]])}catch{p=`full`,await S(`git`,[`clone`,c,u,...i.recursive?[`--recursive`]:[]]),await S(`git`,[`checkout`,r.branch],{cwd:u})}let h=Number(((performance.now()-m)/1e3).toFixed(2)),g=n.resolve(u,r.path),_=await e.promises.stat(g),v=[],y=performance.now();_.isDirectory()?(await e.promises.mkdir(a,{recursive:!0}),v=await P(g,a)):(await e.promises.mkdir(n.dirname(a),{recursive:!0}),await e.promises.copyFile(g,a),v=[n.basename(a)]);let b=Number(((performance.now()-y)/1e3).toFixed(2)),x=Number(((performance.now()-f)/1e3).toFixed(2)),C=0;for(let t of v)try{let r=await e.promises.stat(n.join(a,t));C+=r.size}catch{let t=await e.promises.stat(a);C+=t.size;break}return o||(i.watch?console.log(`- Synced at `+new Date().toLocaleTimeString()):d.success(`Picked ${r.type}${r.type===`repository`?` without .git`:` from repository`} in ${x} seconds.`)),s&&(console.log(E(` clone: ${p} (depth=${p===`shallow`?`1`:`full`})`)),console.log(E(` from: ${l} @ ${A(r.branch)}`)),console.log(E(` to: ${a}`)),console.log(E(` files: ${v.length} (${ne(C)})`)),console.log(E(` network: ${h}s`)),console.log(E(` copy: ${b}s`)),console.log(E(` total: ${x}s`))),await e.promises.rm(u,{recursive:!0,force:!0}),F.delete(u),{files:v,duration:x,networkTime:h,copyTime:b,totalSize:C,cloneStrategy:p}},R=e=>e.replace(/\x1B\[\d+(?:;\d+)*m/g,``);function re(e){let t=[],n=new Map,r=[...e].sort((e,t)=>e.type===t.type?e.path.localeCompare(t.path,void 0,{sensitivity:`base`}):e.type===`tree`?-1:1);for(let e of r){let r=e.path.split(`/`),i={name:r[r.length-1],path:e.path,type:e.type,size:e.size||0,children:[],expanded:!1,selected:!1,depth:r.length-1};if(e.type===`tree`&&n.set(e.path,i),r.length===1)t.push(i);else{let e=r.slice(0,-1).join(`/`),a=n.get(e);if(a)a.children.push(i);else{let e=``,a=t;for(let t=0;t<r.length-1;t++){e=e?e+`/`+r[t]:r[t];let i=n.get(e);i||(i={name:r[t],path:e,type:`tree`,size:0,children:[],expanded:!1,selected:!1,depth:t},n.set(e,i),a.push(i)),a=i.children}a.push(i)}}}function i(e){e.sort((e,t)=>e.type===t.type?e.name.localeCompare(t.name,void 0,{sensitivity:`base`}):e.type===`tree`?-1:1);for(let t of e)t.children.length&&i(t.children)}return i(t),t}function ie(e){let t=[];function n(e,r){for(let i=0;i<e.length;i++){let a=e[i],o=i===e.length-1,s=o?`āāā `:`āāā `;t.push({node:a,prefix:r,connector:s}),a.type===`tree`&&a.expanded&&n(a.children,r+(o?` `:`ā `))}}return n(e,``),t}function z(e,t){e.selected=t;for(let n of e.children)z(n,t)}function ae(e){let t=[];function n(e){for(let r of e)r.selected?r.type===`tree`?r.children.length>0&&r.children.every(e=>e.selected)||r.children.length===0?t.push(r.path):n(r.children):t.push(r.path):r.type===`tree`&&n(r.children)}return n(e),t}function oe(e){let t=0,n=0,r=0;function i(e){for(let a of e)a.selected&&(a.type===`tree`?n++:(t++,r+=a.size)),a.children.length&&i(a.children)}return i(e),{files:t,folders:n,size:r}}const se=e=>e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`;function ce(e,t){return new Promise(n=>{let r=re(e);if(!r.length){n([]);return}function i(e,t,n=0){for(let r of e)r.type===`tree`&&n<=t&&(r.expanded=!0,i(r.children,t,n+1))}e.length<=30?i(r,1/0):i(r,1);let a=0,o=0,s=process.stdout,c=process.stdin,l=c.isRaw;c.setRawMode(!0),c.resume(),s.write(`\x1B[?1049h\x1B[?25l`);function u(){c.setRawMode(l??!1),c.pause(),c.removeListener(`data`,m),s.write(`\x1B[?25h\x1B[?1049l`)}let d=()=>{s.write(`\x1B[?25h\x1B[?1049l`)},f=()=>{u(),process.removeListener(`exit`,d),process.removeListener(`SIGINT`,f),n([]),process.exit(0)};process.on(`exit`,d),process.on(`SIGINT`,f);function p(){let e=s.rows||24,n=s.columns||80,i=Math.max(1,e-3-1-5),c=ie(r),l=a-1;l>=0?(l<o&&(o=l),l>=o+i&&(o=l-i+1)):o=0,o<0&&(o=0);let u=c.slice(o,o+i),{files:d,folders:f,size:p}=oe(r),m=`\x1B[H\x1B[2J`;m+=`\n ${t}\n\n`;let h=r.every(e=>e.selected),g=a===0,_=h?O(`ā`):E(`ā`),v=`${g?k(`>`):` `} ${_} ${E(`.`)}`;if(g){let e=Math.max(0,n-R(v).length);v=`\x1B[48;5;236m${v}${` `.repeat(e)}\x1B[49m`}m+=v+`
|
|
5
|
+
`;for(let e=0;e<u.length;e++){let t=u[e],r=o+e+1===a,i=t.node.selected?O(`ā`):E(`ā`),s=t.node.type===`tree`?A(t.node.name+`/`):t.node.name,c=t.node.type===`tree`?t.node.expanded?E(`ā¾ `):E(`āø `):` `,l=`${r?k(`>`):` `} ${i} ${E(t.prefix)}${E(t.connector)}${c}${s}`;if(r){let e=Math.max(0,n-R(l).length);l=`\x1B[48;5;236m${l}${` `.repeat(e)}\x1B[49m`}m+=l+`
|
|
6
6
|
`}for(let e=u.length;e<i;e++)m+=`
|
|
7
7
|
`;m+=`
|
|
8
|
-
`;let y=[];f>0&&y.push(A(`${f} folder${f===1?``:`s`}`)),d>0&&y.push(`${d} file${d===1?``:`s`}`);let b=[];y.length>0&&b.push(y.join(` `)),b.length>0&&b.push(E(
|
|
8
|
+
`;let y=[];f>0&&y.push(A(`${f} folder${f===1?``:`s`}`)),d>0&&y.push(`${d} file${d===1?``:`s`}`);let b=[];y.length>0&&b.push(y.join(` `)),b.length>0&&b.push(E(se(p)));let x=c.length>i?E(` ⢠${o+1}-${Math.min(o+i,c.length)}/${c.length}`):``,S=b.length>0?` ${b.join(E(` ⢠`))}${x}`:E(` nothing selected`)+x;m+=S+`
|
|
9
9
|
`,m+=`
|
|
10
|
-
`;let C=E(`āā:navigate enter:expand space:select c:confirm q:quit`);m+=` ${C}\n`,s.write(m)}function
|
|
11
|
-
`){s++,n=!1,i+=Y(e,r,s),r=s;continue}else if(n===
|
|
12
|
-
`)n=!1,i+=Y(e,r,s),r=s;else if(!n&&c+l===`/*`){i+=e.slice(r,s),r=s,n=
|
|
13
|
-
`&&(i+=e.slice(r,s),r=s,o=-1))}let s=n===
|
|
10
|
+
`;let C=E(`āā:navigate enter:expand space:select c:confirm q:quit`);m+=` ${C}\n`,s.write(m)}function m(e){let t=ie(r),i=t.length+1,o=e.toString();if(o===``||o===`q`||o===`Q`){u(),process.removeListener(`exit`,d),process.removeListener(`SIGINT`,f),n([]);return}if(o===`c`||o===`C`){u(),process.removeListener(`exit`,d),process.removeListener(`SIGINT`,f),n(ae(r));return}if((o===`\x1B[A`||o===`k`)&&a>0&&a--,(o===`\x1B[B`||o===`j`)&&a<i-1&&a++,a===0&&(o===` `||o===`\r`)){let e=r.every(e=>e.selected);for(let t of r)z(t,!e)}if(o===` `&&a>0){let e=t[a-1];e&&z(e.node,!e.node.selected)}if(o===`\r`&&a>0){let e=t[a-1];e&&e.node.type===`tree`&&(e.node.expanded=!e.node.expanded)}if((o===`\x1B[C`||o===`l`)&&a>0){let e=t[a-1];e&&e.node.type===`tree`&&(e.node.expanded=!0)}if((o===`\x1B[D`||o===`h`)&&a>0){let e=t[a-1];e&&e.node.type===`tree`&&(e.node.expanded=!1)}p()}c.on(`data`,m),p()})}function B(e){if(typeof e==`number`||/^\d+$/.test(e))return typeof e==`number`?e:parseInt(e,10);let t=/(\d+)([hms])/g,n=0,r;for(;(r=t.exec(e))!==null;){let e=parseInt(r[1],10);switch(r[2]){case`h`:n+=e*36e5;break;case`m`:n+=e*6e4;break;case`s`:n+=e*1e3;break}}return n}const V=async e=>{let t=(await S(`git`,[`ls-remote`,e])).stdout,n=t.match(/(.+)\s+HEAD/)?.[1],r=t.match(RegExp(`${n}\\s+refs/heads/(.+)`))?.[1];if(!r)throw Error(`Could not determine default branch!`);return r},H=[{prefix:`git@github.com:`,host:`github.com`},{prefix:`https://github.com/`,host:`github.com`},{prefix:`https://raw.githubusercontent.com/`,host:`github.com`},{prefix:`git@gitlab.com:`,host:`gitlab.com`},{prefix:`https://gitlab.com/`,host:`gitlab.com`},{prefix:`git@bitbucket.org:`,host:`bitbucket.org`},{prefix:`https://bitbucket.org/`,host:`bitbucket.org`}];async function le(e,{branch:t,target:n}){let r=e.match(/^https:\/\/([^@]+)@(github\.com|gitlab\.com|bitbucket\.org)/),i=``;if(r)i=r[1],e=e.replace(`${r[1]}@`,``);else{let t={"github.com":process.env.GITHUB_TOKEN||process.env.GH_TOKEN||``,"gitlab.com":process.env.GITLAB_TOKEN||``,"bitbucket.org":process.env.BITBUCKET_TOKEN||``};for(let{prefix:n,host:r}of H)if(e.startsWith(n)){i=t[r];break}!i&&!e.startsWith(`https://`)&&!e.startsWith(`git@`)&&(i=t[`github.com`])}let a=`github.com`;for(let{prefix:t,host:n}of H)if(e.startsWith(t)){a=n,e=e.replace(t,``);break}let o=e.split(`/`),s=o[0],c=o[1]?.endsWith(`.git`)?o[1].slice(0,-4):o[1],l=`https://${i&&i+`@`}${a}/${s}/${c}`,u,d,f;a===`github.com`?o[2]===`refs`&&[`heads`,`tags`].includes(o[3])?(u=`raw`,d=t||o[4],f=o.slice(5).join(`/`)):o[2]===`refs`&&o[3]===`remotes`?(u=`raw`,d=t||`${o[4]}/${o[5]}`,f=o.slice(6).join(`/`)):o[2]===`blob`?(u=`blob`,d=t||o[3],f=o.slice(4).join(`/`)):o[2]===`tree`?(u=`tree`,d=t||o[3],f=o.slice(4).join(`/`)):o[2]===`commit`?(u=`repository`,d=t||o[3],f=``):(u=`repository`,d=t||await V(l),f=``):a===`gitlab.com`?o[2]===`-`&&o[3]===`blob`?(u=`blob`,d=t||o[4],f=o.slice(5).join(`/`)):o[2]===`-`&&o[3]===`tree`?(u=`tree`,d=t||o[4],f=o.slice(5).join(`/`)):(u=`repository`,d=t||await V(l),f=``):o[2]===`src`?(u=`tree`,d=t||o[3],f=o.slice(4).join(`/`)):(u=`repository`,d=t||await V(l),f=``);let p=n||(u===`blob`?`.`:f.split(`/`).pop()||c);return{token:i,host:a,owner:s,repository:c,type:u,branch:d,path:f,target:p}}const U=n.join(t.homedir(),`.cache`,`gitpick`),W=n.join(U,`update-check.json`);function G(){try{return JSON.parse(e.readFileSync(W,`utf-8`))}catch{return null}}function ue(t){try{e.mkdirSync(U,{recursive:!0}),e.writeFileSync(W,JSON.stringify(t))}catch{}}function de(){return new Promise(e=>{let t=d.get(`https://registry.npmjs.org/gitpick/latest`,{headers:{Accept:`application/json`},timeout:3e3},t=>{if(t.statusCode!==200)return t.resume(),e(null);let n=``;t.on(`data`,e=>n+=e),t.on(`end`,()=>{try{e(JSON.parse(n).version||null)}catch{e(null)}})});t.on(`error`,()=>e(null)),t.on(`timeout`,()=>{t.destroy(),e(null)})})}function fe(e,t){let n=e.split(`.`).map(Number),r=t.split(`.`).map(Number);for(let e=0;e<3;e++){if((n[e]||0)>(r[e]||0))return!0;if((n[e]||0)<(r[e]||0))return!1}return!1}function K(e,t){if(t)return;let n=G();n&&fe(n.latestVersion,e)&&console.log(E(`\n Update available: ${k(e)} ā ${A(T(n.latestVersion))}\n Run ${A(`npm i -g gitpick`)} to update\n`))}function pe(){let e=G();e&&Date.now()-e.lastCheck<864e5||setTimeout(async()=>{let e=await de();e&&ue({lastCheck:Date.now(),latestVersion:e})},0)}const q=Symbol(`singleComment`),J=Symbol(`multiComment`),Y=(e,t,n)=>e.slice(t,n).replace(/[^ \t\r\n]/g,` `),me=(e,t)=>{let n=t-1,r=0;for(;e[n]===`\\`;)--n,r+=1;return!!(r%2)};function he(e){if(typeof e!=`string`)throw TypeError(`Expected argument \`jsonString\` to be a \`string\`, got \`${typeof e}\``);let t=!1,n=!1,r=0,i=``,a=``,o=-1;for(let s=0;s<e.length;s++){let c=e[s],l=e[s+1];if(!n&&c===`"`&&(me(e,s)||(t=!t)),!t)if(!n&&c+l===`//`)i+=e.slice(r,s),r=s,n=q,s++;else if(n===q&&c+l===`\r
|
|
11
|
+
`){s++,n=!1,i+=Y(e,r,s),r=s;continue}else if(n===q&&c===`
|
|
12
|
+
`)n=!1,i+=Y(e,r,s),r=s;else if(!n&&c+l===`/*`){i+=e.slice(r,s),r=s,n=J,s++;continue}else if(n===J&&c+l===`*/`){s++,n=!1,i+=Y(e,r,s+1),r=s+1;continue}else n||(o===-1?c===`,`&&(a+=i+e.slice(r,s),i=``,r=s,o=s):c===`}`||c===`]`?(i+=e.slice(r,s),a+=Y(i,0,1)+i.slice(1),i=``,r=s,o=-1):c!==` `&&c!==` `&&c!==`\r`&&c!==`
|
|
13
|
+
`&&(i+=e.slice(r,s),r=s,o=-1))}let s=n===q?Y(e,r):e.slice(r);return a+i+s}const ge=[`.gitpick.json`,`.gitpick.jsonc`],_e=async()=>{let t;for(let r of ge){let i=n.resolve(r);if(e.existsSync(i)){t=i;break}}if(!t)return!1;let r=await e.promises.readFile(t,`utf-8`),i=JSON.parse(he(r));if(!Array.isArray(i)||!i.every(e=>typeof e==`string`))throw Error(`${n.basename(t)} must be an array of strings`);for(let e of i)await S(process.argv[0],[...process.argv.slice(1),...e.split(/\s+/),`-o`],{stdio:`inherit`});return!0};var ve=`gitpick`,X=`4.20.0-canary.10`;const Z=(e,t)=>`\x1b]8;;${t}\x07${e}\x1b]8;;\x07`,ye=`
|
|
14
14
|
With ${T(`${Z(`GitPick`,`https://github.com/nrjdalal/gitpick`)}`)} clone specific directories or files from GitHub, GitLab and Bitbucket!
|
|
15
15
|
|
|
16
16
|
$ gitpick ${k(`<url>`)} ${O(`[target]`)} ${A(`[options]`)}
|
|
@@ -47,9 +47,9 @@ ${T(`Examples:`)}
|
|
|
47
47
|
$ gitpick https://gitlab.com/owner/repo
|
|
48
48
|
$ gitpick https://bitbucket.org/owner/repo
|
|
49
49
|
|
|
50
|
-
š More awesome tools at ${A(`https://github.com/nrjdalal`)}`,Q=e=>{let r=process.cwd(),i=t.homedir(),a=n.sep;return e===r?`.`:e.startsWith(r+a)?`./`+n.relative(r,e).replaceAll(a,`/`):e.startsWith(i+a)?`~/`+n.relative(i,e).replaceAll(a,`/`):e},$=async(t,r=``)=>{let i=(await e.promises.readdir(t,{withFileTypes:!0})).filter(e=>e.name!==`.git`).sort((e,t)=>e.name.localeCompare(t.name,void 0,{sensitivity:`base`}));for(let a=0;a<i.length;a++){let o=i[a],s=a===i.length-1,c=s?`āāā `:`āāā `,l=n.join(t,o.name);if(o.isSymbolicLink()){let t=await e.promises.readlink(l),n=!1;try{n=e.statSync(l).isDirectory()}catch{}process.stdout.write(`${r}${c}${k(o.name)} -> ${n?A(t):t}\n`)}else o.isDirectory()?(process.stdout.write(`${r}${c}${A(o.name)}\n`),await $(l,`${r}${s?` `:`ā `}`)):process.stdout.write(`${r}${c}${o.name}\n`)}},
|
|
51
|
-
Repository has no files.`)),process.exit(0));let
|
|
52
|
-
No files selected.`),process.exit(0)),console.log(`\n${O(`ā`)}
|
|
53
|
-
`)),
|
|
54
|
-
`)};if(s.dryRun){if(s.tree){let r=n.resolve(t.tmpdir(),`gitpick-dry-${Date.now()}${Math.random().toString(16).slice(2,6)}`);try{await
|
|
50
|
+
š More awesome tools at ${A(`https://github.com/nrjdalal`)}`,Q=e=>{let r=process.cwd(),i=t.homedir(),a=n.sep;return e===r?`.`:e.startsWith(r+a)?`./`+n.relative(r,e).replaceAll(a,`/`):e.startsWith(i+a)?`~/`+n.relative(i,e).replaceAll(a,`/`):e},$=async(t,r=``)=>{let i=(await e.promises.readdir(t,{withFileTypes:!0})).filter(e=>e.name!==`.git`).sort((e,t)=>e.name.localeCompare(t.name,void 0,{sensitivity:`base`}));for(let a=0;a<i.length;a++){let o=i[a],s=a===i.length-1,c=s?`āāā `:`āāā `,l=n.join(t,o.name);if(o.isSymbolicLink()){let t=await e.promises.readlink(l),n=!1;try{n=e.statSync(l).isDirectory()}catch{}process.stdout.write(`${r}${c}${k(o.name)} -> ${n?A(t):t}\n`)}else o.isDirectory()?(process.stdout.write(`${r}${c}${A(o.name)}\n`),await $(l,`${r}${s?` `:`ā `}`)):process.stdout.write(`${r}${c}${o.name}\n`)}},be=e=>{try{return r(e)}catch(e){throw Error(`Error parsing arguments: ${e.message}`)}};(async()=>{pe();try{let{positionals:r,values:i}=be({allowPositionals:!0,options:{branch:{type:`string`,short:`b`},"dry-run":{type:`boolean`,short:`n`},force:{type:`boolean`,short:`f`},help:{type:`boolean`,short:`h`},interactive:{type:`boolean`,short:`i`},quiet:{type:`boolean`,short:`q`},tree:{type:`boolean`},verbose:{type:`boolean`},overwrite:{type:`boolean`,short:`o`},recursive:{type:`boolean`,short:`r`},version:{type:`boolean`,short:`v`},watch:{type:`string`,short:`w`}}});r.length||(i.version&&(console.log(`\n${ve}@${X}`),process.exit(0)),await _e()&&process.exit(0),console.log(ye),process.exit(0)),r[0]===`clone`&&r.shift();let[a,o]=r,s={branch:i.branch,dryRun:i[`dry-run`],force:i.force,interactive:i.interactive,quiet:i.quiet,tree:i.tree,verbose:i.verbose,overwrite:i.overwrite,recursive:i.recursive,watch:i.watch},c=s.tree||s.quiet;c||console.log(`\nWith ${T(`${Z(`GitPick`,`https://github.com/nrjdalal/gitpick`)}`)} clone specific files, folders, branches,\ncommits and much more from GitHub, GitLab and Bitbucket!`);let l=await le(a,{branch:s.branch,target:o});if(l.type===`blob`){let e=l.target.split(/[/\\]/).filter(e=>e!==``),t=e[e.length-1];t!==`.`&&t!==`..`&&t.includes(`.`)?e.pop():t=l.path.split(`/`).pop()||t,l.target=[...e,t].join(`/`)}c||console.info(`\n${O(`ā`)} ${l.owner}/${l.repository} ${A(l.type+`:`+l.branch)} ${l.type===`repository`?`> ${O(l.target)}`:`${l.path.length?k(l.path)+` >`:`>`} ${O(l.target)}`}`);let u=n.resolve(l.target);if(s.interactive){if(!process.stdout.isTTY)throw Error(`Interactive mode requires a TTY`);let r=n.resolve(t.tmpdir(),`gitpick-interactive-${Date.now()}${Math.random().toString(16).slice(2,6)}`),i=`https://${l.token?l.token+`@`:``}${l.host}/${l.owner}/${l.repository}.git`,a=N();a.start(`Fetching ${l.owner}/${l.repository}...`);try{await S(`git`,[`clone`,i,r,`--branch`,l.branch,`--depth`,`1`,`--single-branch`,...s.recursive?[`--recursive`]:[]])}catch{await S(`git`,[`clone`,i,r,...s.recursive?[`--recursive`]:[]]),await S(`git`,[`checkout`,l.branch],{cwd:r})}let o=[];async function c(t,r){let i=await e.promises.readdir(t,{withFileTypes:!0});for(let a of i){if(a.name===`.git`)continue;let i=r?`${r}/${a.name}`:a.name,s=n.join(t,a.name);if(a.isDirectory())o.push({path:i,type:`tree`}),await c(s,i);else{let t=await e.promises.stat(s);o.push({path:i,type:`blob`,size:t.size})}}}await c(r,``),a.success(`Fetched ${l.owner}/${l.repository} (${o.length} entries)`),o.length||(await e.promises.rm(r,{recursive:!0,force:!0}),console.log(k(`
|
|
51
|
+
Repository has no files.`)),process.exit(0));let d=await ce(o,`${l.owner}/${l.repository} ${A(`repository:`+l.branch)} > ${O(l.target)}`);if(d.length||(await e.promises.rm(r,{recursive:!0,force:!0}),console.log(`
|
|
52
|
+
No files selected.`),process.exit(0)),s.dryRun){console.log(`\n${O(`ā`)} Would pick ${d.length} path${d.length===1?``:`s`}:`);for(let e of d)console.log(` ${e}`);await e.promises.rm(r,{recursive:!0,force:!0}),console.log(),K(X,!1),process.exit(0)}console.log(`\n${O(`ā`)} Picking ${d.length} selected path${d.length===1?``:`s`}...`),e.existsSync(u)&&!s.overwrite&&(await e.promises.readdir(u)).length&&(await e.promises.rm(r,{recursive:!0,force:!0}),console.log(`${k(`\nWarning: The target directory exists at ${O(l.target)} and is not empty. Use ${A(`-f`)} or ${A(`-o`)} to overwrite.`)}`),process.exit(1)),await e.promises.mkdir(u,{recursive:!0});let f=0;for(let t of d){let i=n.join(r,t),a=n.join(u,t),o=await e.promises.stat(i).catch(()=>null);if(o)if(o.isDirectory()){await e.promises.mkdir(a,{recursive:!0});let t=await P(i,a);f+=t.length}else await e.promises.mkdir(n.dirname(a),{recursive:!0}),await e.promises.copyFile(i,a),f++}await e.promises.rm(r,{recursive:!0,force:!0}),console.log(O(`ā Copied ${f} file${f===1?``:`s`} to ${Q(u)}`)),s.tree&&(process.stdout.write(`\n${T(A(Q(u)))}\n`),await $(u),process.stdout.write(`
|
|
53
|
+
`)),K(X,!1),process.exit(0)}let d=async t=>{e.statSync(t).isDirectory()?(process.stdout.write(`${T(A(Q(u)))}\n`),await $(t)):(process.stdout.write(`${T(A(Q(n.dirname(u))))}\n`),process.stdout.write(`āāā ${n.basename(u)}\n`)),process.stdout.write(`
|
|
54
|
+
`)};if(s.dryRun){if(s.tree){let r=n.resolve(t.tmpdir(),`gitpick-dry-${Date.now()}${Math.random().toString(16).slice(2,6)}`);try{await L(l,s,r),await d(r)}finally{await e.promises.rm(r,{recursive:!0,force:!0})}}c||console.log(),K(X,c),process.exit(0)}if(s.overwrite=s.overwrite||s.force,s.watch&&(s.overwrite=!0),e.existsSync(u)&&!s.overwrite&&(l.type===`blob`&&(console.log(`${k(`\nWarning: The target file exists at ${O(l.target)}. Use ${A(`-f`)} or ${A(`-o`)} to overwrite.`)}`),process.exit(1)),(await e.promises.readdir(u)).length&&(console.log(`${k(`\nWarning: The target directory exists at ${O(l.target)} and is not empty. Use ${A(`-f`)} or ${A(`-o`)} to overwrite.`)}`),process.exit(1))),s.watch){c||console.log(`\nš Watching every ${B(s.watch)/1e3+`s`}\n`),await L(l,s,u),s.tree&&await d(u);let e=B(s.watch);setInterval(async()=>{await L(l,s,u),s.tree&&await d(u)},e)}else await L(l,s,u),s.tree&&await d(u),K(X,c),process.exit(0)}catch(e){e instanceof Error?console.log(T(`\n${D(`Error: `)}`)+e.message):console.log(T(`${D(`
|
|
55
55
|
Unexpected Error: `)}`)+JSON.stringify(e,null,2)),process.exit(1)}})();export{};
|