Skip to content

Commit

Permalink
Merge pull request #165 from electron/cut-snapshot
Browse files Browse the repository at this point in the history
v1: Cut mksnapshot, update dependencies, promisify
  • Loading branch information
malept committed Feb 19, 2019
2 parents 108fab1 + f567bcf commit 2ec15c1
Show file tree
Hide file tree
Showing 13 changed files with 3,190 additions and 1,321 deletions.
109 changes: 52 additions & 57 deletions bin/asar.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,73 +3,68 @@ var asar = require('../lib/asar')
var program = require('commander')

program.version('v' + require('../package.json').version)
.description('Manipulate asar archive files')
.description('Manipulate asar archive files')

program.command('pack <dir> <output>')
.alias('p')
.description('create asar archive')
.option('--ordering <file path>', 'path to a text file for ordering contents')
.option('--unpack <expression>', 'do not pack files matching glob <expression>')
.option('--unpack-dir <expression>', 'do not pack dirs matching glob <expression> or starting with literal <expression>')
.option('--snapshot', 'create snapshot')
.option('--exclude-hidden', 'exclude hidden files')
.option('--sv <version>', '(snapshot) version of Electron')
.option('--sa <arch>', '(snapshot) arch of Electron')
.option('--sb <builddir>', '(snapshot) where to put downloaded files')
.action(function (dir, output, options) {
options = {
unpack: options.unpack,
unpackDir: options.unpackDir,
snapshot: options.snapshot,
ordering: options.ordering,
version: options.sv,
arch: options.sa,
builddir: options.sb,
dot: !options.excludeHidden
}
asar.createPackageWithOptions(dir, output, options, function (error) {
if (error) {
console.error(error.stack)
process.exit(1)
}
})
})
.alias('p')
.description('create asar archive')
.option('--ordering <file path>', 'path to a text file for ordering contents')
.option('--unpack <expression>', 'do not pack files matching glob <expression>')
.option('--unpack-dir <expression>', 'do not pack dirs matching glob <expression> or starting with literal <expression>')
.option('--exclude-hidden', 'exclude hidden files')
.action(function (dir, output, options) {
options = {
unpack: options.unpack,
unpackDir: options.unpackDir,
ordering: options.ordering,
version: options.sv,
arch: options.sa,
builddir: options.sb,
dot: !options.excludeHidden
}
asar.createPackageWithOptions(dir, output, options, function (error) {
if (error) {
console.error(error.stack)
process.exit(1)
}
})
})

program.command('list <archive>')
.alias('l')
.description('list files of asar archive')
.option('-i, --is-pack', 'each file in the asar is pack or unpack')
.action(function (archive, options) {
options = {
isPack: options.isPack
}
var files = asar.listPackage(archive, options)
for (var i in files) {
console.log(files[i])
}
// This is in order to disappear help
process.exit(0)
})
.alias('l')
.description('list files of asar archive')
.option('-i, --is-pack', 'each file in the asar is pack or unpack')
.action(function (archive, options) {
options = {
isPack: options.isPack
}
var files = asar.listPackage(archive, options)
for (var i in files) {
console.log(files[i])
}
// This is in order to disappear help
process.exit(0)
})

program.command('extract-file <archive> <filename>')
.alias('ef')
.description('extract one file from archive')
.action(function (archive, filename) {
require('fs').writeFileSync(require('path').basename(filename),
asar.extractFile(archive, filename))
})
.alias('ef')
.description('extract one file from archive')
.action(function (archive, filename) {
require('fs').writeFileSync(require('path').basename(filename),
asar.extractFile(archive, filename))
})

program.command('extract <archive> <dest>')
.alias('e')
.description('extract archive')
.action(function (archive, dest) {
asar.extractAll(archive, dest)
})
.alias('e')
.description('extract archive')
.action(function (archive, dest) {
asar.extractAll(archive, dest)
})

program.command('*')
.action(function (cmd) {
console.log('asar: \'%s\' is not an asar command. See \'asar --help\'.', cmd)
})
.action(function (cmd) {
console.log('asar: \'%s\' is not an asar command. See \'asar --help\'.', cmd)
})

