diff --git a/README.md b/README.md index bc91ae89c..07ca555a6 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ You can create a `component.json` file in your project's root, specifying all of Put this under your project's root, listing all of your dependencies. When you run `bower install`, Bower will read this `component.json` file, resolve all the relevant dependencies and install them. -For now, `name`, `version`, `main`, and `dependencies` are the only properties that are used by Bower. If you have several files you're distributing as part of your package, pass an array to `main` like this: +For now, `name`, `version`, `main`, `dependencies`, and `ignore` are the only properties that are used by Bower. If you have several files you're distributing as part of your package, pass an array to `main` like this: ```json { @@ -133,14 +133,27 @@ For now, `name`, `version`, `main`, and `dependencies` are the only properties t Bower only recognizes versions that follow the [semver](http://semver.org/) specification. There should only be at most one file per file type in the `main` list. So only one `.js` or `.css`. -You can also point to packages by adding their URL or file path in the dependency's property, just like. +You can also point to packages by adding their URL or file path in the dependency's property. ```json -"dependencies": { - "eventEmitter": "Wolfy87/EventEmitter", // GitHub short URL - "eventEmitter": "Wolfy87/EventEmitter#>=3", // with version - "eventEmitter": "git://github.com/Wolfy87/EventEmitter", - "eventEmitter": "git@github.com:Wolfy87/EventEmitter.git" +{ + "dependencies": { + "eventEmitter": "Wolfy87/EventEmitter", // GitHub short URL + "eventEmitter": "Wolfy87/EventEmitter#>=3", // with version + "eventEmitter": "git://github.com/Wolfy87/EventEmitter", + "eventEmitter": "git@github.com:Wolfy87/EventEmitter.git" + } +} +``` + +Chances are you have a bunch of extra stuff in the repo that are not needed in production. List these non-necessary file paths in `ignore`. + +```json +{ + "ignore": [ + "tests/", + "**/*.txt" + ] } ``` diff --git a/lib/core/package.js b/lib/core/package.js index 50ae0fa54..bd950e24d 100644 --- a/lib/core/package.js +++ b/lib/core/package.js @@ -21,6 +21,7 @@ var async = require('async'); var https = require('https'); var http = require('http'); var path = require('path'); +var glob = require('glob'); var url = require('url'); var tmp = require('tmp'); var fs = require('fs'); @@ -237,10 +238,51 @@ Package.prototype.cleanUpLocal = function () { fs.writeFile(path.join(this.localPath, this.localConfig.json), jsonStr); if (this.gitUrl || this.gitPath) fs.writeFile(path.join(this.gitPath, this.localConfig.json), jsonStr); - rimraf(path.join(this.localPath, '.git'), this.emit.bind(this, 'install')); + this.removeLocalPaths(); }.bind(this)).readLocalConfig(); }; +// finish clean up local by removing .git/ and any ignored files +Package.prototype.removeLocalPaths = function () { + var removePatterns = ['.git']; + if (this.json.ignore) { + removePatterns.push.apply(removePatterns, this.json.ignore); + } + + var removePaths = []; + + // 3: done + var pathsRemoved = function (err) { + if (err) return this.emit('error', err); + this.emit('install'); + }.bind(this); + + // 2: trigger after paths have been globbed + var rimrafPaths = function (err) { + if (err) return this.emit('error', err); + async.forEach(removePaths, function (removePath, next) { + // rimraf all the paths + rimraf(removePath, function (err) { + if (err) return this.emit('error', err); + next(); + }.bind(this)); + // finished callback + }.bind(this), pathsRemoved); + }.bind(this); + + // 1: get paths + var globOpts = { dot: true }; + async.forEach(removePatterns, function (removePattern, next) { + // glob path for file path pattern matching + var globPattern = path.join(this.localPath, removePattern); + glob(globPattern, globOpts, function (err, globPaths) { + if (err) return this.emit('error', err); + removePaths = removePaths.concat(globPaths); + next(); + }.bind(this)); + }.bind(this), rimrafPaths); +}; + Package.prototype.generateAssetJSON = function () { return { name: this.name, diff --git a/test/assets/package-ignorables/.casey b/test/assets/package-ignorables/.casey new file mode 100644 index 000000000..f5f35a378 --- /dev/null +++ b/test/assets/package-ignorables/.casey @@ -0,0 +1 @@ +Casey Jones diff --git a/test/assets/package-ignorables/.hide/turtle-location.mdown b/test/assets/package-ignorables/.hide/turtle-location.mdown new file mode 100644 index 000000000..5eea78164 --- /dev/null +++ b/test/assets/package-ignorables/.hide/turtle-location.mdown @@ -0,0 +1 @@ +NYC Sewer System diff --git a/test/assets/package-ignorables/component.json b/test/assets/package-ignorables/component.json new file mode 100644 index 000000000..29df483ef --- /dev/null +++ b/test/assets/package-ignorables/component.json @@ -0,0 +1,12 @@ +{ + "name": "turtles", + "version": "0.0.1", + "dependencies": {}, + "ignore": [ + "test/", + "**/*.txt", + "config/**/*", + ".casey", + "**/turtle-location*" + ] +} diff --git a/test/assets/package-ignorables/config/.jshintrc b/test/assets/package-ignorables/config/.jshintrc new file mode 100644 index 000000000..77a940634 --- /dev/null +++ b/test/assets/package-ignorables/config/.jshintrc @@ -0,0 +1,3 @@ +{ + "asi": false +} diff --git a/test/assets/package-ignorables/don.txt b/test/assets/package-ignorables/don.txt new file mode 100644 index 000000000..042a139b4 --- /dev/null +++ b/test/assets/package-ignorables/don.txt @@ -0,0 +1 @@ +Donatello diff --git a/test/assets/package-ignorables/index.js b/test/assets/package-ignorables/index.js new file mode 100644 index 000000000..4694cda55 --- /dev/null +++ b/test/assets/package-ignorables/index.js @@ -0,0 +1,7 @@ +/** + * after bower install, this packge should not have *.txt or test/ + */ +(function () { + // heroes in a half shell + console.log('turtle power'); +})(); diff --git a/test/assets/package-ignorables/leo.txt b/test/assets/package-ignorables/leo.txt new file mode 100644 index 000000000..266e524ef --- /dev/null +++ b/test/assets/package-ignorables/leo.txt @@ -0,0 +1 @@ +Leonardo diff --git a/test/assets/package-ignorables/lib/april.txt b/test/assets/package-ignorables/lib/april.txt new file mode 100644 index 000000000..83deb68d8 --- /dev/null +++ b/test/assets/package-ignorables/lib/april.txt @@ -0,0 +1 @@ +April wears yellow. diff --git a/test/assets/package-ignorables/names.txt b/test/assets/package-ignorables/names.txt new file mode 100644 index 000000000..3a43c454b --- /dev/null +++ b/test/assets/package-ignorables/names.txt @@ -0,0 +1,4 @@ +Leonardo +Donatello +Raphael +Michelangelo diff --git a/test/assets/package-ignorables/test/shredder.js b/test/assets/package-ignorables/test/shredder.js new file mode 100644 index 000000000..3de674727 --- /dev/null +++ b/test/assets/package-ignorables/test/shredder.js @@ -0,0 +1,3 @@ +(function () { + return 'Shredder'; +})(); diff --git a/test/assets/package-ignorables/test/splinter.js b/test/assets/package-ignorables/test/splinter.js new file mode 100644 index 000000000..b6ddd019c --- /dev/null +++ b/test/assets/package-ignorables/test/splinter.js @@ -0,0 +1,3 @@ +(function () { + return 'Splinter'; +})(); diff --git a/test/package.js b/test/package.js index c0d297388..40923d9c1 100644 --- a/test/package.js +++ b/test/package.js @@ -2,9 +2,11 @@ var assert = require('assert'); var fs = require('fs'); +var path = require('path'); var nock = require('nock'); var _ = require('lodash'); var rimraf = require('rimraf'); +var glob = require('glob'); var async = require('async'); var config = require('../lib/core/config'); var Package = require('../lib/core/package'); @@ -518,4 +520,66 @@ describe('package', function () { pkg.resolve(); }); + + it('Should remove ignored filepaths', function (next) { + var pkg = new Package('turtles', __dirname + '/assets/package-ignorables'); + + pkg.on('resolve', function () { + pkg.install(); + }); + + pkg.on('error', function (err) { + throw new Error(err); + }); + + var pkgInstallPath = path.join(__dirname, '/../components/turtles/'); + pkg.on('install', function () { + // these files should have been deleted + assert(!fs.existsSync(pkgInstallPath + 'don.txt')); + assert(!fs.existsSync(pkgInstallPath + 'leo.txt')); + assert(!fs.existsSync(pkgInstallPath + '/test/')); + // ignored dot files + assert(!fs.existsSync(pkgInstallPath + '/config/.jshintrc')); + assert(!fs.existsSync(pkgInstallPath + '.casey')); + assert(!fs.existsSync(pkgInstallPath + '.hide/turtle-location.mdown')); + // this file should still be there + assert(fs.existsSync(pkgInstallPath + 'index.js')); + // all ignore file pattern should be removed + async.forEach(pkg.json.ignore, function (ignorePattern, asyncNext) { + var pattern = path.join(__dirname, '/../components/turtles/' + ignorePattern); + glob(pattern, function (err, globPath) { + assert(globPath.length === 0); + asyncNext(); + }); + }, next); + }); + + pkg.resolve(); + }); + + it('Should remove .git directory', function (next) { + var dir = __dirname + '/assets/package-repo'; + + fs.renameSync(dir + '/git_repo', dir + '/.git'); + + var pkg = new Package('spark-md5', dir); + + pkg.on('resolve', function () { + pkg.install(); + }); + + pkg.on('error', function (err) { + fs.renameSync(dir + '/.git', dir + '/git_repo'); + throw new Error(err); + }); + + var pkgInstallPath = path.join(__dirname, '/../components/spark-md5/'); + pkg.on('install', function () { + fs.renameSync(dir + '/.git', dir + '/git_repo'); + assert(!fs.existsSync(pkgInstallPath + '/.git/')); + next(); + }); + + pkg.resolve(); + }); });