Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add includeBaseDirectory param to zip & zipSync #28

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export function zip (input: string, output: string, cb?: (err: Error | null) => void): void;
export function zip (input: string, output: string, includeBaseDirectory: boolean, cb?: (err: Error | null) => void): void;

export function zipSync (input: string, output: string, includeBaseDirectory?: boolean): void;

export function unzip (input: string, output: string, cb?: (err: Error | null) => void): void;

export function unzipSync (input: string, output: string): void;
123 changes: 72 additions & 51 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,74 +11,75 @@ var fs = require('fs')
var os = require('os')
var path = require('path')

function zip (inPath, outPath, cb) {
if (!cb) cb = function () {}
if (process.platform === 'win32') {
fs.stat(inPath, function (err, stats) {
if (err) return cb(err)
if (stats.isFile()) {
copyToTemp()
} else {
doZip()
}
})
function zip (inPath, outPath, includeBaseDirectory, cb) {
if (typeof includeBaseDirectory === 'boolean') {
if (!cb) cb = function () {}
} else if (typeof includeBaseDirectory === 'function') {
cb = includeBaseDirectory
includeBaseDirectory = false
} else {
doZip()
includeBaseDirectory = arguments.length === 2 ? false : !!includeBaseDirectory
if (!cb) cb = function () {}
}

// Windows zip command cannot zip files, only directories. So move the file into
// a temporary directory before zipping.
fs.stat(inPath, function (err, stats) {
if (err) return cb(err)
if (stats.isFile()) {
includeBaseDirectory = false
copyToTemp()
} else {
doZip()
}
})

function copyToTemp () {
fs.readFile(inPath, function (err, inFile) {
var tmpPath = path.join(os.tmpdir(), 'cross-zip-' + Date.now())
fs.mkdir(tmpPath, { recursive: true }, function (err) {
if (err) return cb(err)
var tmpPath = path.join(os.tmpdir(), 'cross-zip-' + Date.now())
fs.mkdir(tmpPath, function (err) {
fs.copyFile(inPath, path.join(tmpPath, path.basename(inPath)), function (err) {
if (err) return cb(err)
fs.writeFile(path.join(tmpPath, path.basename(inPath)), inFile, function (err) {
if (err) return cb(err)
inPath = tmpPath
doZip()
})

inPath = tmpPath
doZip()
})
})
}

// Windows zip command does not overwrite existing files. So do it manually first.
function doZip () {
if (process.platform === 'win32') {
fs.rmdir(outPath, { recursive: true, maxRetries: 3 }, doZip2)
} else {
doZip2()
}
fs.rmdir(outPath, { recursive: true, maxRetries: 3 }, doZip2)
}

function doZip2 () {
const { args, cwd } = getZipArgs(inPath, outPath, includeBaseDirectory)
var opts = {
cwd: path.dirname(inPath),
cwd: cwd,
maxBuffer: Infinity
}
cp.execFile(getZipCommand(), getZipArgs(inPath, outPath), opts, function (err) {
cp.execFile(getZipCommand(), args, opts, function (err) {
cb(err)
})
}
}

function zipSync (inPath, outPath) {
if (process.platform === 'win32') {
if (fs.statSync(inPath).isFile()) {
var inFile = fs.readFileSync(inPath)
var tmpPath = path.join(os.tmpdir(), 'cross-zip-' + Date.now())
fs.mkdirSync(tmpPath)
fs.writeFileSync(path.join(tmpPath, path.basename(inPath)), inFile)
inPath = tmpPath
}
fs.rmdirSync(outPath, { recursive: true, maxRetries: 3 })
function zipSync (inPath, outPath, includeBaseDirectory) {
includeBaseDirectory = !!includeBaseDirectory

if (fs.statSync(inPath).isFile()) {
includeBaseDirectory = false
var tmpPath = path.join(os.tmpdir(), 'cross-zip-' + Date.now())
fs.mkdirSync(tmpPath, { recursive: true })
fs.copyFileSync(inPath, path.join(tmpPath, path.basename(inPath)))
inPath = tmpPath
}
fs.rmdirSync(outPath, { recursive: true, maxRetries: 3 })

const { args, cwd } = getZipArgs(inPath, outPath, includeBaseDirectory)
var opts = {
cwd: path.dirname(inPath),
cwd: cwd,
maxBuffer: Infinity
}
cp.execFileSync(getZipCommand(), getZipArgs(inPath, outPath), opts)
cp.execFileSync(getZipCommand(), args, opts)
}

function unzip (inPath, outPath, cb) {
Expand Down Expand Up @@ -118,18 +119,38 @@ function quotePath (pathToTransform) {
return '"' + pathToTransform + '"'
}

function getZipArgs (inPath, outPath) {
/**
* @param {string} inPath
* @param {string} outPath
* @param {boolean} includeBaseDirectory
* @returns {{ args: string[]; cwd: string }}
*/
function getZipArgs (inPath, outPath, includeBaseDirectory) {
if (process.platform === 'win32') {
return [
'-nologo',
'-noprofile',
'-command', '& { param([String]$myInPath, [String]$myOutPath); Add-Type -A "System.IO.Compression.FileSystem"; [IO.Compression.ZipFile]::CreateFromDirectory($myInPath, $myOutPath); exit !$? }',
'-myInPath', quotePath(inPath),
'-myOutPath', quotePath(outPath)
]
return {
args: [
'-nologo',
'-noprofile',
'-command', '& { param([String]$myInPath, [String]$myOutPath, [Boolean]$includeBaseDirectory); Add-Type -A "System.IO.Compression.FileSystem"; [IO.Compression.ZipFile]::CreateFromDirectory($myInPath, $myOutPath, [IO.Compression.CompressionLevel]::Fastest, $includeBaseDirectory); exit !$? }',
'-myInPath', quotePath(inPath),
'-myOutPath', quotePath(outPath),
'-includeBaseDirectory', `$${!!includeBaseDirectory}`
],
cwd: process.cwd()
}
} else {
var fileName = path.basename(inPath)
return ['-r', '-y', outPath, fileName]
if (includeBaseDirectory) {
const dir = path.dirname(inPath)
const fileName = path.basename(inPath)
return {
args: ['-r', '-y', outPath, fileName],
cwd: dir
}
}
return {
args: ['-r', '-y', outPath, '.'],
cwd: inPath
}
}
}

Expand Down
71 changes: 71 additions & 0 deletions test/zip.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ var zip = require('../')

var filePath = path.join(__dirname, 'content', 'file.txt')
var tmpPath = path.join(__dirname, 'tmp')
var contentPath = path.join(__dirname, 'content')
var tmpContentPath = path.join(__dirname, 'tmp', 'content')

fs.mkdirSync(tmpPath, { recursive: true })

Expand All @@ -20,6 +22,23 @@ test('zipSync', function (t) {
var file = fs.readFileSync(filePath)

t.deepEqual(tmpFile, file)

var contentZipPathIncludeParentFolder = path.join(tmpPath, 'file2.zip')
zip.zipSync(contentPath, contentZipPathIncludeParentFolder, true)
zip.unzipSync(contentZipPathIncludeParentFolder, tmpPath)
t.ok(fs.existsSync(tmpContentPath) && fs.statSync(tmpContentPath).isDirectory())
t.deepEqual(fs.readFileSync(path.join(tmpContentPath, 'file.txt')), file)
fs.rmdirSync(tmpContentPath, { recursive: true })
fs.rmdirSync(contentZipPathIncludeParentFolder, { recursive: true })

var contentZipPathWithoutParentFolder = path.join(tmpPath, 'file3.zip')
zip.zipSync(contentPath, contentZipPathWithoutParentFolder)
zip.unzipSync(contentZipPathWithoutParentFolder, path.join(tmpPath, 'file3'))
t.ok(!fs.existsSync(tmpContentPath))
t.deepEqual(fs.readFileSync(path.join(tmpPath, 'file3/file.txt')), file)
fs.rmdirSync(contentZipPathWithoutParentFolder, { recursive: true })
fs.rmdirSync(path.join(tmpPath, 'file3'), { recursive: true })

t.end()
})

Expand All @@ -45,3 +64,55 @@ test('zip', function (t) {
})
})
})

test('zip dir with parent folder', function (t) {
t.plan(6)

var contentZipPathIncludeParentFolder = path.join(tmpPath, 'file2.zip')
zip.zip(contentPath, contentZipPathIncludeParentFolder, true, function (err) {
t.error(err)

zip.unzip(contentZipPathIncludeParentFolder, tmpPath, function (err) {
t.error(err)

t.ok(fs.existsSync(tmpContentPath) && fs.statSync(tmpContentPath).isDirectory())
var file = fs.readFileSync(filePath)
t.deepEqual(fs.readFileSync(path.join(tmpContentPath, 'file.txt')), file)
fs.rmdir(tmpContentPath, { recursive: true }, function (err) {
t.error(err)

fs.rmdir(contentZipPathIncludeParentFolder, { recursive: true }, function (err) {
t.error(err)
})
})
})
})
})

test('zip dir without parent folder', function (t) {
t.plan(7)

var contentZipPathWithoutParentFolder = path.join(tmpPath, 'file3.zip')
zip.zip(contentPath, contentZipPathWithoutParentFolder, function (err) {
t.error(err)

zip.unzip(contentZipPathWithoutParentFolder, path.join(tmpPath, 'file3'), function (err) {
t.error(err)

t.ok(!fs.existsSync(tmpContentPath))
var file = fs.readFileSync(filePath)
t.deepEqual(fs.readFileSync(path.join(tmpPath, 'file3/file.txt')), file)
fs.rmdir(tmpContentPath, { recursive: true }, function (err) {
t.error(err)

fs.rmdir(contentZipPathWithoutParentFolder, { recursive: true }, function (err) {
t.error(err)

fs.rmdir(path.join(tmpPath, 'file3'), { recursive: true }, function (err) {
t.error(err)
})
})
})
})
})
})