gitpick 4.20.0-canary.1 ā 4.20.0-canary.3
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 +56 -0
- package/dist/index.mjs +12 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,6 +24,9 @@ Unlike other tools that force you to tweak URLs or follow strict formats to clon
|
|
|
24
24
|
### See [Quick Usage](#-quick-usage) for to learn more.
|
|
25
25
|
|
|
26
26
|
```sh
|
|
27
|
+
# interactive mode ā browse and pick files/folders
|
|
28
|
+
npx gitpick owner/repo -i
|
|
29
|
+
npx gitpick https://github.com/owner/repo -i
|
|
27
30
|
# clone a repo without .git
|
|
28
31
|
npx gitpick owner/repo
|
|
29
32
|
npx gitpick https://github.com/owner/repo
|
|
@@ -71,6 +74,7 @@ npx gitpick owner/repo --dry-run
|
|
|
71
74
|
- š Sync changes remotely with `--watch` using intervals (e.g., `15s`, `1m`, `1h`)
|
|
72
75
|
- š Silent mode with `--quiet` for CI pipelines, debug mode with `--verbose`
|
|
73
76
|
- š Config file support (`.gitpick.json` / `.gitpick.jsonc`) for multi-path picks
|
|
77
|
+
- **š Interactive mode** ā browse and cherry-pick files/folders with `-i` | `--interactive`
|
|
74
78
|
|
|
75
79
|
---
|
|
76
80
|
|
|
@@ -105,10 +109,62 @@ npx gitpick https://bitbucket.org/owner/repo # Bitbucket
|
|
|
105
109
|
|
|
106
110
|
---
|
|
107
111
|
|
|
112
|
+
## š Interactive Mode
|
|
113
|
+
|
|
114
|
+
> **New in v5.0** ā Browse any repository's file tree in your terminal and cherry-pick exactly the files and folders you want.
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
npx gitpick owner/repo -i
|
|
118
|
+
npx gitpick owner/repo -i -b canary
|
|
119
|
+
npx gitpick https://github.com/owner/repo -i
|
|
120
|
+
npx gitpick https://gitlab.com/owner/repo -i
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**How it works:**
|
|
124
|
+
|
|
125
|
+
1. GitPick fetches the repository
|
|
126
|
+
2. An interactive file tree appears in your terminal
|
|
127
|
+
3. Navigate with arrow keys, select with space, expand/collapse folders with enter
|
|
128
|
+
4. Press `c` to confirm ā only your selected files get copied
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
nrjdalal/gitpick repository:main > gitpick
|
|
132
|
+
|
|
133
|
+
> ā .
|
|
134
|
+
ā āāā ā¾ bin/
|
|
135
|
+
ā ā āāā āø external/
|
|
136
|
+
ā ā āāā āø utils/
|
|
137
|
+
ā ā āāā index.ts
|
|
138
|
+
ā āāā āø tests/
|
|
139
|
+
ā āāā package.json
|
|
140
|
+
ā āāā README.md
|
|
141
|
+
|
|
142
|
+
2 folders 3 files ⢠12.4 KB
|
|
143
|
+
|
|
144
|
+
āā:navigate enter:expand space:select c:confirm q:quit
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Controls:**
|
|
148
|
+
|
|
149
|
+
| Key | Action |
|
|
150
|
+
| ----------------- | -------------------------- |
|
|
151
|
+
| `ā` `ā` / `j` `k` | Navigate up/down |
|
|
152
|
+
| `ā` `ā` / `h` `l` | Collapse/expand folder |
|
|
153
|
+
| `Enter` | Toggle expand/collapse |
|
|
154
|
+
| `Space` | Toggle selection |
|
|
155
|
+
| `.` (first row) | Select/deselect all |
|
|
156
|
+
| `c` | Confirm and clone selected |
|
|
157
|
+
| `q` / `Ctrl+C` | Quit without cloning |
|
|
158
|
+
|
|
159
|
+
Works with GitHub, GitLab, Bitbucket, public and private repos.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
108
163
|
## š§ Options
|
|
109
164
|
|
|
110
165
|
```
|
|
111
166
|
-b, --branch Branch/SHA to clone
|
|
167
|
+
-i, --interactive Browse and pick files/folders interactively
|
|
112
168
|
-n, --dry-run Show what would be cloned without cloning
|
|
113
169
|
-o, --overwrite Skip overwrite prompt
|
|
114
170
|
-r, --recursive Clone submodules
|
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%
|
|
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
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.3`;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(`ā`)} Picking ${
|
|
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)}`);d.length||(await e.promises.rm(r,{recursive:!0,force:!0}),console.log(`
|
|
52
|
+
No files selected.`),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{};
|