Skip to content

Commit 88b2f14

Browse files
committed
feat: Allow setting the target directory to write ouptut files to
1 parent d45cf4f commit 88b2f14

File tree

8 files changed

+45
-18
lines changed

8 files changed

+45
-18
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ interface GrabOptions {
8383
// archive name without the platform suffix; if not specified, it will be
8484
// inferred from the first archive asset found for the current platform
8585
platformSuffixes?: PlatformSuffixes
86+
// directory to write the archive or executable to; if not specified,
87+
// files will be written to the current directory
88+
targetDirectory?: string
8689
// unpack the executable and remove the archive
8790
unpackExecutable?: boolean
8891
}

bin/grab-github-release.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Options:
1212
-i|--version-spec <semver> semantic version specifier or "latest"
1313
-n|--name <file-name> archive name without the platform suffix
1414
-p|--platform-suffixes <map> unpack the executable and remove the archive
15+
-t|--target-dir <dir-name> directory to write the output files to
1516
-e|--unpack-exe unpack the executable and remove the archive
1617
-v|--verbose prints extra information on the console
1718
-V|--version print version number and exit
@@ -31,7 +32,7 @@ function fail(message) {
3132
}
3233

3334
const { argv } = process
34-
let repository, version, name, platformSuffixes, unpackExecutable, verbose
35+
let repository, version, name, platformSuffixes, targetDirectory, unpackExecutable, verbose
3536

3637
for (let i = 2, l = argv.length; i < l; ++i) {
3738
const arg = argv[i]
@@ -58,6 +59,9 @@ for (let i = 2, l = argv.length; i < l; ++i) {
5859
platformSuffixes[key.trim()] = val.trim()
5960
}
6061
return
62+
case 't': case 'target-dir':
63+
targetDirectory = match[4] || argv[++i]
64+
return
6165
case 'e': case 'unpack-exe':
6266
unpackExecutable = flag
6367
return

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
"check-coverage": "true",
5555
"reporter": [
5656
"lcov",
57-
"text-summary"
57+
"text"
5858
],
5959
"branches": 100,
6060
"functions": 100,

rollup.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export default [
1414
sourcemap: true
1515
}
1616
],
17-
external: ['debug', 'fs', 'os', 'semver', 'stream', 'yauzl'],
17+
external: ['debug', 'fs', 'os', 'path', 'semver', 'stream', 'yauzl'],
1818
plugins: [cleanup()]
1919
}
2020
]

src/index.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ interface GrabOptions {
2323
* inferred from the first archive asset found for the current platform
2424
*/
2525
platformSuffixes?: PlatformSuffixes
26+
/**
27+
* directory to write the archive or executable to; if not specified,
28+
* files will be written to the current directory
29+
*/
30+
targetDirectory?: string
2631
/**
2732
* unpack the executable and remove the archive
2833
*/

src/index.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import debug from 'debug'
22
import { createWriteStream, promises } from 'fs'
33
import { platform, arch } from 'os'
4+
import { join } from 'path'
45
import { clean, satisfies, valid } from 'semver'
56
import { Readable } from 'stream'
67
import { open as openArchive } from 'yauzl'
@@ -63,7 +64,7 @@ async function download(url, archive) {
6364
})
6465
}
6566

