Skip to content

Commit

Permalink
Merge pull request #477 from malept/sanitize-out-ignores
Browse files Browse the repository at this point in the history
Sanitize ignores created when the output dir resolves to CWD
  • Loading branch information
malept authored Sep 1, 2016
2 parents 53bbb83 + 18187c8 commit bc0085d
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 96 deletions.
51 changes: 2 additions & 49 deletions common.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const asar = require('asar')
const child = require('child_process')
const debug = require('debug')('electron-packager')
const fs = require('fs-extra')
const ignore = require('./ignore')
const minimist = require('minimist')
const os = require('os')
const path = require('path')
Expand Down Expand Up @@ -99,54 +100,6 @@ function subOptionWarning (properties, optionName, parameter, value) {
properties[parameter] = value
}

function userIgnoreFilter (opts) {
var ignore = opts.ignore || []
var ignoreFunc = null

if (typeof (ignore) === 'function') {
ignoreFunc = function (file) { return !ignore(file) }
} else {
if (!Array.isArray(ignore)) ignore = [ignore]

ignoreFunc = function filterByRegexes (file) {
for (var i = 0; i < ignore.length; i++) {
if (file.match(ignore[i])) {
return false
}
}

return true
}
}

var normalizedOut = opts.out ? path.resolve(opts.out) : null
var outIgnores = []
if (normalizedOut === null || normalizedOut === process.cwd()) {
platforms.forEach(function (platform) {
archs.forEach(function (arch) {
outIgnores.push(path.join(process.cwd(), `${opts.name}-${platform}-${arch}`))
})
})
} else {
outIgnores.push(normalizedOut)
}

return function filter (file) {
if (outIgnores.indexOf(file) !== -1) {
return false
}

var name = file.split(path.resolve(opts.dir))[1]

if (path.sep === '\\') {
// convert slashes so unix-format ignores work
name = name.replace(/\\/g, '/')
}

return ignoreFunc(name)
}
}

