mirror of
https://github.com/bower/bower.git
synced 2026-04-24 03:00:19 -04:00
Merge branch 'master' into link-install-deps
This commit is contained in:
10
CHANGELOG.md
10
CHANGELOG.md
@@ -1,6 +1,16 @@
|
||||
# Changelog
|
||||
|
||||
|
||||
##1.2.8 - 2013-12-02
|
||||
- Fix absolute paths ending with / not going through the FsResolver, ([#898](https://github.com/bower/bower/issues/898))
|
||||
- Allow query string parameters in package URLs
|
||||
- Swapped 'unzip' module for 'decompress-zip', and some other small unzipping fixes([#873](https://github.com/bower/bower/issues/873), [#896](https://github.com/bower/bower/issues/896))
|
||||
- Allow the root-check to be overidden when calling bower programmatically.
|
||||
- Fixed some bugs relating to packages with a very large dependency tree
|
||||
- Fix a bug caused by a recent change to semver
|
||||
|
||||
|
||||
|
||||
## 1.2.7 - 2013-09-29
|
||||
|
||||
- Do not swallow sync errors when using the programmatic API ([#849](https://github.com/bower/bower/issues/849))
|
||||
|
||||
144
README.md
144
README.md
@@ -1,4 +1,8 @@
|
||||
# BOWER [](http://travis-ci.org/bower/bower)
|
||||
# Bower
|
||||
|
||||
[](http://travis-ci.org/bower/bower) [](https://sourcegraph.com/github.com/bower/bower)
|
||||
|
||||
<img align="right" height="300" src="http://bower.io/img/bower-logo.png">
|
||||
|
||||
Bower is a package manager for the web. It offers a generic, unopinionated
|
||||
solution to the problem of **front-end package management**, while exposing the
|
||||
@@ -31,27 +35,24 @@ packages require it to be fetched and installed.
|
||||
Much more information is available via `bower help` once it's installed. This
|
||||
is just enough to get you started.
|
||||
|
||||
#### Warning
|
||||
|
||||
On `prezto` or `oh-my-zsh`, do not forget to `alias bower='noglob bower'` or `bower install jquery\#1.9.1`
|
||||
|
||||
#### Running commands with sudo
|
||||
|
||||
Bower is a user command, there is no need to execute it with superuser permissions.
|
||||
However, if you still want to run commands with sudo, use `--allow-root` option.
|
||||
|
||||
### Installing packages and dependencies
|
||||
|
||||
Bower offers several ways to install packages:
|
||||
|
||||
#####Using the dependencies listed in the current directory's bower.json
|
||||
```
|
||||
# Using the dependencies listed in the current directory's bower.json
|
||||
bower install
|
||||
# Using a local or remote package
|
||||
```
|
||||
##### Using a local or remote package
|
||||
```
|
||||
bower install <package>
|
||||
# Using a specific version of a package
|
||||
```
|
||||
##### Using a specific version of a package
|
||||
```
|
||||
bower install <package>#<version>
|
||||
# Using a different name and a specific version of a package
|
||||
```
|
||||
##### Using a different name and a specific version of a package
|
||||
```
|
||||
bower install <name>=<package>#<version>
|
||||
```
|
||||
|
||||
@@ -75,8 +76,20 @@ You should **never** directly modify the contents of this directory.
|
||||
Using `bower list` will show all the packages that are installed locally.
|
||||
|
||||
**N.B.** If you aren't authoring a package that is intended to be consumed by
|
||||
others (e.g., you're building a web app), you should always check installed
|
||||
packages into source control.
|
||||
others (e.g., you're building a web app), you should always [check installed
|
||||
packages into source control](http://addyosmani.com/blog/checking-in-front-end-dependencies/).
|
||||
|
||||
|
||||
### Custom install directory
|
||||
|
||||
A custom install location can be set in a .bowerrc file using the `directory` property. The .bowerrc file should be a sibling of your project's bower.json.
|
||||
|
||||
```json
|
||||
{
|
||||
"directory": "public/bower_components"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Finding packages
|
||||
|
||||
@@ -94,7 +107,7 @@ The easiest approach is to use Bower statically, just reference the package's
|
||||
installed components manually using a `script` tag:
|
||||
|
||||
```html
|
||||
<script src="/bower_components/jquery/index.js"></script>
|
||||
<script src="/bower_components/jquery/jquery.js"></script>
|
||||
```
|
||||
|
||||
For more complex projects, you'll probably want to concatenate your scripts or
|
||||
@@ -102,29 +115,6 @@ use a module loader. Bower is just a package manager, but there are plenty of
|
||||
other tools -- such as [Sprockets](https://github.com/sstephenson/sprockets)
|
||||
and [RequireJS](http://requirejs.org/) -- that will help you do this.
|
||||
|
||||
### Registering packages
|
||||
|
||||
To register a new package:
|
||||
|
||||
* There **must** be a valid manifest JSON in the current working directory.
|
||||
* Your package should use [semver](http://semver.org/) Git tags.
|
||||
* Your package **must** be available at a Git endpoint (e.g., GitHub); remember
|
||||
to push your Git tags!
|
||||
|
||||
Then use the following command:
|
||||
|
||||
```
|
||||
bower register <my-package-name> <git-endpoint>
|
||||
```
|
||||
|
||||
The Bower registry does not have authentication or user management at this point
|
||||
in time. It's on a first come, first served basis. Think of it like a URL
|
||||
shortener. Now anyone can run `bower install <my-package-name>`, and get your
|
||||
library installed.
|
||||
|
||||
There is no direct way to unregister a package yet. For now, you can [request a
|
||||
package be unregistered](https://github.com/bower/bower/issues/120).
|
||||
|
||||
### Uninstalling packages
|
||||
|
||||
To uninstall a locally installed package:
|
||||
@@ -134,6 +124,43 @@ bower uninstall <package-name>
|
||||
```
|
||||
|
||||
|
||||
#### Warning
|
||||
|
||||
On `prezto` or `oh-my-zsh`, do not forget to `alias bower='noglob bower'` or `bower install jquery\#1.9.1`
|
||||
|
||||
#### Running commands with sudo
|
||||
|
||||
Bower is a user command, there is no need to execute it with superuser permissions.
|
||||
However, if you still want to run commands with sudo, use `--allow-root` option.
|
||||
|
||||
#### A note for Windows users
|
||||
|
||||
To use Bower on Windows, you must install
|
||||
[msysgit](http://code.google.com/p/msysgit/) correctly. Be sure to check the
|
||||
option shown below:
|
||||
|
||||

|
||||
|
||||
Note that if you use TortoiseGit and if Bower keeps asking for your SSH
|
||||
password, you should add the following environment variable: `GIT_SSH -
|
||||
C:\Program Files\TortoiseGit\bin\TortoisePlink.exe`. Adjust the `TortoisePlink`
|
||||
path if needed.
|
||||
|
||||
### Using bower's cache
|
||||
|
||||
Bower supports installing packages from its local cache (without internet connection), if the packages were installed before.
|
||||
```
|
||||
bower install <package-name> --offline
|
||||
```
|
||||
The content of the cache can be listed with:
|
||||
```
|
||||
bower cache list
|
||||
```
|
||||
The cache can be cleaned with:
|
||||
```
|
||||
bower cache clean
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Bower can be configured using JSON in a `.bowerrc` file.
|
||||
@@ -193,6 +220,29 @@ The `bower.json` defines several options:
|
||||
}
|
||||
```
|
||||
|
||||
### Registering packages
|
||||
|
||||
To register a new package:
|
||||
|
||||
* There **must** be a valid manifest JSON in the current working directory.
|
||||
* Your package should use [semver](http://semver.org/) Git tags.
|
||||
* Your package **must** be available at a Git endpoint (e.g., GitHub); remember
|
||||
to push your Git tags!
|
||||
|
||||
Then use the following command:
|
||||
|
||||
```
|
||||
bower register <my-package-name> <git-endpoint>
|
||||
```
|
||||
|
||||
The Bower registry does not have authentication or user management at this point
|
||||
in time. It's on a first come, first served basis. Think of it like a URL
|
||||
shortener. Now anyone can run `bower install <my-package-name>`, and get your
|
||||
library installed.
|
||||
|
||||
There is no direct way to unregister a package yet. For now, you can [request a
|
||||
package be unregistered](https://github.com/bower/bower/issues/120).
|
||||
|
||||
|
||||
## Consuming a package
|
||||
|
||||
@@ -277,20 +327,6 @@ bower completion >> ~/.bash_profile
|
||||
```
|
||||
|
||||
|
||||
## A note for Windows users
|
||||
|
||||
To use Bower on Windows, you must install
|
||||
[msysgit](http://code.google.com/p/msysgit/) correctly. Be sure to check the
|
||||
option shown below:
|
||||
|
||||

|
||||
|
||||
Note that if you use TortoiseGit and if Bower keeps asking for your SSH
|
||||
password, you should add the following environment variable: `GIT_SSH -
|
||||
C:\Program Files\TortoiseGit\bin\TortoisePlink.exe`. Adjust the `TortoisePlink`
|
||||
path if needed.
|
||||
|
||||
|
||||
## Contact
|
||||
|
||||
Have a question?
|
||||
|
||||
124
bin/bower
124
bin/bower
@@ -11,6 +11,7 @@ var bower = require('../lib');
|
||||
var pkg = require(path.join(__dirname, '..', 'package.json'));
|
||||
var cli = require('../lib/util/cli');
|
||||
var rootCheck = require('../lib/util/rootCheck');
|
||||
var analytics = require('../lib/util/analytics');
|
||||
|
||||
// --------
|
||||
|
||||
@@ -69,71 +70,74 @@ while (options.argv.remain.length) {
|
||||
options.argv.remain.pop();
|
||||
}
|
||||
|
||||
// Execute the command
|
||||
commandFunc = command && mout.object.get(bower.commands, command);
|
||||
command = command && command.replace(/\./g, ' ');
|
||||
// Ask for Insights on first run.
|
||||
analytics.setup().then(function () {
|
||||
// Execute the command
|
||||
commandFunc = command && mout.object.get(bower.commands, command);
|
||||
command = command && command.replace(/\./g, ' ');
|
||||
|
||||
// If no command was specified, show bower help
|
||||
// Do the same if the command is unknown
|
||||
if (!commandFunc) {
|
||||
logger = bower.commands.help();
|
||||
command = 'help';
|
||||
// If the user requested help, show the command's help
|
||||
// Do the same if the actual command is a group of other commands (e.g.: cache)
|
||||
} else if (options.help || !commandFunc.line) {
|
||||
logger = bower.commands.help(command);
|
||||
command = 'help';
|
||||
// Call the line method
|
||||
} else {
|
||||
logger = commandFunc.line(process.argv);
|
||||
|
||||
// If the method failed to interpret the process arguments
|
||||
// show the command help
|
||||
if (!logger) {
|
||||
// If no command was specified, show bower help
|
||||
// Do the same if the command is unknown
|
||||
if (!commandFunc) {
|
||||
logger = bower.commands.help();
|
||||
command = 'help';
|
||||
// If the user requested help, show the command's help
|
||||
// Do the same if the actual command is a group of other commands (e.g.: cache)
|
||||
} else if (options.help || !commandFunc.line) {
|
||||
logger = bower.commands.help(command);
|
||||
command = 'help';
|
||||
}
|
||||
}
|
||||
// Call the line method
|
||||
} else {
|
||||
logger = commandFunc.line(process.argv);
|
||||
|
||||
// Get the renderer and configure it with the executed command
|
||||
renderer = cli.getRenderer(command, logger.json, bower.config);
|
||||
|
||||
logger
|
||||
.on('end', function (data) {
|
||||
if (!bower.config.silent) {
|
||||
renderer.end(data);
|
||||
}
|
||||
})
|
||||
.on('error', function (err) {
|
||||
if (levels.error >= loglevel) {
|
||||
renderer.error(err);
|
||||
// If the method failed to interpret the process arguments
|
||||
// show the command help
|
||||
if (!logger) {
|
||||
logger = bower.commands.help(command);
|
||||
command = 'help';
|
||||
}
|
||||
}
|
||||
|
||||
process.exit(1);
|
||||
})
|
||||
.on('log', function (log) {
|
||||
if (levels[log.level] >= loglevel) {
|
||||
renderer.log(log);
|
||||
}
|
||||
})
|
||||
.on('prompt', function (prompt, callback) {
|
||||
renderer.prompt(prompt)
|
||||
.then(function (answer) {
|
||||
callback(answer);
|
||||
// Get the renderer and configure it with the executed command
|
||||
renderer = cli.getRenderer(command, logger.json, bower.config);
|
||||
|
||||
logger
|
||||
.on('end', function (data) {
|
||||
if (!bower.config.silent) {
|
||||
renderer.end(data);
|
||||
}
|
||||
})
|
||||
.on('error', function (err) {
|
||||
if (levels.error >= loglevel) {
|
||||
renderer.error(err);
|
||||
}
|
||||
|
||||
process.exit(1);
|
||||
})
|
||||
.on('log', function (log) {
|
||||
if (levels[log.level] >= loglevel) {
|
||||
renderer.log(log);
|
||||
}
|
||||
})
|
||||
.on('prompt', function (prompt, callback) {
|
||||
renderer.prompt(prompt)
|
||||
.then(function (answer) {
|
||||
callback(answer);
|
||||
});
|
||||
});
|
||||
|
||||
// Warn if HOME is not SET
|
||||
if (!osenv.home()) {
|
||||
logger.warn('no-home', 'HOME not set, user configuration will not be loaded');
|
||||
}
|
||||
|
||||
// Check for newer version of Bower
|
||||
notifier = updateNotifier({
|
||||
packageName: pkg.name,
|
||||
packageVersion: pkg.version
|
||||
});
|
||||
|
||||
if (notifier.update && levels.info >= loglevel) {
|
||||
renderer.updateNotice(notifier.update);
|
||||
}
|
||||
});
|
||||
|
||||
// Warn if HOME is not SET
|
||||
if (!osenv.home()) {
|
||||
logger.warn('no-home', 'HOME not set, user configuration will not be loaded');
|
||||
}
|
||||
|
||||
// Check for newer version of Bower
|
||||
notifier = updateNotifier({
|
||||
packageName: pkg.name,
|
||||
packageVersion: pkg.version
|
||||
});
|
||||
|
||||
if (notifier.update && levels.info >= loglevel) {
|
||||
renderer.updateNotice(notifier.update);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ function home(name, config) {
|
||||
} else {
|
||||
decEndpoint = endpointParser.decompose(name);
|
||||
promise = project.getPackageRepository().fetch(decEndpoint)
|
||||
.spread(function (canonicalDir, pkgMeta) {
|
||||
.spread(function (canonicalDir, pkgMeta) {
|
||||
return pkgMeta;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,17 +4,21 @@ var Logger = require('bower-logger');
|
||||
var endpointParser = require('bower-endpoint-parser');
|
||||
var PackageRepository = require('../core/PackageRepository');
|
||||
var cli = require('../util/cli');
|
||||
var Tracker = require('../util/analytics').Tracker;
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function info(endpoint, property, config) {
|
||||
var repository;
|
||||
var decEndpoint;
|
||||
var tracker;
|
||||
var logger = new Logger();
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
repository = new PackageRepository(config, logger);
|
||||
tracker = new Tracker(config);
|
||||
|
||||
decEndpoint = endpointParser.decompose(endpoint);
|
||||
tracker.trackDecomposedEndpoints('info', [decEndpoint]);
|
||||
|
||||
Q.all([
|
||||
getPkgMeta(repository, decEndpoint, property),
|
||||
|
||||
@@ -3,25 +3,30 @@ var Logger = require('bower-logger');
|
||||
var endpointParser = require('bower-endpoint-parser');
|
||||
var Project = require('../core/Project');
|
||||
var cli = require('../util/cli');
|
||||
var Tracker = require('../util/analytics').Tracker;
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function install(endpoints, options, config) {
|
||||
var project;
|
||||
var decEndpoints;
|
||||
var tracker;
|
||||
var logger = new Logger();
|
||||
|
||||
options = options || {};
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
project = new Project(config, logger);
|
||||
tracker = new Tracker(config);
|
||||
|
||||
// Convert endpoints to decomposed endpoints
|
||||
endpoints = endpoints || [];
|
||||
decEndpoints = endpoints.map(function (endpoint) {
|
||||
return endpointParser.decompose(endpoint);
|
||||
});
|
||||
tracker.trackDecomposedEndpoints('install', decEndpoints);
|
||||
|
||||
project.install(decEndpoints, options)
|
||||
.done(function (installed) {
|
||||
tracker.trackPackages('installed', installed);
|
||||
logger.emit('end', installed);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
|
||||
@@ -4,6 +4,7 @@ var chalk = require('chalk');
|
||||
var PackageRepository = require('../core/PackageRepository');
|
||||
var Logger = require('bower-logger');
|
||||
var Config = require('bower-config');
|
||||
var Tracker = require('../util/analytics').Tracker;
|
||||
var cli = require('../util/cli');
|
||||
var createError = require('../util/createError');
|
||||
var defaultConfig = require('../config');
|
||||
@@ -12,11 +13,13 @@ var GitHubResolver = require('../core/resolvers/GitHubResolver');
|
||||
function register(name, url, config) {
|
||||
var repository;
|
||||
var registryClient;
|
||||
var tracker;
|
||||
var logger = new Logger();
|
||||
var force;
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
force = config.force;
|
||||
tracker = new Tracker(config);
|
||||
|
||||
// Bypass any cache
|
||||
config.offline = false;
|
||||
@@ -42,6 +45,8 @@ function register(name, url, config) {
|
||||
}
|
||||
}
|
||||
|
||||
tracker.track('register');
|
||||
|
||||
// Attempt to resolve the package referenced by the URL to ensure
|
||||
// everything is ok before registering
|
||||
repository = new PackageRepository(config, logger);
|
||||
@@ -81,6 +86,7 @@ function register(name, url, config) {
|
||||
return Q.nfcall(registryClient.register.bind(registryClient), name, url);
|
||||
})
|
||||
.done(function (result) {
|
||||
tracker.track('registered');
|
||||
logger.emit('end', result);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
|
||||
@@ -3,17 +3,20 @@ var Q = require('q');
|
||||
var Logger = require('bower-logger');
|
||||
var RegistryClient = require('bower-registry-client');
|
||||
var cli = require('../util/cli');
|
||||
var Tracker = require('../util/analytics').Tracker;
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function search(name, config) {
|
||||
var registryClient;
|
||||
var promise;
|
||||
var tracker;
|
||||
var logger = new Logger();
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config.cache = config.storage.registry;
|
||||
|
||||
registryClient = new RegistryClient(config, logger);
|
||||
tracker = new Tracker(config);
|
||||
|
||||
// If no name was specified, list all packages
|
||||
if (!name) {
|
||||
@@ -25,6 +28,7 @@ function search(name, config) {
|
||||
|
||||
promise
|
||||
.done(function (results) {
|
||||
tracker.track('searched', name);
|
||||
logger.emit('end', results);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
|
||||
@@ -3,15 +3,20 @@ var Logger = require('bower-logger');
|
||||
var Q = require('q');
|
||||
var Project = require('../core/Project');
|
||||
var cli = require('../util/cli');
|
||||
var Tracker = require('../util/analytics').Tracker;
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function uninstall(names, options, config) {
|
||||
var project;
|
||||
var tracker;
|
||||
var logger = new Logger();
|
||||
|
||||
options = options || {};
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
project = new Project(config, logger);
|
||||
tracker = new Tracker(config);
|
||||
|
||||
tracker.trackNames('uninstall', names);
|
||||
|
||||
project.getTree()
|
||||
.spread(function (tree, flattened) {
|
||||
@@ -35,6 +40,7 @@ function uninstall(names, options, config) {
|
||||
})
|
||||
.done(function (uninstalled) {
|
||||
logger.emit('end', uninstalled);
|
||||
tracker.trackNames('uninstalled', Object.keys(uninstalled));
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
|
||||
@@ -12,6 +12,12 @@ if (config.interactive == null) {
|
||||
config.interactive = process.bin === 'bower' && tty.isatty(1);
|
||||
}
|
||||
|
||||
// If `analytics` hasn't been explicitly set, we disable
|
||||
// it when ran programatically.
|
||||
if (config.analytics == null) {
|
||||
config.analytics = config.interactive;
|
||||
}
|
||||
|
||||
// Merge common CLI options into the config
|
||||
mout.object.mixIn(config, cli.readOptions({
|
||||
force: { type: Boolean, shorthand: 'f' },
|
||||
|
||||
@@ -371,6 +371,8 @@ Manager.prototype._failFast = function () {
|
||||
};
|
||||
|
||||
Manager.prototype._parseDependencies = function (decEndpoint, pkgMeta, jsonKey) {
|
||||
var pending = [];
|
||||
|
||||
decEndpoint.dependencies = decEndpoint.dependencies || {};
|
||||
|
||||
// Parse package dependencies
|
||||
@@ -426,10 +428,7 @@ Manager.prototype._parseDependencies = function (decEndpoint, pkgMeta, jsonKey)
|
||||
}, this);
|
||||
|
||||
if (compatible) {
|
||||
compatible.promise
|
||||
.then(function () {
|
||||
this._parseDependencies(decEndpoint, pkgMeta, jsonKey);
|
||||
}.bind(this));
|
||||
pending.push(compatible.promise);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -442,6 +441,13 @@ Manager.prototype._parseDependencies = function (decEndpoint, pkgMeta, jsonKey)
|
||||
childDecEndpoint.dependants = [decEndpoint];
|
||||
this._fetch(childDecEndpoint);
|
||||
}, this);
|
||||
|
||||
if (pending.length > 0) {
|
||||
Q.all(pending)
|
||||
.then(function () {
|
||||
this._parseDependencies(decEndpoint, pkgMeta, jsonKey);
|
||||
}.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
Manager.prototype._dissect = function () {
|
||||
@@ -791,7 +797,7 @@ Manager.prototype._areCompatible = function (candidate, resolved) {
|
||||
|
||||
// If target is a range, check if the max versions of the range are the same
|
||||
// and if the resolved version satisfies the candidate target
|
||||
if (semver.validRange(candidate.target)) {
|
||||
if (semver.validRange(candidate.target) && semver.validRange(resolved.target)) {
|
||||
highestCandidate = this._getCap(semver.toComparators(candidate.target), 'highest');
|
||||
highestResolved = this._getCap(semver.toComparators(resolved.target), 'highest');
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ function getConstructor(source, config, registryClient) {
|
||||
// If source is ./ or ../ or an absolute path
|
||||
absolutePath = path.resolve(config.cwd, source);
|
||||
|
||||
if (/^\.\.?[\/\\]/.test(source) || /^~\//.test(source) || path.normalize(source) === absolutePath) {
|
||||
if (/^\.\.?[\/\\]/.test(source) || /^~\//.test(source) || path.normalize(source).replace(/[\/\\]+$/, '') === absolutePath) {
|
||||
promise = Q.nfcall(fs.stat, path.join(absolutePath, '.git'))
|
||||
.then(function (stats) {
|
||||
if (stats.isDirectory()) {
|
||||
|
||||
@@ -19,6 +19,12 @@ function FsResolver(decEndpoint, config, logger) {
|
||||
if (this._target !== '*') {
|
||||
throw createError('File system sources can\'t resolve targets', 'ENORESTARGET');
|
||||
}
|
||||
|
||||
// If the name was guessed
|
||||
if (this._guessedName) {
|
||||
// Remove extension
|
||||
this._name = this._name.substr(0, this._name.length - path.extname(this._name).length);
|
||||
}
|
||||
}
|
||||
|
||||
util.inherits(FsResolver, Resolver);
|
||||
|
||||
@@ -12,8 +12,6 @@ var extract = require('../../util/extract');
|
||||
var createError = require('../../util/createError');
|
||||
|
||||
function UrlResolver(decEndpoint, config, logger) {
|
||||
var pos;
|
||||
|
||||
Resolver.call(this, decEndpoint, config, logger);
|
||||
|
||||
// If target was specified, error out
|
||||
@@ -21,12 +19,12 @@ function UrlResolver(decEndpoint, config, logger) {
|
||||
throw createError('URL sources can\'t resolve targets', 'ENORESTARGET');
|
||||
}
|
||||
|
||||
// If the name was guessed, remove the ? part
|
||||
// If the name was guessed
|
||||
if (this._guessedName) {
|
||||
pos = this._name.indexOf('?');
|
||||
if (pos !== -1) {
|
||||
this._name = path.basename(this._name.substr(0, pos));
|
||||
}
|
||||
// Remove the ?xxx part
|
||||
this._name = this._name.replace(/\?.*$/, '');
|
||||
// Remove extension
|
||||
this._name = this._name.substr(0, this._name.length - path.extname(this._name).length);
|
||||
}
|
||||
|
||||
this._remote = url.parse(this._source);
|
||||
@@ -107,7 +105,8 @@ UrlResolver.prototype._resolve = function () {
|
||||
// -----------------
|
||||
|
||||
UrlResolver.prototype._download = function () {
|
||||
var file = path.join(this._tempDir, path.basename(this._source));
|
||||
var fileName = url.parse(path.basename(this._source)).pathname;
|
||||
var file = path.join(this._tempDir, fileName);
|
||||
var reqHeaders = {};
|
||||
var that = this;
|
||||
|
||||
@@ -199,6 +198,8 @@ UrlResolver.prototype._extract = function (file, response) {
|
||||
if (mimeType) {
|
||||
// Clean everything after ; and trim the end result
|
||||
mimeType = mimeType.split(';')[0].trim();
|
||||
// Some servers add quotes around the content-type, so we trim that also
|
||||
mimeType = mout.string.trim(mimeType, ['"', '\'']);
|
||||
}
|
||||
|
||||
if (!extract.canExtract(file, mimeType)) {
|
||||
|
||||
@@ -419,7 +419,7 @@ StandardRenderer.prototype._tree2archy = function (node) {
|
||||
|
||||
// State labels
|
||||
if (node.missing) {
|
||||
label += chalk.red(' missing');
|
||||
label += chalk.red(' not installed');
|
||||
return label;
|
||||
}
|
||||
|
||||
|
||||
61
lib/util/analytics.js
Normal file
61
lib/util/analytics.js
Normal file
@@ -0,0 +1,61 @@
|
||||
var Q = require('q');
|
||||
var Insight = require('insight');
|
||||
var mout = require('mout');
|
||||
var config = require('../config');
|
||||
var pkg = require('../../package.json');
|
||||
|
||||
var analytics = module.exports;
|
||||
var insight;
|
||||
|
||||
// Initializes the application-wide insight singleton and asks for the
|
||||
// permission on the CLI during the first run.
|
||||
analytics.setup = function setup() {
|
||||
var deferred = Q.defer();
|
||||
insight = new Insight({
|
||||
trackingCode: 'UA-43531210-1',
|
||||
packageName: pkg.name,
|
||||
packageVersion: pkg.version
|
||||
});
|
||||
|
||||
// Display the ask prompt only if it hasn't been answered before
|
||||
// and the current session is interactive.
|
||||
if (insight.optOut === undefined && config.interactive) {
|
||||
insight.askPermission(null, deferred.resolve);
|
||||
} else {
|
||||
deferred.resolve();
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
var Tracker = analytics.Tracker = function Tracker(config) {
|
||||
if (!config.analytics) {
|
||||
this.track = function noop() {};
|
||||
}
|
||||
};
|
||||
|
||||
Tracker.prototype.track = function track() {
|
||||
if (!insight) {
|
||||
throw new Error('You must call analytics.setup() prior to tracking.');
|
||||
}
|
||||
insight.track.apply(insight, arguments);
|
||||
};
|
||||
|
||||
Tracker.prototype.trackDecomposedEndpoints = function trackDecomposedEndpoints(command, endpoints) {
|
||||
endpoints.forEach(function (endpoint) {
|
||||
this.track(command, endpoint.source, endpoint.target);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Tracker.prototype.trackPackages = function trackPackages(command, packages) {
|
||||
mout.object.forOwn(packages, function (package) {
|
||||
var meta = package.pkgMeta;
|
||||
this.track(command, meta.name, meta.version);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Tracker.prototype.trackNames = function trackNames(command, names) {
|
||||
names.forEach(function (name) {
|
||||
this.track(command, name);
|
||||
}.bind(this));
|
||||
};
|
||||
@@ -3,8 +3,15 @@ var path = require('path');
|
||||
var Q = require('q');
|
||||
var mout = require('mout');
|
||||
var which = require('which');
|
||||
var PThrottler = require('p-throttler');
|
||||
var createError = require('./createError');
|
||||
|
||||
// The concurrency limit here is kind of magic. You don't really gain a lot from
|
||||
// having a large number of commands spawned at once, so it isn't super
|
||||
// important for this number to be large. However, it would still be nice to
|
||||
// *know* how high this number can be, rather than having to guess low.
|
||||
var throttler = new PThrottler(50);
|
||||
|
||||
var winBatchExtensions;
|
||||
var winWhichCache;
|
||||
var isWin = process.platform === 'win32';
|
||||
@@ -44,7 +51,7 @@ function getWindowsCommand(command) {
|
||||
// If an error occurs, a meaningful error is generated
|
||||
// Returns a promise that gets fulfilled if the command succeeds
|
||||
// or rejected if it fails
|
||||
function cmd(command, args, options) {
|
||||
function executeCmd(command, args, options) {
|
||||
var process;
|
||||
var stderr = '';
|
||||
var stdout = '';
|
||||
@@ -103,4 +110,8 @@ function cmd(command, args, options) {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function cmd(command, args, options) {
|
||||
return throttler.enqueue(executeCmd.bind(null, command, args, options));
|
||||
}
|
||||
|
||||
module.exports = cmd;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
var path = require('path');
|
||||
var fs = require('graceful-fs');
|
||||
var zlib = require('zlib');
|
||||
var unzip = require('unzip');
|
||||
var DecompressZip = require('decompress-zip');
|
||||
var tar = require('tar');
|
||||
var Q = require('q');
|
||||
var mout = require('mout');
|
||||
@@ -22,6 +22,7 @@ extractors = {
|
||||
'.tgz': extractTarGz,
|
||||
'.gz': extractGz,
|
||||
'application/zip': extractZip,
|
||||
'application/x-zip': extractZip,
|
||||
'application/x-tar': extractTar,
|
||||
'application/x-tgz': extractTarGz,
|
||||
'application/x-gzip': extractGz
|
||||
@@ -32,15 +33,14 @@ extractorTypes = Object.keys(extractors);
|
||||
function extractZip(archive, dst) {
|
||||
var deferred = Q.defer();
|
||||
|
||||
fs.createReadStream(archive)
|
||||
new DecompressZip(archive)
|
||||
.on('error', deferred.reject)
|
||||
.pipe(unzip.Extract({
|
||||
.on('extract', deferred.resolve.bind(deferred, dst))
|
||||
.extract({
|
||||
path: dst,
|
||||
follow: false, // Do not follow symlinks (#699)
|
||||
filter: filterSymlinks // Filter symlink files
|
||||
}))
|
||||
.on('error', deferred.reject)
|
||||
.on('close', deferred.resolve.bind(deferred, dst));
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ function rootCheck(options, config) {
|
||||
var errorMsg;
|
||||
|
||||
// Allow running the command as root
|
||||
if (options.allowRoot) {
|
||||
if (options.allowRoot || config.allowRoot) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bower",
|
||||
"version": "1.2.7",
|
||||
"version": "1.2.8",
|
||||
"description": "The browser package manager.",
|
||||
"author": "Twitter",
|
||||
"licenses": [
|
||||
@@ -29,6 +29,7 @@
|
||||
"cardinal": "~0.4.0",
|
||||
"chalk": "~0.2.0",
|
||||
"chmodr": "~0.1.0",
|
||||
"decompress-zip": "~0.0.3",
|
||||
"fstream": "~0.1.22",
|
||||
"fstream-ignore": "~0.0.6",
|
||||
"glob": "~3.2.1",
|
||||
@@ -53,9 +54,10 @@
|
||||
"sudo-block": "~0.2.0",
|
||||
"tar": "~0.1.17",
|
||||
"tmp": "~0.0.20",
|
||||
"unzip": "~0.1.7",
|
||||
"update-notifier": "~0.1.3",
|
||||
"which": "~1.0.5"
|
||||
"which": "~1.0.5",
|
||||
"p-throttler": "~0.0.1",
|
||||
"insight": "~0.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"expect.js": "~0.2.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"command": "list",
|
||||
"description": "List local packages.",
|
||||
"description": "List local packages - and possible updates.",
|
||||
"usage": [
|
||||
"list [<options>]"
|
||||
],
|
||||
|
||||
@@ -303,6 +303,11 @@ describe('resolverFactory', function () {
|
||||
temp = path.resolve(__dirname, '../assets/package-a');
|
||||
endpoints[temp] = temp;
|
||||
|
||||
// Absolute path that ends with a /
|
||||
// See: https://github.com/bower/bower/issues/898
|
||||
temp = path.resolve(__dirname, '../assets/package-a') + '/';
|
||||
endpoints[temp] = temp;
|
||||
|
||||
// Relative path
|
||||
endpoints[__dirname + '/../assets/package-a'] = temp;
|
||||
|
||||
|
||||
@@ -45,9 +45,9 @@ describe('FsResolver', function () {
|
||||
|
||||
describe('.constructor', function () {
|
||||
it('should guess the name from the path', function () {
|
||||
var resolver = create(testPackage);
|
||||
var resolver = create(path.resolve('../../assets/package-zip.zip'));
|
||||
|
||||
expect(resolver.getName()).to.equal('package-a');
|
||||
expect(resolver.getName()).to.equal('package-zip');
|
||||
});
|
||||
|
||||
it('should make paths absolute and normalized', function () {
|
||||
|
||||
@@ -43,13 +43,13 @@ describe('UrlResolver', function () {
|
||||
it('should guess the name from the URL', function () {
|
||||
var resolver = create('http://bower.io/foo.txt');
|
||||
|
||||
expect(resolver.getName()).to.equal('foo.txt');
|
||||
expect(resolver.getName()).to.equal('foo');
|
||||
});
|
||||
|
||||
it('should remove ?part from the URL when guessing the name', function () {
|
||||
var resolver = create('http://bower.io/foo.txt?bar');
|
||||
|
||||
expect(resolver.getName()).to.equal('foo.txt');
|
||||
expect(resolver.getName()).to.equal('foo');
|
||||
});
|
||||
|
||||
it('should not guess the name or remove ?part from the URL if not guessing', function () {
|
||||
@@ -430,6 +430,11 @@ describe('UrlResolver', function () {
|
||||
'Content-Type': ' application/zip ; charset=UTF-8'
|
||||
})
|
||||
|
||||
.get('/package-zip4')
|
||||
.replyWithFile(200, path.resolve(__dirname, '../../assets/package-zip.zip'), {
|
||||
'Content-Type': '"application/x-zip"' // Test with quotes
|
||||
})
|
||||
|
||||
.get('/package-tar')
|
||||
.replyWithFile(200, path.resolve(__dirname, '../../assets/package-tar.tar.gz'), {
|
||||
'Content-Type': ' application/x-tgz ; charset=UTF-8'
|
||||
@@ -462,7 +467,7 @@ describe('UrlResolver', function () {
|
||||
expect(fs.existsSync(path.join(dir, 'foo.js'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(dir, 'bar.js'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(dir, 'package-zip'))).to.be(false);
|
||||
expect(fs.existsSync(path.join(dir, 'package-zip2.zip'))).to.be(false);
|
||||
expect(fs.existsSync(path.join(dir, 'package-zip3.zip'))).to.be(false);
|
||||
|
||||
resolver = create('http://bower.io/package-zip3');
|
||||
|
||||
@@ -472,7 +477,16 @@ describe('UrlResolver', function () {
|
||||
expect(fs.existsSync(path.join(dir, 'foo.js'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(dir, 'bar.js'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(dir, 'package-zip'))).to.be(false);
|
||||
expect(fs.existsSync(path.join(dir, 'package-zip3.zip'))).to.be(false);
|
||||
expect(fs.existsSync(path.join(dir, 'package-zip4.zip'))).to.be(false);
|
||||
|
||||
resolver = create('http://bower.io/package-zip4');
|
||||
|
||||
return resolver.resolve();
|
||||
})
|
||||
.then(function (dir) {
|
||||
expect(fs.existsSync(path.join(dir, 'foo.js'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(dir, 'bar.js'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(dir, 'package-tar'))).to.be(false);
|
||||
|
||||
resolver = create('http://bower.io/package-tar');
|
||||
|
||||
@@ -554,6 +568,32 @@ describe('UrlResolver', function () {
|
||||
.done();
|
||||
});
|
||||
|
||||
it('should allow for query strings in URL', function (next) {
|
||||
var resolver;
|
||||
|
||||
nock('http://bower.io')
|
||||
.get('/foo.js?bar=baz')
|
||||
.reply(200, 'foo contents');
|
||||
|
||||
resolver = create('http://bower.io/foo.js?bar=baz');
|
||||
|
||||
resolver.resolve()
|
||||
.then(function (dir) {
|
||||
var contents;
|
||||
|
||||
expect(fs.existsSync(path.join(dir, 'index.js'))).to.be(true);
|
||||
expect(fs.existsSync(path.join(dir, 'foo.js'))).to.be(false);
|
||||
expect(fs.existsSync(path.join(dir, 'foo.js?bar=baz'))).to.be(false);
|
||||
|
||||
contents = fs.readFileSync(path.join(dir, 'index.js')).toString();
|
||||
expect(contents).to.equal('foo contents');
|
||||
|
||||
assertMain(dir, 'index.js')
|
||||
.then(next.bind(next, null));
|
||||
})
|
||||
.done();
|
||||
});
|
||||
|
||||
it('should save cache headers', function (next) {
|
||||
var resolver;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user