Skip to content

Commit

Permalink
feat: Allow setting the target directory to write ouptut files to
Browse files Browse the repository at this point in the history
  • Loading branch information
prantlf committed Oct 26, 2023
1 parent d45cf4f commit 88b2f14
Show file tree
Hide file tree
Showing 8 changed files with 45 additions and 18 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ interface GrabOptions {
// archive name without the platform suffix; if not specified, it will be
// inferred from the first archive asset found for the current platform
platformSuffixes?: PlatformSuffixes
// directory to write the archive or executable to; if not specified,
// files will be written to the current directory
targetDirectory?: string
// unpack the executable and remove the archive
unpackExecutable?: boolean
}
Expand Down
6 changes: 5 additions & 1 deletion bin/grab-github-release.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Options:
-i|--version-spec <semver> semantic version specifier or "latest"
-n|--name <file-name> archive name without the platform suffix
-p|--platform-suffixes <map> unpack the executable and remove the archive
-t|--target-dir <dir-name> directory to write the output files to
-e|--unpack-exe unpack the executable and remove the archive
-v|--verbose prints extra information on the console
-V|--version print version number and exit
Expand All @@ -31,7 +32,7 @@ function fail(message) {
}

const { argv } = process
let repository, version, name, platformSuffixes, unpackExecutable, verbose
let repository, version, name, platformSuffixes, targetDirectory, unpackExecutable, verbose

for (let i = 2, l = argv.length; i < l; ++i) {
const arg = argv[i]
Expand All @@ -58,6 +59,9 @@ for (let i = 2, l = argv.length; i < l; ++i) {
platformSuffixes[key.trim()] = val.trim()
}
return
case 't': case 'target-dir':
targetDirectory = match[4] || argv[++i]
return
case 'e': case 'unpack-exe':
unpackExecutable = flag
return
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"check-coverage": "true",
"reporter": [
"lcov",
"text-summary"
"text"
],
"branches": 100,
"functions": 100,
Expand Down
2 changes: 1 addition & 1 deletion rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default [
sourcemap: true
}
],
external: ['debug', 'fs', 'os', 'semver', 'stream', 'yauzl'],
external: ['debug', 'fs', 'os', 'path', 'semver', 'stream', 'yauzl'],
plugins: [cleanup()]
}
]
5 changes: 5 additions & 0 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ interface GrabOptions {
* inferred from the first archive asset found for the current platform
*/
platformSuffixes?: PlatformSuffixes
/**
* directory to write the archive or executable to; if not specified,
* files will be written to the current directory
*/
targetDirectory?: string
/**
* unpack the executable and remove the archive
*/
Expand Down
15 changes: 9 additions & 6 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import debug from 'debug'
import { createWriteStream, promises } from 'fs'
import { platform, arch } from 'os'
import { join } from 'path'
import { clean, satisfies, valid } from 'semver'
import { Readable } from 'stream'
import { open as openArchive } from 'yauzl'
Expand Down Expand Up @@ -63,7 +64,7 @@ async function download(url, archive) {
})
}

function unpack(archive) {
function unpack(archive, targetDirectory) {
log('unpack "%s"', archive)
return new Promise((resolve, reject) =>
openArchive(archive, { lazyEntries: true }, (err, zip) => {
Expand All @@ -74,14 +75,15 @@ function unpack(archive) {
const { fileName } = entry
/* c8 ignore next */
if (fileName.endsWith('/')) return new Error('directory in archive')
log('write "%s"', fileName)
const filePath = targetDirectory ? join(targetDirectory, fileName) : fileName
log('write "%s"', filePath)
zip.openReadStream(entry, (err, stream) => {
/* c8 ignore next */
if (err) return reject(err)
stream
.on('error', reject)
.pipe(createWriteStream(fileName))
.on('finish', () => resolve(fileName))
.pipe(createWriteStream(filePath))
.on('finish', () => resolve(filePath))
.on('error', reject)
})
})
Expand All @@ -99,7 +101,7 @@ async function makeExecutable(executable) {
}
}

export default async function grab({ name, repository, version, platformSuffixes, unpackExecutable, verbose }) {
export default async function grab({ name, repository, version, platformSuffixes, targetDirectory, unpackExecutable, verbose }) {
if (verbose) log = console.log.bind(console)
if (!version) version = 'latest'
const verspec = clean(version) || version
Expand All @@ -111,9 +113,10 @@ export default async function grab({ name, repository, version, platformSuffixes
} else {
({ name, version, archive, url } = await getRelease(name, repository, verspec, platformSuffixes))
}
if (targetDirectory) archive = join(targetDirectory, archive)
await download(url, archive)
if (unpackExecutable) {
const executable = await unpack(archive)
const executable = await unpack(archive, targetDirectory)
await makeExecutable(executable)
log('remove "%s"', archive)
await unlink(archive)
Expand Down
29 changes: 20 additions & 9 deletions test/mocked.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { strictEqual } from 'assert'
import { access, readFile, rm } from 'fs/promises'
import { ok, strictEqual } from 'assert'
import { access, mkdir, readFile, rm } from 'fs/promises'
import { after, before, beforeEach, test, mock } from 'node:test'
import { arch, platform } from 'os'
import { dirname, join } from 'path'
Expand All @@ -13,7 +13,7 @@ const __dirname = dirname(fileURLToPath(import.meta.url))

const repository = 'prantlf/v-jsonlint'
const name = 'jsonlint'
const executable = platform() != 'win32' ? name : `${name}.exe`
const executable = join('.', platform() != 'win32' ? name : `${name}.exe`)
const version = '0.0.6'
const platformSuffixes = {
linux: 'linux',
Expand All @@ -25,11 +25,15 @@ const content = new Blob(
[await readFile(join(__dirname, `data/${archive}`))],
{ type: 'applicaiton.zip' }
)
const targetDirectory = join(__dirname, 'tmp')

function cleanup() {
return Promise.all([
async function cleanup() {
// failed on Windows on GitHub
if (platform() == 'win32') return
await Promise.all([
rm(archive, { force: true }),
rm(executable, { force: true })
rm(executable, { force: true }),
rm(targetDirectory, { recursive: true, force: true })
])
}

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

after(async () => {
// failed on Windows on GitHub
if (platform() != 'win32') await cleanup()
await cleanup()
mock.reset()
})

Expand Down Expand Up @@ -114,5 +117,13 @@ test('download archive from the latest implicit version and unpack executable',
if (!await exists(executable)) throw new Error('executable not found')
strictEqual(actualVersion, version)
strictEqual(actualExecutable, executable)
strictEqual(actualExecutable, executable)
})

test('download archive from the latest implicit version and unpack executable to a custom directory', async () => {
await mkdir(targetDirectory, { recursive: true })
const { executable: actualExecutable, version: actualVersion } = await grab(
{ name, repository, platformSuffixes, targetDirectory, unpackExecutable: true })
if (!await exists(actualExecutable)) throw new Error('executable not found')
strictEqual(actualVersion, version)
ok(actualExecutable.endsWith(executable))
})
1 change: 1 addition & 0 deletions test/types.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ test('Type declarations for TypeScript', () => {
darwin: '',
win32: ''
},
targetDirectory: '',
unpackExecutable: true
})
})

0 comments on commit 88b2f14

Please sign in to comment.