66-
function unpack(archive) {
67+
function unpack(archive, targetDirectory) {
6768
log('unpack "%s"', archive)
6869
return new Promise((resolve, reject) =>
6970
openArchive(archive, { lazyEntries: true }, (err, zip) => {
@@ -74,14 +75,15 @@ function unpack(archive) {
7475
const { fileName } = entry
7576
/* c8 ignore next */
7677
if (fileName.endsWith('/')) return new Error('directory in archive')
77-
log('write "%s"', fileName)
78+
const filePath = targetDirectory ? join(targetDirectory, fileName) : fileName
79+
log('write "%s"', filePath)
7880
zip.openReadStream(entry, (err, stream) => {
7981
/* c8 ignore next */
8082
if (err) return reject(err)
8183
stream
8284
.on('error', reject)
83-
.pipe(createWriteStream(fileName))
84-
.on('finish', () => resolve(fileName))
85+
.pipe(createWriteStream(filePath))
86+
.on('finish', () => resolve(filePath))
8587
.on('error', reject)
8688
})
8789
})
@@ -99,7 +101,7 @@ async function makeExecutable(executable) {
99101
}
100102
}
101103

102-
export default async function grab({ name, repository, version, platformSuffixes, unpackExecutable, verbose }) {
104+
export default async function grab({ name, repository, version, platformSuffixes, targetDirectory, unpackExecutable, verbose }) {
103105
if (verbose) log = console.log.bind(console)
104106
if (!version) version = 'latest'
105107
const verspec = clean(version) || version
@@ -111,9 +113,10 @@ export default async function grab({ name, repository, version, platformSuffixes
111113
} else {
112114
({ name, version, archive, url } = await getRelease(name, repository, verspec, platformSuffixes))
113115
}
116+
if (targetDirectory) archive = join(targetDirectory, archive)
114117
await download(url, archive)
115118
if (unpackExecutable) {
116-
const executable = await unpack(archive)
119+
const executable = await unpack(archive, targetDirectory)
117120
await makeExecutable(executable)
118121
log('remove "%s"', archive)
119122
await unlink(archive)

test/mocked.js

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { strictEqual } from 'assert'
2-
import { access, readFile, rm } from 'fs/promises'
1+
import { ok, strictEqual } from 'assert'
2+
import { access, mkdir, readFile, rm } from 'fs/promises'
33
import { after, before, beforeEach, test, mock } from 'node:test'
44
import { arch, platform } from 'os'
55
import { dirname, join } from 'path'
@@ -13,7 +13,7 @@ const __dirname = dirname(fileURLToPath(import.meta.url))
1313

1414
const repository = 'prantlf/v-jsonlint'
1515
const name = 'jsonlint'
16-
const executable = platform() != 'win32' ? name : `${name}.exe`
16+
const executable = join('.', platform() != 'win32' ? name : `${name}.exe`)
1717
const version = '0.0.6'
1818
const platformSuffixes = {
1919
linux: 'linux',
@@ -25,11 +25,15 @@ const content = new Blob(
2525
[await readFile(join(__dirname, `data/${archive}`))],
2626
{ type: 'applicaiton.zip' }
2727
)
28+
const targetDirectory = join(__dirname, 'tmp')
2829

29-
function cleanup() {
30-
return Promise.all([
30+
async function cleanup() {
31+
// failed on Windows on GitHub
32+
if (platform() == 'win32') return
33+
await Promise.all([
3134
rm(archive, { force: true }),
32-
rm(executable, { force: true })
35+
rm(executable, { force: true }),
36+
rm(targetDirectory, { recursive: true, force: true })
3337
])
3438
}
3539

@@ -54,8 +58,7 @@ before(() => {
5458
beforeEach(cleanup)
5559

5660
after(async () => {
57-
// failed on Windows on GitHub
58-
if (platform() != 'win32') await cleanup()
61+
await cleanup()
5962
mock.reset()
6063
})
6164

@@ -114,5 +117,13 @@ test('download archive from the latest implicit version and unpack executable',
114117
if (!await exists(executable)) throw new Error('executable not found')
115118
strictEqual(actualVersion, version)
116119
strictEqual(actualExecutable, executable)
117-
strictEqual(actualExecutable, executable)
120+
})
121+
122+
test('download archive from the latest implicit version and unpack executable to a custom directory', async () => {
123+
await mkdir(targetDirectory, { recursive: true })
124+
const { executable: actualExecutable, version: actualVersion } = await grab(
125+
{ name, repository, platformSuffixes, targetDirectory, unpackExecutable: true })
126+
if (!await exists(actualExecutable)) throw new Error('executable not found')
127+
strictEqual(actualVersion, version)
128+
ok(actualExecutable.endsWith(executable))
118129
})

test/types.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ test('Type declarations for TypeScript', () => {
1717
darwin: '',
1818
win32: ''
1919
},
20+
targetDirectory: '',
2021
unpackExecutable: true
2122
})
2223
})

0 commit comments

Comments
 (0)