program.parse(process.argv)

Expand Down
95 changes: 40 additions & 55 deletions lib/asar.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,39 @@
'use strict'

const pify = require('pify')

const fs = process.versions.electron ? require('original-fs') : require('fs')
const path = require('path')
const minimatch = require('minimatch')
const mkdirp = require('mkdirp')
const mkdirp = pify(require('mkdirp'))

const Filesystem = require('./filesystem')
const disk = require('./disk')
const crawlFilesystem = require('./crawlfs')
const createSnapshot = require('./snapshot')

// Return whether or not a directory should be excluded from packing due to
// "--unpack-dir" option
//
// @param {string} path - diretory path to check
// @param {string} pattern - literal prefix [for backward compatibility] or glob pattern
// @param {array} unpackDirs - Array of directory paths previously marked as unpacked
//
const isUnpackDir = function (path, pattern, unpackDirs) {
if (path.indexOf(pattern) === 0 || minimatch(path, pattern)) {
if (unpackDirs.indexOf(path) === -1) {
unpackDirs.push(path)

/**
* Whether a directory should be excluded from packing due to the `--unpack-dir" option.
*
* @param {string} dirPath - directory path to check
* @param {string} pattern - literal prefix [for backward compatibility] or glob pattern
* @param {array} unpackDirs - Array of directory paths previously marked as unpacked
*/
function isUnpackedDir (dirPath, pattern, unpackDirs) {
if (dirPath.startsWith(pattern) || minimatch(dirPath, pattern)) {
if (!unpackDirs.includes(dirPath)) {
unpackDirs.push(dirPath)
}
return true
} else {
for (let i = 0; i < unpackDirs.length; i++) {
if (path.indexOf(unpackDirs[i]) === 0) {
return true
}
}
return false
return unpackDirs.some(unpackDir => dirPath.startsWith(unpackDir))
}
}

module.exports.createPackage = function (src, dest, callback) {
return module.exports.createPackageWithOptions(src, dest, {}, callback)
module.exports.createPackage = function (src, dest) {
return module.exports.createPackageWithOptions(src, dest, {})
}

module.exports.createPackageWithOptions = function (src, dest, options, callback) {
module.exports.createPackageWithOptions = function (src, dest, options) {
const globOptions = options.globOptions ? options.globOptions : {}
globOptions.dot = options.dot === undefined ? true : options.dot

Expand All @@ -45,10 +42,8 @@ module.exports.createPackageWithOptions = function (src, dest, options, callback
pattern = src + options.pattern
}

return crawlFilesystem(pattern, globOptions, function (error, filenames, metadata) {
if (error) { return callback(error) }
module.exports.createPackageFromFiles(src, dest, filenames, metadata, options, callback)
})
return crawlFilesystem(pattern, globOptions)
.then(([filenames, metadata]) => module.exports.createPackageFromFiles(src, dest, filenames, metadata, options))
}

/*
Expand All @@ -58,9 +53,8 @@ dest: Archive filename (& path).
filenames: Array of filenames relative to src.
metadata: Object with filenames as keys and {type='directory|file|link', stat: fs.stat} as values. (Optional)
options: The options.
callback: The callback function. Accepts (err).
*/
module.exports.createPackageFromFiles = function (src, dest, filenames, metadata, options, callback) {
module.exports.createPackageFromFiles = function (src, dest, filenames, metadata, options) {
if (typeof metadata === 'undefined' || metadata === null) { metadata = {} }
if (typeof options === 'undefined' || options === null) { options = {} }

Expand Down Expand Up @@ -112,67 +106,58 @@ module.exports.createPackageFromFiles = function (src, dest, filenames, metadata
filenamesSorted = filenames
}

const handleFile = function (filename, done) {
const handleFile = function (filename) {
let file = metadata[filename]
let type
if (!file) {
const stat = fs.lstatSync(filename)
if (stat.isDirectory()) { type = 'directory' }
if (stat.isFile()) { type = 'file' }
if (stat.isSymbolicLink()) { type = 'link' }
file = {stat, type}
file = { stat, type }
metadata[filename] = file
}

let shouldUnpack
switch (file.type) {
case 'directory':
shouldUnpack = options.unpackDir
? isUnpackDir(path.relative(src, filename), options.unpackDir, unpackDirs)
: false
if (options.unpackDir) {
shouldUnpack = isUnpackedDir(path.relative(src, filename), options.unpackDir, unpackDirs)
} else {
shouldUnpack = false
}
filesystem.insertDirectory(filename, shouldUnpack)
break
case 'file':
shouldUnpack = false
if (options.unpack) {
shouldUnpack = minimatch(filename, options.unpack, {matchBase: true})
shouldUnpack = minimatch(filename, options.unpack, { matchBase: true })
}
if (!shouldUnpack && options.unpackDir) {
const dirName = path.relative(src, path.dirname(filename))
shouldUnpack = isUnpackDir(dirName, options.unpackDir, unpackDirs)
shouldUnpack = isUnpackedDir(dirName, options.unpackDir, unpackDirs)
}
files.push({filename: filename, unpack: shouldUnpack})
filesystem.insertFile(filename, shouldUnpack, file, options, done)
return
files.push({ filename: filename, unpack: shouldUnpack })
return filesystem.insertFile(filename, shouldUnpack, file, options)
case 'link':
filesystem.insertLink(filename, file.stat)
break
}
return process.nextTick(done)
return Promise.resolve()
}

const insertsDone = function () {
return mkdirp(path.dirname(dest), function (error) {
if (error) { return callback(error) }
return disk.writeFilesystem(dest, filesystem, files, metadata, function (error) {
if (error) { return callback(error) }
if (options.snapshot) {
return createSnapshot(src, dest, filenames, metadata, options, callback)
} else {
return callback(null)
}
})
})
return mkdirp(path.dirname(dest))
.then(() => disk.writeFilesystem(dest, filesystem, files, metadata))
}

const names = filenamesSorted.slice()

const next = function (name) {
if (!name) { return insertsDone() }

return handleFile(name, function () {
return next(names.shift())
})
return handleFile(name)
.then(() => next(names.shift()))
}

return next(names.shift())
Expand Down Expand Up @@ -203,7 +188,7 @@ module.exports.extractAll = function (archive, dest) {
mkdirp.sync(dest)

return filenames.map((filename) => {
filename = filename.substr(1) // get rid of leading slash
filename = filename.substr(1) // get rid of leading slash
const destFilename = path.join(dest, filename)
const file = filesystem.getFile(filename, followLinks)
if (file.files) {
Expand Down
44 changes: 30 additions & 14 deletions lib/crawlfs.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,37 @@
'use strict'
const fs = process.versions.electron ? require('original-fs') : require('fs')
const glob = require('glob')

module.exports = function (dir, options, callback) {
const metadata = {}
return glob(dir, options, function (error, filenames) {
if (error) { return callback(error) }
for (const filename of filenames) {
const stat = fs.lstatSync(filename)
const pify = require('pify')

const fs = pify(process.versions.electron ? require('original-fs') : require('fs'))
const glob = pify(require('glob'))

function determineFileType (filename) {
return fs.lstat(filename)
.then(stat => {
if (stat.isFile()) {
metadata[filename] = {type: 'file', stat: stat}
return [filename, { type: 'file', stat: stat }]
} else if (stat.isDirectory()) {
metadata[filename] = {type: 'directory', stat: stat}
return [filename, { type: 'directory', stat: stat }]
} else if (stat.isSymbolicLink()) {
metadata[filename] = {type: 'link', stat: stat}
return [filename, { type: 'link', stat: stat }]
}

return [filename, undefined]
})
}

module.exports = function (dir, options) {
const metadata = {}
return glob(dir, options)
.then(filenames => Promise.all(filenames.map(filename => determineFileType(filename))))
.then(results => {
const filenames = []
for (const [filename, type] of results) {
filenames.push(filename)
if (type) {
metadata[filename] = type
}
}
}
return callback(null, filenames, metadata)
})
return [filenames, metadata]
})
}
Loading

0 comments on commit 2ec15c1

Please sign in to comment.