function createAsarOpts (opts) {
let asarOptions
if (opts.asar === true) {
Expand Down Expand Up @@ -223,7 +176,7 @@ module.exports = {
shouldDeref = opts.derefSymlinks
}

fs.copy(opts.dir, appPath, {filter: userIgnoreFilter(opts), dereference: shouldDeref}, cb)
fs.copy(opts.dir, appPath, {filter: ignore.userIgnoreFilter(opts), dereference: shouldDeref}, cb)
},
function (cb) {
var afterCopyHooks = (opts.afterCopy || []).map(function (afterCopyFn) {
Expand Down
91 changes: 91 additions & 0 deletions ignore.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
'use strict'

const debug = require('debug')('electron-packager')
const path = require('path')

const DEFAULT_IGNORES = [
'/node_modules/electron($|/)',
'/node_modules/electron-prebuilt($|/)',
'/node_modules/electron-packager($|/)',
'/\\.git($|/)',
'/node_modules/\\.bin($|/)'
]

function generateIgnores (opts) {
if (typeof (opts.ignore) !== 'function') {
if (opts.ignore && !Array.isArray(opts.ignore)) opts.ignore = [opts.ignore]
opts.ignore = (opts.ignore) ? opts.ignore.concat(DEFAULT_IGNORES) : DEFAULT_IGNORES

debug('Ignored path regular expressions:', opts.ignore)
}
}

function generateOutIgnores (opts) {
// Avoid a circular require that breaks things
const common = require('./common')

let normalizedOut = opts.out ? path.resolve(opts.out) : null
let outIgnores = []
if (normalizedOut === null || normalizedOut === process.cwd()) {
for (let platform of common.platforms) {
for (let arch of common.archs) {
let basenameOpts = {
arch: arch,
name: opts.name,
platform: platform
}
outIgnores.push(path.join(process.cwd(), common.generateFinalBasename(basenameOpts)))
}
}
} else {
outIgnores.push(normalizedOut)
}

debug('Ignored paths based on the out param:', outIgnores)

return outIgnores
}

function userIgnoreFilter (opts) {
var ignore = opts.ignore || []
var ignoreFunc = null

if (typeof (ignore) === 'function') {
ignoreFunc = file => { return !ignore(file) }
} else {
if (!Array.isArray(ignore)) ignore = [ignore]

ignoreFunc = function filterByRegexes (file) {
for (var i = 0; i < ignore.length; i++) {
if (file.match(ignore[i])) {
return false
}
}

return true
}
}

let outIgnores = generateOutIgnores(opts)

return function filter (file) {
if (outIgnores.indexOf(file) !== -1) {
return false
}

var name = file.split(path.resolve(opts.dir))[1]

if (path.sep === '\\') {
// convert slashes so unix-format ignores work
name = name.replace(/\\/g, '/')
}

return ignoreFunc(name)
}
}

module.exports = {
generateIgnores: generateIgnores,
generateOutIgnores: generateOutIgnores,
userIgnoreFilter: userIgnoreFilter
}
17 changes: 2 additions & 15 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const download = require('electron-download')
const extract = require('extract-zip')
const fs = require('fs-extra')
const getPackageInfo = require('get-package-info')
const ignore = require('./ignore')
const metadata = require('./package.json')
const os = require('os')
const path = require('path')
Expand Down Expand Up @@ -250,21 +251,7 @@ module.exports = function packager (opts, cb) {
debug(`Application name: ${opts.name}`)
debug(`Target Electron version: ${opts.version}`)

// Ignore this and related modules by default
var defaultIgnores = [
'/node_modules/electron($|/)',
'/node_modules/electron-prebuilt($|/)',
'/node_modules/electron-packager($|/)',
'/\\.git($|/)',
'/node_modules/\\.bin($|/)'
]

if (typeof (opts.ignore) !== 'function') {
if (opts.ignore && !Array.isArray(opts.ignore)) opts.ignore = [opts.ignore]
opts.ignore = (opts.ignore) ? opts.ignore.concat(defaultIgnores) : defaultIgnores

debug(`Ignored path regular expressions:\n${opts.ignore.map(function (ignore) { return `* ${ignore}` }).join('\n')}`)
}
ignore.generateIgnores(opts)

series(createSeries(opts, archs, platforms), function (err, appPaths) {
if (err) return cb(err)
Expand Down
76 changes: 44 additions & 32 deletions test/ignore.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
const common = require('../common')
const config = require('./config.json')
const fs = require('fs-extra')
const ignore = require('../ignore')
const path = require('path')
const packager = require('..')
const series = require('run-series')
const test = require('tape')
const util = require('./util')
const waterfall = require('run-waterfall')

function createIgnoreTest (opts, ignorePattern, ignoredFile) {
return function (t) {
return (t) => {
t.timeoutAfter(config.timeout)

opts.name = 'basicTest'
Expand All @@ -20,26 +22,26 @@ function createIgnoreTest (opts, ignorePattern, ignoredFile) {
var appPath

waterfall([
function (cb) {
(cb) => {
packager(opts, cb)
}, function (paths, cb) {
}, (paths, cb) => {
appPath = path.join(paths[0], util.generateResourcesPath(opts), 'app')
fs.stat(path.join(appPath, 'package.json'), cb)
}, function (stats, cb) {
}, (stats, cb) => {
t.true(stats.isFile(), 'The expected output directory should exist and contain files')
fs.exists(path.join(appPath, ignoredFile), function (exists) {
fs.exists(path.join(appPath, ignoredFile), exists => {
t.false(exists, 'Ignored file should not exist in output app directory')
cb()
})
}
], function (err) {
], (err) => {
t.end(err)
})
}
}

function createIgnoreOutDirTest (opts, distPath) {
return function (t) {
return (t) => {
t.timeoutAfter(config.timeout)

opts.name = 'basicTest'
Expand All @@ -51,39 +53,41 @@ function createIgnoreOutDirTest (opts, distPath) {
opts.out = outDir

series([
function (cb) {
fs.copy(util.fixtureSubdir('basic'), appDir, {dereference: true, stopOnErr: true, filter: function (file) {
return path.basename(file) !== 'node_modules'
}}, cb)
(cb) => {
fs.copy(util.fixtureSubdir('basic'), appDir, {
dereference: true,
stopOnErr: true,
filter: file => { return path.basename(file) !== 'node_modules' }
}, cb)
},
function (cb) {
(cb) => {
// create out dir before packager (real world issue - when second run includes uningnored out dir)
fs.mkdirp(outDir, cb)
},
function (cb) {
(cb) => {
// create file to ensure that directory will be not ignored because empty
fs.open(path.join(outDir, 'ignoreMe'), 'w', function (err, fd) {
fs.open(path.join(outDir, 'ignoreMe'), 'w', (err, fd) => {
if (err) return cb(err)
fs.close(fd, cb)
})
},
function (cb) {
(cb) => {
packager(opts, cb)
},
function (cb) {
fs.exists(path.join(outDir, common.generateFinalBasename(opts), util.generateResourcesPath(opts), 'app', path.basename(outDir)), function (exists) {
(cb) => {
fs.exists(path.join(outDir, common.generateFinalBasename(opts), util.generateResourcesPath(opts), 'app', path.basename(outDir)), (exists) => {
t.false(exists, 'Out dir must not exist in output app directory')
cb()
})
}
], function (err) {
], (err) => {
t.end(err)
})
}
}

function createIgnoreImplicitOutDirTest (opts) {
return function (t) {
return (t) => {
t.timeoutAfter(config.timeout)

opts.name = 'basicTest'
Expand All @@ -96,43 +100,51 @@ function createIgnoreImplicitOutDirTest (opts) {
var previousPackedResultDir

series([
function (cb) {
fs.copy(util.fixtureSubdir('basic'), appDir, {dereference: true, stopOnErr: true, filter: function (file) {
return path.basename(file) !== 'node_modules'
}}, cb)
(cb) => {
fs.copy(util.fixtureSubdir('basic'), appDir, {
dereference: true,
stopOnErr: true,
filter: file => { return path.basename(file) !== 'node_modules' }
}, cb)
},
function (cb) {
previousPackedResultDir = path.join(outDir, `${opts.name}-linux-ia32`)
(cb) => {
previousPackedResultDir = path.join(outDir, `${common.sanitizeAppName(opts.name)}-linux-ia32`)
fs.mkdirp(previousPackedResultDir, cb)
},
function (cb) {
(cb) => {
// create file to ensure that directory will be not ignored because empty
fs.open(path.join(previousPackedResultDir, testFilename), 'w', function (err, fd) {
fs.open(path.join(previousPackedResultDir, testFilename), 'w', (err, fd) => {
if (err) return cb(err)
fs.close(fd, cb)
})
},
function (cb) {
(cb) => {
packager(opts, cb)
},
function (cb) {
fs.exists(path.join(outDir, common.generateFinalBasename(opts), util.generateResourcesPath(opts), 'app', testFilename), function (exists) {
(cb) => {
fs.exists(path.join(outDir, common.generateFinalBasename(opts), util.generateResourcesPath(opts), 'app', testFilename), (exists) => {
t.false(exists, 'Out dir must not exist in output app directory')
cb()
})
}
], function (err) {
], (err) => {
t.end(err)
})
}
}

test('generateOutIgnores ignores all possible platform/arch permutations', (t) => {
let ignores = ignore.generateOutIgnores({name: 'test'})
t.equal(ignores.length, common.platforms.length * common.archs.length)
t.end()
})

util.testSinglePlatform('ignore test: string in array', createIgnoreTest, ['ignorethis'],
'ignorethis.txt')
util.testSinglePlatform('ignore test: string', createIgnoreTest, 'ignorethis', 'ignorethis.txt')
util.testSinglePlatform('ignore test: RegExp', createIgnoreTest, /ignorethis/, 'ignorethis.txt')
util.testSinglePlatform('ignore test: Function', createIgnoreTest,
function (file) { return file.match(/ignorethis/) }, 'ignorethis.txt')
file => { return file.match(/ignorethis/) }, 'ignorethis.txt')
util.testSinglePlatform('ignore test: string with slash', createIgnoreTest, 'ignore/this',
path.join('ignore', 'this.txt'))
util.testSinglePlatform('ignore test: only match subfolder of app', createIgnoreTest,
Expand Down

0 comments on commit bc0085d

Please sign in to comment.