Skip to content

Commit 6b09a1f

Browse files
committed
chore: add several minor improvements
1 parent d1a6803 commit 6b09a1f

7 files changed

Lines changed: 951 additions & 21 deletions

File tree

bin/cli.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import type { GitItOptions } from '../src/types'
44
import { spawn } from 'node:child_process'
55
import { relative } from 'node:path'
66
import process from 'node:process'
7-
import { CAC } from 'cac'
7+
import { CLI } from '@stacksjs/clapp'
88
import { version } from '../package.json'
99
import { downloadTemplate } from '../src/gitit'
1010
import { startShell } from '../src/utils'
1111

12-
const cli = new CAC('gitit')
12+
const cli = new CLI('gitit')
1313

1414
cli
1515
.command('[template] [dir]', 'Clone a template from a repository')

bun.lock

Lines changed: 0 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

deps.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
dependencies:
2-
bun.sh: ^1.2.10
2+
bun.sh: ^1.3.10

package.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,6 @@
7272
"format": "bunx --bun pickier . --format",
7373
"format:fix": "bunx --bun pickier . --format --write"
7474
},
75-
"dependencies": {
76-
"nanotar": "^0.2.0"
77-
},
7875
"devDependencies": {
7976
"better-dx": "^0.2.7",
8077
"bunfig": "^0.15.6"

pantry.lock

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"version": "1.0",
3+
"packages": {
4+
"bun.sh@1.3.11": {
5+
"name": "bun.sh",
6+
"version": "1.3.11",
7+
"resolved": "registry:bun.sh@1.3.11",
8+
"integrity": "sha256:61aefeb2d13032a726efaca2ceff6667342381a393cb6550ded85f0ebb76890d"
9+
}
10+
}
11+
}

src/gitit.ts

Lines changed: 79 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import { existsSync, readdirSync } from 'node:fs'
55
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises'
66
import { dirname, join, resolve } from 'node:path'
77
import { gunzipSync } from 'node:zlib'
8-
import defu from 'defu'
9-
import { parseTar } from 'nanotar'
108
import { providers } from './providers'
119
import { registryProvider } from './registry'
1210
import { cacheDirectory, debug, download, normalizeHeaders } from './utils'
@@ -58,8 +56,81 @@ async function installDependencies(options: InstallOptions): Promise < void> {
5856
})
5957
}
6058

59+
export interface TarEntry {
60+
name: string
61+
type: 'file' | 'directory'
62+
size: number
63+
data?: Uint8Array
64+
}
65+
66+
/**
67+
* Parse a tar archive buffer into entries (POSIX ustar + GNU long name support)
68+
*/
69+
export function parseTar(data: Uint8Array): TarEntry[] {
70+
const entries: TarEntry[] = []
71+
let offset = 0
72+
const decoder = new TextDecoder()
73+
let longName: string | null = null
74+
75+
while (offset + 512 <= data.length) {
76+
const header = data.subarray(offset, offset + 512)
77+
78+
// End of archive: zero block
79+
let allZero = true
80+
for (let i = 0; i < 512; i++) {
81+
if (header[i] !== 0) {
82+
allZero = false
83+
break
84+
}
85+
}
86+
if (allZero)
87+
break
88+
89+
const nameRaw = decoder.decode(header.subarray(0, 100)).replace(/\0.*$/, '')
90+
const prefix = decoder.decode(header.subarray(345, 500)).replace(/\0.*$/, '')
91+
const sizeStr = decoder.decode(header.subarray(124, 136)).replace(/\0.*$/, '').trim()
92+
const size = sizeStr ? Number.parseInt(sizeStr, 8) : 0
93+
const typeflag = String.fromCharCode(header[156]!)
94+
95+
offset += 512
96+
const dataBlocks = Math.ceil(size / 512) * 512
97+
98+
// GNU long name extension
99+
if (typeflag === 'L') {
100+
longName = decoder.decode(data.subarray(offset, offset + size)).replace(/\0.*$/, '')
101+
offset += dataBlocks
102+
continue
103+
}
104+
105+
// Pax extended header — extract path if present
106+
if (typeflag === 'x' || typeflag === 'g') {
107+
const paxData = decoder.decode(data.subarray(offset, offset + size))
108+
const pathMatch = paxData.match(/\d+ path=(.+)\n/)
109+
if (pathMatch)
110+
longName = pathMatch[1]!
111+
offset += dataBlocks
112+
continue
113+
}
114+
115+
const name = longName ?? (prefix ? `${prefix}/${nameRaw}` : nameRaw)
116+
longName = null
117+
118+
if (typeflag === '5') {
119+
entries.push({ name, type: 'directory', size })
120+
}
121+
else if (typeflag === '0' || typeflag === '\0' || typeflag === '') {
122+
const fileData = size > 0 ? data.slice(offset, offset + size) : undefined
123+
entries.push({ name, type: 'file', size, data: fileData })
124+
}
125+
126+
offset += dataBlocks
127+
}
128+
129+
return entries
130+
}
131+
61132
/**
62-
* Extract a tarball using nanotar (cross - platform)
133+
* Extract a tarball (cross-platform)
63134
*/
64135
async function extractTar(options: GitItExtractOptions): Promise < void> {
65136
const { file, cwd, onentry } = options
@@ -214,13 +285,11 @@ export async function downloadTemplate(
214285
input: string,
215286
options: DownloadTemplateOptions = {},
216287
): Promise < DownloadTemplateResult> {
217-
options = defu(
218-
{
219-
registry: process.env.GITIT_REGISTRY,
220-
auth: process.env.GITIT_AUTH,
221-
},
222-
options,
223-
) as DownloadTemplateOptions
288+
options = {
289+
...options,
290+
registry: process.env.GITIT_REGISTRY ?? options.registry,
291+
auth: process.env.GITIT_AUTH ?? options.auth,
292+
} as DownloadTemplateOptions
224293

225294
// Load hooks
226295
const hooks = loadHooks(options)

0 commit comments

Comments
 (0)