-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit c999791
Showing
7 changed files
with
433 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
.idea/ | ||
node_modules/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# glob-zip <a href="https://www.github.com/JanMalch/glob-zip"><img src="https://user-images.githubusercontent.com/25508038/63974103-75242700-caac-11e9-8ca4-71cc5b905e90.png" width="90" height="90" align="right"></a> | ||
|
||
[![npm](https://badgen.net/bpm/v/glob-zip)](https://www.npmjs.com/package/glob-zip) | ||
[![Build](https://github.com/JanMalch/glob-zip/workflows/Build/badge.svg)](https://github.com/JanMalch/glob-zip/workflows/Build) | ||
|
||
_Create zip files based on glob patterns._ | ||
|
||
## Installation | ||
|
||
``` | ||
npm i -g glob-zip | ||
``` | ||
|
||
## Usage | ||
|
||
``` | ||
$ glob-zip --help | ||
Usage: glob-zip [options] <outFile> [globPattern] | ||
Options: | ||
-V, --version output the version number | ||
-g, --glob <pattern> Add a glob pattern | ||
-a, --append Appends to the specified outFile if present (default: false) | ||
-l, --lift <depth> Lift files the given amount of directories for the path in the zip (default: 0) | ||
-w, --wrap [name] Define the root path within the zip, defaults to current directory name if flag is present without value | ||
-F, --no-fail Do not fail when zip would be empty | ||
-E, --no-empty Do not include empty directories | ||
-d, --dry-run Do not write the final zip (default: false) | ||
-v, --verbose Use verbose output (default: false) | ||
-h, --help display help for command | ||
Examples: | ||
$ glob-zip out.zip *.json # easiest usage | ||
$ glob-zip out.zip -g *.json -g *.js # multiple glob patterns | ||
$ glob-zip out.zip src/**/*.js --wrap backup --lift 1 # effectively renames "src" to "backup" in zip | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
const { program } = require('commander'); | ||
const path = require('path'); | ||
const chalk = require('chalk'); | ||
const pkg = require('./package.json'); | ||
const { globZip } = require('.'); | ||
|
||
const globPatterns = new Set(); | ||
let output = null; | ||
|
||
function addGlobPattern(pattern) { | ||
if (pattern != null) { | ||
globPatterns.add(pattern); | ||
} | ||
} | ||
|
||
function resolveWrap(value) { | ||
if (typeof value === 'string') { | ||
return value; | ||
} else { | ||
return path.basename(process.cwd()); | ||
} | ||
} | ||
|
||
// FIXME: change argument usage to "glob-zip [options] <outFile> <pattern> [patterns...]" | ||
|
||
program | ||
.name('glob-zip') | ||
.arguments('<outFile> [globPattern]') | ||
.on('option:verbose', function () { | ||
process.env.VERBOSE = this.verbose; | ||
}) | ||
.on('option:wrap', function (value) { | ||
this.wrap = resolveWrap(value); | ||
}) | ||
.on('--help', () => { | ||
console.log(''); | ||
console.log('Examples:'); | ||
console.log(' $ glob-zip out.zip *.json # easiest usage'); | ||
console.log(' $ glob-zip out.zip *.json --glob="sp ace.txt" -g *.js # three glob patterns'); | ||
console.log(' $ glob-zip out.zip src/**/*.js --wrap backup --lift 1 # effectively renames "src" to "backup" in zip'); | ||
}) | ||
.option('-g, --glob <pattern>', 'Add a glob pattern', addGlobPattern) | ||
.option( | ||
'-w, --wrap [name]', | ||
'Define the root path within the zip, defaults to current directory name if flag is present without value' | ||
) | ||
.option( | ||
'-l, --lift <depth>', | ||
'Lift files the given amount of directories for the path in the zip', | ||
(v) => parseInt(v, 10), | ||
0 | ||
) | ||
.option('-a, --append', 'Appends to the specified outFile if present. If not, a file with the same name would be removed.', false) | ||
.option('-F, --no-fail', 'Do not fail when zip would be empty', false) | ||
.option('-E, --no-empty', 'Do not include empty directories', false) | ||
.option('-d, --dry-run', 'Do not write or delete any files', false) | ||
.option('-v, --verbose', 'Use verbose output', false) | ||
.version(pkg.version) | ||
.action((outFile, globPattern) => { | ||
output = path.resolve(outFile); | ||
addGlobPattern(globPattern); | ||
}); | ||
|
||
program.parse(process.argv); | ||
|
||
if (globPatterns.size === 0) { | ||
console.error('error: no glob patterns defined'); | ||
process.exit(1); | ||
} | ||
|
||
if (process.env.VERBOSE) { | ||
console.log(`using ${chalk.blue( | ||
globPatterns.size.toString(10) | ||
)} glob pattern${globPatterns.size === 1 ? '' : 's'}: | ||
${Array.from(globPatterns.values()) | ||
.map((p) => chalk.green(p)) | ||
.join('\n ')} | ||
`); | ||
} | ||
|
||
const prettyPrintSrcDest = (src, dest) => { | ||
const srcCwdPart = src.substring(0, process.cwd().length + 1); | ||
const srcFilePart = src.substring(srcCwdPart.length); | ||
const destCwdPart = path.dirname(output); | ||
const destFilePart = path.basename(output); | ||
|
||
console.log( | ||
chalk.blue(dest.endsWith(path.sep) ? 'empty dir:' : 'file:'), | ||
chalk.gray(srcCwdPart) + chalk.green(srcFilePart), | ||
'->', | ||
( | ||
chalk.gray(destCwdPart + path.sep) + | ||
destFilePart + path.sep + | ||
chalk.green(dest.startsWith(path.sep) ? dest.substring(1) : dest) | ||
) | ||
); | ||
}; | ||
|
||
try { | ||
globZip({ | ||
...program, | ||
outFile: output, | ||
globPatterns, | ||
fileInfoCallback: process.env.VERBOSE ? prettyPrintSrcDest : undefined, | ||
}); | ||
} catch (e) { | ||
console.error('error:', e.message); | ||
process.exit(1); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
export interface GlobZipOptions { | ||
outFile: string; | ||
globPatterns: string | string[] | Set<string>; | ||
append?: boolean; | ||
fail?: boolean; | ||
empty?: boolean; | ||
wrap?: string; | ||
dryRun?: boolean; | ||
lift?: number; | ||
fileInfoCallback?: (src: string, dest: string) => void; | ||
} | ||
|
||
export declare function globZip(options: GlobZipOptions, callback?: () => void); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
const { glob } = require('glob'); | ||
const path = require('path'); | ||
const fs = require('fs'); | ||
const AdmZip = require('adm-zip'); | ||
|
||
|
||
module.exports.globZip = function ( | ||
{ | ||
outFile, | ||
globPatterns: _globPatterns, | ||
append, | ||
fail: failIfZipEmpty, | ||
empty: includeEmptyDirectories, | ||
wrap, | ||
dryRun, | ||
lift, | ||
fileInfoCallback = () => { | ||
}, | ||
}, | ||
callback = () => {} | ||
) { | ||
let globPatterns; | ||
if (_globPatterns instanceof Set) { | ||
globPatterns = _globPatterns; | ||
} else if (typeof _globPatterns === 'string') { | ||
globPatterns = new Set([_globPatterns]); | ||
} else if (Array.isArray(_globPatterns)) { | ||
globPatterns = new Set(_globPatterns); | ||
} else { | ||
throw new TypeError(`cannot use given globPatterns`); | ||
} | ||
|
||
const files = Array.from(globPatterns.values()).reduce( | ||
(acc, p) => acc.concat(glob.sync(p, { dot: true })), | ||
[] | ||
); | ||
|
||
if (!dryRun && fs.existsSync(outFile) && append !== true) { | ||
fs.unlinkSync(outFile); | ||
} | ||
|
||
const zip = | ||
append === true && fs.existsSync(outFile) | ||
? new AdmZip(outFile) | ||
: new AdmZip(); | ||
|
||
const prefix = | ||
wrap == null ? '' : wrap.endsWith(path.sep) ? wrap : wrap + path.sep; | ||
|
||
files.forEach((file) => { | ||
const segments = path.normalize(file).split(path.sep); | ||
if (segments.length <= lift) { | ||
throw new Error( | ||
`cannot lift '${file}' ${lift} directories (${ | ||
lift + 1 - segments.length | ||
} too many)` | ||
); | ||
} | ||
const srcPath = path.resolve(process.cwd(), file); | ||
const destPath = prefix + segments.slice(lift, -1).join(path.sep); | ||
const destPathWithName = | ||
destPath + path.sep + segments[segments.length - 1]; | ||
if (fs.lstatSync(srcPath).isDirectory()) { | ||
if (includeEmptyDirectories && fs.readdirSync(srcPath).length === 0) { | ||
zip.addFile(destPathWithName + path.sep, Buffer.alloc(0)); | ||
fileInfoCallback(srcPath + path.sep, destPathWithName + path.sep); | ||
} | ||
} else { | ||
zip.addLocalFile(srcPath, destPath); | ||
fileInfoCallback(srcPath, destPathWithName); | ||
} | ||
}); | ||
|
||
if (failIfZipEmpty && zip.getEntries().length === 0) { | ||
throw new Error('no files found'); | ||
} | ||
|
||
if (!dryRun) { | ||
zip.writeZip(outFile, callback); | ||
} else { | ||
callback(); | ||
} | ||
}; |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.