mirror of
https://github.com/apache/cordova-android.git
synced 2026-01-30 00:05:28 +08:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d654de809a | ||
|
|
86f9b618ef | ||
|
|
ec1cc70c8b | ||
|
|
a64203f817 | ||
|
|
f4b315961b | ||
|
|
3bc755de7c | ||
|
|
c5ffdff49b | ||
|
|
2829ed77cc | ||
|
|
f3885692d9 | ||
|
|
d7fc37d365 | ||
|
|
c3bdebdb83 | ||
|
|
9514a3ed94 | ||
|
|
050dd088cf | ||
|
|
26f0401fda | ||
|
|
e4e04927b6 | ||
|
|
6b3ef11715 | ||
|
|
cf0fdf5ac0 | ||
|
|
33614d1273 | ||
|
|
1f735935b9 | ||
|
|
8c14e33bb6 | ||
|
|
7375154228 | ||
|
|
1427c13504 | ||
|
|
5538a231a8 | ||
|
|
9be110683b | ||
|
|
cfc36140bc | ||
|
|
72e947e5c7 | ||
|
|
7320ce8ea7 | ||
|
|
3e07f26bc4 |
37
.gitignore
vendored
37
.gitignore
vendored
@@ -2,29 +2,28 @@
|
||||
default.properties
|
||||
gen
|
||||
assets/www/cordova.js
|
||||
framework/assets/www/.tmp*
|
||||
local.properties
|
||||
framework/lib
|
||||
proguard.cfg
|
||||
proguard.cfg
|
||||
proguard-project.txt
|
||||
/framework/lib
|
||||
/framework/build
|
||||
/framework/bin
|
||||
/framework/assets/www/.DS_Store
|
||||
/framework/assets/www/cordova-*.js
|
||||
/framework/assets/www/phonegap-*.js
|
||||
/framework/libs
|
||||
/framework/javadoc-public
|
||||
/framework/javadoc-private
|
||||
/test/libs
|
||||
framework/bin
|
||||
framework/test/org/apache/cordova/*.class
|
||||
framework/assets/www/.DS_Store
|
||||
framework/assets/www/cordova-*.js
|
||||
framework/assets/www/phonegap-*.js
|
||||
framework/libs
|
||||
framework/javadoc-public
|
||||
framework/javadoc-private
|
||||
test/libs
|
||||
example
|
||||
/test/bin
|
||||
/test/assets/www/.tmp*
|
||||
/test/assets/www/cordova.js
|
||||
/test/gradle
|
||||
/test/gradlew
|
||||
/test/gradlew.bat
|
||||
/test/build
|
||||
.gradle
|
||||
./test
|
||||
test/bin
|
||||
test/assets/www/.tmp*
|
||||
test/assets/www/cordova.js
|
||||
test/cordova/plugins/org.apache.cordova.device/www/device.js
|
||||
test/cordova/plugins/org.apache.cordova.device/src/android/Device.java
|
||||
tmp/**
|
||||
.metadata
|
||||
tmp/**/*
|
||||
@@ -39,5 +38,5 @@ Desktop.ini
|
||||
*.iml
|
||||
.idea
|
||||
npm-debug.log
|
||||
/node_modules
|
||||
/framework/build
|
||||
node_modules/
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
bin/node_modules/*
|
||||
bin/templates/project/*
|
||||
10
.jshintrc
10
.jshintrc
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"node": true
|
||||
, "bitwise": true
|
||||
, "undef": true
|
||||
, "trailing": true
|
||||
, "quotmark": true
|
||||
, "indent": 4
|
||||
, "unused": "vars"
|
||||
, "latedef": "nofunc"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
*.properties
|
||||
bin
|
||||
gen
|
||||
proguard-project.txt
|
||||
@@ -1,10 +1,5 @@
|
||||
language: android
|
||||
sudo: false
|
||||
install:
|
||||
- "(pushd .. && git clone https://github.com/apache/cordova-lib.git && popd)"
|
||||
- npm link ../cordova-lib/cordova-common
|
||||
- npm install
|
||||
- echo y | android update sdk -u --filter android-23
|
||||
install: npm install
|
||||
script:
|
||||
- npm test
|
||||
- npm run test-build
|
||||
- npm run test-build
|
||||
@@ -27,7 +27,7 @@ There are multiple ways to contribute: report bugs, improve the docs, and
|
||||
contribute code.
|
||||
|
||||
For instructions on this, start with the
|
||||
[contribution overview](http://cordova.apache.org/contribute/).
|
||||
[contribution overview](http://cordova.apache.org/#contribute).
|
||||
|
||||
The details are explained there, but the important items are:
|
||||
- Sign and submit an Apache ICLA (Contributor License Agreement).
|
||||
|
||||
43
LICENSE
43
LICENSE
@@ -187,7 +187,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2015 Apache Cordova
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -226,9 +226,11 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
|
||||
|
||||
================================================================================
|
||||
bin/node_modules/shelljs
|
||||
================================================================================
|
||||
|
||||
Copyright (c) 2012, Artur Adib <aadib@mozilla.com>
|
||||
All rights reserved.
|
||||
|
||||
@@ -245,19 +247,19 @@ modification, are permitted provided that the following conditions are met:
|
||||
names of the contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL ARTUR ADIB BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
================================================================================
|
||||
bin/node_modules/nopt
|
||||
bin/node_modules/shelljs
|
||||
================================================================================
|
||||
Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
|
||||
All rights reserved.
|
||||
@@ -283,32 +285,3 @@ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
================================================================================
|
||||
bin/node_modules/which
|
||||
================================================================================
|
||||
|
||||
Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
|
||||
4
NOTICE
4
NOTICE
@@ -1,5 +1,5 @@
|
||||
Apache Cordova
|
||||
Copyright 2015 The Apache Software Foundation
|
||||
Copyright 2014 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org)
|
||||
@@ -13,3 +13,5 @@ The Apache Software Foundation (http://www.apache.org)
|
||||
This product includes software developed as part of
|
||||
The Android Open Source Project (http://source.android.com).
|
||||
|
||||
This software includes software developed at Square, Inc.
|
||||
Copyright (C) 2013 Square, Inc.
|
||||
|
||||
53
README.md
53
README.md
@@ -18,31 +18,37 @@
|
||||
# under the License.
|
||||
#
|
||||
-->
|
||||
# Cordova Android
|
||||
Cordova Android
|
||||
===
|
||||
|
||||
Cordova Android is an Android application library that allows for Cordova-based
|
||||
projects to be built for the Android Platform. Cordova based applications are,
|
||||
at the core, applications written with web technology: HTML, CSS and JavaScript.
|
||||
|
||||
[Apache Cordova](https://cordova.apache.org) is a project of The Apache Software Foundation (ASF).
|
||||
[Apache Cordova](http://cordova.io) is a project of The Apache Software Foundation (ASF).
|
||||
|
||||
|
||||
## Requires
|
||||
Requires
|
||||
---
|
||||
|
||||
- Java JDK 1.6 or greater
|
||||
- Java JDK 1.5 or greater
|
||||
- Apache Ant 1.8.0 or greater
|
||||
- Android SDK [http://developer.android.com](http://developer.android.com)
|
||||
|
||||
|
||||
## Cordova Android Developer Tools
|
||||
Cordova Android Developer Tools
|
||||
---
|
||||
|
||||
We recommend using the [Cordova command-line tool](https://www.npmjs.com/package/cordova) to create projects and be able to easily install plugins.
|
||||
The Cordova developer tooling is split between general tooling and project level tooling.
|
||||
|
||||
However, the following scripts can be used instead:
|
||||
General Commands
|
||||
|
||||
./bin/create [path package activity] ... creates the ./example app or a cordova android project
|
||||
./bin/check_reqs ....................... checks that your environment is set up for cordova-android development
|
||||
./bin/update [path] .................... updates an existing cordova-android project to the version of the framework
|
||||
|
||||
Project Commands
|
||||
|
||||
These commands live in a generated Cordova Android project. Any interactions with the emulator require you to have an AVD defined.
|
||||
|
||||
./cordova/clean ........................ cleans the project
|
||||
@@ -51,8 +57,35 @@ These commands live in a generated Cordova Android project. Any interactions wit
|
||||
./cordova/run ........................ calls `build` then deploys to a connected Android device. If no Android device is detected, will launch an emulator and deploy to it.
|
||||
./cordova/version ...................... returns the cordova-android version of the current project
|
||||
|
||||
## Using Android Studio
|
||||
Importing a Cordova Android Project into Eclipse
|
||||
----
|
||||
|
||||
1. Create a project
|
||||
2. Import it via "Non-Android Studio Project"
|
||||
1. File > New > Project...
|
||||
2. Android > Android Project
|
||||
3. Create project from existing source (point to the generated app found in tmp/android)
|
||||
4. Right click on libs/cordova.jar and add to build path
|
||||
5. Right click on the project root: Run as > Run Configurations
|
||||
6. Click on the Target tab and select Manual (this way you can choose the emulator or device to build to)
|
||||
|
||||
Building without the Tooling
|
||||
---
|
||||
Note: The Developer Tools handle this. This is only to be done if the tooling fails, or if
|
||||
you are developing directly against the framework.
|
||||
|
||||
|
||||
To create your `cordova.jar` file, run in the framework directory:
|
||||
|
||||
android update project -p . -t android-19
|
||||
ant jar
|
||||
|
||||
|
||||
Running Tests
|
||||
----
|
||||
Please see details under test/README.md.
|
||||
|
||||
Further Reading
|
||||
----
|
||||
|
||||
- [http://developer.android.com](http://developer.android.com)
|
||||
- [http://cordova.apache.org/](http://cordova.apache.org)
|
||||
- [http://wiki.apache.org/cordova/](http://wiki.apache.org/cordova/)
|
||||
|
||||
144
RELEASENOTES.md
144
RELEASENOTES.md
@@ -19,153 +19,11 @@
|
||||
#
|
||||
-->
|
||||
## Release Notes for Cordova (Android) ##
|
||||
Update these notes using: git log --pretty=format:'* %s' --topo-order --no-merges *remote*/4.1.x...HEAD
|
||||
|
||||
### 5.0.0 (Nov 01, 2015)
|
||||
* Update CordovaWebViewEngine.java
|
||||
* CB-9909 Shouldn't escape spaces in paths on Windows.
|
||||
* CB-9870 updated hello world template
|
||||
* CB-9880 Fixes platform update failure when upgrading from android@<4.1.0
|
||||
* CB-9844 Remove old .java after renaming activity
|
||||
* CB-9800 Fixing contribute link.
|
||||
* CB-9782 Check in `cordova-common` dependency
|
||||
* Adds licence header to Adb to pass rat audit
|
||||
* CB-9835 Downgrade `properties-parser` to prevent failures in Node < 4.x
|
||||
* CB-9782 Implements PlatformApi contract for Android platform.
|
||||
* CB-9826 Fixed `test-build` script on windows.
|
||||
* Refactor of the Cordova Plugin/Permissions API
|
||||
* Manually updating version to 5.0.0-dev for engine tags
|
||||
* Bump up to API level 23
|
||||
* Commiting code to handle permissions, and the special case of the Geolocation Plugin
|
||||
* CB-9608 cordova-android no longer builds on Node 0.10 or below
|
||||
* CB-9080 Cordova CLI run for Android versions 4.1.1 and lower throws error
|
||||
* CB-9557 Fixes apk install failure when switching from debug to release build
|
||||
* CB-9496 removed permissions added for crosswalk
|
||||
* CB-9402 Allow to set gradle distubutionUrl via env variable CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL
|
||||
* CB-9428 update script now bumps up minSdkVersion to 14 if it is less than that.
|
||||
* CB-9430 Fixes check_reqs failure when javac returns an extra line
|
||||
* CB-9172 Improved emulator deploy stability. This closes #188.
|
||||
* CB-9404 Fixed an exception when path contained -debug or -release
|
||||
* CB-8320 Setting up gradle so we can use CordovaLib as a standard Android Library
|
||||
* CB-9185 Fixed an issue when unsigned apks couldn't be found.
|
||||
* CB-9397 Fixes minor issues with `cordova requirements android`
|
||||
* CB-9389 Fixes build/check_reqs hang
|
||||
|
||||
### Release 4.1.1 (Aug 2015) ###
|
||||
|
||||
* CB-9428 update script now bumps up minSdkVersion to 14 if it is less than that
|
||||
* CB-9430 Fixes check_reqs failure when javac returns an extra line
|
||||
|
||||
### Release 4.1.0 (Jul 2015) ###
|
||||
* CB-9392 Fixed printing flavored versions. This closes #184.
|
||||
* CB-9382 [Android] Fix KeepRunning setting when Plugin activity is showed. This closes #200
|
||||
* CB-9391 Fixes cdvBuildMultipleApks option casting
|
||||
* CB-9343 Split the Content-Type to obtain a clean mimetype
|
||||
* CB-9255 Make getUriType case insensitive.
|
||||
* CB-9149 Fixes JSHint issue introduced by 899daa9
|
||||
* CB-9372: Remove unused files: 'main.js' & 'master.css'. This closes #198
|
||||
* CB-9149 Make gradle alias subprojects in order to handle libs that depend on libs. This closes #182
|
||||
* Update min SDK version to 14
|
||||
* Update licenses. This closes #190
|
||||
* CB-9185 Fix signed release build exception. This closes #193.
|
||||
* CB-9286 Fixes build failure when ANDROID_HOME is not set.
|
||||
* CB-9284 Fix for handling absolute path for keystore in build.json
|
||||
* CB-9260 Install Android-22 on Travis-CI
|
||||
* Adding .ratignore file.
|
||||
* CB-9119 Adding lib/retry.js for retrying promise-returning functions. Retrying 'adb install' in emulator.js because it sometimes hangs.
|
||||
* CB-9115 android: Grant Lollipop permission req
|
||||
* Remove extra console message
|
||||
* CB-8898 Report expected gradle location properly
|
||||
* CB-8898 Fixes gradle check failure due to missing quotes
|
||||
* CB-9080: -d option is not supported on Android 4.1.1 and lower, removing
|
||||
* CB-8954 Adds `requirements` command support to check_reqs module
|
||||
* Update JS snapshot to version 4.1.0-dev (via coho)
|
||||
* CB-8417 updated platform specific files from cordova.js repo
|
||||
* Adding tests to confirm that preferences aren't changed by Intents
|
||||
* Forgot to remove the method that copied over the intent data
|
||||
* Getting around to removing this old Intent code
|
||||
* Update JS snapshot to version 4.1.0-dev (via coho)
|
||||
* Fix CordovaPluginTest on KitKat (start-up events seem to change)
|
||||
* CB-3360 Allow setting a custom User-Agent (close #162)
|
||||
* CB-8902 Use immersive mode when available when going fullscreen (close #175)
|
||||
* Make BridgeMode methods public (they were always supposed to be)
|
||||
* Simplify: EncodingUtils.getBytes(str) -> str.getBytes()
|
||||
* Don't show warning when gradlew file is read-only
|
||||
* Don't show warning when prepEnv copies gradlew and it's read-only
|
||||
* Make gradle wrapper prepEnv code work even when android-sdk is read-only
|
||||
* CB-8897 Delete drawable/icon.png since it duplicates drawable-mdpi/icon.png
|
||||
* Updating the template to target mininumSdkTarget=14
|
||||
* CB-8894: Updating the template to target mininumSdkTarget=14
|
||||
* CB-8891 Add a note about when the gradle helpers were added
|
||||
* CB-8891 Add a gradle helper for retrieving config.xml preference values
|
||||
* CB-8884 Delete Eclipse tweaks from create script
|
||||
* CB-8834 Don't fail to install on VERSION_DOWNGRADE
|
||||
* Automated tools fail, and you have to remember all four places where this is set.
|
||||
* Update the package.json
|
||||
* CB-9042 coho failed to update version, so here we are
|
||||
* CB9042 - Updating Release Notes
|
||||
* Adding tests to confirm that preferences aren't changed by Intents
|
||||
* updating existing test code
|
||||
* Forgot to remove the method that copied over the intent data
|
||||
* Getting around to removing this old Intent code
|
||||
* CB-8834 Don't fail to install on VERSION_DOWNGRADE
|
||||
|
||||
### Release 4.0.2 (May 2015) ###
|
||||
### Release 3.7.2 (May 2015) ###
|
||||
|
||||
* Removed Intent Functionality from Preferences - Preferences can no longer be set by intents
|
||||
|
||||
### Release 4.0.1 (April 2015) ###
|
||||
|
||||
* Bug fixed where platform failed to install on a version downgrade
|
||||
|
||||
### Release 4.0.0 (March 2015) ###
|
||||
|
||||
This release adds significant functionality, and also introduces a number
|
||||
of breaking changes. Some of the changes to the code base will be of
|
||||
particular interest to plugin developers.
|
||||
|
||||
#### Major Changes ####
|
||||
* Support for pluggable WebViews
|
||||
* The system WebView can be replaced in your app, via a plugin
|
||||
* Core WebView functionality is encapsulated, with extension points exposed
|
||||
via interfaces
|
||||
* Support for Crosswalk to bring the modern Chromium WebView to older devices
|
||||
* Uses the pluggable WebView framework
|
||||
* You will need to add the new [cordova-crosswalk-engine](https://github.com/MobileChromeApps/cordova-crosswalk-engine) plugin
|
||||
* Splash screen functionality is now provided via plugin
|
||||
* You will need to add the new [cordova-plugin-splashscreen](https://github.com/apache/cordova-plugin-splashscreen) plugin to continue using a splash screen
|
||||
* Whitelist functionality is now provided via plugin (CB-7747)
|
||||
* The whitelist has been enhanced to be more secure and configurable
|
||||
* Setting of Content-Security-Policy is now supported by the framework (see details in plugin readme)
|
||||
* You will need to add the new [cordova-plugin-whitelist](https://github.com/apache/cordova-plugin-whitelist) plugin
|
||||
* Legacy whitelist behaviour is still available via plugin (although not recommended).
|
||||
|
||||
Changes For Plugin Developers:
|
||||
|
||||
* Develop in Android Studio
|
||||
* Android Studio is now fully supported, and recommended over Eclipse
|
||||
* Build using Gradle
|
||||
* All builds [use Gradle by default](Android%20Shell%20Tool%20Guide_building_with_gradle), instead of Ant
|
||||
* Plugins can add their own gradle build steps!
|
||||
* Plugins can depend on Maven libraries using `<framework>` tags
|
||||
* New APIs: `onStart`, `onStop`, `onConfigurationChanged`
|
||||
* `"onScrollChanged"` message removed. Use `view.getViewTreeObserver().addOnScrollChangedListener(...)` instead
|
||||
* CB-8702 New API for plugins to override `shouldInterceptRequest` with a stream
|
||||
|
||||
#### Other Changes ####
|
||||
* CB-8378 Removed `hidekeyboard` and `showkeyboard` events (apps should use a plugin instead)
|
||||
* CB-8735 `bin/create` regex relaxed / better support for numbers
|
||||
* CB-8699 Fix CordovaResourceApi `copyResource` creating zero-length files when src=uncompressed asset
|
||||
* CB-8693 CordovaLib should not contain icons / splashscreens
|
||||
* CB-8592 Fix NPE if lifecycle events reach CordovaWebView before `init()` has been called
|
||||
* CB-8588 Add CATEGORY_BROWSABLE to intents from showWebPage openExternal=true
|
||||
* CB-8587 Don't allow WebView navigations within showWebPage that are not whitelisted
|
||||
* CB-7827 Add `--activity-name` for `bin/create`
|
||||
* CB-8548 Use debug-signing.properties and release-signing.properties when they exist
|
||||
* CB-8545 Don't add a layout as a parent of the WebView
|
||||
* CB-7159 BackgroundColor not used when `<html style="opacity:0">`, nor during screen rotation
|
||||
* CB-6630 Removed OkHttp from core library. It's now available as a plugin: [cordova-plugin-okhttp](https://www.npmjs.com/package/cordova-plugin-okhttp)
|
||||
|
||||
### Release 3.7.1 (January 2015) ###
|
||||
* CB-8411 Initialize plugins only after `createViews()` is called (regression in 3.7.0)
|
||||
|
||||
|
||||
32
bin/create
32
bin/create
@@ -19,38 +19,18 @@
|
||||
under the License.
|
||||
*/
|
||||
var path = require('path');
|
||||
var ConfigParser = require('cordova-common').ConfigParser;
|
||||
var Api = require('./templates/cordova/Api');
|
||||
var create = require('./lib/create');
|
||||
var args = require('./lib/simpleargs').getArgs(process.argv);
|
||||
|
||||
var argv = require('nopt')({
|
||||
'help' : Boolean,
|
||||
'cli' : Boolean,
|
||||
'shared' : Boolean,
|
||||
'link' : Boolean,
|
||||
'activity-name' : [String, undefined]
|
||||
});
|
||||
|
||||
if (argv.help || argv.argv.remain.length === 0) {
|
||||
console.log('Usage: ' + path.relative(process.cwd(), path.join(__dirname, 'create')) + ' <path_to_new_project> <package_name> <project_name> [<template_path>] [--activity-name <activity_name>] [--link]');
|
||||
if (args['--help'] || args._.length === 0) {
|
||||
console.log('Usage: ' + path.relative(process.cwd(), path.join(__dirname, 'create')) + ' <path_to_new_project> <package_name> <project_name> [<template_path>] [--shared]');
|
||||
console.log(' <path_to_new_project>: Path to your new Cordova Android project');
|
||||
console.log(' <package_name>: Package name, following reverse-domain style convention');
|
||||
console.log(' <project_name>: Project name');
|
||||
console.log(' <template_path>: Path to a custom application template to use');
|
||||
console.log(' --activity-name <activity_name>: Activity name');
|
||||
console.log(' --link will use the CordovaLib project directly instead of making a copy.');
|
||||
console.log(' --shared will use the CordovaLib project directly instead of making a copy.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var config = new ConfigParser(path.resolve(__dirname, 'templates/project/res/xml/config.xml'));
|
||||
create.createProject(args._[0], args._[1], args._[2], args._[3], args['--shared'], args['--cli']).done();
|
||||
|
||||
if (argv.argv.remain[1]) config.setPackageName(argv.argv.remain[1]);
|
||||
if (argv.argv.remain[2]) config.setName(argv.argv.remain[2]);
|
||||
if (argv['activity-name']) config.setName(argv['activity-name']);
|
||||
|
||||
var options = {
|
||||
link: argv.link || argv.shared,
|
||||
customTemplate: argv.argv.remain[3],
|
||||
activityName: argv['activity-name']
|
||||
};
|
||||
|
||||
Api.createPlatform(argv.argv.remain[0], config, options).done();
|
||||
|
||||
@@ -19,20 +19,21 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var child_process = require('child_process'),
|
||||
var shell = require('shelljs'),
|
||||
child_process = require('child_process'),
|
||||
Q = require('q');
|
||||
|
||||
var get_highest_sdk = function(results){
|
||||
get_highest_sdk = function(results){
|
||||
var reg = /\d+/;
|
||||
var apiLevels = [];
|
||||
for(var i=0;i<results.length;i++){
|
||||
apiLevels[i] = parseInt(results[i].match(reg)[0]);
|
||||
}
|
||||
apiLevels.sort(function(a,b){return b-a;});
|
||||
apiLevels.sort(function(a,b){return b-a});
|
||||
console.log(apiLevels[0]);
|
||||
};
|
||||
}
|
||||
|
||||
var get_sdks = function() {
|
||||
get_sdks = function() {
|
||||
var d = Q.defer();
|
||||
child_process.exec('android list targets', function(err, stdout, stderr) {
|
||||
if (err) d.reject(stderr);
|
||||
@@ -56,9 +57,9 @@ var get_sdks = function() {
|
||||
return Q.reject(new Error('An error occurred while listing Android targets'));
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
module.exports.run = function() {
|
||||
return Q.all([get_sdks()]);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -19,33 +19,29 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
/* jshint sub:true */
|
||||
|
||||
var shelljs = require('shelljs'),
|
||||
child_process = require('child_process'),
|
||||
Q = require('q'),
|
||||
path = require('path'),
|
||||
fs = require('fs'),
|
||||
which = require('which'),
|
||||
ROOT = path.join(__dirname, '..', '..');
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
|
||||
var isWindows = process.platform == 'win32';
|
||||
|
||||
function forgivingWhichSync(cmd) {
|
||||
try {
|
||||
return fs.realpathSync(shelljs.which(cmd));
|
||||
return fs.realpathSync(which.sync(cmd));
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function tryCommand(cmd, errMsg, catchStderr) {
|
||||
function tryCommand(cmd, errMsg) {
|
||||
var d = Q.defer();
|
||||
child_process.exec(cmd, function(err, stdout, stderr) {
|
||||
if (err) d.reject(new CordovaError(errMsg));
|
||||
// Sometimes it is necessary to return an stderr instead of stdout in case of success, since
|
||||
// some commands prints theirs output to stderr instead of stdout. 'javac' is the example
|
||||
else d.resolve((catchStderr ? stderr : stdout).trim());
|
||||
if (err) d.reject(new Error(errMsg));
|
||||
else d.resolve(stdout);
|
||||
});
|
||||
return d.promise;
|
||||
}
|
||||
@@ -67,27 +63,19 @@ module.exports.get_target = function() {
|
||||
return extractFromFile(path.join(ROOT, 'project.properties'));
|
||||
}
|
||||
throw new Error('Could not find android target. File missing: ' + path.join(ROOT, 'project.properties'));
|
||||
};
|
||||
}
|
||||
|
||||
// Returns a promise. Called only by build and clean commands.
|
||||
module.exports.check_ant = function() {
|
||||
return tryCommand('ant -version', 'Failed to run "ant -version", make sure you have ant installed and added to your PATH.')
|
||||
.then(function (output) {
|
||||
// Parse Ant version from command output
|
||||
return /version ((?:\d+\.)+(?:\d+))/i.exec(output)[1];
|
||||
});
|
||||
return tryCommand('ant -version', 'Failed to run "ant -version", make sure you have ant installed and added to your PATH.');
|
||||
};
|
||||
|
||||
// Returns a promise. Called only by build and clean commands.
|
||||
module.exports.check_gradle = function() {
|
||||
var sdkDir = process.env['ANDROID_HOME'];
|
||||
if (!sdkDir)
|
||||
return Q.reject(new CordovaError('Could not find gradle wrapper within Android SDK. Could not find Android SDK directory.\n' +
|
||||
'Might need to install Android SDK or set up \'ANDROID_HOME\' env variable.'));
|
||||
|
||||
var wrapperDir = path.join(sdkDir, 'tools', 'templates', 'gradle', 'wrapper');
|
||||
if (!fs.existsSync(wrapperDir)) {
|
||||
return Q.reject(new CordovaError('Could not find gradle wrapper within Android SDK. Might need to update your Android SDK.\n' +
|
||||
return Q.reject(new Error('Could not find gradle wrapper within android sdk. Might need to update your Android SDK.\n' +
|
||||
'Looked here: ' + wrapperDir));
|
||||
}
|
||||
return Q.when();
|
||||
@@ -105,10 +93,9 @@ module.exports.check_java = function() {
|
||||
}
|
||||
} else {
|
||||
if (javacPath) {
|
||||
var msg = 'Failed to find \'JAVA_HOME\' environment variable. Try setting setting it manually.';
|
||||
// OS X has a command for finding JAVA_HOME.
|
||||
if (fs.existsSync('/usr/libexec/java_home')) {
|
||||
return tryCommand('/usr/libexec/java_home', msg)
|
||||
return tryCommand('/usr/libexec/java_home', 'Failed to run: /usr/libexec/java_home')
|
||||
.then(function(stdout) {
|
||||
process.env['JAVA_HOME'] = stdout.trim();
|
||||
});
|
||||
@@ -119,7 +106,7 @@ module.exports.check_java = function() {
|
||||
if (fs.existsSync(path.join(maybeJavaHome, 'lib', 'tools.jar'))) {
|
||||
process.env['JAVA_HOME'] = maybeJavaHome;
|
||||
} else {
|
||||
throw new CordovaError(msg);
|
||||
throw new Error('Could not find JAVA_HOME. Try setting the environment variable manually');
|
||||
}
|
||||
}
|
||||
} else if (isWindows) {
|
||||
@@ -150,15 +137,10 @@ module.exports.check_java = function() {
|
||||
}
|
||||
return tryCommand('java -version', msg)
|
||||
.then(function() {
|
||||
// We use tryCommand with catchStderr = true, because
|
||||
// javac writes version info to stderr instead of stdout
|
||||
return tryCommand('javac -version', msg, true);
|
||||
}).then(function (output) {
|
||||
var match = /javac ((?:\d+\.)+(?:\d+))/i.exec(output)[1];
|
||||
return match && match[1];
|
||||
return tryCommand('javac -version', msg);
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// Returns a promise.
|
||||
module.exports.check_android = function() {
|
||||
@@ -211,31 +193,25 @@ module.exports.check_android = function() {
|
||||
process.env['ANDROID_HOME'] = grandParentDir;
|
||||
hasAndroidHome = true;
|
||||
} else {
|
||||
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
|
||||
'Detected \'android\' command at ' + parentDir + ' but no \'tools\' directory found near.\n' +
|
||||
'Try reinstall Android SDK or update your PATH to include path to valid SDK directory.');
|
||||
throw new Error('ANDROID_HOME is not set and no "tools" directory found at ' + parentDir);
|
||||
}
|
||||
}
|
||||
if (hasAndroidHome && !adbInPath) {
|
||||
process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'platform-tools');
|
||||
}
|
||||
if (!process.env['ANDROID_HOME']) {
|
||||
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
|
||||
'Failed to find \'android\' command in your \'PATH\'. Try update your \'PATH\' to include path to valid SDK directory.');
|
||||
throw new Error('ANDROID_HOME is not set and "android" command not in your PATH. You must fulfill at least one of these conditions.');
|
||||
}
|
||||
if (!fs.existsSync(process.env['ANDROID_HOME'])) {
|
||||
throw new CordovaError('\'ANDROID_HOME\' environment variable is set to non-existent path: ' + process.env['ANDROID_HOME'] +
|
||||
'\nTry update it manually to point to valid SDK directory.');
|
||||
throw new Error('ANDROID_HOME is set to a non-existant path: ' + process.env['ANDROID_HOME']);
|
||||
}
|
||||
// Check that the target sdk level is installed.
|
||||
return module.exports.check_android_target(module.exports.get_target());
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.getAbsoluteAndroidCmd = function () {
|
||||
var cmd = forgivingWhichSync('android');
|
||||
if (process.platform === 'win32') {
|
||||
return '"' + cmd + '"';
|
||||
}
|
||||
return cmd.replace(/(\s)/g, '\\$1');
|
||||
module.exports.getAbsoluteAndroidCmd = function() {
|
||||
return forgivingWhichSync('android').replace(/(\s)/g, '\\$1');
|
||||
};
|
||||
|
||||
module.exports.check_android_target = function(valid_target) {
|
||||
@@ -244,87 +220,23 @@ module.exports.check_android_target = function(valid_target) {
|
||||
// android-L
|
||||
// Google Inc.:Google APIs:20
|
||||
// Google Inc.:Glass Development Kit Preview:20
|
||||
if (!valid_target) valid_target = module.exports.get_target();
|
||||
var msg = 'Android SDK not found. Make sure that it is installed. If it is not at the default location, set the ANDROID_HOME environment variable.';
|
||||
return tryCommand('android list targets --compact', msg)
|
||||
.then(function(output) {
|
||||
var targets = output.split('\n');
|
||||
if (targets.indexOf(valid_target) >= 0) {
|
||||
return targets;
|
||||
if (output.split('\n').indexOf(valid_target) == -1) {
|
||||
var androidCmd = module.exports.getAbsoluteAndroidCmd();
|
||||
throw new Error('Please install Android target: "' + valid_target + '".\n\n' +
|
||||
'Hint: Open the SDK manager by running: ' + androidCmd + '\n' +
|
||||
'You will require:\n' +
|
||||
'1. "SDK Platform" for ' + valid_target + '\n' +
|
||||
'2. "Android SDK Platform-tools (latest)\n' +
|
||||
'3. "Android SDK Build-tools" (latest)');
|
||||
}
|
||||
|
||||
var androidCmd = module.exports.getAbsoluteAndroidCmd();
|
||||
throw new CordovaError('Please install Android target: "' + valid_target + '".\n\n' +
|
||||
'Hint: Open the SDK manager by running: ' + androidCmd + '\n' +
|
||||
'You will require:\n' +
|
||||
'1. "SDK Platform" for ' + valid_target + '\n' +
|
||||
'2. "Android SDK Platform-tools (latest)\n' +
|
||||
'3. "Android SDK Build-tools" (latest)');
|
||||
});
|
||||
};
|
||||
|
||||
// Returns a promise.
|
||||
module.exports.run = function() {
|
||||
return Q.all([this.check_java(), this.check_android().then(this.check_android_target)])
|
||||
.then(function() {
|
||||
console.log('ANDROID_HOME=' + process.env['ANDROID_HOME']);
|
||||
console.log('JAVA_HOME=' + process.env['JAVA_HOME']);
|
||||
});
|
||||
};
|
||||
return Q.all([this.check_java(), this.check_android()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Object thar represents one of requirements for current platform.
|
||||
* @param {String} id The unique identifier for this requirements.
|
||||
* @param {String} name The name of requirements. Human-readable field.
|
||||
* @param {String} version The version of requirement installed. In some cases could be an array of strings
|
||||
* (for example, check_android_target returns an array of android targets installed)
|
||||
* @param {Boolean} installed Indicates whether the requirement is installed or not
|
||||
*/
|
||||
var Requirement = function (id, name, version, installed) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.installed = installed || false;
|
||||
this.metadata = {
|
||||
version: version,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Methods that runs all checks one by one and returns a result of checks
|
||||
* as an array of Requirement objects. This method intended to be used by cordova-lib check_reqs method
|
||||
*
|
||||
* @return Promise<Requirement[]> Array of requirements. Due to implementation, promise is always fulfilled.
|
||||
*/
|
||||
module.exports.check_all = function() {
|
||||
|
||||
var requirements = [
|
||||
new Requirement('java', 'Java JDK'),
|
||||
new Requirement('androidSdk', 'Android SDK'),
|
||||
new Requirement('androidTarget', 'Android target'),
|
||||
new Requirement('gradle', 'Gradle')
|
||||
];
|
||||
|
||||
var checkFns = [
|
||||
this.check_java,
|
||||
this.check_android,
|
||||
this.check_android_target,
|
||||
this.check_gradle
|
||||
];
|
||||
|
||||
// Then execute requirement checks one-by-one
|
||||
return checkFns.reduce(function (promise, checkFn, idx) {
|
||||
// Update each requirement with results
|
||||
var requirement = requirements[idx];
|
||||
return promise.then(checkFn)
|
||||
.then(function (version) {
|
||||
requirement.installed = true;
|
||||
requirement.metadata.version = version;
|
||||
}, function (err) {
|
||||
requirement.metadata.reason = err instanceof Error ? err.message : err;
|
||||
});
|
||||
}, Q())
|
||||
.then(function () {
|
||||
// When chain is completed, return requirements array to upstream API
|
||||
return requirements;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -18,18 +18,26 @@
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var shell = require('shelljs'),
|
||||
child_process = require('child_process'),
|
||||
Q = require('q'),
|
||||
path = require('path'),
|
||||
fs = require('fs'),
|
||||
check_reqs = require('./check_reqs'),
|
||||
ROOT = path.join(__dirname, '..', '..');
|
||||
|
||||
var MIN_SDK_VERSION = 14;
|
||||
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
var AndroidManifest = require('../templates/cordova/lib/AndroidManifest');
|
||||
// Returns a promise.
|
||||
function exec(command, opt_cwd) {
|
||||
var d = Q.defer();
|
||||
console.log('Running: ' + command);
|
||||
child_process.exec(command, { cwd: opt_cwd }, function(err, stdout, stderr) {
|
||||
stdout && console.log(stdout);
|
||||
stderr && console.error(stderr);
|
||||
if (err) d.reject(err);
|
||||
else d.resolve(stdout);
|
||||
});
|
||||
return d.promise;
|
||||
}
|
||||
|
||||
function setShellFatal(value, func) {
|
||||
var oldVal = shell.config.fatal;
|
||||
@@ -44,67 +52,52 @@ function getFrameworkDir(projectPath, shared) {
|
||||
|
||||
function copyJsAndLibrary(projectPath, shared, projectName) {
|
||||
var nestedCordovaLibPath = getFrameworkDir(projectPath, false);
|
||||
var srcCordovaJsPath = path.join(ROOT, 'bin', 'templates', 'project', 'assets', 'www', 'cordova.js');
|
||||
shell.cp('-f', srcCordovaJsPath, path.join(projectPath, 'assets', 'www', 'cordova.js'));
|
||||
|
||||
// Copy the cordova.js file to platforms/<platform>/platform_www/
|
||||
// The www dir is nuked on each prepare so we keep cordova.js in platform_www
|
||||
shell.mkdir('-p', path.join(projectPath, 'platform_www'));
|
||||
shell.cp('-f', srcCordovaJsPath, path.join(projectPath, 'platform_www'));
|
||||
|
||||
// Copy cordova-js-src directory into platform_www directory.
|
||||
// We need these files to build cordova.js if using browserify method.
|
||||
shell.cp('-rf', path.join(ROOT, 'cordova-js-src'), path.join(projectPath, 'platform_www'));
|
||||
|
||||
shell.cp('-f', path.join(ROOT, 'framework', 'assets', 'www', 'cordova.js'), path.join(projectPath, 'assets', 'www', 'cordova.js'));
|
||||
// Don't fail if there are no old jars.
|
||||
setShellFatal(false, function() {
|
||||
shell.ls(path.join(projectPath, 'libs', 'cordova-*.jar')).forEach(function(oldJar) {
|
||||
console.log('Deleting ' + oldJar);
|
||||
console.log("Deleting " + oldJar);
|
||||
shell.rm('-f', oldJar);
|
||||
});
|
||||
var wasSymlink = true;
|
||||
try {
|
||||
// Delete the symlink if it was one.
|
||||
fs.unlinkSync(nestedCordovaLibPath);
|
||||
} catch (e) {
|
||||
wasSymlink = false;
|
||||
}
|
||||
// Delete old library project if it existed.
|
||||
if (shared) {
|
||||
shell.rm('-rf', nestedCordovaLibPath);
|
||||
} else if (!wasSymlink) {
|
||||
// Delete only the src, since Eclipse / Android Studio can't handle their project files being deleted.
|
||||
} else {
|
||||
// Delete only the src, since eclipse can't handle its .project file being deleted.
|
||||
shell.rm('-rf', path.join(nestedCordovaLibPath, 'src'));
|
||||
}
|
||||
});
|
||||
if (shared) {
|
||||
var relativeFrameworkPath = path.relative(projectPath, getFrameworkDir(projectPath, true));
|
||||
fs.symlinkSync(relativeFrameworkPath, nestedCordovaLibPath, 'dir');
|
||||
} else {
|
||||
if (!shared) {
|
||||
shell.mkdir('-p', nestedCordovaLibPath);
|
||||
shell.cp('-f', path.join(ROOT, 'framework', 'AndroidManifest.xml'), nestedCordovaLibPath);
|
||||
shell.cp('-f', path.join(ROOT, 'framework', 'project.properties'), nestedCordovaLibPath);
|
||||
shell.cp('-f', path.join(ROOT, 'framework', 'build.gradle'), nestedCordovaLibPath);
|
||||
shell.cp('-f', path.join(ROOT, 'framework', 'cordova.gradle'), nestedCordovaLibPath);
|
||||
shell.cp('-r', path.join(ROOT, 'framework', 'src'), nestedCordovaLibPath);
|
||||
// Create an eclipse project file and set the name of it to something unique.
|
||||
// Without this, you can't import multiple CordovaLib projects into the same workspace.
|
||||
var eclipseProjectFilePath = path.join(nestedCordovaLibPath, '.project');
|
||||
if (!fs.existsSync(eclipseProjectFilePath)) {
|
||||
var data = '<?xml version="1.0" encoding="UTF-8"?><projectDescription><name>' + projectName + '-' + 'CordovaLib</name></projectDescription>';
|
||||
fs.writeFileSync(eclipseProjectFilePath, data, 'utf8');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function extractSubProjectPaths(data) {
|
||||
var ret = {};
|
||||
var r = /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg;
|
||||
var r = /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg
|
||||
var m;
|
||||
while ((m = r.exec(data))) {
|
||||
while (m = r.exec(data)) {
|
||||
ret[m[1]] = 1;
|
||||
}
|
||||
return Object.keys(ret);
|
||||
}
|
||||
|
||||
function writeProjectProperties(projectPath, target_api) {
|
||||
function writeProjectProperties(projectPath, target_api, shared) {
|
||||
var dstPath = path.join(projectPath, 'project.properties');
|
||||
var templatePath = path.join(ROOT, 'bin', 'templates', 'project', 'project.properties');
|
||||
var srcPath = fs.existsSync(dstPath) ? dstPath : templatePath;
|
||||
|
||||
var data = fs.readFileSync(srcPath, 'utf8');
|
||||
data = data.replace(/^target=.*/m, 'target=' + target_api);
|
||||
var subProjects = extractSubProjectPaths(data);
|
||||
@@ -114,7 +107,7 @@ function writeProjectProperties(projectPath, target_api) {
|
||||
/^(\.\.[\\\/])+framework$/m.exec(p)
|
||||
);
|
||||
});
|
||||
subProjects.unshift('CordovaLib');
|
||||
subProjects.unshift(shared ? path.relative(projectPath, path.join(ROOT, 'framework')) : 'CordovaLib');
|
||||
data = data.replace(/^\s*android\.library\.reference\.\d+=.*\n/mg, '');
|
||||
if (!/\n$/.exec(data)) {
|
||||
data += '\n';
|
||||
@@ -125,13 +118,9 @@ function writeProjectProperties(projectPath, target_api) {
|
||||
fs.writeFileSync(dstPath, data);
|
||||
}
|
||||
|
||||
function prepBuildFiles(projectPath) {
|
||||
var buildModule = require(path.join(path.resolve(projectPath), 'cordova', 'lib', 'build'));
|
||||
buildModule.prepBuildFiles();
|
||||
}
|
||||
|
||||
function copyBuildRules(projectPath) {
|
||||
var srcDir = path.join(ROOT, 'bin', 'templates', 'project');
|
||||
shell.cp('-f', path.join(srcDir, 'custom_rules.xml'), projectPath);
|
||||
|
||||
shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath);
|
||||
}
|
||||
@@ -143,8 +132,8 @@ function copyScripts(projectPath) {
|
||||
shell.rm('-rf', destScriptsDir);
|
||||
// Copy in the new ones.
|
||||
shell.cp('-r', srcScriptsDir, projectPath);
|
||||
shell.cp('-r', path.join(ROOT, 'node_modules'), destScriptsDir);
|
||||
shell.cp(path.join(ROOT, 'bin', 'check_reqs*'), destScriptsDir);
|
||||
shell.cp('-r', path.join(ROOT, 'bin', 'node_modules'), destScriptsDir);
|
||||
shell.cp(path.join(ROOT, 'bin', 'check_reqs'), path.join(destScriptsDir, 'check_reqs'));
|
||||
shell.cp(path.join(ROOT, 'bin', 'lib', 'check_reqs.js'), path.join(projectPath, 'cordova', 'lib', 'check_reqs.js'));
|
||||
shell.cp(path.join(ROOT, 'bin', 'android_sdk_version'), path.join(destScriptsDir, 'android_sdk_version'));
|
||||
shell.cp(path.join(ROOT, 'bin', 'lib', 'android_sdk_version.js'), path.join(projectPath, 'cordova', 'lib', 'android_sdk_version.js'));
|
||||
@@ -157,16 +146,14 @@ function copyScripts(projectPath) {
|
||||
*/
|
||||
function validatePackageName(package_name) {
|
||||
//Make the package conform to Java package types
|
||||
//http://developer.android.com/guide/topics/manifest/manifest-element.html#package
|
||||
//Enforce underscore limitation
|
||||
var msg = 'Error validating package name. ';
|
||||
if (!/^[a-zA-Z][a-zA-Z0-9_]+(\.[a-zA-Z][a-zA-Z0-9_]*)+$/.test(package_name)) {
|
||||
return Q.reject(new CordovaError(msg + 'Package name must look like: com.company.Name'));
|
||||
if (!/^[a-zA-Z]+(\.[a-zA-Z0-9][a-zA-Z0-9_]*)+$/.test(package_name)) {
|
||||
return Q.reject('Package name must look like: com.company.Name');
|
||||
}
|
||||
|
||||
//Class is a reserved word
|
||||
if(/\b[Cc]lass\b/.test(package_name)) {
|
||||
return Q.reject(new CordovaError(msg + '"class" is a reserved word'));
|
||||
return Q.reject('class is a reserved word');
|
||||
}
|
||||
|
||||
return Q.resolve();
|
||||
@@ -178,152 +165,156 @@ function validatePackageName(package_name) {
|
||||
* otherwise.
|
||||
*/
|
||||
function validateProjectName(project_name) {
|
||||
var msg = 'Error validating project name. ';
|
||||
//Make sure there's something there
|
||||
if (project_name === '') {
|
||||
return Q.reject(new CordovaError(msg + 'Project name cannot be empty'));
|
||||
return Q.reject('Project name cannot be empty');
|
||||
}
|
||||
|
||||
//Enforce stupid name error
|
||||
if (project_name === 'CordovaActivity') {
|
||||
return Q.reject(new CordovaError(msg + 'Project name cannot be CordovaActivity'));
|
||||
return Q.reject('Project name cannot be CordovaActivity');
|
||||
}
|
||||
|
||||
//Classes in Java don't begin with numbers
|
||||
if (/^[0-9]/.test(project_name)) {
|
||||
return Q.reject(new CordovaError(msg + 'Project name must not begin with a number'));
|
||||
return Q.reject('Project name must not begin with a number');
|
||||
}
|
||||
|
||||
return Q.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* $ create [options]
|
||||
*
|
||||
* Creates an android application with the given options.
|
||||
*
|
||||
* @param {String} project_path Path to the new Cordova android project.
|
||||
* @param {ConfigParser} config Instance of ConfigParser to retrieve basic
|
||||
* project properties.
|
||||
* @param {Object} [options={}] Various options
|
||||
* @param {String} [options.activityName='MainActivity'] Name for the
|
||||
* activity
|
||||
* @param {Boolean} [options.link=false] Specifies whether javascript files
|
||||
* and CordovaLib framework will be symlinked to created application.
|
||||
* @param {String} [options.customTemplate] Path to project template
|
||||
* (override)
|
||||
* @param {EventEmitter} [events] An EventEmitter instance for logging
|
||||
* events
|
||||
* Options:
|
||||
*
|
||||
* @return {Promise<String>} Directory where application has been created
|
||||
* - `project_path` {String} Path to the new Cordova android project.
|
||||
* - `package_name`{String} Package name, following reverse-domain style convention.
|
||||
* - `project_name` {String} Project name.
|
||||
* - 'project_template_dir' {String} Path to project template (override).
|
||||
*
|
||||
* Returns a promise.
|
||||
*/
|
||||
exports.create = function(project_path, config, options, events) {
|
||||
|
||||
options = options || {};
|
||||
exports.createProject = function(project_path, package_name, project_name, project_template_dir, use_shared_project, use_cli_template) {
|
||||
var VERSION = fs.readFileSync(path.join(ROOT, 'VERSION'), 'utf-8').trim();
|
||||
|
||||
// Set default values for path, package and name
|
||||
project_path = path.relative(process.cwd(), (project_path || 'CordovaExample'));
|
||||
project_path = typeof project_path !== 'undefined' ? project_path : "CordovaExample";
|
||||
project_path = path.relative(process.cwd(), project_path);
|
||||
package_name = typeof package_name !== 'undefined' ? package_name : 'my.cordova.project';
|
||||
project_name = typeof project_name !== 'undefined' ? project_name : 'CordovaExample';
|
||||
project_template_dir = typeof project_template_dir !== 'undefined' ?
|
||||
project_template_dir :
|
||||
path.join(ROOT, 'bin', 'templates', 'project');
|
||||
|
||||
var package_as_path = package_name.replace(/\./g, path.sep);
|
||||
var activity_dir = path.join(project_path, 'src', package_as_path);
|
||||
// safe_activity_name is being hardcoded to avoid issues with unicode app name (https://issues.apache.org/jira/browse/CB-6511)
|
||||
// TODO: provide option to specify activity name via CLI (proposal: https://issues.apache.org/jira/browse/CB-7231)
|
||||
var safe_activity_name = 'MainActivity';
|
||||
var activity_path = path.join(activity_dir, safe_activity_name + '.java');
|
||||
var target_api = check_reqs.get_target();
|
||||
var manifest_path = path.join(project_path, 'AndroidManifest.xml');
|
||||
|
||||
// Check if project already exists
|
||||
if(fs.existsSync(project_path)) {
|
||||
return Q.reject(new CordovaError('Project already exists! Delete and recreate'));
|
||||
return Q.reject('Project already exists! Delete and recreate');
|
||||
}
|
||||
|
||||
var package_name = config.packageName() || 'my.cordova.project';
|
||||
var project_name = config.name() ?
|
||||
config.name().replace(/[^\w.]/g,'_') : 'CordovaExample';
|
||||
|
||||
var safe_activity_name = config.android_activityName() || options.activityName || 'MainActivity';
|
||||
var target_api = check_reqs.get_target();
|
||||
|
||||
//Make the package conform to Java package types
|
||||
return validatePackageName(package_name)
|
||||
.then(function() {
|
||||
validateProjectName(project_name);
|
||||
}).then(function() {
|
||||
// Log the given values for the project
|
||||
events.emit('log', 'Creating Cordova project for the Android platform:');
|
||||
events.emit('log', '\tPath: ' + project_path);
|
||||
events.emit('log', '\tPackage: ' + package_name);
|
||||
events.emit('log', '\tName: ' + project_name);
|
||||
events.emit('log', '\tActivity: ' + safe_activity_name);
|
||||
events.emit('log', '\tAndroid target: ' + target_api);
|
||||
console.log('Creating Cordova project for the Android platform:');
|
||||
console.log('\tPath: ' + project_path);
|
||||
console.log('\tPackage: ' + package_name);
|
||||
console.log('\tName: ' + project_name);
|
||||
console.log('\tAndroid target: ' + target_api);
|
||||
|
||||
events.emit('verbose', 'Copying template files...');
|
||||
console.log('Copying template files...');
|
||||
|
||||
setShellFatal(true, function() {
|
||||
var project_template_dir = options.customTemplate || path.join(ROOT, 'bin', 'templates', 'project');
|
||||
// copy project template
|
||||
shell.cp('-r', path.join(project_template_dir, 'assets'), project_path);
|
||||
shell.cp('-r', path.join(project_template_dir, 'res'), project_path);
|
||||
shell.cp('-r', path.join(ROOT, 'framework', 'res', 'xml'), path.join(project_path, 'res'));
|
||||
shell.cp(path.join(project_template_dir, 'gitignore'), path.join(project_path, '.gitignore'));
|
||||
|
||||
// Manually create directories that would be empty within the template (since git doesn't track directories).
|
||||
shell.mkdir(path.join(project_path, 'libs'));
|
||||
|
||||
// Add in the proper eclipse project file.
|
||||
if (use_cli_template) {
|
||||
var note = 'To show `assets/www` or `res/xml/config.xml`, go to:\n' +
|
||||
' Project -> Properties -> Resource -> Resource Filters\n' +
|
||||
'And delete the exclusion filter.\n';
|
||||
shell.cp(path.join(project_template_dir, 'eclipse-project-CLI'), path.join(project_path, '.project'));
|
||||
fs.writeFileSync(path.join(project_path, 'assets', '_where-is-www.txt'), note);
|
||||
} else {
|
||||
shell.cp(path.join(project_template_dir, 'eclipse-project'), path.join(project_path, '.project'));
|
||||
}
|
||||
|
||||
// copy cordova.js, cordova.jar
|
||||
copyJsAndLibrary(project_path, options.link, safe_activity_name);
|
||||
copyJsAndLibrary(project_path, use_shared_project, safe_activity_name);
|
||||
|
||||
// interpolate the activity name and package
|
||||
var packagePath = package_name.replace(/\./g, path.sep);
|
||||
var activity_dir = path.join(project_path, 'src', packagePath);
|
||||
var activity_path = path.join(activity_dir, safe_activity_name + '.java');
|
||||
shell.mkdir('-p', activity_dir);
|
||||
shell.cp('-f', path.join(project_template_dir, 'Activity.java'), activity_path);
|
||||
shell.sed('-i', /__ACTIVITY__/, safe_activity_name, activity_path);
|
||||
shell.sed('-i', /__NAME__/, project_name, path.join(project_path, 'res', 'values', 'strings.xml'));
|
||||
shell.sed('-i', /__NAME__/, project_name, path.join(project_path, '.project'));
|
||||
shell.sed('-i', /__ID__/, package_name, activity_path);
|
||||
|
||||
var manifest = new AndroidManifest(path.join(project_template_dir, 'AndroidManifest.xml'));
|
||||
manifest.setPackageId(package_name)
|
||||
.setTargetSdkVersion(target_api.split('-')[1])
|
||||
.getActivity().setName(safe_activity_name);
|
||||
|
||||
var manifest_path = path.join(project_path, 'AndroidManifest.xml');
|
||||
manifest.write(manifest_path);
|
||||
|
||||
shell.cp('-f', path.join(project_template_dir, 'AndroidManifest.xml'), manifest_path);
|
||||
shell.sed('-i', /__ACTIVITY__/, safe_activity_name, manifest_path);
|
||||
shell.sed('-i', /__PACKAGE__/, package_name, manifest_path);
|
||||
shell.sed('-i', /__APILEVEL__/, target_api.split('-')[1], manifest_path);
|
||||
copyScripts(project_path);
|
||||
copyBuildRules(project_path);
|
||||
});
|
||||
// Link it to local android install.
|
||||
writeProjectProperties(project_path, target_api);
|
||||
prepBuildFiles(project_path);
|
||||
events.emit('log', generateDoneMessage('create', options.link));
|
||||
}).thenResolve(project_path);
|
||||
};
|
||||
writeProjectProperties(project_path, target_api, use_shared_project);
|
||||
}).then(function() {
|
||||
console.log('Project successfully created.');
|
||||
});
|
||||
}
|
||||
|
||||
function generateDoneMessage(type, link) {
|
||||
var pkg = require('../../package');
|
||||
var msg = 'Android project ' + (type == 'update' ? 'updated ' : 'created ') + 'with ' + pkg.name + '@' + pkg.version;
|
||||
if (link) {
|
||||
msg += ' and has a linked CordovaLib';
|
||||
// Attribute removed in Cordova 4.4 (CB-5447).
|
||||
function removeDebuggableFromManifest(projectPath) {
|
||||
var manifestPath = path.join(projectPath, 'AndroidManifest.xml');
|
||||
shell.sed('-i', /\s*android:debuggable="true"/, '', manifestPath);
|
||||
}
|
||||
|
||||
function extractProjectNameFromManifest(projectPath) {
|
||||
var manifestPath = path.join(projectPath, 'AndroidManifest.xml');
|
||||
var manifestData = fs.readFileSync(manifestPath, 'utf8');
|
||||
var m = /<activity[\s\S]*?android:name\s*=\s*"(.*?)"/i.exec(manifestData);
|
||||
if (!m) {
|
||||
throw new Error('Could not find activity name in ' + manifestPath);
|
||||
}
|
||||
return msg;
|
||||
return m[1];
|
||||
}
|
||||
|
||||
// Returns a promise.
|
||||
exports.update = function(projectPath, options, events) {
|
||||
options = options || {};
|
||||
|
||||
exports.updateProject = function(projectPath, shared) {
|
||||
var newVersion = fs.readFileSync(path.join(ROOT, 'VERSION'), 'utf-8').trim();
|
||||
return Q()
|
||||
.then(function() {
|
||||
|
||||
var manifest = new AndroidManifest(path.join(projectPath, 'AndroidManifest.xml'));
|
||||
|
||||
if (Number(manifest.getMinSdkVersion()) < MIN_SDK_VERSION) {
|
||||
events.emit('verbose', 'Updating minSdkVersion to ' + MIN_SDK_VERSION + ' in AndroidManifest.xml');
|
||||
manifest.setMinSdkVersion(MIN_SDK_VERSION);
|
||||
}
|
||||
|
||||
manifest.setDebuggable(false).write();
|
||||
|
||||
var projectName = manifest.getActivity().getName();
|
||||
var projectName = extractProjectNameFromManifest(projectPath);
|
||||
var target_api = check_reqs.get_target();
|
||||
|
||||
copyJsAndLibrary(projectPath, options.link, projectName);
|
||||
copyJsAndLibrary(projectPath, shared, projectName);
|
||||
copyScripts(projectPath);
|
||||
copyBuildRules(projectPath);
|
||||
writeProjectProperties(projectPath, target_api);
|
||||
prepBuildFiles(projectPath);
|
||||
events.emit('log', generateDoneMessage('update', options.link));
|
||||
}).thenResolve(projectPath);
|
||||
removeDebuggableFromManifest(projectPath);
|
||||
writeProjectProperties(projectPath, target_api, shared);
|
||||
console.log('Android project is now at version ' + newVersion);
|
||||
console.log('If you updated from a pre-3.2.0 version and use an IDE, we now require that you import the "CordovaLib" library project.');
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
32
bin/lib/simpleargs.js
Normal file
32
bin/lib/simpleargs.js
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
exports.getArgs = function(argv) {
|
||||
var ret = {};
|
||||
var posArgs = [];
|
||||
for (var i = 2, arg; arg = argv[i] || i < argv.length; ++i) {
|
||||
if (/^--/.exec(arg)) {
|
||||
ret[arg] = true;
|
||||
} else {
|
||||
posArgs.push(arg);
|
||||
}
|
||||
}
|
||||
ret._ = posArgs;
|
||||
return ret;
|
||||
};
|
||||
1
bin/node_modules/.bin/shjs
generated
vendored
Symbolic link
1
bin/node_modules/.bin/shjs
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../shelljs/bin/shjs
|
||||
40
bin/node_modules/q/CONTRIBUTING.md
generated
vendored
Normal file
40
bin/node_modules/q/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
For pull requests:
|
||||
|
||||
- Be consistent with prevalent style and design decisions.
|
||||
- Add a Jasmine spec to `specs/q-spec.js`.
|
||||
- Use `npm test` to avoid regressions.
|
||||
- Run tests in `q-spec/run.html` in as many supported browsers as you
|
||||
can find the will to deal with.
|
||||
- Do not build minified versions; we do this each release.
|
||||
- If you would be so kind, add a note to `CHANGES.md` in an
|
||||
appropriate section:
|
||||
|
||||
- `Next Major Version` if it introduces backward incompatibilities
|
||||
to code in the wild using documented features.
|
||||
- `Next Minor Version` if it adds a new feature.
|
||||
- `Next Patch Version` if it fixes a bug.
|
||||
|
||||
For releases:
|
||||
|
||||
- Run `npm test`.
|
||||
- Run tests in `q-spec/run.html` in a representative sample of every
|
||||
browser under the sun.
|
||||
- Run `npm run cover` and make sure you're happy with the results.
|
||||
- Run `npm run minify` and be sure to commit the resulting `q.min.js`.
|
||||
- Note the Gzipped size output by the previous command, and update
|
||||
`README.md` if it has changed to 1 significant digit.
|
||||
- Stash any local changes.
|
||||
- Update `CHANGES.md` to reflect all changes in the differences
|
||||
between `HEAD` and the previous tagged version. Give credit where
|
||||
credit is due.
|
||||
- Update `README.md` to address all new, non-experimental features.
|
||||
- Update the API reference on the Wiki to reflect all non-experimental
|
||||
features.
|
||||
- Use `npm version major|minor|patch` to update `package.json`,
|
||||
commit, and tag the new version.
|
||||
- Use `npm publish` to send up a new release.
|
||||
- Send an email to the q-continuum mailing list announcing the new
|
||||
release and the notes from the change log. This helps folks
|
||||
maintaining other package ecosystems.
|
||||
|
||||
3
node_modules/q/LICENSE → bin/node_modules/q/LICENSE
generated
vendored
3
node_modules/q/LICENSE → bin/node_modules/q/LICENSE
generated
vendored
@@ -1,4 +1,5 @@
|
||||
Copyright 2009–2014 Kristopher Michael Kowal. All rights reserved.
|
||||
|
||||
Copyright 2009–2012 Kristopher Michael Kowal. All rights reserved.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
88
node_modules/q/README.md → bin/node_modules/q/README.md
generated
vendored
88
node_modules/q/README.md → bin/node_modules/q/README.md
generated
vendored
@@ -1,17 +1,10 @@
|
||||
[](http://travis-ci.org/kriskowal/q)
|
||||
|
||||
<a href="http://promises-aplus.github.com/promises-spec">
|
||||
<img src="http://kriskowal.github.io/q/q.png"
|
||||
align="right" alt="Q logo" />
|
||||
<img src="http://promises-aplus.github.com/promises-spec/assets/logo-small.png"
|
||||
align="right" alt="Promises/A+ logo" />
|
||||
</a>
|
||||
|
||||
*This is Q version 1, from the `v1` branch in Git. This documentation applies to
|
||||
the latest of both the version 1 and version 0.9 release trains. These releases
|
||||
are stable. There will be no further releases of 0.9 after 0.9.7 which is nearly
|
||||
equivalent to version 1.0.0. All further releases of `q@~1.0` will be backward
|
||||
compatible. The version 2 release train introduces significant and
|
||||
backward-incompatible changes and is experimental at this time.*
|
||||
|
||||
If a function cannot return a value or throw an exception without
|
||||
blocking, it can return a promise instead. A promise is an object
|
||||
that represents the return value or the thrown exception that the
|
||||
@@ -80,7 +73,7 @@ The Q module can be loaded as:
|
||||
the [q](https://npmjs.org/package/q) package
|
||||
- An AMD module
|
||||
- A [component](https://github.com/component/component) as ``microjs/q``
|
||||
- Using [bower](http://bower.io/) as `q#1.0.1`
|
||||
- Using [bower](http://bower.io/) as ``q``
|
||||
- Using [NuGet](http://nuget.org/) as [Q](https://nuget.org/packages/q)
|
||||
|
||||
Q can exchange promises with jQuery, Dojo, When.js, WinJS, and more.
|
||||
@@ -294,7 +287,7 @@ If you have a promise for an array, you can use ``spread`` as a
|
||||
replacement for ``then``. The ``spread`` function “spreads” the
|
||||
values over the arguments of the fulfillment handler. The rejection handler
|
||||
will get called at the first sign of failure. That is, whichever of
|
||||
the received promises fails first gets handled by the rejection handler.
|
||||
the recived promises fails first gets handled by the rejection handler.
|
||||
|
||||
```javascript
|
||||
function eventualAdd(a, b) {
|
||||
@@ -335,18 +328,6 @@ Q.allSettled(promises)
|
||||
});
|
||||
```
|
||||
|
||||
The ``any`` function accepts an array of promises and returns a promise that is
|
||||
fulfilled by the first given promise to be fulfilled, or rejected if all of the
|
||||
given promises are rejected.
|
||||
|
||||
```javascript
|
||||
Q.any(promises)
|
||||
.then(function (first) {
|
||||
// Any of the promises was fulfilled.
|
||||
}, function (error) {
|
||||
// All of the promises were rejected.
|
||||
});
|
||||
```
|
||||
|
||||
### Sequences
|
||||
|
||||
@@ -378,16 +359,16 @@ return funcs.reduce(function (soFar, f) {
|
||||
}, Q(initialVal));
|
||||
```
|
||||
|
||||
Or, you could use the ultra-compact version:
|
||||
Or, you could use th ultra-compact version:
|
||||
|
||||
```javascript
|
||||
return funcs.reduce(Q.when, Q(initialVal));
|
||||
return funcs.reduce(Q.when, Q());
|
||||
```
|
||||
|
||||
### Handling Errors
|
||||
|
||||
One sometimes-unintuive aspect of promises is that if you throw an
|
||||
exception in the fulfillment handler, it will not be caught by the error
|
||||
exception in the fulfillment handler, it will not be be caught by the error
|
||||
handler.
|
||||
|
||||
```javascript
|
||||
@@ -622,46 +603,6 @@ requestOkText("http://localhost:3000")
|
||||
});
|
||||
```
|
||||
|
||||
#### Using `Q.Promise`
|
||||
|
||||
This is an alternative promise-creation API that has the same power as
|
||||
the deferred concept, but without introducing another conceptual entity.
|
||||
|
||||
Rewriting the `requestOkText` example above using `Q.Promise`:
|
||||
|
||||
```javascript
|
||||
function requestOkText(url) {
|
||||
return Q.Promise(function(resolve, reject, notify) {
|
||||
var request = new XMLHttpRequest();
|
||||
|
||||
request.open("GET", url, true);
|
||||
request.onload = onload;
|
||||
request.onerror = onerror;
|
||||
request.onprogress = onprogress;
|
||||
request.send();
|
||||
|
||||
function onload() {
|
||||
if (request.status === 200) {
|
||||
resolve(request.responseText);
|
||||
} else {
|
||||
reject(new Error("Status code was " + request.status));
|
||||
}
|
||||
}
|
||||
|
||||
function onerror() {
|
||||
reject(new Error("Can't XHR " + JSON.stringify(url)));
|
||||
}
|
||||
|
||||
function onprogress(event) {
|
||||
notify(event.loaded / event.total);
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
If `requestOkText` were to throw an exception, the returned promise would be
|
||||
rejected with that thrown exception as the rejection reason.
|
||||
|
||||
### The Middle
|
||||
|
||||
If you are using a function that may return a promise, but just might
|
||||
@@ -850,20 +791,11 @@ From previous event:
|
||||
at Object.<anonymous> (/path/to/test.js:7:1)
|
||||
```
|
||||
|
||||
Note how you can see the function that triggered the async operation in the
|
||||
Note how you can see the the function that triggered the async operation in the
|
||||
stack trace! This is very helpful for debugging, as otherwise you end up getting
|
||||
only the first line, plus a bunch of Q internals, with no sign of where the
|
||||
operation started.
|
||||
|
||||
In node.js, this feature can also be enabled through the Q_DEBUG environment
|
||||
variable:
|
||||
|
||||
```
|
||||
Q_DEBUG=1 node server.js
|
||||
```
|
||||
|
||||
This will enable long stack support in every instance of Q.
|
||||
|
||||
This feature does come with somewhat-serious performance and memory overhead,
|
||||
however. If you're working with lots of promises, or trying to scale a server
|
||||
to many users, you should probably keep it off. But in development, go for it!
|
||||
@@ -872,10 +804,10 @@ to many users, you should probably keep it off. But in development, go for it!
|
||||
|
||||
You can view the results of the Q test suite [in your browser][tests]!
|
||||
|
||||
[tests]: https://rawgithub.com/kriskowal/q/v1/spec/q-spec.html
|
||||
[tests]: https://rawgithub.com/kriskowal/q/master/spec/q-spec.html
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2009–2015 Kristopher Michael Kowal and contributors
|
||||
Copyright 2009–2013 Kristopher Michael Kowal
|
||||
MIT License (enclosed)
|
||||
|
||||
71
bin/node_modules/q/benchmark/compare-with-callbacks.js
generated
vendored
Normal file
71
bin/node_modules/q/benchmark/compare-with-callbacks.js
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
"use strict";
|
||||
|
||||
var Q = require("../q");
|
||||
var fs = require("fs");
|
||||
|
||||
suite("A single simple async operation", function () {
|
||||
bench("with an immediately-fulfilled promise", function (done) {
|
||||
Q().then(done);
|
||||
});
|
||||
|
||||
bench("with direct setImmediate usage", function (done) {
|
||||
setImmediate(done);
|
||||
});
|
||||
|
||||
bench("with direct setTimeout(…, 0)", function (done) {
|
||||
setTimeout(done, 0);
|
||||
});
|
||||
});
|
||||
|
||||
suite("A fs.readFile", function () {
|
||||
var denodeified = Q.denodeify(fs.readFile);
|
||||
|
||||
set("iterations", 1000);
|
||||
set("delay", 1000);
|
||||
|
||||
bench("directly, with callbacks", function (done) {
|
||||
fs.readFile(__filename, done);
|
||||
});
|
||||
|
||||
bench("with Q.nfcall", function (done) {
|
||||
Q.nfcall(fs.readFile, __filename).then(done);
|
||||
});
|
||||
|
||||
bench("with a Q.denodeify'ed version", function (done) {
|
||||
denodeified(__filename).then(done);
|
||||
});
|
||||
|
||||
bench("with manual usage of deferred.makeNodeResolver", function (done) {
|
||||
var deferred = Q.defer();
|
||||
fs.readFile(__filename, deferred.makeNodeResolver());
|
||||
deferred.promise.then(done);
|
||||
});
|
||||
});
|
||||
|
||||
suite("1000 operations in parallel", function () {
|
||||
function makeCounter(desiredCount, ultimateCallback) {
|
||||
var soFar = 0;
|
||||
return function () {
|
||||
if (++soFar === desiredCount) {
|
||||
ultimateCallback();
|
||||
}
|
||||
};
|
||||
}
|
||||
var numberOfOps = 1000;
|
||||
|
||||
bench("with immediately-fulfilled promises", function (done) {
|
||||
var counter = makeCounter(numberOfOps, done);
|
||||
|
||||
for (var i = 0; i < numberOfOps; ++i) {
|
||||
Q().then(counter);
|
||||
}
|
||||
});
|
||||
|
||||
bench("with direct setImmediate usage", function (done) {
|
||||
var counter = makeCounter(numberOfOps, done);
|
||||
|
||||
for (var i = 0; i < numberOfOps; ++i) {
|
||||
setImmediate(counter);
|
||||
}
|
||||
});
|
||||
});
|
||||
36
bin/node_modules/q/benchmark/scenarios.js
generated
vendored
Normal file
36
bin/node_modules/q/benchmark/scenarios.js
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
"use strict";
|
||||
|
||||
var Q = require("../q");
|
||||
|
||||
suite("Chaining", function () {
|
||||
var numberToChain = 1000;
|
||||
|
||||
bench("Chaining many already-fulfilled promises together", function (done) {
|
||||
var currentPromise = Q();
|
||||
for (var i = 0; i < numberToChain; ++i) {
|
||||
currentPromise = currentPromise.then(function () {
|
||||
return Q();
|
||||
});
|
||||
}
|
||||
|
||||
currentPromise.then(done);
|
||||
});
|
||||
|
||||
bench("Chaining and then fulfilling the end of the chain", function (done) {
|
||||
var deferred = Q.defer();
|
||||
|
||||
var currentPromise = deferred.promise;
|
||||
for (var i = 0; i < numberToChain; ++i) {
|
||||
(function () {
|
||||
var promiseToReturn = currentPromise;
|
||||
currentPromise = Q().then(function () {
|
||||
return promiseToReturn;
|
||||
});
|
||||
}());
|
||||
}
|
||||
|
||||
currentPromise.then(done);
|
||||
|
||||
deferred.resolve();
|
||||
});
|
||||
});
|
||||
93
bin/node_modules/q/package.json
generated
vendored
Normal file
93
bin/node_modules/q/package.json
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
359
node_modules/q/q.js → bin/node_modules/q/q.js
generated
vendored
359
node_modules/q/q.js → bin/node_modules/q/q.js
generated
vendored
@@ -27,7 +27,8 @@
|
||||
*/
|
||||
|
||||
(function (definition) {
|
||||
"use strict";
|
||||
// Turn off strict mode for this function so we can assign to global.Q
|
||||
/* jshint strict: false */
|
||||
|
||||
// This file will function properly as a <script> tag, or a module
|
||||
// using CommonJS and NodeJS or RequireJS module formats. In
|
||||
@@ -39,7 +40,7 @@
|
||||
bootstrap("promise", definition);
|
||||
|
||||
// CommonJS
|
||||
} else if (typeof exports === "object" && typeof module === "object") {
|
||||
} else if (typeof exports === "object") {
|
||||
module.exports = definition();
|
||||
|
||||
// RequireJS
|
||||
@@ -55,25 +56,8 @@
|
||||
}
|
||||
|
||||
// <script>
|
||||
} else if (typeof window !== "undefined" || typeof self !== "undefined") {
|
||||
// Prefer window over self for add-on scripts. Use self for
|
||||
// non-windowed contexts.
|
||||
var global = typeof window !== "undefined" ? window : self;
|
||||
|
||||
// Get the `window` object, save the previous Q global
|
||||
// and initialize Q as a global.
|
||||
var previousQ = global.Q;
|
||||
global.Q = definition();
|
||||
|
||||
// Add a noConflict function so Q can be removed from the
|
||||
// global namespace.
|
||||
global.Q.noConflict = function () {
|
||||
global.Q = previousQ;
|
||||
return this;
|
||||
};
|
||||
|
||||
} else {
|
||||
throw new Error("This environment was not anticipated by Q. Please file a bug.");
|
||||
Q = definition();
|
||||
}
|
||||
|
||||
})(function () {
|
||||
@@ -105,67 +89,57 @@ var nextTick =(function () {
|
||||
var flushing = false;
|
||||
var requestTick = void 0;
|
||||
var isNodeJS = false;
|
||||
// queue for late tasks, used by unhandled rejection tracking
|
||||
var laterQueue = [];
|
||||
|
||||
function flush() {
|
||||
/* jshint loopfunc: true */
|
||||
var task, domain;
|
||||
|
||||
while (head.next) {
|
||||
head = head.next;
|
||||
task = head.task;
|
||||
var task = head.task;
|
||||
head.task = void 0;
|
||||
domain = head.domain;
|
||||
var domain = head.domain;
|
||||
|
||||
if (domain) {
|
||||
head.domain = void 0;
|
||||
domain.enter();
|
||||
}
|
||||
runSingle(task, domain);
|
||||
|
||||
}
|
||||
while (laterQueue.length) {
|
||||
task = laterQueue.pop();
|
||||
runSingle(task);
|
||||
}
|
||||
flushing = false;
|
||||
}
|
||||
// runs a single function in the async queue
|
||||
function runSingle(task, domain) {
|
||||
try {
|
||||
task();
|
||||
try {
|
||||
task();
|
||||
|
||||
} catch (e) {
|
||||
if (isNodeJS) {
|
||||
// In node, uncaught exceptions are considered fatal errors.
|
||||
// Re-throw them synchronously to interrupt flushing!
|
||||
} catch (e) {
|
||||
if (isNodeJS) {
|
||||
// In node, uncaught exceptions are considered fatal errors.
|
||||
// Re-throw them synchronously to interrupt flushing!
|
||||
|
||||
// Ensure continuation if the uncaught exception is suppressed
|
||||
// listening "uncaughtException" events (as domains does).
|
||||
// Continue in next event to avoid tick recursion.
|
||||
if (domain) {
|
||||
domain.exit();
|
||||
}
|
||||
setTimeout(flush, 0);
|
||||
if (domain) {
|
||||
domain.enter();
|
||||
}
|
||||
// Ensure continuation if the uncaught exception is suppressed
|
||||
// listening "uncaughtException" events (as domains does).
|
||||
// Continue in next event to avoid tick recursion.
|
||||
if (domain) {
|
||||
domain.exit();
|
||||
}
|
||||
setTimeout(flush, 0);
|
||||
if (domain) {
|
||||
domain.enter();
|
||||
}
|
||||
|
||||
throw e;
|
||||
|
||||
} else {
|
||||
// In browsers, uncaught exceptions are not fatal.
|
||||
// Re-throw them asynchronously to avoid slow-downs.
|
||||
setTimeout(function () {
|
||||
throw e;
|
||||
}, 0);
|
||||
|
||||
} else {
|
||||
// In browsers, uncaught exceptions are not fatal.
|
||||
// Re-throw them asynchronously to avoid slow-downs.
|
||||
setTimeout(function() {
|
||||
throw e;
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (domain) {
|
||||
domain.exit();
|
||||
}
|
||||
}
|
||||
|
||||
if (domain) {
|
||||
domain.exit();
|
||||
}
|
||||
flushing = false;
|
||||
}
|
||||
|
||||
nextTick = function (task) {
|
||||
@@ -181,16 +155,9 @@ var nextTick =(function () {
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof process === "object" &&
|
||||
process.toString() === "[object process]" && process.nextTick) {
|
||||
// Ensure Q is in a real Node environment, with a `process.nextTick`.
|
||||
// To see through fake Node environments:
|
||||
// * Mocha test runner - exposes a `process` global without a `nextTick`
|
||||
// * Browserify - exposes a `process.nexTick` function that uses
|
||||
// `setTimeout`. In this case `setImmediate` is preferred because
|
||||
// it is faster. Browserify's `process.toString()` yields
|
||||
// "[object Object]", while in a real Node environment
|
||||
// `process.nextTick()` yields "[object process]".
|
||||
if (typeof process !== "undefined" && process.nextTick) {
|
||||
// Node.js before 0.9. Note that some fake-Node environments, like the
|
||||
// Mocha test runner, introduce a `process` global without a `nextTick`.
|
||||
isNodeJS = true;
|
||||
|
||||
requestTick = function () {
|
||||
@@ -234,16 +201,7 @@ var nextTick =(function () {
|
||||
setTimeout(flush, 0);
|
||||
};
|
||||
}
|
||||
// runs a task after all other tasks have been run
|
||||
// this is useful for unhandled rejection tracking that needs to happen
|
||||
// after all `then`d tasks have been run.
|
||||
nextTick.runAfter = function (task) {
|
||||
laterQueue.push(task);
|
||||
if (!flushing) {
|
||||
flushing = true;
|
||||
requestTick();
|
||||
}
|
||||
};
|
||||
|
||||
return nextTick;
|
||||
})();
|
||||
|
||||
@@ -253,8 +211,9 @@ var nextTick =(function () {
|
||||
// If you need a security guarantee, these primordials need to be
|
||||
// deeply frozen anyway, and if you don’t need a security guarantee,
|
||||
// this is just plain paranoid.
|
||||
// However, this **might** have the nice side-effect of reducing the size of
|
||||
// the minified code by reducing x.call() to merely x()
|
||||
// However, this does have the nice side-effect of reducing the size
|
||||
// of the code by reducing x.call() to merely x(), eliminating many
|
||||
// hard-to-minify characters.
|
||||
// See Mark Miller’s explanation of what this does.
|
||||
// http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming
|
||||
var call = Function.call;
|
||||
@@ -366,6 +325,22 @@ if (typeof ReturnValue !== "undefined") {
|
||||
};
|
||||
}
|
||||
|
||||
// Until V8 3.19 / Chromium 29 is released, SpiderMonkey is the only
|
||||
// engine that has a deployed base of browsers that support generators.
|
||||
// However, SM's generators use the Python-inspired semantics of
|
||||
// outdated ES6 drafts. We would like to support ES6, but we'd also
|
||||
// like to make it possible to use generators in deployed browsers, so
|
||||
// we also support Python-style generators. At some point we can remove
|
||||
// this block.
|
||||
var hasES6Generators;
|
||||
try {
|
||||
/* jshint evil: true, nonew: false */
|
||||
new Function("(function* (){ yield 1; })");
|
||||
hasES6Generators = true;
|
||||
} catch (e) {
|
||||
hasES6Generators = false;
|
||||
}
|
||||
|
||||
// long stack traces
|
||||
|
||||
var STACK_JUMP_SEPARATOR = "From previous event:";
|
||||
@@ -492,7 +467,7 @@ function Q(value) {
|
||||
// If the object is already a Promise, return it directly. This enables
|
||||
// the resolve function to both be used to created references from objects,
|
||||
// but to tolerably coerce non-promises to promises.
|
||||
if (value instanceof Promise) {
|
||||
if (isPromise(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -516,11 +491,6 @@ Q.nextTick = nextTick;
|
||||
*/
|
||||
Q.longStackSupport = false;
|
||||
|
||||
// enable long stacks if Q_DEBUG is set
|
||||
if (typeof process === "object" && process && process.env && process.env.Q_DEBUG) {
|
||||
Q.longStackSupport = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {promise, resolve, reject} object.
|
||||
*
|
||||
@@ -552,14 +522,14 @@ function defer() {
|
||||
progressListeners.push(operands[1]);
|
||||
}
|
||||
} else {
|
||||
Q.nextTick(function () {
|
||||
nextTick(function () {
|
||||
resolvedPromise.promiseDispatch.apply(resolvedPromise, args);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// XXX deprecated
|
||||
promise.valueOf = function () {
|
||||
promise.valueOf = deprecate(function () {
|
||||
if (messages) {
|
||||
return promise;
|
||||
}
|
||||
@@ -568,7 +538,7 @@ function defer() {
|
||||
resolvedPromise = nearerValue; // shorten chain
|
||||
}
|
||||
return nearerValue;
|
||||
};
|
||||
}, "valueOf", "inspect");
|
||||
|
||||
promise.inspect = function () {
|
||||
if (!resolvedPromise) {
|
||||
@@ -600,7 +570,7 @@ function defer() {
|
||||
promise.source = newPromise;
|
||||
|
||||
array_reduce(messages, function (undefined, message) {
|
||||
Q.nextTick(function () {
|
||||
nextTick(function () {
|
||||
newPromise.promiseDispatch.apply(newPromise, message);
|
||||
});
|
||||
}, void 0);
|
||||
@@ -638,7 +608,7 @@ function defer() {
|
||||
}
|
||||
|
||||
array_reduce(progressListeners, function (undefined, progressListener) {
|
||||
Q.nextTick(function () {
|
||||
nextTick(function () {
|
||||
progressListener(progress);
|
||||
});
|
||||
}, void 0);
|
||||
@@ -671,7 +641,6 @@ defer.prototype.makeNodeResolver = function () {
|
||||
* @returns a promise that may be resolved with the given resolve and reject
|
||||
* functions, or rejected by a thrown exception in resolver
|
||||
*/
|
||||
Q.Promise = promise; // ES6
|
||||
Q.promise = promise;
|
||||
function promise(resolver) {
|
||||
if (typeof resolver !== "function") {
|
||||
@@ -686,11 +655,6 @@ function promise(resolver) {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
promise.race = race; // ES6
|
||||
promise.all = all; // ES6
|
||||
promise.reject = reject; // ES6
|
||||
promise.resolve = Q; // ES6
|
||||
|
||||
// XXX experimental. This method is a way to denote that a local value is
|
||||
// serializable and should be immediately dispatched to a remote upon request,
|
||||
// instead of passing a reference.
|
||||
@@ -731,15 +695,15 @@ Promise.prototype.join = function (that) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a promise for the first of an array of promises to become settled.
|
||||
* Returns a promise for the first of an array of promises to become fulfilled.
|
||||
* @param answers {Array[Any*]} promises to race
|
||||
* @returns {Any*} the first promise to be settled
|
||||
* @returns {Any*} the first promise to be fulfilled
|
||||
*/
|
||||
Q.race = race;
|
||||
function race(answerPs) {
|
||||
return promise(function (resolve, reject) {
|
||||
return promise(function(resolve, reject) {
|
||||
// Switch to this once we can assume at least ES5
|
||||
// answerPs.forEach(function (answerP) {
|
||||
// answerPs.forEach(function(answerP) {
|
||||
// Q(answerP).then(resolve, reject);
|
||||
// });
|
||||
// Use this in the meantime
|
||||
@@ -806,14 +770,14 @@ function Promise(descriptor, fallback, inspect) {
|
||||
promise.exception = inspected.reason;
|
||||
}
|
||||
|
||||
promise.valueOf = function () {
|
||||
promise.valueOf = deprecate(function () {
|
||||
var inspected = inspect();
|
||||
if (inspected.state === "pending" ||
|
||||
inspected.state === "rejected") {
|
||||
return promise;
|
||||
}
|
||||
return inspected.value;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
return promise;
|
||||
@@ -853,7 +817,7 @@ Promise.prototype.then = function (fulfilled, rejected, progressed) {
|
||||
return typeof progressed === "function" ? progressed(value) : value;
|
||||
}
|
||||
|
||||
Q.nextTick(function () {
|
||||
nextTick(function () {
|
||||
self.promiseDispatch(function (value) {
|
||||
if (done) {
|
||||
return;
|
||||
@@ -894,30 +858,6 @@ Promise.prototype.then = function (fulfilled, rejected, progressed) {
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
Q.tap = function (promise, callback) {
|
||||
return Q(promise).tap(callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Works almost like "finally", but not called for rejections.
|
||||
* Original resolution value is passed through callback unaffected.
|
||||
* Callback may return a promise that will be awaited for.
|
||||
* @param {Function} callback
|
||||
* @returns {Q.Promise}
|
||||
* @example
|
||||
* doSomething()
|
||||
* .then(...)
|
||||
* .tap(console.log)
|
||||
* .then(...);
|
||||
*/
|
||||
Promise.prototype.tap = function (callback) {
|
||||
callback = Q(callback);
|
||||
|
||||
return this.then(function (value) {
|
||||
return callback.fcall(value).thenResolve(value);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Registers an observer on a promise.
|
||||
*
|
||||
@@ -983,7 +923,9 @@ function nearer(value) {
|
||||
*/
|
||||
Q.isPromise = isPromise;
|
||||
function isPromise(object) {
|
||||
return object instanceof Promise;
|
||||
return isObject(object) &&
|
||||
typeof object.promiseDispatch === "function" &&
|
||||
typeof object.inspect === "function";
|
||||
}
|
||||
|
||||
Q.isPromiseAlike = isPromiseAlike;
|
||||
@@ -1037,15 +979,43 @@ Promise.prototype.isRejected = function () {
|
||||
// shimmed environments, this would naturally be a `Set`.
|
||||
var unhandledReasons = [];
|
||||
var unhandledRejections = [];
|
||||
var reportedUnhandledRejections = [];
|
||||
var unhandledReasonsDisplayed = false;
|
||||
var trackUnhandledRejections = true;
|
||||
function displayUnhandledReasons() {
|
||||
if (
|
||||
!unhandledReasonsDisplayed &&
|
||||
typeof window !== "undefined" &&
|
||||
!window.Touch &&
|
||||
window.console
|
||||
) {
|
||||
console.warn("[Q] Unhandled rejection reasons (should be empty):",
|
||||
unhandledReasons);
|
||||
}
|
||||
|
||||
unhandledReasonsDisplayed = true;
|
||||
}
|
||||
|
||||
function logUnhandledReasons() {
|
||||
for (var i = 0; i < unhandledReasons.length; i++) {
|
||||
var reason = unhandledReasons[i];
|
||||
console.warn("Unhandled rejection reason:", reason);
|
||||
}
|
||||
}
|
||||
|
||||
function resetUnhandledRejections() {
|
||||
unhandledReasons.length = 0;
|
||||
unhandledRejections.length = 0;
|
||||
unhandledReasonsDisplayed = false;
|
||||
|
||||
if (!trackUnhandledRejections) {
|
||||
trackUnhandledRejections = true;
|
||||
|
||||
// Show unhandled rejection reasons if Node exits without handling an
|
||||
// outstanding rejection. (Note that Browserify presently produces a
|
||||
// `process` global without the `EventEmitter` `on` method.)
|
||||
if (typeof process !== "undefined" && process.on) {
|
||||
process.on("exit", logUnhandledReasons);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1053,14 +1023,6 @@ function trackRejection(promise, reason) {
|
||||
if (!trackUnhandledRejections) {
|
||||
return;
|
||||
}
|
||||
if (typeof process === "object" && typeof process.emit === "function") {
|
||||
Q.nextTick.runAfter(function () {
|
||||
if (array_indexOf(unhandledRejections, promise) !== -1) {
|
||||
process.emit("unhandledRejection", reason, promise);
|
||||
reportedUnhandledRejections.push(promise);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
unhandledRejections.push(promise);
|
||||
if (reason && typeof reason.stack !== "undefined") {
|
||||
@@ -1068,6 +1030,7 @@ function trackRejection(promise, reason) {
|
||||
} else {
|
||||
unhandledReasons.push("(no stack) " + reason);
|
||||
}
|
||||
displayUnhandledReasons();
|
||||
}
|
||||
|
||||
function untrackRejection(promise) {
|
||||
@@ -1077,15 +1040,6 @@ function untrackRejection(promise) {
|
||||
|
||||
var at = array_indexOf(unhandledRejections, promise);
|
||||
if (at !== -1) {
|
||||
if (typeof process === "object" && typeof process.emit === "function") {
|
||||
Q.nextTick.runAfter(function () {
|
||||
var atReport = array_indexOf(reportedUnhandledRejections, promise);
|
||||
if (atReport !== -1) {
|
||||
process.emit("rejectionHandled", unhandledReasons[at], promise);
|
||||
reportedUnhandledRejections.splice(atReport, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
unhandledRejections.splice(at, 1);
|
||||
unhandledReasons.splice(at, 1);
|
||||
}
|
||||
@@ -1100,6 +1054,9 @@ Q.getUnhandledReasons = function () {
|
||||
|
||||
Q.stopUnhandledRejectionTracking = function () {
|
||||
resetUnhandledRejections();
|
||||
if (typeof process !== "undefined" && process.on) {
|
||||
process.removeListener("exit", logUnhandledReasons);
|
||||
}
|
||||
trackUnhandledRejections = false;
|
||||
};
|
||||
|
||||
@@ -1179,7 +1136,7 @@ function fulfill(value) {
|
||||
*/
|
||||
function coerce(promise) {
|
||||
var deferred = defer();
|
||||
Q.nextTick(function () {
|
||||
nextTick(function () {
|
||||
try {
|
||||
promise.then(deferred.resolve, deferred.reject, deferred.notify);
|
||||
} catch (exception) {
|
||||
@@ -1263,35 +1220,24 @@ function async(makeGenerator) {
|
||||
// when verb is "throw", arg is an exception
|
||||
function continuer(verb, arg) {
|
||||
var result;
|
||||
|
||||
// Until V8 3.19 / Chromium 29 is released, SpiderMonkey is the only
|
||||
// engine that has a deployed base of browsers that support generators.
|
||||
// However, SM's generators use the Python-inspired semantics of
|
||||
// outdated ES6 drafts. We would like to support ES6, but we'd also
|
||||
// like to make it possible to use generators in deployed browsers, so
|
||||
// we also support Python-style generators. At some point we can remove
|
||||
// this block.
|
||||
|
||||
if (typeof StopIteration === "undefined") {
|
||||
// ES6 Generators
|
||||
if (hasES6Generators) {
|
||||
try {
|
||||
result = generator[verb](arg);
|
||||
} catch (exception) {
|
||||
return reject(exception);
|
||||
}
|
||||
if (result.done) {
|
||||
return Q(result.value);
|
||||
return result.value;
|
||||
} else {
|
||||
return when(result.value, callback, errback);
|
||||
}
|
||||
} else {
|
||||
// SpiderMonkey Generators
|
||||
// FIXME: Remove this case when SM does ES6 generators.
|
||||
try {
|
||||
result = generator[verb](arg);
|
||||
} catch (exception) {
|
||||
if (isStopIteration(exception)) {
|
||||
return Q(exception.value);
|
||||
return exception.value;
|
||||
} else {
|
||||
return reject(exception);
|
||||
}
|
||||
@@ -1387,7 +1333,7 @@ function dispatch(object, op, args) {
|
||||
Promise.prototype.dispatch = function (op, args) {
|
||||
var self = this;
|
||||
var deferred = defer();
|
||||
Q.nextTick(function () {
|
||||
nextTick(function () {
|
||||
self.promiseDispatch(deferred.resolve, op, args);
|
||||
});
|
||||
return deferred.promise;
|
||||
@@ -1560,7 +1506,7 @@ Promise.prototype.keys = function () {
|
||||
Q.all = all;
|
||||
function all(promises) {
|
||||
return when(promises, function (promises) {
|
||||
var pendingCount = 0;
|
||||
var countDown = 0;
|
||||
var deferred = defer();
|
||||
array_reduce(promises, function (undefined, promise, index) {
|
||||
var snapshot;
|
||||
@@ -1570,12 +1516,12 @@ function all(promises) {
|
||||
) {
|
||||
promises[index] = snapshot.value;
|
||||
} else {
|
||||
++pendingCount;
|
||||
++countDown;
|
||||
when(
|
||||
promise,
|
||||
function (value) {
|
||||
promises[index] = value;
|
||||
if (--pendingCount === 0) {
|
||||
if (--countDown === 0) {
|
||||
deferred.resolve(promises);
|
||||
}
|
||||
},
|
||||
@@ -1586,7 +1532,7 @@ function all(promises) {
|
||||
);
|
||||
}
|
||||
}, void 0);
|
||||
if (pendingCount === 0) {
|
||||
if (countDown === 0) {
|
||||
deferred.resolve(promises);
|
||||
}
|
||||
return deferred.promise;
|
||||
@@ -1597,55 +1543,6 @@ Promise.prototype.all = function () {
|
||||
return all(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the first resolved promise of an array. Prior rejected promises are
|
||||
* ignored. Rejects only if all promises are rejected.
|
||||
* @param {Array*} an array containing values or promises for values
|
||||
* @returns a promise fulfilled with the value of the first resolved promise,
|
||||
* or a rejected promise if all promises are rejected.
|
||||
*/
|
||||
Q.any = any;
|
||||
|
||||
function any(promises) {
|
||||
if (promises.length === 0) {
|
||||
return Q.resolve();
|
||||
}
|
||||
|
||||
var deferred = Q.defer();
|
||||
var pendingCount = 0;
|
||||
array_reduce(promises, function (prev, current, index) {
|
||||
var promise = promises[index];
|
||||
|
||||
pendingCount++;
|
||||
|
||||
when(promise, onFulfilled, onRejected, onProgress);
|
||||
function onFulfilled(result) {
|
||||
deferred.resolve(result);
|
||||
}
|
||||
function onRejected() {
|
||||
pendingCount--;
|
||||
if (pendingCount === 0) {
|
||||
deferred.reject(new Error(
|
||||
"Can't get fulfillment value from any promise, all " +
|
||||
"promises were rejected."
|
||||
));
|
||||
}
|
||||
}
|
||||
function onProgress(progress) {
|
||||
deferred.notify({
|
||||
index: index,
|
||||
value: progress
|
||||
});
|
||||
}
|
||||
}, undefined);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
Promise.prototype.any = function () {
|
||||
return any(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Waits for all promises to be settled, either fulfilled or
|
||||
* rejected. This is distinct from `all` since that would stop
|
||||
@@ -1779,7 +1676,7 @@ Promise.prototype.done = function (fulfilled, rejected, progress) {
|
||||
var onUnhandledError = function (error) {
|
||||
// forward to a future turn so that ``when``
|
||||
// does not catch it and turn it into a rejection.
|
||||
Q.nextTick(function () {
|
||||
nextTick(function () {
|
||||
makeStackTraceLong(error, promise);
|
||||
if (Q.onerror) {
|
||||
Q.onerror(error);
|
||||
@@ -1806,22 +1703,18 @@ Promise.prototype.done = function (fulfilled, rejected, progress) {
|
||||
* some milliseconds time out.
|
||||
* @param {Any*} promise
|
||||
* @param {Number} milliseconds timeout
|
||||
* @param {Any*} custom error message or Error object (optional)
|
||||
* @param {String} custom error message (optional)
|
||||
* @returns a promise for the resolution of the given promise if it is
|
||||
* fulfilled before the timeout, otherwise rejected.
|
||||
*/
|
||||
Q.timeout = function (object, ms, error) {
|
||||
return Q(object).timeout(ms, error);
|
||||
Q.timeout = function (object, ms, message) {
|
||||
return Q(object).timeout(ms, message);
|
||||
};
|
||||
|
||||
Promise.prototype.timeout = function (ms, error) {
|
||||
Promise.prototype.timeout = function (ms, message) {
|
||||
var deferred = defer();
|
||||
var timeoutId = setTimeout(function () {
|
||||
if (!error || "string" === typeof error) {
|
||||
error = new Error(error || "Timed out after " + ms + " ms");
|
||||
error.code = "ETIMEDOUT";
|
||||
}
|
||||
deferred.reject(error);
|
||||
deferred.reject(new Error(message || "Timed out after " + ms + " ms"));
|
||||
}, ms);
|
||||
|
||||
this.then(function (value) {
|
||||
@@ -2023,11 +1916,11 @@ function nodeify(object, nodeback) {
|
||||
Promise.prototype.nodeify = function (nodeback) {
|
||||
if (nodeback) {
|
||||
this.then(function (value) {
|
||||
Q.nextTick(function () {
|
||||
nextTick(function () {
|
||||
nodeback(null, value);
|
||||
});
|
||||
}, function (error) {
|
||||
Q.nextTick(function () {
|
||||
nextTick(function () {
|
||||
nodeback(error);
|
||||
});
|
||||
});
|
||||
@@ -2036,10 +1929,6 @@ Promise.prototype.nodeify = function (nodeback) {
|
||||
}
|
||||
};
|
||||
|
||||
Q.noConflict = function() {
|
||||
throw new Error("Q.noConflict only works when Q is used as a global");
|
||||
};
|
||||
|
||||
// All code before this point will be filtered from stack traces.
|
||||
var qEndingLine = captureLine();
|
||||
|
||||
0
node_modules/q/queue.js → bin/node_modules/q/queue.js
generated
vendored
0
node_modules/q/queue.js → bin/node_modules/q/queue.js
generated
vendored
0
node_modules/shelljs/.documentup.json → bin/node_modules/shelljs/.documentup.json
generated
vendored
0
node_modules/shelljs/.documentup.json → bin/node_modules/shelljs/.documentup.json
generated
vendored
0
node_modules/shelljs/.jshintrc → bin/node_modules/shelljs/.jshintrc
generated
vendored
0
node_modules/shelljs/.jshintrc → bin/node_modules/shelljs/.jshintrc
generated
vendored
0
node_modules/shelljs/.npmignore → bin/node_modules/shelljs/.npmignore
generated
vendored
0
node_modules/shelljs/.npmignore → bin/node_modules/shelljs/.npmignore
generated
vendored
@@ -2,3 +2,4 @@ language: node_js
|
||||
node_js:
|
||||
- "0.8"
|
||||
- "0.10"
|
||||
- "0.11"
|
||||
0
node_modules/shelljs/LICENSE → bin/node_modules/shelljs/LICENSE
generated
vendored
0
node_modules/shelljs/LICENSE → bin/node_modules/shelljs/LICENSE
generated
vendored
53
node_modules/shelljs/README.md → bin/node_modules/shelljs/README.md
generated
vendored
53
node_modules/shelljs/README.md → bin/node_modules/shelljs/README.md
generated
vendored
@@ -13,8 +13,6 @@ The project is [unit-tested](http://travis-ci.org/arturadib/shelljs) and battled
|
||||
|
||||
and [many more](https://npmjs.org/browse/depended/shelljs).
|
||||
|
||||
Connect with [@r2r](http://twitter.com/r2r) on Twitter for questions, suggestions, etc.
|
||||
|
||||
## Installing
|
||||
|
||||
Via npm:
|
||||
@@ -132,21 +130,15 @@ target.docs = ->
|
||||
text.to 'docs/my_docs.md'
|
||||
```
|
||||
|
||||
To run the target `all`, call the above script without arguments: `$ node make`. To run the target `docs`: `$ node make docs`.
|
||||
|
||||
You can also pass arguments to your targets by using the `--` separator. For example, to pass `arg1` and `arg2` to a target `bundle`, do `$ node make bundle -- arg1 arg2`:
|
||||
|
||||
```javascript
|
||||
require('shelljs/make');
|
||||
|
||||
target.bundle = function(argsArray) {
|
||||
// argsArray = ['arg1', 'arg2']
|
||||
/* ... */
|
||||
}
|
||||
```
|
||||
To run the target `all`, call the above script without arguments: `$ node make`. To run the target `docs`: `$ node make docs`, and so on.
|
||||
|
||||
|
||||
<!-- DO NOT MODIFY BEYOND THIS POINT - IT'S AUTOMATICALLY GENERATED -->
|
||||
|
||||
<!--
|
||||
|
||||
DO NOT MODIFY BEYOND THIS POINT - IT'S AUTOMATICALLY GENERATED
|
||||
|
||||
-->
|
||||
|
||||
|
||||
## Command reference
|
||||
@@ -274,7 +266,7 @@ Available expression primaries:
|
||||
+ `'-d', 'path'`: true if path is a directory
|
||||
+ `'-e', 'path'`: true if path exists
|
||||
+ `'-f', 'path'`: true if path is a regular file
|
||||
+ `'-L', 'path'`: true if path is a symbolic link
|
||||
+ `'-L', 'path'`: true if path is a symboilc link
|
||||
+ `'-p', 'path'`: true if path is a pipe (FIFO)
|
||||
+ `'-S', 'path'`: true if path is a socket
|
||||
|
||||
@@ -328,7 +320,7 @@ Analogous to the redirect-and-append operator `>>` in Unix, but works with JavaS
|
||||
those returned by `cat`, `grep`, etc).
|
||||
|
||||
|
||||
### sed([options ,] search_regex, replacement, file)
|
||||
### sed([options ,] search_regex, replace_str, file)
|
||||
Available options:
|
||||
|
||||
+ `-i`: Replace contents of 'file' in-place. _Note that no backups will be created!_
|
||||
@@ -341,7 +333,7 @@ sed(/.*DELETE_THIS_LINE.*\n/, '', 'source.js');
|
||||
```
|
||||
|
||||
Reads an input string from `file` and performs a JavaScript `replace()` on the input
|
||||
using the given search regex and replacement string or function. Returns the new string after replacement.
|
||||
using the given search regex and replacement string. Returns the new string after replacement.
|
||||
|
||||
|
||||
### grep([options ,] regex_filter, file [, file ...])
|
||||
@@ -447,23 +439,6 @@ Display the list of currently remembered directories. Returns an array of paths
|
||||
See also: pushd, popd
|
||||
|
||||
|
||||
### ln(options, source, dest)
|
||||
### ln(source, dest)
|
||||
Available options:
|
||||
|
||||
+ `s`: symlink
|
||||
+ `f`: force
|
||||
|
||||
Examples:
|
||||
|
||||
```javascript
|
||||
ln('file', 'newlink');
|
||||
ln('-sf', 'file', 'existing');
|
||||
```
|
||||
|
||||
Links source to dest. Use -f to force the link, should dest already exist.
|
||||
|
||||
|
||||
### exit(code)
|
||||
Exits the current process with the given exit code.
|
||||
|
||||
@@ -556,11 +531,10 @@ otherwise returns string explaining the error
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
var sh = require('shelljs');
|
||||
var silentState = sh.config.silent; // save old silent state
|
||||
sh.config.silent = true;
|
||||
var silentState = config.silent; // save old silent state
|
||||
config.silent = true;
|
||||
/* ... */
|
||||
sh.config.silent = silentState; // restore old silent state
|
||||
config.silent = silentState; // restore old silent state
|
||||
```
|
||||
|
||||
Suppresses all command output if `true`, except for `echo()` calls.
|
||||
@@ -570,7 +544,6 @@ Default is `false`.
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
require('shelljs/global');
|
||||
config.fatal = true;
|
||||
cp('this_file_does_not_exist', '/dev/null'); // dies here
|
||||
/* more commands... */
|
||||
0
node_modules/shelljs/bin/shjs → bin/node_modules/shelljs/bin/shjs
generated
vendored
0
node_modules/shelljs/bin/shjs → bin/node_modules/shelljs/bin/shjs
generated
vendored
0
node_modules/shelljs/global.js → bin/node_modules/shelljs/global.js
generated
vendored
0
node_modules/shelljs/global.js → bin/node_modules/shelljs/global.js
generated
vendored
19
node_modules/shelljs/make.js → bin/node_modules/shelljs/make.js
generated
vendored
19
node_modules/shelljs/make.js → bin/node_modules/shelljs/make.js
generated
vendored
@@ -3,18 +3,9 @@ require('./global');
|
||||
global.config.fatal = true;
|
||||
global.target = {};
|
||||
|
||||
var args = process.argv.slice(2),
|
||||
targetArgs,
|
||||
dashesLoc = args.indexOf('--');
|
||||
|
||||
// split args, everything after -- if only for targets
|
||||
if (dashesLoc > -1) {
|
||||
targetArgs = args.slice(dashesLoc + 1, args.length);
|
||||
args = args.slice(0, dashesLoc);
|
||||
}
|
||||
|
||||
// This ensures we only execute the script targets after the entire script has
|
||||
// been evaluated
|
||||
var args = process.argv.slice(2);
|
||||
setTimeout(function() {
|
||||
var t;
|
||||
|
||||
@@ -30,8 +21,8 @@ setTimeout(function() {
|
||||
(function(t, oldTarget){
|
||||
|
||||
// Wrap it
|
||||
global.target[t] = function() {
|
||||
if (oldTarget.done)
|
||||
global.target[t] = function(force) {
|
||||
if (oldTarget.done && !force)
|
||||
return;
|
||||
oldTarget.done = true;
|
||||
return oldTarget.apply(oldTarget, arguments);
|
||||
@@ -44,13 +35,13 @@ setTimeout(function() {
|
||||
if (args.length > 0) {
|
||||
args.forEach(function(arg) {
|
||||
if (arg in global.target)
|
||||
global.target[arg](targetArgs);
|
||||
global.target[arg]();
|
||||
else {
|
||||
console.log('no such target: ' + arg);
|
||||
}
|
||||
});
|
||||
} else if ('all' in global.target) {
|
||||
global.target.all(targetArgs);
|
||||
global.target.all();
|
||||
}
|
||||
|
||||
}, 0);
|
||||
48
bin/node_modules/shelljs/package.json
generated
vendored
Normal file
48
bin/node_modules/shelljs/package.json
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
12
node_modules/shelljs/shell.js → bin/node_modules/shelljs/shell.js
generated
vendored
12
node_modules/shelljs/shell.js → bin/node_modules/shelljs/shell.js
generated
vendored
@@ -85,10 +85,6 @@ exports.pushd = common.wrap('pushd', _pushd);
|
||||
var _popd = require('./src/dirs').popd;
|
||||
exports.popd = common.wrap("popd", _popd);
|
||||
|
||||
//@include ./src/ln
|
||||
var _ln = require('./src/ln');
|
||||
exports.ln = common.wrap('ln', _ln);
|
||||
|
||||
//@
|
||||
//@ ### exit(code)
|
||||
//@ Exits the current process with the given exit code.
|
||||
@@ -135,11 +131,10 @@ exports.config = common.config;
|
||||
//@ Example:
|
||||
//@
|
||||
//@ ```javascript
|
||||
//@ var sh = require('shelljs');
|
||||
//@ var silentState = sh.config.silent; // save old silent state
|
||||
//@ sh.config.silent = true;
|
||||
//@ var silentState = config.silent; // save old silent state
|
||||
//@ config.silent = true;
|
||||
//@ /* ... */
|
||||
//@ sh.config.silent = silentState; // restore old silent state
|
||||
//@ config.silent = silentState; // restore old silent state
|
||||
//@ ```
|
||||
//@
|
||||
//@ Suppresses all command output if `true`, except for `echo()` calls.
|
||||
@@ -150,7 +145,6 @@ exports.config = common.config;
|
||||
//@ Example:
|
||||
//@
|
||||
//@ ```javascript
|
||||
//@ require('shelljs/global');
|
||||
//@ config.fatal = true;
|
||||
//@ cp('this_file_does_not_exist', '/dev/null'); // dies here
|
||||
//@ /* more commands... */
|
||||
0
node_modules/shelljs/src/cat.js → bin/node_modules/shelljs/src/cat.js
generated
vendored
0
node_modules/shelljs/src/cat.js → bin/node_modules/shelljs/src/cat.js
generated
vendored
0
node_modules/shelljs/src/cd.js → bin/node_modules/shelljs/src/cd.js
generated
vendored
0
node_modules/shelljs/src/cd.js → bin/node_modules/shelljs/src/cd.js
generated
vendored
0
node_modules/shelljs/src/chmod.js → bin/node_modules/shelljs/src/chmod.js
generated
vendored
0
node_modules/shelljs/src/chmod.js → bin/node_modules/shelljs/src/chmod.js
generated
vendored
18
node_modules/shelljs/src/common.js → bin/node_modules/shelljs/src/common.js
generated
vendored
18
node_modules/shelljs/src/common.js → bin/node_modules/shelljs/src/common.js
generated
vendored
@@ -92,22 +92,8 @@ exports.parseOptions = parseOptions;
|
||||
function expand(list) {
|
||||
var expanded = [];
|
||||
list.forEach(function(listEl) {
|
||||
// Wildcard present on directory names ?
|
||||
if(listEl.search(/\*[^\/]*\//) > -1 || listEl.search(/\*\*[^\/]*\//) > -1) {
|
||||
var match = listEl.match(/^([^*]+\/|)(.*)/);
|
||||
var root = match[1];
|
||||
var rest = match[2];
|
||||
var restRegex = rest.replace(/\*\*/g, ".*").replace(/\*/g, "[^\\/]*");
|
||||
restRegex = new RegExp(restRegex);
|
||||
|
||||
_ls('-R', root).filter(function (e) {
|
||||
return restRegex.test(e);
|
||||
}).forEach(function(file) {
|
||||
expanded.push(file);
|
||||
});
|
||||
}
|
||||
// Wildcard present on file names ?
|
||||
else if (listEl.search(/\*/) > -1) {
|
||||
// Wildcard present?
|
||||
if (listEl.search(/\*/) > -1) {
|
||||
_ls('', listEl).forEach(function(file) {
|
||||
expanded.push(file);
|
||||
});
|
||||
8
node_modules/shelljs/src/cp.js → bin/node_modules/shelljs/src/cp.js
generated
vendored
8
node_modules/shelljs/src/cp.js → bin/node_modules/shelljs/src/cp.js
generated
vendored
@@ -1,7 +1,6 @@
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var common = require('./common');
|
||||
var os = require('os');
|
||||
|
||||
// Buffered file copy, synchronous
|
||||
// (Using readFileSync() + writeFileSync() could easily cause a memory overflow
|
||||
@@ -73,7 +72,7 @@ function cpdirSyncRecursive(sourceDir, destDir, opts) {
|
||||
cpdirSyncRecursive(srcFile, destFile, opts);
|
||||
} else if (srcFileStat.isSymbolicLink()) {
|
||||
var symlinkFull = fs.readlinkSync(srcFile);
|
||||
fs.symlinkSync(symlinkFull, destFile, os.platform() === "win32" ? "junction" : null);
|
||||
fs.symlinkSync(symlinkFull, destFile);
|
||||
} else {
|
||||
/* At this point, we've hit a file actually worth copying... so copy it on over. */
|
||||
if (fs.existsSync(destFile) && !opts.force) {
|
||||
@@ -174,10 +173,7 @@ function _cp(options, sources, dest) {
|
||||
fs.mkdirSync(newDest, checkDir.mode);
|
||||
} catch (e) {
|
||||
//if the directory already exists, that's okay
|
||||
if (e.code !== 'EEXIST') {
|
||||
common.error('dest file no such file or directory: ' + newDest, true);
|
||||
throw e;
|
||||
}
|
||||
if (e.code !== 'EEXIST') throw e;
|
||||
}
|
||||
|
||||
cpdirSyncRecursive(src, newDest, {force: options.force});
|
||||
0
node_modules/shelljs/src/dirs.js → bin/node_modules/shelljs/src/dirs.js
generated
vendored
0
node_modules/shelljs/src/dirs.js → bin/node_modules/shelljs/src/dirs.js
generated
vendored
0
node_modules/shelljs/src/echo.js → bin/node_modules/shelljs/src/echo.js
generated
vendored
0
node_modules/shelljs/src/echo.js → bin/node_modules/shelljs/src/echo.js
generated
vendored
0
node_modules/shelljs/src/error.js → bin/node_modules/shelljs/src/error.js
generated
vendored
0
node_modules/shelljs/src/error.js → bin/node_modules/shelljs/src/error.js
generated
vendored
71
node_modules/shelljs/src/exec.js → bin/node_modules/shelljs/src/exec.js
generated
vendored
71
node_modules/shelljs/src/exec.js → bin/node_modules/shelljs/src/exec.js
generated
vendored
@@ -40,67 +40,32 @@ function execSync(cmd, opts) {
|
||||
return (str+'').replace(/([\\"'])/g, "\\$1").replace(/\0/g, "\\0");
|
||||
}
|
||||
|
||||
cmd += ' > '+stdoutFile+' 2>&1'; // works on both win/unix
|
||||
|
||||
var script =
|
||||
"var child = require('child_process')," +
|
||||
" fs = require('fs');" +
|
||||
"child.exec('"+escape(cmd)+"', {env: process.env, maxBuffer: 20*1024*1024}, function(err) {" +
|
||||
" fs.writeFileSync('"+escape(codeFile)+"', err ? err.code.toString() : '0');" +
|
||||
"});";
|
||||
|
||||
if (fs.existsSync(scriptFile)) common.unlinkSync(scriptFile);
|
||||
if (fs.existsSync(stdoutFile)) common.unlinkSync(stdoutFile);
|
||||
if (fs.existsSync(codeFile)) common.unlinkSync(codeFile);
|
||||
|
||||
var execCommand = '"'+process.execPath+'" '+scriptFile;
|
||||
var execOptions = {
|
||||
fs.writeFileSync(scriptFile, script);
|
||||
child.exec('"'+process.execPath+'" '+scriptFile, {
|
||||
env: process.env,
|
||||
cwd: _pwd(),
|
||||
maxBuffer: 20*1024*1024
|
||||
};
|
||||
});
|
||||
|
||||
if (typeof child.execSync === 'function') {
|
||||
var script = [
|
||||
"var child = require('child_process')",
|
||||
" , fs = require('fs');",
|
||||
"var childProcess = child.exec('"+escape(cmd)+"', {env: process.env, maxBuffer: 20*1024*1024}, function(err) {",
|
||||
" fs.writeFileSync('"+escape(codeFile)+"', err ? err.code.toString() : '0');",
|
||||
"});",
|
||||
"var stdoutStream = fs.createWriteStream('"+escape(stdoutFile)+"');",
|
||||
"childProcess.stdout.pipe(stdoutStream, {end: false});",
|
||||
"childProcess.stderr.pipe(stdoutStream, {end: false});",
|
||||
"childProcess.stdout.pipe(process.stdout);",
|
||||
"childProcess.stderr.pipe(process.stderr);",
|
||||
"var stdoutEnded = false, stderrEnded = false;",
|
||||
"function tryClosing(){ if(stdoutEnded && stderrEnded){ stdoutStream.end(); } }",
|
||||
"childProcess.stdout.on('end', function(){ stdoutEnded = true; tryClosing(); });",
|
||||
"childProcess.stderr.on('end', function(){ stderrEnded = true; tryClosing(); });"
|
||||
].join('\n');
|
||||
|
||||
fs.writeFileSync(scriptFile, script);
|
||||
|
||||
if (options.silent) {
|
||||
execOptions.stdio = 'ignore';
|
||||
} else {
|
||||
execOptions.stdio = [0, 1, 2];
|
||||
}
|
||||
|
||||
// Welcome to the future
|
||||
child.execSync(execCommand, execOptions);
|
||||
} else {
|
||||
cmd += ' > '+stdoutFile+' 2>&1'; // works on both win/unix
|
||||
|
||||
var script = [
|
||||
"var child = require('child_process')",
|
||||
" , fs = require('fs');",
|
||||
"var childProcess = child.exec('"+escape(cmd)+"', {env: process.env, maxBuffer: 20*1024*1024}, function(err) {",
|
||||
" fs.writeFileSync('"+escape(codeFile)+"', err ? err.code.toString() : '0');",
|
||||
"});"
|
||||
].join('\n');
|
||||
|
||||
fs.writeFileSync(scriptFile, script);
|
||||
|
||||
child.exec(execCommand, execOptions);
|
||||
|
||||
// The wait loop
|
||||
// sleepFile is used as a dummy I/O op to mitigate unnecessary CPU usage
|
||||
// (tried many I/O sync ops, writeFileSync() seems to be only one that is effective in reducing
|
||||
// CPU usage, though apparently not so much on Windows)
|
||||
while (!fs.existsSync(codeFile)) { updateStdout(); fs.writeFileSync(sleepFile, 'a'); }
|
||||
while (!fs.existsSync(stdoutFile)) { updateStdout(); fs.writeFileSync(sleepFile, 'a'); }
|
||||
}
|
||||
// The wait loop
|
||||
// sleepFile is used as a dummy I/O op to mitigate unnecessary CPU usage
|
||||
// (tried many I/O sync ops, writeFileSync() seems to be only one that is effective in reducing
|
||||
// CPU usage, though apparently not so much on Windows)
|
||||
while (!fs.existsSync(codeFile)) { updateStdout(); fs.writeFileSync(sleepFile, 'a'); }
|
||||
while (!fs.existsSync(stdoutFile)) { updateStdout(); fs.writeFileSync(sleepFile, 'a'); }
|
||||
|
||||
// At this point codeFile exists, but it's not necessarily flushed yet.
|
||||
// Keep reading it until it is.
|
||||
0
node_modules/shelljs/src/find.js → bin/node_modules/shelljs/src/find.js
generated
vendored
0
node_modules/shelljs/src/find.js → bin/node_modules/shelljs/src/find.js
generated
vendored
0
node_modules/shelljs/src/grep.js → bin/node_modules/shelljs/src/grep.js
generated
vendored
0
node_modules/shelljs/src/grep.js → bin/node_modules/shelljs/src/grep.js
generated
vendored
0
node_modules/shelljs/src/ls.js → bin/node_modules/shelljs/src/ls.js
generated
vendored
0
node_modules/shelljs/src/ls.js → bin/node_modules/shelljs/src/ls.js
generated
vendored
0
node_modules/shelljs/src/mkdir.js → bin/node_modules/shelljs/src/mkdir.js
generated
vendored
0
node_modules/shelljs/src/mkdir.js → bin/node_modules/shelljs/src/mkdir.js
generated
vendored
0
node_modules/shelljs/src/mv.js → bin/node_modules/shelljs/src/mv.js
generated
vendored
0
node_modules/shelljs/src/mv.js → bin/node_modules/shelljs/src/mv.js
generated
vendored
0
node_modules/shelljs/src/popd.js → bin/node_modules/shelljs/src/popd.js
generated
vendored
0
node_modules/shelljs/src/popd.js → bin/node_modules/shelljs/src/popd.js
generated
vendored
0
node_modules/shelljs/src/pushd.js → bin/node_modules/shelljs/src/pushd.js
generated
vendored
0
node_modules/shelljs/src/pushd.js → bin/node_modules/shelljs/src/pushd.js
generated
vendored
0
node_modules/shelljs/src/pwd.js → bin/node_modules/shelljs/src/pwd.js
generated
vendored
0
node_modules/shelljs/src/pwd.js → bin/node_modules/shelljs/src/pwd.js
generated
vendored
20
node_modules/shelljs/src/rm.js → bin/node_modules/shelljs/src/rm.js
generated
vendored
20
node_modules/shelljs/src/rm.js → bin/node_modules/shelljs/src/rm.js
generated
vendored
@@ -48,25 +48,7 @@ function rmdirSyncRecursive(dir, force) {
|
||||
|
||||
var result;
|
||||
try {
|
||||
// Retry on windows, sometimes it takes a little time before all the files in the directory are gone
|
||||
var start = Date.now();
|
||||
while (true) {
|
||||
try {
|
||||
result = fs.rmdirSync(dir);
|
||||
if (fs.existsSync(dir)) throw { code: "EAGAIN" }
|
||||
break;
|
||||
} catch(er) {
|
||||
// In addition to error codes, also check if the directory still exists and loop again if true
|
||||
if (process.platform === "win32" && (er.code === "ENOTEMPTY" || er.code === "EBUSY" || er.code === "EPERM" || er.code === "EAGAIN")) {
|
||||
if (Date.now() - start > 1000) throw er;
|
||||
} else if (er.code === "ENOENT") {
|
||||
// Directory did not exist, deletion was successful
|
||||
break;
|
||||
} else {
|
||||
throw er;
|
||||
}
|
||||
}
|
||||
}
|
||||
result = fs.rmdirSync(dir);
|
||||
} catch(e) {
|
||||
common.error('could not remove directory (code '+e.code+'): ' + dir, true);
|
||||
}
|
||||
6
node_modules/shelljs/src/sed.js → bin/node_modules/shelljs/src/sed.js
generated
vendored
6
node_modules/shelljs/src/sed.js → bin/node_modules/shelljs/src/sed.js
generated
vendored
@@ -2,7 +2,7 @@ var common = require('./common');
|
||||
var fs = require('fs');
|
||||
|
||||
//@
|
||||
//@ ### sed([options ,] search_regex, replacement, file)
|
||||
//@ ### sed([options ,] search_regex, replace_str, file)
|
||||
//@ Available options:
|
||||
//@
|
||||
//@ + `-i`: Replace contents of 'file' in-place. _Note that no backups will be created!_
|
||||
@@ -15,13 +15,13 @@ var fs = require('fs');
|
||||
//@ ```
|
||||
//@
|
||||
//@ Reads an input string from `file` and performs a JavaScript `replace()` on the input
|
||||
//@ using the given search regex and replacement string or function. Returns the new string after replacement.
|
||||
//@ using the given search regex and replacement string. Returns the new string after replacement.
|
||||
function _sed(options, regex, replacement, file) {
|
||||
options = common.parseOptions(options, {
|
||||
'i': 'inplace'
|
||||
});
|
||||
|
||||
if (typeof replacement === 'string' || typeof replacement === 'function')
|
||||
if (typeof replacement === 'string')
|
||||
replacement = replacement; // no-op
|
||||
else if (typeof replacement === 'number')
|
||||
replacement = replacement.toString(); // fallback
|
||||
0
node_modules/shelljs/src/tempdir.js → bin/node_modules/shelljs/src/tempdir.js
generated
vendored
0
node_modules/shelljs/src/tempdir.js → bin/node_modules/shelljs/src/tempdir.js
generated
vendored
0
node_modules/shelljs/src/test.js → bin/node_modules/shelljs/src/test.js
generated
vendored
0
node_modules/shelljs/src/test.js → bin/node_modules/shelljs/src/test.js
generated
vendored
0
node_modules/shelljs/src/to.js → bin/node_modules/shelljs/src/to.js
generated
vendored
0
node_modules/shelljs/src/to.js → bin/node_modules/shelljs/src/to.js
generated
vendored
0
node_modules/shelljs/src/toEnd.js → bin/node_modules/shelljs/src/toEnd.js
generated
vendored
0
node_modules/shelljs/src/toEnd.js → bin/node_modules/shelljs/src/toEnd.js
generated
vendored
14
node_modules/shelljs/src/which.js → bin/node_modules/shelljs/src/which.js
generated
vendored
14
node_modules/shelljs/src/which.js → bin/node_modules/shelljs/src/which.js
generated
vendored
@@ -15,10 +15,6 @@ function splitPath(p) {
|
||||
return p.split(':');
|
||||
}
|
||||
|
||||
function checkPath(path) {
|
||||
return fs.existsSync(path) && fs.statSync(path).isDirectory() == false;
|
||||
}
|
||||
|
||||
//@
|
||||
//@ ### which(command)
|
||||
//@
|
||||
@@ -46,7 +42,7 @@ function _which(options, cmd) {
|
||||
return; // already found it
|
||||
|
||||
var attempt = path.resolve(dir + '/' + cmd);
|
||||
if (checkPath(attempt)) {
|
||||
if (fs.existsSync(attempt)) {
|
||||
where = attempt;
|
||||
return;
|
||||
}
|
||||
@@ -54,17 +50,17 @@ function _which(options, cmd) {
|
||||
if (common.platform === 'win') {
|
||||
var baseAttempt = attempt;
|
||||
attempt = baseAttempt + '.exe';
|
||||
if (checkPath(attempt)) {
|
||||
if (fs.existsSync(attempt)) {
|
||||
where = attempt;
|
||||
return;
|
||||
}
|
||||
attempt = baseAttempt + '.cmd';
|
||||
if (checkPath(attempt)) {
|
||||
if (fs.existsSync(attempt)) {
|
||||
where = attempt;
|
||||
return;
|
||||
}
|
||||
attempt = baseAttempt + '.bat';
|
||||
if (checkPath(attempt)) {
|
||||
if (fs.existsSync(attempt)) {
|
||||
where = attempt;
|
||||
return;
|
||||
}
|
||||
@@ -73,7 +69,7 @@ function _which(options, cmd) {
|
||||
}
|
||||
|
||||
// Command not found anywhere?
|
||||
if (!checkPath(cmd) && !where)
|
||||
if (!fs.existsSync(cmd) && !where)
|
||||
return null;
|
||||
|
||||
where = where || path.resolve(cmd);
|
||||
5
bin/node_modules/which/README.md
generated
vendored
Normal file
5
bin/node_modules/which/README.md
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
The "which" util from npm's guts.
|
||||
|
||||
Finds the first instance of a specified executable in the PATH
|
||||
environment variable. Does not cache the results, so `hash -r` is not
|
||||
needed when the PATH changes.
|
||||
14
bin/node_modules/which/bin/which
generated
vendored
Executable file
14
bin/node_modules/which/bin/which
generated
vendored
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env node
|
||||
var which = require("../")
|
||||
if (process.argv.length < 3) {
|
||||
console.error("Usage: which <thing>")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
which(process.argv[2], function (er, thing) {
|
||||
if (er) {
|
||||
console.error(er.message)
|
||||
process.exit(er.errno || 127)
|
||||
}
|
||||
console.log(thing)
|
||||
})
|
||||
31
bin/node_modules/which/package.json
generated
vendored
Normal file
31
bin/node_modules/which/package.json
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"author": {
|
||||
"name": "Isaac Z. Schlueter",
|
||||
"email": "i@izs.me",
|
||||
"url": "http://blog.izs.me"
|
||||
},
|
||||
"name": "which",
|
||||
"description": "Like which(1) unix command. Find the first instance of an executable in the PATH.",
|
||||
"version": "1.0.5",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/isaacs/node-which.git"
|
||||
},
|
||||
"main": "which.js",
|
||||
"bin": {
|
||||
"which": "./bin/which"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {},
|
||||
"readme": "The \"which\" util from npm's guts.\n\nFinds the first instance of a specified executable in the PATH\nenvironment variable. Does not cache the results, so `hash -r` is not\nneeded when the PATH changes.\n",
|
||||
"readmeFilename": "README.md",
|
||||
"bugs": {
|
||||
"url": "https://github.com/isaacs/node-which/issues"
|
||||
},
|
||||
"homepage": "https://github.com/isaacs/node-which",
|
||||
"_id": "which@1.0.5",
|
||||
"_from": "which@"
|
||||
}
|
||||
104
bin/node_modules/which/which.js
generated
vendored
Normal file
104
bin/node_modules/which/which.js
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
module.exports = which
|
||||
which.sync = whichSync
|
||||
|
||||
var path = require("path")
|
||||
, fs
|
||||
, COLON = process.platform === "win32" ? ";" : ":"
|
||||
, isExe
|
||||
|
||||
try {
|
||||
fs = require("graceful-fs")
|
||||
} catch (ex) {
|
||||
fs = require("fs")
|
||||
}
|
||||
|
||||
if (process.platform == "win32") {
|
||||
// On windows, there is no good way to check that a file is executable
|
||||
isExe = function isExe () { return true }
|
||||
} else {
|
||||
isExe = function isExe (mod, uid, gid) {
|
||||
//console.error(mod, uid, gid);
|
||||
//console.error("isExe?", (mod & 0111).toString(8))
|
||||
var ret = (mod & 0001)
|
||||
|| (mod & 0010) && process.getgid && gid === process.getgid()
|
||||
|| (mod & 0100) && process.getuid && uid === process.getuid()
|
||||
//console.error("isExe?", ret)
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function which (cmd, cb) {
|
||||
if (isAbsolute(cmd)) return cb(null, cmd)
|
||||
var pathEnv = (process.env.PATH || "").split(COLON)
|
||||
, pathExt = [""]
|
||||
if (process.platform === "win32") {
|
||||
pathEnv.push(process.cwd())
|
||||
pathExt = (process.env.PATHEXT || ".EXE").split(COLON)
|
||||
if (cmd.indexOf(".") !== -1) pathExt.unshift("")
|
||||
}
|
||||
//console.error("pathEnv", pathEnv)
|
||||
;(function F (i, l) {
|
||||
if (i === l) return cb(new Error("not found: "+cmd))
|
||||
var p = path.resolve(pathEnv[i], cmd)
|
||||
;(function E (ii, ll) {
|
||||
if (ii === ll) return F(i + 1, l)
|
||||
var ext = pathExt[ii]
|
||||
//console.error(p + ext)
|
||||
fs.stat(p + ext, function (er, stat) {
|
||||
if (!er &&
|
||||
stat &&
|
||||
stat.isFile() &&
|
||||
isExe(stat.mode, stat.uid, stat.gid)) {
|
||||
//console.error("yes, exe!", p + ext)
|
||||
return cb(null, p + ext)
|
||||
}
|
||||
return E(ii + 1, ll)
|
||||
})
|
||||
})(0, pathExt.length)
|
||||
})(0, pathEnv.length)
|
||||
}
|
||||
|
||||
function whichSync (cmd) {
|
||||
if (isAbsolute(cmd)) return cmd
|
||||
var pathEnv = (process.env.PATH || "").split(COLON)
|
||||
, pathExt = [""]
|
||||
if (process.platform === "win32") {
|
||||
pathEnv.push(process.cwd())
|
||||
pathExt = (process.env.PATHEXT || ".EXE").split(COLON)
|
||||
if (cmd.indexOf(".") !== -1) pathExt.unshift("")
|
||||
}
|
||||
for (var i = 0, l = pathEnv.length; i < l; i ++) {
|
||||
var p = path.join(pathEnv[i], cmd)
|
||||
for (var j = 0, ll = pathExt.length; j < ll; j ++) {
|
||||
var cur = p + pathExt[j]
|
||||
var stat
|
||||
try { stat = fs.statSync(cur) } catch (ex) {}
|
||||
if (stat &&
|
||||
stat.isFile() &&
|
||||
isExe(stat.mode, stat.uid, stat.gid)) return cur
|
||||
}
|
||||
}
|
||||
throw new Error("not found: "+cmd)
|
||||
}
|
||||
|
||||
var isAbsolute = process.platform === "win32" ? absWin : absUnix
|
||||
|
||||
function absWin (p) {
|
||||
if (absUnix(p)) return true
|
||||
// pull off the device/UNC bit from a windows path.
|
||||
// from node's lib/path.js
|
||||
var splitDeviceRe =
|
||||
/^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?([\\\/])?/
|
||||
, result = splitDeviceRe.exec(p)
|
||||
, device = result[1] || ''
|
||||
, isUnc = device && device.charAt(1) !== ':'
|
||||
, isAbsolute = !!result[2] || isUnc // UNC paths are always absolute
|
||||
|
||||
return isAbsolute
|
||||
}
|
||||
|
||||
function absUnix (p) {
|
||||
return p.charAt(0) === "/" || p === ""
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"node": true
|
||||
, "bitwise": true
|
||||
, "undef": true
|
||||
, "trailing": true
|
||||
, "quotmark": true
|
||||
, "indent": 4
|
||||
, "unused": "vars"
|
||||
, "latedef": "nofunc"
|
||||
}
|
||||
492
bin/templates/cordova/Api.js
vendored
492
bin/templates/cordova/Api.js
vendored
@@ -1,492 +0,0 @@
|
||||
/**
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var Q = require('q');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var shell = require('shelljs');
|
||||
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
var PlatformJson = require('cordova-common').PlatformJson;
|
||||
var ActionStack = require('cordova-common').ActionStack;
|
||||
var AndroidProject = require('./lib/AndroidProject');
|
||||
var PlatformMunger = require('cordova-common').ConfigChanges.PlatformMunger;
|
||||
var PluginInfoProvider = require('cordova-common').PluginInfoProvider;
|
||||
|
||||
var ConsoleLogger = require('./lib/ConsoleLogger');
|
||||
var pluginHandlers = require('./lib/pluginHandlers');
|
||||
|
||||
var PLATFORM = 'android';
|
||||
|
||||
/**
|
||||
* Class, that acts as abstraction over particular platform. Encapsulates the
|
||||
* platform's properties and methods.
|
||||
*
|
||||
* Platform that implements own PlatformApi instance _should implement all
|
||||
* prototype methods_ of this class to be fully compatible with cordova-lib.
|
||||
*
|
||||
* The PlatformApi instance also should define the following field:
|
||||
*
|
||||
* * platform: String that defines a platform name.
|
||||
*/
|
||||
function Api(platform, platformRootDir, events) {
|
||||
this.platform = PLATFORM;
|
||||
this.root = path.resolve(__dirname, '..');
|
||||
this.events = events || ConsoleLogger.get();
|
||||
// NOTE: trick to share one EventEmitter instance across all js code
|
||||
require('cordova-common').events = this.events;
|
||||
|
||||
this._platformJson = PlatformJson.load(this.root, platform);
|
||||
this._pluginInfoProvider = new PluginInfoProvider();
|
||||
this._munger = new PlatformMunger(this.platform, this.root, this._platformJson, this._pluginInfoProvider);
|
||||
|
||||
var self = this;
|
||||
|
||||
this.locations = {
|
||||
root: self.root,
|
||||
www: path.join(self.root, 'assets/www'),
|
||||
platformWww: path.join(self.root, 'platform_www'),
|
||||
configXml: path.join(self.root, 'res/xml/config.xml'),
|
||||
defaultConfigXml: path.join(self.root, 'cordova/defaults.xml'),
|
||||
strings: path.join(self.root, 'res/values/strings.xml'),
|
||||
manifest: path.join(self.root, 'AndroidManifest.xml'),
|
||||
// NOTE: Due to platformApi spec we need to return relative paths here
|
||||
cordovaJs: 'bin/templates/project/assets/www/cordova.js',
|
||||
cordovaJsSrc: 'cordova-js-src'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs platform to specified directory and creates a platform project.
|
||||
*
|
||||
* @param {String} destination Destination directory, where insatll platform to
|
||||
* @param {ConfigParser} [config] ConfgiParser instance, used to retrieve
|
||||
* project creation options, such as package id and project name.
|
||||
* @param {Object} [options] An options object. The most common options are:
|
||||
* @param {String} [options.customTemplate] A path to custom template, that
|
||||
* should override the default one from platform.
|
||||
* @param {Boolean} [options.link] Flag that indicates that platform's
|
||||
* sources will be linked to installed platform instead of copying.
|
||||
* @param {EventEmitter} [events] An EventEmitter instance that will be used for
|
||||
* logging purposes. If no EventEmitter provided, all events will be logged to
|
||||
* console
|
||||
*
|
||||
* @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi
|
||||
* instance or rejected with CordovaError.
|
||||
*/
|
||||
Api.createPlatform = function (destination, config, options, events) {
|
||||
return require('../../lib/create')
|
||||
.create(destination, config, options, events || ConsoleLogger.get())
|
||||
.then(function (destination) {
|
||||
var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
|
||||
return new PlatformApi(PLATFORM, destination, events);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates already installed platform.
|
||||
*
|
||||
* @param {String} destination Destination directory, where platform installed
|
||||
* @param {Object} [options] An options object. The most common options are:
|
||||
* @param {String} [options.customTemplate] A path to custom template, that
|
||||
* should override the default one from platform.
|
||||
* @param {Boolean} [options.link] Flag that indicates that platform's
|
||||
* sources will be linked to installed platform instead of copying.
|
||||
* @param {EventEmitter} [events] An EventEmitter instance that will be used for
|
||||
* logging purposes. If no EventEmitter provided, all events will be logged to
|
||||
* console
|
||||
*
|
||||
* @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi
|
||||
* instance or rejected with CordovaError.
|
||||
*/
|
||||
Api.updatePlatform = function (destination, options, events) {
|
||||
return require('../../lib/create')
|
||||
.update(destination, options, events || ConsoleLogger.get())
|
||||
.then(function (destination) {
|
||||
var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
|
||||
return new PlatformApi('android', destination, events);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets a CordovaPlatform object, that represents the platform structure.
|
||||
*
|
||||
* @return {CordovaPlatform} A structure that contains the description of
|
||||
* platform's file structure and other properties of platform.
|
||||
*/
|
||||
Api.prototype.getPlatformInfo = function () {
|
||||
var result = {};
|
||||
result.locations = this.locations;
|
||||
result.root = this.root;
|
||||
result.name = this.platform;
|
||||
result.version = require('./version');
|
||||
result.projectConfig = this._config;
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates installed platform with provided www assets and new app
|
||||
* configuration. This method is required for CLI workflow and will be called
|
||||
* each time before build, so the changes, made to app configuration and www
|
||||
* code, will be applied to platform.
|
||||
*
|
||||
* @param {CordovaProject} cordovaProject A CordovaProject instance, that defines a
|
||||
* project structure and configuration, that should be applied to platform
|
||||
* (contains project's www location and ConfigParser instance for project's
|
||||
* config).
|
||||
*
|
||||
* @return {Promise} Return a promise either fulfilled, or rejected with
|
||||
* CordovaError instance.
|
||||
*/
|
||||
Api.prototype.prepare = function (cordovaProject) {
|
||||
return require('./lib/prepare').prepare.call(this, cordovaProject);
|
||||
};
|
||||
|
||||
/**
|
||||
* Installs a new plugin into platform. This method only copies non-www files
|
||||
* (sources, libs, etc.) to platform. It also doesn't resolves the
|
||||
* dependencies of plugin. Both of handling of www files, such as assets and
|
||||
* js-files and resolving dependencies are the responsibility of caller.
|
||||
*
|
||||
* @param {PluginInfo} plugin A PluginInfo instance that represents plugin
|
||||
* that will be installed.
|
||||
* @param {Object} installOptions An options object. Possible options below:
|
||||
* @param {Boolean} installOptions.link: Flag that specifies that plugin
|
||||
* sources will be symlinked to app's directory instead of copying (if
|
||||
* possible).
|
||||
* @param {Object} installOptions.variables An object that represents
|
||||
* variables that will be used to install plugin. See more details on plugin
|
||||
* variables in documentation:
|
||||
* https://cordova.apache.org/docs/en/4.0.0/plugin_ref_spec.md.html
|
||||
*
|
||||
* @return {Promise} Return a promise either fulfilled, or rejected with
|
||||
* CordovaError instance.
|
||||
*/
|
||||
Api.prototype.addPlugin = function (plugin, installOptions) {
|
||||
|
||||
if (!plugin || plugin.constructor.name !== 'PluginInfo')
|
||||
return Q.reject(new CordovaError('The parameter is incorrect. The first parameter to addPlugin should be a PluginInfo instance'));
|
||||
|
||||
installOptions = installOptions || {};
|
||||
installOptions.variables = installOptions.variables || {};
|
||||
|
||||
var self = this;
|
||||
var actions = new ActionStack();
|
||||
var project = AndroidProject.getProjectFile(this.root);
|
||||
|
||||
// gather all files needs to be handled during install
|
||||
plugin.getFilesAndFrameworks(this.platform)
|
||||
.concat(plugin.getAssets(this.platform))
|
||||
.concat(plugin.getJsModules(this.platform))
|
||||
.forEach(function(item) {
|
||||
actions.push(actions.createAction(
|
||||
pluginHandlers.getInstaller(item.itemType), [item, plugin, project, installOptions],
|
||||
pluginHandlers.getUninstaller(item.itemType), [item, plugin, project, installOptions]));
|
||||
});
|
||||
|
||||
// run through the action stack
|
||||
return actions.process(this.platform)
|
||||
.then(function () {
|
||||
if (project) {
|
||||
project.write();
|
||||
}
|
||||
|
||||
// Add PACKAGE_NAME variable into vars
|
||||
if (!installOptions.variables.PACKAGE_NAME) {
|
||||
installOptions.variables.PACKAGE_NAME = project.getPackageName();
|
||||
}
|
||||
|
||||
self._munger
|
||||
// Ignore passed `is_top_level` option since platform itself doesn't know
|
||||
// anything about managing dependencies - it's responsibility of caller.
|
||||
.add_plugin_changes(plugin, installOptions.variables, /*is_top_level=*/true, /*should_increment=*/true)
|
||||
.save_all();
|
||||
|
||||
var targetDir = installOptions.usePlatformWww ?
|
||||
self.locations.platformWww :
|
||||
self.locations.www;
|
||||
|
||||
self._addModulesInfo(plugin, targetDir);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes an installed plugin from platform.
|
||||
*
|
||||
* Since method accepts PluginInfo instance as input parameter instead of plugin
|
||||
* id, caller shoud take care of managing/storing PluginInfo instances for
|
||||
* future uninstalls.
|
||||
*
|
||||
* @param {PluginInfo} plugin A PluginInfo instance that represents plugin
|
||||
* that will be installed.
|
||||
*
|
||||
* @return {Promise} Return a promise either fulfilled, or rejected with
|
||||
* CordovaError instance.
|
||||
*/
|
||||
Api.prototype.removePlugin = function (plugin, uninstallOptions) {
|
||||
|
||||
if (!plugin || plugin.constructor.name !== 'PluginInfo')
|
||||
return Q.reject(new CordovaError('The parameter is incorrect. The first parameter to addPlugin should be a PluginInfo instance'));
|
||||
|
||||
var self = this;
|
||||
var actions = new ActionStack();
|
||||
var project = AndroidProject.getProjectFile(this.root);
|
||||
|
||||
// queue up plugin files
|
||||
plugin.getFilesAndFrameworks(this.platform)
|
||||
.concat(plugin.getAssets(this.platform))
|
||||
.concat(plugin.getJsModules(this.platform))
|
||||
.forEach(function(item) {
|
||||
actions.push(actions.createAction(
|
||||
pluginHandlers.getUninstaller(item.itemType), [item, plugin, project, uninstallOptions],
|
||||
pluginHandlers.getInstaller(item.itemType), [item, plugin, project, uninstallOptions]));
|
||||
});
|
||||
|
||||
// run through the action stack
|
||||
return actions.process(this.platform)
|
||||
.then(function() {
|
||||
if (project) {
|
||||
project.write();
|
||||
}
|
||||
|
||||
self._munger
|
||||
// Ignore passed `is_top_level` option since platform itself doesn't know
|
||||
// anything about managing dependencies - it's responsibility of caller.
|
||||
.remove_plugin_changes(plugin, /*is_top_level=*/true)
|
||||
.save_all();
|
||||
|
||||
var targetDir = uninstallOptions.usePlatformWww ?
|
||||
self.locations.platformWww :
|
||||
self.locations.www;
|
||||
|
||||
self._removeModulesInfo(plugin, targetDir);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds an application package for current platform.
|
||||
*
|
||||
* @param {Object} buildOptions A build options. This object's structure is
|
||||
* highly depends on platform's specific. The most common options are:
|
||||
* @param {Boolean} buildOptions.debug Indicates that packages should be
|
||||
* built with debug configuration. This is set to true by default unless the
|
||||
* 'release' option is not specified.
|
||||
* @param {Boolean} buildOptions.release Indicates that packages should be
|
||||
* built with release configuration. If not set to true, debug configuration
|
||||
* will be used.
|
||||
* @param {Boolean} buildOptions.device Specifies that built app is intended
|
||||
* to run on device
|
||||
* @param {Boolean} buildOptions.emulator: Specifies that built app is
|
||||
* intended to run on emulator
|
||||
* @param {String} buildOptions.target Specifies the device id that will be
|
||||
* used to run built application.
|
||||
* @param {Boolean} buildOptions.nobuild Indicates that this should be a
|
||||
* dry-run call, so no build artifacts will be produced.
|
||||
* @param {String[]} buildOptions.archs Specifies chip architectures which
|
||||
* app packages should be built for. List of valid architectures is depends on
|
||||
* platform.
|
||||
* @param {String} buildOptions.buildConfig The path to build configuration
|
||||
* file. The format of this file is depends on platform.
|
||||
* @param {String[]} buildOptions.argv Raw array of command-line arguments,
|
||||
* passed to `build` command. The purpose of this property is to pass a
|
||||
* platform-specific arguments, and eventually let platform define own
|
||||
* arguments processing logic.
|
||||
*
|
||||
* @return {Promise<Object[]>} A promise either fulfilled with an array of build
|
||||
* artifacts (application packages) if package was built successfully,
|
||||
* or rejected with CordovaError. The resultant build artifact objects is not
|
||||
* strictly typed and may conatin arbitrary set of fields as in sample below.
|
||||
*
|
||||
* {
|
||||
* architecture: 'x86',
|
||||
* buildType: 'debug',
|
||||
* path: '/path/to/build',
|
||||
* type: 'app'
|
||||
* }
|
||||
*
|
||||
* The return value in most cases will contain only one item but in some cases
|
||||
* there could be multiple items in output array, e.g. when multiple
|
||||
* arhcitectures is specified.
|
||||
*/
|
||||
Api.prototype.build = function (buildOptions) {
|
||||
var self = this;
|
||||
return require('./lib/check_reqs').run()
|
||||
.then(function () {
|
||||
return require('./lib/build').run.call(self, buildOptions);
|
||||
})
|
||||
.then(function (buildResults) {
|
||||
// Cast build result to array of build artifacts
|
||||
return buildResults.apkPaths.map(function (apkPath) {
|
||||
return {
|
||||
buildType: buildResults.buildType,
|
||||
buildMethod: buildResults.buildMethod,
|
||||
path: apkPath,
|
||||
type: 'apk'
|
||||
};
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds an application package for current platform and runs it on
|
||||
* specified/default device. If no 'device'/'emulator'/'target' options are
|
||||
* specified, then tries to run app on default device if connected, otherwise
|
||||
* runs the app on emulator.
|
||||
*
|
||||
* @param {Object} runOptions An options object. The structure is the same
|
||||
* as for build options.
|
||||
*
|
||||
* @return {Promise} A promise either fulfilled if package was built and ran
|
||||
* successfully, or rejected with CordovaError.
|
||||
*/
|
||||
Api.prototype.run = function(runOptions) {
|
||||
var self = this;
|
||||
return require('./lib/check_reqs').run()
|
||||
.then(function () {
|
||||
return require('./lib/run').run.call(self, runOptions);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Cleans out the build artifacts from platform's directory.
|
||||
*
|
||||
* @return {Promise} Return a promise either fulfilled, or rejected with
|
||||
* CordovaError.
|
||||
*/
|
||||
Api.prototype.clean = function(cleanOptions) {
|
||||
var self = this;
|
||||
return require('./lib/check_reqs').run()
|
||||
.then(function () {
|
||||
return require('./lib/build').runClean.call(self, cleanOptions);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs a requirements check for current platform. Each platform defines its
|
||||
* own set of requirements, which should be resolved before platform can be
|
||||
* built successfully.
|
||||
*
|
||||
* @return {Promise<Requirement[]>} Promise, resolved with set of Requirement
|
||||
* objects for current platform.
|
||||
*/
|
||||
Api.prototype.requirements = function() {
|
||||
return require('./lib/check_reqs').check_all();
|
||||
};
|
||||
|
||||
module.exports = Api;
|
||||
|
||||
/**
|
||||
* Removes the specified modules from list of installed modules and updates
|
||||
* platform_json and cordova_plugins.js on disk.
|
||||
*
|
||||
* @param {PluginInfo} plugin PluginInfo instance for plugin, which modules
|
||||
* needs to be added.
|
||||
* @param {String} targetDir The directory, where updated cordova_plugins.js
|
||||
* should be written to.
|
||||
*/
|
||||
Api.prototype._addModulesInfo = function(plugin, targetDir) {
|
||||
var installedModules = this._platformJson.root.modules || [];
|
||||
|
||||
var installedPaths = installedModules.map(function (installedModule) {
|
||||
return installedModule.file;
|
||||
});
|
||||
|
||||
var modulesToInstall = plugin.getJsModules(this.platform)
|
||||
.filter(function (moduleToInstall) {
|
||||
return installedPaths.indexOf(moduleToInstall.file) === -1;
|
||||
}).map(function (moduleToInstall) {
|
||||
var moduleName = plugin.id + '.' + ( moduleToInstall.name || moduleToInstall.src.match(/([^\/]+)\.js/)[1] );
|
||||
var obj = {
|
||||
file: ['plugins', plugin.id, moduleToInstall.src].join('/'),
|
||||
id: moduleName
|
||||
};
|
||||
if (moduleToInstall.clobbers.length > 0) {
|
||||
obj.clobbers = moduleToInstall.clobbers.map(function(o) { return o.target; });
|
||||
}
|
||||
if (moduleToInstall.merges.length > 0) {
|
||||
obj.merges = moduleToInstall.merges.map(function(o) { return o.target; });
|
||||
}
|
||||
if (moduleToInstall.runs) {
|
||||
obj.runs = true;
|
||||
}
|
||||
|
||||
return obj;
|
||||
});
|
||||
|
||||
this._platformJson.root.modules = installedModules.concat(modulesToInstall);
|
||||
this._writePluginModules(targetDir);
|
||||
this._platformJson.save();
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the specified modules from list of installed modules and updates
|
||||
* platform_json and cordova_plugins.js on disk.
|
||||
*
|
||||
* @param {PluginInfo} plugin PluginInfo instance for plugin, which modules
|
||||
* needs to be removed.
|
||||
* @param {String} targetDir The directory, where updated cordova_plugins.js
|
||||
* should be written to.
|
||||
*/
|
||||
Api.prototype._removeModulesInfo = function(plugin, targetDir) {
|
||||
var installedModules = this._platformJson.root.modules || [];
|
||||
var modulesToRemove = plugin.getJsModules(this.platform)
|
||||
.map(function (jsModule) {
|
||||
return ['plugins', plugin.id, jsModule.src].join('/');
|
||||
});
|
||||
|
||||
var updatedModules = installedModules
|
||||
.filter(function (installedModule) {
|
||||
return (modulesToRemove.indexOf(installedModule.file) === -1);
|
||||
});
|
||||
|
||||
this._platformJson.root.modules = updatedModules;
|
||||
this._writePluginModules(targetDir);
|
||||
this._platformJson.save();
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetches all installed modules, generates cordova_plugins contents and writes
|
||||
* it to file.
|
||||
*
|
||||
* @param {String} targetDir Directory, where write cordova_plugins.js to.
|
||||
* Ususally it is either <platform>/www or <platform>/platform_www
|
||||
* directories.
|
||||
*/
|
||||
Api.prototype._writePluginModules = function (targetDir) {
|
||||
var self = this;
|
||||
// Write out moduleObjects as JSON wrapped in a cordova module to cordova_plugins.js
|
||||
var final_contents = 'cordova.define(\'cordova/plugin_list\', function(require, exports, module) {\n';
|
||||
final_contents += 'module.exports = ' + JSON.stringify(this._platformJson.root.modules, null, ' ') + ';\n';
|
||||
final_contents += 'module.exports.metadata = \n';
|
||||
final_contents += '// TOP OF METADATA\n';
|
||||
|
||||
var pluginMetadata = Object.keys(this._platformJson.root.installed_plugins)
|
||||
.reduce(function (metadata, plugin) {
|
||||
metadata[plugin] = self._platformJson.root.installed_plugins[plugin].version;
|
||||
return metadata;
|
||||
}, {});
|
||||
|
||||
final_contents += JSON.stringify(pluginMetadata, null, 4) + '\n';
|
||||
final_contents += '// BOTTOM OF METADATA\n';
|
||||
final_contents += '});'; // Close cordova.define.
|
||||
|
||||
shell.mkdir('-p', targetDir);
|
||||
fs.writeFileSync(path.join(targetDir, 'cordova_plugins.js'), final_contents, 'utf-8');
|
||||
};
|
||||
@@ -19,30 +19,23 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var args = process.argv;
|
||||
var Api = require('./Api');
|
||||
var nopt = require('nopt');
|
||||
var path = require('path');
|
||||
var build = require('./lib/build'),
|
||||
reqs = require('./lib/check_reqs'),
|
||||
args = process.argv;
|
||||
|
||||
// Support basic help commands
|
||||
if(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0)
|
||||
require('./lib/build').help();
|
||||
|
||||
// Do some basic argument parsing
|
||||
var buildOpts = nopt({
|
||||
'verbose' : Boolean,
|
||||
'silent' : Boolean,
|
||||
'debug' : Boolean,
|
||||
'release' : Boolean,
|
||||
'nobuild': Boolean,
|
||||
'buildConfig' : path
|
||||
}, { 'd' : '--verbose' });
|
||||
|
||||
// Make buildOptions compatible with PlatformApi build method spec
|
||||
buildOpts.argv = buildOpts.argv.remain;
|
||||
|
||||
new Api().build(buildOpts)
|
||||
.catch(function(err) {
|
||||
console.error(err.stack);
|
||||
process.exit(2);
|
||||
});
|
||||
if(args[2] == '--help' ||
|
||||
args[2] == '/?' ||
|
||||
args[2] == '-h' ||
|
||||
args[2] == 'help' ||
|
||||
args[2] == '-help' ||
|
||||
args[2] == '/help') {
|
||||
build.help();
|
||||
} else {
|
||||
reqs.run().done(function() {
|
||||
return build.run(args.slice(2));
|
||||
}, function(err) {
|
||||
console.error(err);
|
||||
process.exit(2);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -19,18 +19,26 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var Api = require('./Api');
|
||||
var build = require('./lib/build'),
|
||||
reqs = require('./lib/check_reqs'),
|
||||
args = process.argv;
|
||||
var path = require('path');
|
||||
|
||||
// Support basic help commands
|
||||
if(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0) {
|
||||
if(args[2] == '--help' ||
|
||||
args[2] == '/?' ||
|
||||
args[2] == '-h' ||
|
||||
args[2] == 'help' ||
|
||||
args[2] == '-help' ||
|
||||
args[2] == '/help') {
|
||||
console.log('Usage: ' + path.relative(process.cwd(), process.argv[1]));
|
||||
console.log('Cleans the project directory.');
|
||||
process.exit(0);
|
||||
} else {
|
||||
reqs.run().done(function() {
|
||||
return build.runClean(args.slice(2));
|
||||
}, function(err) {
|
||||
console.error(err);
|
||||
process.exit(2);
|
||||
});
|
||||
}
|
||||
|
||||
new Api().clean({argv: process.argv.slice(2)})
|
||||
.catch(function(err) {
|
||||
console.error(err.stack);
|
||||
process.exit(2);
|
||||
});
|
||||
|
||||
96
bin/templates/cordova/lib/Adb.js
vendored
96
bin/templates/cordova/lib/Adb.js
vendored
@@ -1,96 +0,0 @@
|
||||
/**
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var Q = require('q');
|
||||
var os = require('os');
|
||||
var events = require('cordova-common').events;
|
||||
var spawn = require('cordova-common').superspawn.spawn;
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
|
||||
var Adb = {};
|
||||
|
||||
function isDevice(line) {
|
||||
return line.match(/\w+\tdevice/) && !line.match(/emulator/);
|
||||
}
|
||||
|
||||
function isEmulator(line) {
|
||||
return line.match(/device/) && line.match(/emulator/);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists available/connected devices and emulators
|
||||
*
|
||||
* @param {Object} opts Various options
|
||||
* @param {Boolean} opts.emulators Specifies whether this method returns
|
||||
* emulators only
|
||||
*
|
||||
* @return {Promise<String[]>} list of available/connected
|
||||
* devices/emulators
|
||||
*/
|
||||
Adb.devices = function (opts) {
|
||||
return spawn('adb', ['devices'], {cwd: os.tmpdir()})
|
||||
.then(function(output) {
|
||||
return output.split('\n').filter(function (line) {
|
||||
// Filter out either real devices or emulators, depending on options
|
||||
return (line && opts && opts.emulators) ? isEmulator(line) : isDevice(line);
|
||||
}).map(function (line) {
|
||||
return line.replace(/\tdevice/, '').replace('\r', '');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Adb.install = function (target, packagePath, opts) {
|
||||
events.emit('verbose', 'Installing apk ' + packagePath + ' on ' + target + '...');
|
||||
var args = ['-s', target, 'install'];
|
||||
if (opts && opts.replace) args.push('-r');
|
||||
return spawn('adb', args.concat(packagePath), {cwd: os.tmpdir()})
|
||||
.then(function(output) {
|
||||
// 'adb install' seems to always returns no error, even if installation fails
|
||||
// so we catching output to detect installation failure
|
||||
if (output.match(/Failure/))
|
||||
return Q.reject(new CordovaError('Failed to install apk to device: ' + output));
|
||||
});
|
||||
};
|
||||
|
||||
Adb.uninstall = function (target, packageId) {
|
||||
events.emit('verbose', 'Uninstalling ' + packageId + ' from ' + target + '...');
|
||||
return spawn('adb', ['-s', target, 'uninstall', packageId], {cwd: os.tmpdir()});
|
||||
};
|
||||
|
||||
Adb.shell = function (target, shellCommand) {
|
||||
events.emit('verbose', 'Running command "' + shellCommand + '" on ' + target + '...');
|
||||
var args = ['-s', target, 'shell'];
|
||||
shellCommand = shellCommand.split(/\s+/);
|
||||
return spawn('adb', args.concat(shellCommand), {cwd: os.tmpdir()})
|
||||
.catch(function (output) {
|
||||
return Q.reject(new CordovaError('Failed to execute shell command "' +
|
||||
shellCommand + '"" on device: ' + output));
|
||||
});
|
||||
};
|
||||
|
||||
Adb.start = function (target, activityName) {
|
||||
events.emit('verbose', 'Starting application "' + activityName + '" on ' + target + '...');
|
||||
return Adb.shell(target, 'am start -W -a android.intent.action.MAIN -n' + activityName)
|
||||
.catch(function (output) {
|
||||
return Q.reject(new CordovaError('Failed to start application "' +
|
||||
activityName + '"" on device: ' + output));
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = Adb;
|
||||
161
bin/templates/cordova/lib/AndroidManifest.js
vendored
161
bin/templates/cordova/lib/AndroidManifest.js
vendored
@@ -1,161 +0,0 @@
|
||||
/**
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var fs = require('fs');
|
||||
var et = require('elementtree');
|
||||
var xml= require('cordova-common').xmlHelpers;
|
||||
|
||||
var DEFAULT_ORIENTATION = 'default';
|
||||
|
||||
/** Wraps an AndroidManifest file */
|
||||
function AndroidManifest(path) {
|
||||
this.path = path;
|
||||
this.doc = xml.parseElementtreeSync(path);
|
||||
if (this.doc.getroot().tag !== 'manifest') {
|
||||
throw new Error(path + ' has incorrect root node name (expected "manifest")');
|
||||
}
|
||||
}
|
||||
|
||||
AndroidManifest.prototype.getVersionName = function() {
|
||||
return this.doc.getroot().attrib['android:versionName'];
|
||||
};
|
||||
|
||||
AndroidManifest.prototype.setVersionName = function(versionName) {
|
||||
this.doc.getroot().attrib['android:versionName'] = versionName;
|
||||
return this;
|
||||
};
|
||||
|
||||
AndroidManifest.prototype.getVersionCode = function() {
|
||||
return this.doc.getroot().attrib['android:versionCode'];
|
||||
};
|
||||
|
||||
AndroidManifest.prototype.setVersionCode = function(versionCode) {
|
||||
this.doc.getroot().attrib['android:versionCode'] = versionCode;
|
||||
return this;
|
||||
};
|
||||
|
||||
AndroidManifest.prototype.getPackageId = function() {
|
||||
/*jshint -W069 */
|
||||
return this.doc.getroot().attrib['package'];
|
||||
/*jshint +W069 */
|
||||
};
|
||||
|
||||
AndroidManifest.prototype.setPackageId = function(pkgId) {
|
||||
/*jshint -W069 */
|
||||
this.doc.getroot().attrib['package'] = pkgId;
|
||||
/*jshint +W069 */
|
||||
return this;
|
||||
};
|
||||
|
||||
AndroidManifest.prototype.getActivity = function() {
|
||||
var activity = this.doc.getroot().find('./application/activity');
|
||||
return {
|
||||
getName: function () {
|
||||
return activity.attrib['android:name'];
|
||||
},
|
||||
setName: function (name) {
|
||||
if (!name) {
|
||||
delete activity.attrib['android:name'];
|
||||
} else {
|
||||
activity.attrib['android:name'] = name;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
getOrientation: function () {
|
||||
return activity.attrib['android:screenOrientation'];
|
||||
},
|
||||
setOrientation: function (orientation) {
|
||||
if (!orientation || orientation.toLowerCase() === DEFAULT_ORIENTATION) {
|
||||
delete activity.attrib['android:screenOrientation'];
|
||||
} else {
|
||||
activity.attrib['android:screenOrientation'] = orientation;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
getLaunchMode: function () {
|
||||
return activity.attrib['android:launchMode'];
|
||||
},
|
||||
setLaunchMode: function (launchMode) {
|
||||
if (!launchMode) {
|
||||
delete activity.attrib['android:launchMode'];
|
||||
} else {
|
||||
activity.attrib['android:launchMode'] = launchMode;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
['minSdkVersion', 'maxSdkVersion', 'targetSdkVersion']
|
||||
.forEach(function(sdkPrefName) {
|
||||
// Copy variable reference to avoid closure issues
|
||||
var prefName = sdkPrefName;
|
||||
|
||||
AndroidManifest.prototype['get' + capitalize(prefName)] = function() {
|
||||
var usesSdk = this.doc.getroot().find('./uses-sdk');
|
||||
return usesSdk && usesSdk.attrib['android:' + prefName];
|
||||
};
|
||||
|
||||
AndroidManifest.prototype['set' + capitalize(prefName)] = function(prefValue) {
|
||||
var usesSdk = this.doc.getroot().find('./uses-sdk');
|
||||
|
||||
if (!usesSdk && prefValue) { // if there is no required uses-sdk element, we should create it first
|
||||
usesSdk = new et.Element('uses-sdk');
|
||||
this.doc.getroot().append(usesSdk);
|
||||
}
|
||||
|
||||
if (prefValue) {
|
||||
usesSdk.attrib['android:' + prefName] = prefValue;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
});
|
||||
|
||||
AndroidManifest.prototype.getDebuggable = function() {
|
||||
return this.doc.getroot().find('./application').attrib['android:debuggable'] === 'true';
|
||||
};
|
||||
|
||||
AndroidManifest.prototype.setDebuggable = function(value) {
|
||||
var application = this.doc.getroot().find('./application');
|
||||
if (value) {
|
||||
application.attrib['android:debuggable'] = 'true';
|
||||
} else {
|
||||
// The default value is "false", so we can remove attribute at all.
|
||||
delete application.attrib['android:debuggable'];
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes manifest to disk syncronously. If filename is specified, then manifest
|
||||
* will be written to that file
|
||||
*
|
||||
* @param {String} [destPath] File to write manifest to. If omitted,
|
||||
* manifest will be written to file it has been read from.
|
||||
*/
|
||||
AndroidManifest.prototype.write = function(destPath) {
|
||||
fs.writeFileSync(destPath || this.path, this.doc.write({indent: 4}), 'utf-8');
|
||||
};
|
||||
|
||||
module.exports = AndroidManifest;
|
||||
|
||||
function capitalize (str) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
}
|
||||
184
bin/templates/cordova/lib/AndroidProject.js
vendored
184
bin/templates/cordova/lib/AndroidProject.js
vendored
@@ -1,184 +0,0 @@
|
||||
/**
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var properties_parser = require('properties-parser');
|
||||
var AndroidManifest = require('./AndroidManifest');
|
||||
|
||||
var projectFileCache = {};
|
||||
|
||||
function addToPropertyList(projectProperties, key, value) {
|
||||
var i = 1;
|
||||
while (projectProperties.get(key + '.' + i))
|
||||
i++;
|
||||
|
||||
projectProperties.set(key + '.' + i, value);
|
||||
projectProperties.dirty = true;
|
||||
}
|
||||
|
||||
function removeFromPropertyList(projectProperties, key, value) {
|
||||
var i = 1;
|
||||
var currentValue;
|
||||
while ((currentValue = projectProperties.get(key + '.' + i))) {
|
||||
if (currentValue === value) {
|
||||
while ((currentValue = projectProperties.get(key + '.' + (i + 1)))) {
|
||||
projectProperties.set(key + '.' + i, currentValue);
|
||||
i++;
|
||||
}
|
||||
projectProperties.set(key + '.' + i);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
projectProperties.dirty = true;
|
||||
}
|
||||
|
||||
function getRelativeLibraryPath (parentDir, subDir) {
|
||||
var libraryPath = path.relative(parentDir, subDir);
|
||||
return (path.sep == '\\') ? libraryPath.replace(/\\/g, '/') : libraryPath;
|
||||
}
|
||||
|
||||
function AndroidProject(projectDir) {
|
||||
this._propertiesEditors = {};
|
||||
this._subProjectDirs = {};
|
||||
this._dirty = false;
|
||||
this.projectDir = projectDir;
|
||||
this.platformWww = path.join(this.projectDir, 'platform_www');
|
||||
this.www = path.join(this.projectDir, 'assets/www');
|
||||
}
|
||||
|
||||
AndroidProject.getProjectFile = function (projectDir) {
|
||||
if (!projectFileCache[projectDir]) {
|
||||
projectFileCache[projectDir] = new AndroidProject(projectDir);
|
||||
}
|
||||
|
||||
return projectFileCache[projectDir];
|
||||
};
|
||||
|
||||
AndroidProject.purgeCache = function (projectDir) {
|
||||
if (projectDir) {
|
||||
delete projectFileCache[projectDir];
|
||||
} else {
|
||||
projectFileCache = {};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reads the package name out of the Android Manifest file
|
||||
*
|
||||
* @param {String} projectDir The absolute path to the directory containing the project
|
||||
*
|
||||
* @return {String} The name of the package
|
||||
*/
|
||||
AndroidProject.prototype.getPackageName = function() {
|
||||
return new AndroidManifest(path.join(this.projectDir, 'AndroidManifest.xml')).getPackageId();
|
||||
};
|
||||
|
||||
AndroidProject.prototype.getCustomSubprojectRelativeDir = function(plugin_id, src) {
|
||||
// All custom subprojects are prefixed with the last portion of the package id.
|
||||
// This is to avoid collisions when opening multiple projects in Eclipse that have subprojects with the same name.
|
||||
var packageName = this.getPackageName();
|
||||
var lastDotIndex = packageName.lastIndexOf('.');
|
||||
var prefix = packageName.substring(lastDotIndex + 1);
|
||||
var subRelativeDir = path.join(plugin_id, prefix + '-' + path.basename(src));
|
||||
return subRelativeDir;
|
||||
};
|
||||
|
||||
AndroidProject.prototype.addSubProject = function(parentDir, subDir) {
|
||||
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
||||
var subProjectFile = path.resolve(subDir, 'project.properties');
|
||||
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
||||
// TODO: Setting the target needs to happen only for pre-3.7.0 projects
|
||||
if (fs.existsSync(subProjectFile)) {
|
||||
var subProperties = this._getPropertiesFile(subProjectFile);
|
||||
subProperties.set('target', parentProperties.get('target'));
|
||||
subProperties.dirty = true;
|
||||
this._subProjectDirs[subDir] = true;
|
||||
}
|
||||
addToPropertyList(parentProperties, 'android.library.reference', getRelativeLibraryPath(parentDir, subDir));
|
||||
|
||||
this._dirty = true;
|
||||
};
|
||||
|
||||
AndroidProject.prototype.removeSubProject = function(parentDir, subDir) {
|
||||
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
||||
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
||||
removeFromPropertyList(parentProperties, 'android.library.reference', getRelativeLibraryPath(parentDir, subDir));
|
||||
delete this._subProjectDirs[subDir];
|
||||
this._dirty = true;
|
||||
};
|
||||
|
||||
AndroidProject.prototype.addGradleReference = function(parentDir, subDir) {
|
||||
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
||||
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
||||
addToPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir));
|
||||
this._dirty = true;
|
||||
};
|
||||
|
||||
AndroidProject.prototype.removeGradleReference = function(parentDir, subDir) {
|
||||
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
||||
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
||||
removeFromPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir));
|
||||
this._dirty = true;
|
||||
};
|
||||
|
||||
AndroidProject.prototype.addSystemLibrary = function(parentDir, value) {
|
||||
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
||||
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
||||
addToPropertyList(parentProperties, 'cordova.system.library', value);
|
||||
this._dirty = true;
|
||||
};
|
||||
|
||||
AndroidProject.prototype.removeSystemLibrary = function(parentDir, value) {
|
||||
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
||||
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
||||
removeFromPropertyList(parentProperties, 'cordova.system.library', value);
|
||||
this._dirty = true;
|
||||
};
|
||||
|
||||
AndroidProject.prototype.write = function() {
|
||||
if (!this._dirty) {
|
||||
return;
|
||||
}
|
||||
this._dirty = false;
|
||||
|
||||
for (var filename in this._propertiesEditors) {
|
||||
var editor = this._propertiesEditors[filename];
|
||||
if (editor.dirty) {
|
||||
fs.writeFileSync(filename, editor.toString());
|
||||
editor.dirty = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
AndroidProject.prototype._getPropertiesFile = function (filename) {
|
||||
if (!this._propertiesEditors[filename]) {
|
||||
if (fs.existsSync(filename)) {
|
||||
this._propertiesEditors[filename] = properties_parser.createEditor(filename);
|
||||
} else {
|
||||
this._propertiesEditors[filename] = properties_parser.createEditor();
|
||||
}
|
||||
}
|
||||
|
||||
return this._propertiesEditors[filename];
|
||||
};
|
||||
|
||||
|
||||
module.exports = AndroidProject;
|
||||
75
bin/templates/cordova/lib/ConsoleLogger.js
vendored
75
bin/templates/cordova/lib/ConsoleLogger.js
vendored
@@ -1,75 +0,0 @@
|
||||
/**
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var loggerInstance;
|
||||
var util = require('util');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
|
||||
/**
|
||||
* @class ConsoleLogger
|
||||
* @extends EventEmitter
|
||||
*
|
||||
* Implementing basic logging for platform. Inherits regular NodeJS
|
||||
* EventEmitter. All events, emitted on this class instance are immediately
|
||||
* logged to console.
|
||||
*
|
||||
* Also attaches handler to process' uncaught exceptions, so these exceptions
|
||||
* logged to console similar to regular error events.
|
||||
*/
|
||||
function ConsoleLogger() {
|
||||
EventEmitter.call(this);
|
||||
|
||||
var isVerbose = process.argv.indexOf('-d') >= 0 || process.argv.indexOf('--verbose') >= 0;
|
||||
// For CordovaError print only the message without stack trace unless we
|
||||
// are in a verbose mode.
|
||||
process.on('uncaughtException', function(err){
|
||||
if ((err instanceof CordovaError) && isVerbose) {
|
||||
console.error(err.stack);
|
||||
} else {
|
||||
console.error(err.message);
|
||||
}
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
this.on('results', console.log);
|
||||
this.on('verbose', function () {
|
||||
if (isVerbose)
|
||||
console.log.apply(console, arguments);
|
||||
});
|
||||
this.on('info', console.log);
|
||||
this.on('log', console.log);
|
||||
this.on('warn', console.warn);
|
||||
}
|
||||
util.inherits(ConsoleLogger, EventEmitter);
|
||||
|
||||
/**
|
||||
* Returns already instantiated/newly created instance of ConsoleLogger class.
|
||||
* This method should be used instead of creating ConsoleLogger directly,
|
||||
* otherwise we'll get multiple handlers attached to process'
|
||||
* uncaughtException
|
||||
*
|
||||
* @return {ConsoleLogger} New or already created instance of ConsoleLogger
|
||||
*/
|
||||
ConsoleLogger.get = function () {
|
||||
loggerInstance = loggerInstance || new ConsoleLogger();
|
||||
return loggerInstance;
|
||||
};
|
||||
|
||||
module.exports = ConsoleLogger;
|
||||
41
bin/templates/cordova/lib/appinfo.js
vendored
Normal file
41
bin/templates/cordova/lib/appinfo.js
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var cachedAppInfo = null;
|
||||
|
||||
function readAppInfoFromManifest() {
|
||||
var manifestPath = path.join(__dirname, '..', '..', 'AndroidManifest.xml');
|
||||
var manifestData = fs.readFileSync(manifestPath, {encoding:'utf8'});
|
||||
var packageName = /\bpackage\s*=\s*"(.+?)"/.exec(manifestData);
|
||||
if (!packageName) throw new Error('Could not find package name within ' + manifestPath);
|
||||
var activityTag = /<activity\b[\s\S]*<\/activity>/.exec(manifestData);
|
||||
if (!activityTag) throw new Error('Could not find <activity> within ' + manifestPath);
|
||||
var activityName = /\bandroid:name\s*=\s*"(.+?)"/.exec(activityTag);
|
||||
if (!activityName) throw new Error('Could not find android:name within ' + manifestPath);
|
||||
|
||||
return packageName[1] + '/.' + activityName[1];
|
||||
}
|
||||
|
||||
exports.getActivityName = function() {
|
||||
return cachedAppInfo = cachedAppInfo || readAppInfoFromManifest();
|
||||
};
|
||||
544
bin/templates/cordova/lib/build.js
vendored
544
bin/templates/cordova/lib/build.js
vendored
@@ -19,98 +19,345 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var Q = require('q'),
|
||||
var shell = require('shelljs'),
|
||||
spawn = require('./spawn'),
|
||||
Q = require('q'),
|
||||
path = require('path'),
|
||||
fs = require('fs'),
|
||||
nopt = require('nopt');
|
||||
os = require('os'),
|
||||
ROOT = path.join(__dirname, '..', '..');
|
||||
var check_reqs = require('./check_reqs');
|
||||
var exec = require('./exec');
|
||||
|
||||
var Adb = require('./Adb');
|
||||
var LOCAL_PROPERTIES_TEMPLATE =
|
||||
'# This file is automatically generated.\n' +
|
||||
'# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n';
|
||||
|
||||
var builders = require('./builders/builders');
|
||||
var events = require('cordova-common').events;
|
||||
var spawn = require('cordova-common').superspawn.spawn;
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
function findApks(directory) {
|
||||
var ret = [];
|
||||
if (fs.existsSync(directory)) {
|
||||
fs.readdirSync(directory).forEach(function(p) {
|
||||
if (path.extname(p) == '.apk') {
|
||||
ret.push(path.join(directory, p));
|
||||
}
|
||||
});
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function sortFilesByDate(files) {
|
||||
return files.map(function(p) {
|
||||
return { p: p, t: fs.statSync(p).mtime };
|
||||
}).sort(function(a, b) {
|
||||
var timeDiff = b.t - a.t;
|
||||
return timeDiff === 0 ? a.p.length - b.p.length : timeDiff;
|
||||
}).map(function(p) { return p.p; });
|
||||
}
|
||||
|
||||
function findOutputApksHelper(dir, build_type, arch) {
|
||||
var ret = findApks(dir).filter(function(candidate) {
|
||||
// Need to choose between release and debug .apk.
|
||||
if (build_type === 'debug') {
|
||||
return /-debug/.exec(candidate) && !/-unaligned|-unsigned/.exec(candidate);
|
||||
}
|
||||
if (build_type === 'release') {
|
||||
return /-release/.exec(candidate) && !/-unaligned/.exec(candidate);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
ret = sortFilesByDate(ret);
|
||||
if (ret.length === 0) {
|
||||
return ret;
|
||||
}
|
||||
// Assume arch-specific build if newest api has -x86 or -arm.
|
||||
var archSpecific = !!/-x86|-arm/.exec(ret[0]);
|
||||
// And show only arch-specific ones (or non-arch-specific)
|
||||
ret = ret.filter(function(p) {
|
||||
return !!/-x86|-arm/.exec(p) == archSpecific;
|
||||
});
|
||||
if (arch && ret.length > 1) {
|
||||
ret = ret.filter(function(p) {
|
||||
return p.indexOf('-' + arch) != -1;
|
||||
});
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function hasCustomRules() {
|
||||
return fs.existsSync(path.join(ROOT, 'custom_rules.xml'));
|
||||
}
|
||||
|
||||
function extractProjectNameFromManifest(projectPath) {
|
||||
var manifestPath = path.join(projectPath, 'AndroidManifest.xml');
|
||||
var manifestData = fs.readFileSync(manifestPath, 'utf8');
|
||||
var m = /<activity[\s\S]*?android:name\s*=\s*"(.*?)"/i.exec(manifestData);
|
||||
if (!m) {
|
||||
throw new Error('Could not find activity name in ' + manifestPath);
|
||||
}
|
||||
return m[1];
|
||||
}
|
||||
|
||||
function extractSubProjectPaths() {
|
||||
var data = fs.readFileSync(path.join(ROOT, 'project.properties'), 'utf8');
|
||||
var ret = {};
|
||||
var r = /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg
|
||||
var m;
|
||||
while (m = r.exec(data)) {
|
||||
ret[m[1]] = 1;
|
||||
}
|
||||
return Object.keys(ret);
|
||||
}
|
||||
|
||||
var builders = {
|
||||
ant: {
|
||||
getArgs: function(cmd) {
|
||||
var args = [cmd, '-f', path.join(ROOT, 'build.xml')];
|
||||
// custom_rules.xml is required for incremental builds.
|
||||
if (hasCustomRules()) {
|
||||
args.push('-Dout.dir=ant-build', '-Dgen.absolute.dir=ant-gen');
|
||||
}
|
||||
return args;
|
||||
},
|
||||
|
||||
prepEnv: function() {
|
||||
return check_reqs.check_ant()
|
||||
.then(function() {
|
||||
// Copy in build.xml on each build so that:
|
||||
// A) we don't require the Android SDK at project creation time, and
|
||||
// B) we always use the SDK's latest version of it.
|
||||
var sdkDir = process.env['ANDROID_HOME'];
|
||||
var buildTemplate = fs.readFileSync(path.join(sdkDir, 'tools', 'lib', 'build.template'), 'utf8');
|
||||
function writeBuildXml(projectPath) {
|
||||
var newData = buildTemplate.replace('PROJECT_NAME', extractProjectNameFromManifest(ROOT));
|
||||
fs.writeFileSync(path.join(projectPath, 'build.xml'), newData);
|
||||
if (!fs.existsSync(path.join(projectPath, 'local.properties'))) {
|
||||
fs.writeFileSync(path.join(projectPath, 'local.properties'), LOCAL_PROPERTIES_TEMPLATE);
|
||||
}
|
||||
}
|
||||
var subProjects = extractSubProjectPaths();
|
||||
writeBuildXml(ROOT);
|
||||
for (var i = 0; i < subProjects.length; ++i) {
|
||||
writeBuildXml(path.join(ROOT, subProjects[i]));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/*
|
||||
* Builds the project with ant.
|
||||
* Returns a promise.
|
||||
*/
|
||||
build: function(build_type) {
|
||||
// Without our custom_rules.xml, we need to clean before building.
|
||||
var ret = Q();
|
||||
if (!hasCustomRules()) {
|
||||
// clean will call check_ant() for us.
|
||||
ret = this.clean();
|
||||
}
|
||||
|
||||
var builder = this;
|
||||
var args = this.getArgs(build_type == 'debug' ? 'debug' : 'release');
|
||||
return check_reqs.check_ant()
|
||||
.then(function() {
|
||||
return spawn('ant', args);
|
||||
});
|
||||
},
|
||||
|
||||
clean: function() {
|
||||
var args = this.getArgs('clean');
|
||||
return check_reqs.check_ant()
|
||||
.then(function() {
|
||||
return spawn('ant', args);
|
||||
});
|
||||
},
|
||||
|
||||
findOutputApks: function(build_type) {
|
||||
var binDir = path.join(ROOT, hasCustomRules() ? 'ant-build' : 'bin');
|
||||
return findOutputApksHelper(binDir, build_type, null);
|
||||
}
|
||||
},
|
||||
gradle: {
|
||||
getArgs: function(cmd, arch, extraArgs) {
|
||||
if (cmd == 'release') {
|
||||
cmd = 'cdvBuildRelease';
|
||||
} else if (cmd == 'debug') {
|
||||
cmd = 'cdvBuildDebug';
|
||||
}
|
||||
var args = [cmd, '-b', path.join(ROOT, 'build.gradle')];
|
||||
if (arch) {
|
||||
args.push('-PcdvBuildArch=' + arch);
|
||||
}
|
||||
|
||||
// 10 seconds -> 6 seconds
|
||||
args.push('-Dorg.gradle.daemon=true');
|
||||
args.push.apply(args, extraArgs);
|
||||
// Shaves another 100ms, but produces a "try at own risk" warning. Not worth it (yet):
|
||||
// args.push('-Dorg.gradle.parallel=true');
|
||||
return args;
|
||||
},
|
||||
|
||||
prepEnv: function() {
|
||||
return check_reqs.check_gradle()
|
||||
.then(function() {
|
||||
// Copy the gradle wrapper on each build so that:
|
||||
// A) we don't require the Android SDK at project creation time, and
|
||||
// B) we always use the SDK's latest version of it.
|
||||
var projectPath = ROOT;
|
||||
// check_reqs ensures that this is set.
|
||||
var sdkDir = process.env['ANDROID_HOME'];
|
||||
var wrapperDir = path.join(sdkDir, 'tools', 'templates', 'gradle', 'wrapper');
|
||||
if (process.platform == 'win32') {
|
||||
shell.cp('-f', path.join(wrapperDir, 'gradlew.bat'), projectPath);
|
||||
} else {
|
||||
shell.cp('-f', path.join(wrapperDir, 'gradlew'), projectPath);
|
||||
}
|
||||
shell.rm('-rf', path.join(projectPath, 'gradle', 'wrapper'));
|
||||
shell.mkdir('-p', path.join(projectPath, 'gradle'));
|
||||
shell.cp('-r', path.join(wrapperDir, 'gradle', 'wrapper'), path.join(projectPath, 'gradle'));
|
||||
|
||||
// If the gradle distribution URL is set, make sure it points to version we want.
|
||||
// If it's not set, do nothing, assuming that we're using a future version of gradle that we don't want to mess with.
|
||||
// For some reason, using ^ and $ don't work. This does the job, though.
|
||||
var distributionUrlRegex = /distributionUrl.*zip/;
|
||||
var distributionUrl = 'distributionUrl=http\\://services.gradle.org/distributions/gradle-2.2.1-all.zip';
|
||||
var gradleWrapperPropertiesPath = path.join(projectPath, 'gradle', 'wrapper', 'gradle-wrapper.properties');
|
||||
shell.sed('-i', distributionUrlRegex, distributionUrl, gradleWrapperPropertiesPath);
|
||||
|
||||
// Update the version of build.gradle in each dependent library.
|
||||
var pluginBuildGradle = path.join(projectPath, 'cordova', 'lib', 'plugin-build.gradle');
|
||||
var subProjects = extractSubProjectPaths();
|
||||
for (var i = 0; i < subProjects.length; ++i) {
|
||||
if (subProjects[i] !== 'CordovaLib') {
|
||||
shell.cp('-f', pluginBuildGradle, path.join(ROOT, subProjects[i], 'build.gradle'));
|
||||
}
|
||||
}
|
||||
|
||||
var subProjectsAsGradlePaths = subProjects.map(function(p) { return ':' + p.replace(/[/\\]/g, ':') });
|
||||
// Write the settings.gradle file.
|
||||
fs.writeFileSync(path.join(projectPath, 'settings.gradle'),
|
||||
'// GENERATED FILE - DO NOT EDIT\n' +
|
||||
'include ":"\n' +
|
||||
'include "' + subProjectsAsGradlePaths.join('"\ninclude "') + '"\n');
|
||||
// Update dependencies within build.gradle.
|
||||
var buildGradle = fs.readFileSync(path.join(projectPath, 'build.gradle'), 'utf8');
|
||||
var depsList = '';
|
||||
subProjectsAsGradlePaths.forEach(function(p) {
|
||||
depsList += ' debugCompile project(path: "' + p + '", configuration: "debug")\n';
|
||||
depsList += ' releaseCompile project(path: "' + p + '", configuration: "release")\n';
|
||||
});
|
||||
buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + ' $2');
|
||||
fs.writeFileSync(path.join(projectPath, 'build.gradle'), buildGradle);
|
||||
});
|
||||
},
|
||||
|
||||
/*
|
||||
* Builds the project with gradle.
|
||||
* Returns a promise.
|
||||
*/
|
||||
build: function(build_type, arch, extraArgs) {
|
||||
var builder = this;
|
||||
var wrapper = path.join(ROOT, 'gradlew');
|
||||
var args = this.getArgs(build_type == 'debug' ? 'debug' : 'release', arch, extraArgs);
|
||||
return Q().then(function() {
|
||||
console.log('Running: ' + wrapper + ' ' + args.concat(extraArgs).join(' '));
|
||||
return spawn(wrapper, args);
|
||||
});
|
||||
},
|
||||
|
||||
clean: function(extraArgs) {
|
||||
var builder = this;
|
||||
var wrapper = path.join(ROOT, 'gradlew');
|
||||
var args = builder.getArgs('clean', null, extraArgs);
|
||||
return Q().then(function() {
|
||||
console.log('Running: ' + wrapper + ' ' + args.concat(extraArgs).join(' '));
|
||||
return spawn(wrapper, args);
|
||||
});
|
||||
},
|
||||
|
||||
findOutputApks: function(build_type, arch) {
|
||||
var binDir = path.join(ROOT, 'build', 'outputs', 'apk');
|
||||
return findOutputApksHelper(binDir, build_type, arch);
|
||||
}
|
||||
},
|
||||
|
||||
none: {
|
||||
prepEnv: function() {
|
||||
return Q();
|
||||
},
|
||||
build: function() {
|
||||
console.log('Skipping build...');
|
||||
return Q(null);
|
||||
},
|
||||
clean: function() {
|
||||
return Q();
|
||||
},
|
||||
findOutputApks: function(build_type, arch) {
|
||||
return sortFilesByDate(builders.ant.findOutputApks(build_type, arch).concat(builders.gradle.findOutputApks(build_type, arch)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function parseOpts(options, resolvedTarget) {
|
||||
options = options || {};
|
||||
options.argv = nopt({
|
||||
gradle: Boolean,
|
||||
ant: Boolean,
|
||||
prepenv: Boolean,
|
||||
versionCode: String,
|
||||
minSdkVersion: String,
|
||||
gradleArg: String,
|
||||
keystore: path,
|
||||
alias: String,
|
||||
storePassword: String,
|
||||
password: String,
|
||||
keystoreType: String
|
||||
}, {}, options.argv, 0);
|
||||
// Backwards-compatibility: Allow a single string argument
|
||||
if (typeof options == "string") options = [options];
|
||||
|
||||
var ret = {
|
||||
buildType: options.release ? 'release' : 'debug',
|
||||
buildMethod: process.env.ANDROID_BUILD || 'gradle',
|
||||
prepEnv: options.argv.prepenv,
|
||||
arch: resolvedTarget && resolvedTarget.arch,
|
||||
buildType: 'debug',
|
||||
buildMethod: process.env['ANDROID_BUILD'] || 'ant',
|
||||
arch: null,
|
||||
extraArgs: []
|
||||
};
|
||||
|
||||
if (options.argv.ant || options.argv.gradle)
|
||||
ret.buildMethod = options.argv.ant ? 'ant' : 'gradle';
|
||||
var multiValueArgs = {
|
||||
'versionCode': true,
|
||||
'minSdkVersion': true,
|
||||
'gradleArg': true
|
||||
};
|
||||
|
||||
if (options.nobuild) ret.buildMethod = 'none';
|
||||
|
||||
if (options.argv.versionCode)
|
||||
ret.extraArgs.push('-PcdvVersionCode=' + options.versionCode);
|
||||
|
||||
if (options.argv.minSdkVersion)
|
||||
ret.extraArgs.push('-PcdvMinSdkVersion=' + options.minSdkVersion);
|
||||
|
||||
if (options.argv.gradleArg)
|
||||
ret.extraArgs.push(options.gradleArg);
|
||||
|
||||
var packageArgs = {};
|
||||
|
||||
if (options.argv.keystore)
|
||||
packageArgs.keystore = path.relative(this.root, path.resolve(options.argv.keystore));
|
||||
|
||||
['alias','storePassword','password','keystoreType'].forEach(function (flagName) {
|
||||
if (options.argv[flagName])
|
||||
packageArgs[flagName] = options.argv[flagName];
|
||||
});
|
||||
|
||||
var buildConfig = options.buildConfig;
|
||||
|
||||
// If some values are not specified as command line arguments - use build config to supplement them.
|
||||
// Command line arguemnts have precedence over build config.
|
||||
if (buildConfig) {
|
||||
if (!fs.existsSync(buildConfig)) {
|
||||
throw new Error('Specified build config file does not exist: ' + buildConfig);
|
||||
}
|
||||
events.emit('log', 'Reading build config file: '+ path.resolve(buildConfig));
|
||||
var config = JSON.parse(fs.readFileSync(buildConfig, 'utf8'));
|
||||
if (config.android && config.android[ret.buildType]) {
|
||||
var androidInfo = config.android[ret.buildType];
|
||||
if(androidInfo.keystore && !packageArgs.keystore) {
|
||||
packageArgs.keystore = path.resolve(path.dirname(buildConfig), androidInfo.keystore);
|
||||
// Iterate through command line options
|
||||
for (var i=0; options && (i < options.length); ++i) {
|
||||
if (/^--/.exec(options[i])) {
|
||||
var keyValue = options[i].substring(2).split('=');
|
||||
var flagName = keyValue.shift();
|
||||
var flagValue = keyValue.join('=');
|
||||
if (multiValueArgs[flagName] && !flagValue) {
|
||||
flagValue = options[i + 1];
|
||||
++i;
|
||||
}
|
||||
|
||||
['alias', 'storePassword', 'password','keystoreType'].forEach(function (key){
|
||||
packageArgs[key] = packageArgs[key] || androidInfo[key];
|
||||
});
|
||||
switch(flagName) {
|
||||
case 'debug':
|
||||
case 'release':
|
||||
ret.buildType = flagName;
|
||||
break;
|
||||
case 'ant':
|
||||
case 'gradle':
|
||||
ret.buildMethod = flagName;
|
||||
break;
|
||||
case 'device':
|
||||
case 'emulator':
|
||||
// Don't need to do anything special to when building for device vs emulator.
|
||||
// iOS uses this flag to switch on architecture.
|
||||
break;
|
||||
case 'nobuild' :
|
||||
ret.buildMethod = 'none';
|
||||
break;
|
||||
case 'versionCode':
|
||||
ret.extraArgs.push('-PcdvVersionCode=' + flagValue);
|
||||
break;
|
||||
case 'minSdkVersion':
|
||||
ret.extraArgs.push('-PcdvMinSdkVersion=' + flagValue);
|
||||
break;
|
||||
case 'gradleArg':
|
||||
ret.extraArgs.push(flagValue);
|
||||
break;
|
||||
default :
|
||||
console.warn('Build option --\'' + flagName + '\' not recognized (ignoring).');
|
||||
}
|
||||
} else {
|
||||
console.warn('Build option \'' + options[i] + '\' not recognized (ignoring).');
|
||||
}
|
||||
}
|
||||
|
||||
if (packageArgs.keystore && packageArgs.alias) {
|
||||
ret.packageInfo = new PackageInfo(packageArgs.keystore, packageArgs.alias, packageArgs.storePassword,
|
||||
packageArgs.password, packageArgs.keystoreType);
|
||||
}
|
||||
|
||||
if(!ret.packageInfo) {
|
||||
if(Object.keys(packageArgs).length > 0) {
|
||||
events.emit('warn', '\'keystore\' and \'alias\' need to be specified to generate a signed archive.');
|
||||
}
|
||||
}
|
||||
ret.arch = resolvedTarget && resolvedTarget.arch;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -121,92 +368,78 @@ function parseOpts(options, resolvedTarget) {
|
||||
*/
|
||||
module.exports.runClean = function(options) {
|
||||
var opts = parseOpts(options);
|
||||
var builder = builders.getBuilder(opts.buildMethod);
|
||||
return builder.prepEnv(opts)
|
||||
var builder = builders[opts.buildMethod];
|
||||
return builder.prepEnv()
|
||||
.then(function() {
|
||||
return builder.clean(opts);
|
||||
return builder.clean(opts.extraArgs);
|
||||
}).then(function() {
|
||||
shell.rm('-rf', path.join(ROOT, 'out'));
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds the project with the specifed options.
|
||||
*
|
||||
* @param {BuildOptions} options A set of options. See PlatformApi.build
|
||||
* method documentation for reference.
|
||||
* @param {Object} optResolvedTarget A deployment target. Used to pass
|
||||
* target architecture from upstream 'run' call. TODO: remove this option in
|
||||
* favor of setting buildOptions.archs field.
|
||||
*
|
||||
* @return {Promise<Object>} Promise, resolved with built packages
|
||||
* information.
|
||||
/*
|
||||
* Builds the project with the specifed options
|
||||
* Returns a promise.
|
||||
*/
|
||||
module.exports.run = function(options, optResolvedTarget) {
|
||||
var opts = parseOpts(options, optResolvedTarget);
|
||||
var builder = builders.getBuilder(opts.buildMethod);
|
||||
var self = this;
|
||||
return builder.prepEnv(opts)
|
||||
var builder = builders[opts.buildMethod];
|
||||
return builder.prepEnv()
|
||||
.then(function() {
|
||||
if (opts.prepEnv) {
|
||||
self.events.emit('verbose', 'Build file successfully prepared.');
|
||||
return;
|
||||
}
|
||||
return builder.build(opts)
|
||||
.then(function() {
|
||||
var apkPaths = builder.findOutputApks(opts.buildType, opts.arch);
|
||||
self.events.emit('log', 'Built the following apk(s): \n\t' + apkPaths.join('\n\t'));
|
||||
return {
|
||||
apkPaths: apkPaths,
|
||||
buildType: opts.buildType,
|
||||
buildMethod: opts.buildMethod
|
||||
};
|
||||
});
|
||||
return builder.build(opts.buildType, opts.arch, opts.extraArgs);
|
||||
}).then(function() {
|
||||
var apkPaths = builder.findOutputApks(opts.buildType, opts.arch);
|
||||
console.log('Built the following apk(s):');
|
||||
console.log(' ' + apkPaths.join('\n '));
|
||||
return {
|
||||
apkPaths: apkPaths,
|
||||
buildType: opts.buildType,
|
||||
buildMethod: opts.buildMethod
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
// Called by plugman after installing plugins, and by create script after creating project.
|
||||
module.exports.prepBuildFiles = function() {
|
||||
return builders.getBuilder('gradle').prepBuildFiles();
|
||||
};
|
||||
|
||||
/*
|
||||
* Detects the architecture of a device/emulator
|
||||
* Returns "arm" or "x86".
|
||||
*/
|
||||
module.exports.detectArchitecture = function(target) {
|
||||
function helper() {
|
||||
return Adb.shell(target, 'cat /proc/cpuinfo')
|
||||
return exec('adb -s ' + target + ' shell cat /proc/cpuinfo', os.tmpdir())
|
||||
.then(function(output) {
|
||||
return /intel/i.exec(output) ? 'x86' : 'arm';
|
||||
if (/intel/i.exec(output)) {
|
||||
return 'x86';
|
||||
}
|
||||
return 'arm';
|
||||
});
|
||||
}
|
||||
// It sometimes happens (at least on OS X), that this command will hang forever.
|
||||
// To fix it, either unplug & replug device, or restart adb server.
|
||||
return helper()
|
||||
.timeout(1000, new CordovaError('Device communication timed out. Try unplugging & replugging the device.'))
|
||||
return helper().timeout(1000, 'Device communication timed out. Try unplugging & replugging the device.')
|
||||
.then(null, function(err) {
|
||||
if (/timed out/.exec('' + err)) {
|
||||
// adb kill-server doesn't seem to do the trick.
|
||||
// Could probably find a x-platform version of killall, but I'm not actually
|
||||
// sure that this scenario even happens on non-OSX machines.
|
||||
return spawn('killall', ['adb'])
|
||||
return exec('killall adb')
|
||||
.then(function() {
|
||||
events.emit('verbose', 'adb seems hung. retrying.');
|
||||
console.log('adb seems hung. retrying.');
|
||||
return helper()
|
||||
.then(null, function() {
|
||||
// The double kill is sadly often necessary, at least on mac.
|
||||
events.emit('warn', 'Now device not found... restarting adb again.');
|
||||
return spawn('killall', ['adb'])
|
||||
console.log('Now device not found... restarting adb again.');
|
||||
return exec('killall adb')
|
||||
.then(function() {
|
||||
return helper()
|
||||
.then(null, function() {
|
||||
return Q.reject(new CordovaError('USB is flakey. Try unplugging & replugging the device.'));
|
||||
return Q.reject('USB is flakey. Try unplugging & replugging the device.');
|
||||
});
|
||||
});
|
||||
});
|
||||
}, function() {
|
||||
// For non-killall OS's.
|
||||
return Q.reject(err);
|
||||
});
|
||||
})
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
@@ -214,18 +447,16 @@ module.exports.detectArchitecture = function(target) {
|
||||
|
||||
module.exports.findBestApkForArchitecture = function(buildResults, arch) {
|
||||
var paths = buildResults.apkPaths.filter(function(p) {
|
||||
var apkName = path.basename(p);
|
||||
if (buildResults.buildType == 'debug') {
|
||||
return /-debug/.exec(apkName);
|
||||
return /-debug/.exec(p);
|
||||
}
|
||||
return !/-debug/.exec(apkName);
|
||||
return !/-debug/.exec(p);
|
||||
});
|
||||
var archPattern = new RegExp('-' + arch);
|
||||
var hasArchPattern = /-x86|-arm/;
|
||||
for (var i = 0; i < paths.length; ++i) {
|
||||
var apkName = path.basename(paths[i]);
|
||||
if (hasArchPattern.exec(apkName)) {
|
||||
if (archPattern.exec(apkName)) {
|
||||
if (hasArchPattern.exec(paths[i])) {
|
||||
if (archPattern.exec(paths[i])) {
|
||||
return paths[i];
|
||||
}
|
||||
} else {
|
||||
@@ -235,67 +466,16 @@ module.exports.findBestApkForArchitecture = function(buildResults, arch) {
|
||||
throw new Error('Could not find apk architecture: ' + arch + ' build-type: ' + buildResults.buildType);
|
||||
};
|
||||
|
||||
function PackageInfo(keystore, alias, storePassword, password, keystoreType) {
|
||||
this.keystore = {
|
||||
'name': 'key.store',
|
||||
'value': keystore
|
||||
};
|
||||
this.alias = {
|
||||
'name': 'key.alias',
|
||||
'value': alias
|
||||
};
|
||||
if (storePassword) {
|
||||
this.storePassword = {
|
||||
'name': 'key.store.password',
|
||||
'value': storePassword
|
||||
};
|
||||
}
|
||||
if (password) {
|
||||
this.password = {
|
||||
'name': 'key.alias.password',
|
||||
'value': password
|
||||
};
|
||||
}
|
||||
if (keystoreType) {
|
||||
this.keystoreType = {
|
||||
'name': 'key.store.type',
|
||||
'value': keystoreType
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
PackageInfo.prototype = {
|
||||
toProperties: function() {
|
||||
var self = this;
|
||||
var result = '';
|
||||
Object.keys(self).forEach(function(key) {
|
||||
result += self[key].name;
|
||||
result += '=';
|
||||
result += self[key].value.replace(/\\/g, '\\\\');
|
||||
result += '\n';
|
||||
});
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.help = function() {
|
||||
console.log('Usage: ' + path.relative(process.cwd(), path.join('../build')) + ' [flags] [Signed APK flags]');
|
||||
console.log('Usage: ' + path.relative(process.cwd(), path.join(ROOT, 'cordova', 'build')) + ' [flags]');
|
||||
console.log('Flags:');
|
||||
console.log(' \'--debug\': will build project in debug mode (default)');
|
||||
console.log(' \'--release\': will build project for release');
|
||||
console.log(' \'--ant\': will build project with ant');
|
||||
console.log(' \'--gradle\': will build project with gradle (default)');
|
||||
console.log(' \'--ant\': will build project with ant (default)');
|
||||
console.log(' \'--gradle\': will build project with gradle');
|
||||
console.log(' \'--nobuild\': will skip build process (useful when using run command)');
|
||||
console.log(' \'--prepenv\': don\'t build, but copy in build scripts where necessary');
|
||||
console.log(' \'--versionCode=#\': Override versionCode for this build. Useful for uploading multiple APKs. Requires --gradle.');
|
||||
console.log(' \'--minSdkVersion=#\': Override minSdkVersion for this build. Useful for uploading multiple APKs. Requires --gradle.');
|
||||
console.log(' \'--gradleArg=<gradle command line arg>\': Extra args to pass to the gradle command. Use one flag per arg. Ex. --gradleArg=-PcdvBuildMultipleApks=true');
|
||||
console.log('');
|
||||
console.log('Signed APK flags (overwrites debug/release-signing.proprties) :');
|
||||
console.log(' \'--keystore=<path to keystore>\': Key store used to build a signed archive. (Required)');
|
||||
console.log(' \'--alias=\': Alias for the key store. (Required)');
|
||||
console.log(' \'--storePassword=\': Password for the key store. (Optional - prompted)');
|
||||
console.log(' \'--password=\': Password for the key. (Optional - prompted)');
|
||||
console.log(' \'--keystoreType\': Type of the keystore. (Optional)');
|
||||
process.exit(0);
|
||||
};
|
||||
|
||||
141
bin/templates/cordova/lib/builders/AntBuilder.js
vendored
141
bin/templates/cordova/lib/builders/AntBuilder.js
vendored
@@ -1,141 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var Q = require('q');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var util = require('util');
|
||||
var shell = require('shelljs');
|
||||
var spawn = require('cordova-common').superspawn.spawn;
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
var check_reqs = require('../check_reqs');
|
||||
|
||||
var SIGNING_PROPERTIES = '-signing.properties';
|
||||
var MARKER = 'YOUR CHANGES WILL BE ERASED!';
|
||||
var TEMPLATE =
|
||||
'# This file is automatically generated.\n' +
|
||||
'# Do not modify this file -- ' + MARKER + '\n';
|
||||
|
||||
var GenericBuilder = require('./GenericBuilder');
|
||||
|
||||
function AntBuilder (projectRoot) {
|
||||
GenericBuilder.call(this, projectRoot);
|
||||
|
||||
this.binDirs = {ant: this.binDirs.ant};
|
||||
}
|
||||
|
||||
util.inherits(AntBuilder, GenericBuilder);
|
||||
|
||||
AntBuilder.prototype.getArgs = function(cmd, opts) {
|
||||
var args = [cmd, '-f', path.join(this.root, 'build.xml')];
|
||||
// custom_rules.xml is required for incremental builds.
|
||||
if (hasCustomRules()) {
|
||||
args.push('-Dout.dir=ant-build', '-Dgen.absolute.dir=ant-gen');
|
||||
}
|
||||
if(opts.packageInfo) {
|
||||
args.push('-propertyfile=' + path.join(this.root, opts.buildType + SIGNING_PROPERTIES));
|
||||
}
|
||||
return args;
|
||||
};
|
||||
|
||||
AntBuilder.prototype.prepEnv = function(opts) {
|
||||
var self = this;
|
||||
return check_reqs.check_ant()
|
||||
.then(function() {
|
||||
// Copy in build.xml on each build so that:
|
||||
// A) we don't require the Android SDK at project creation time, and
|
||||
// B) we always use the SDK's latest version of it.
|
||||
/*jshint -W069 */
|
||||
var sdkDir = process.env['ANDROID_HOME'];
|
||||
/*jshint +W069 */
|
||||
var buildTemplate = fs.readFileSync(path.join(sdkDir, 'tools', 'lib', 'build.template'), 'utf8');
|
||||
function writeBuildXml(projectPath) {
|
||||
var newData = buildTemplate.replace('PROJECT_NAME', self.extractRealProjectNameFromManifest());
|
||||
fs.writeFileSync(path.join(projectPath, 'build.xml'), newData);
|
||||
if (!fs.existsSync(path.join(projectPath, 'local.properties'))) {
|
||||
fs.writeFileSync(path.join(projectPath, 'local.properties'), TEMPLATE);
|
||||
}
|
||||
}
|
||||
writeBuildXml(self.root);
|
||||
var propertiesObj = self.readProjectProperties();
|
||||
var subProjects = propertiesObj.libs;
|
||||
for (var i = 0; i < subProjects.length; ++i) {
|
||||
writeBuildXml(path.join(self.root, subProjects[i]));
|
||||
}
|
||||
if (propertiesObj.systemLibs.length > 0) {
|
||||
throw new CordovaError('Project contains at least one plugin that requires a system library. This is not supported with ANT. Please build using gradle.');
|
||||
}
|
||||
|
||||
var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
|
||||
var propertiesFilePath = path.join(self.root, propertiesFile);
|
||||
if (opts.packageInfo) {
|
||||
fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
|
||||
} else if(isAutoGenerated(propertiesFilePath)) {
|
||||
shell.rm('-f', propertiesFilePath);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Builds the project with ant.
|
||||
* Returns a promise.
|
||||
*/
|
||||
AntBuilder.prototype.build = function(opts) {
|
||||
// Without our custom_rules.xml, we need to clean before building.
|
||||
var ret = Q();
|
||||
if (!hasCustomRules()) {
|
||||
// clean will call check_ant() for us.
|
||||
ret = this.clean(opts);
|
||||
}
|
||||
|
||||
var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);
|
||||
return check_reqs.check_ant()
|
||||
.then(function() {
|
||||
return spawn('ant', args, {stdio: 'inherit'});
|
||||
});
|
||||
};
|
||||
|
||||
AntBuilder.prototype.clean = function(opts) {
|
||||
var args = this.getArgs('clean', opts);
|
||||
var self = this;
|
||||
return check_reqs.check_ant()
|
||||
.then(function() {
|
||||
return spawn('ant', args, {stdio: 'inherit'});
|
||||
})
|
||||
.then(function () {
|
||||
shell.rm('-rf', path.join(self.root, 'out'));
|
||||
|
||||
['debug', 'release'].forEach(function(config) {
|
||||
var propertiesFilePath = path.join(self.root, config + SIGNING_PROPERTIES);
|
||||
if(isAutoGenerated(propertiesFilePath)){
|
||||
shell.rm('-f', propertiesFilePath);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = AntBuilder;
|
||||
|
||||
function hasCustomRules(projectRoot) {
|
||||
return fs.existsSync(path.join(projectRoot, 'custom_rules.xml'));
|
||||
}
|
||||
|
||||
function isAutoGenerated(file) {
|
||||
return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
|
||||
}
|
||||
138
bin/templates/cordova/lib/builders/GenericBuilder.js
vendored
138
bin/templates/cordova/lib/builders/GenericBuilder.js
vendored
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var Q = require('q');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var shell = require('shelljs');
|
||||
var events = require('cordova-common').events;
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
|
||||
function GenericBuilder (projectDir) {
|
||||
this.root = projectDir || path.resolve(__dirname, '../../..');
|
||||
this.binDirs = {
|
||||
ant: path.join(this.root, hasCustomRules(this.root) ? 'ant-build' : 'bin'),
|
||||
gradle: path.join(this.root, 'build', 'outputs', 'apk')
|
||||
};
|
||||
}
|
||||
|
||||
function hasCustomRules(projectRoot) {
|
||||
return fs.existsSync(path.join(projectRoot, 'custom_rules.xml'));
|
||||
}
|
||||
|
||||
GenericBuilder.prototype.prepEnv = function() {
|
||||
return Q();
|
||||
};
|
||||
|
||||
GenericBuilder.prototype.build = function() {
|
||||
events.emit('log', 'Skipping build...');
|
||||
return Q(null);
|
||||
};
|
||||
|
||||
GenericBuilder.prototype.clean = function() {
|
||||
return Q();
|
||||
};
|
||||
|
||||
GenericBuilder.prototype.findOutputApks = function(build_type, arch) {
|
||||
var self = this;
|
||||
return Object.keys(this.binDirs)
|
||||
.reduce(function (result, builderName) {
|
||||
var binDir = self.binDirs[builderName];
|
||||
return result.concat(findOutputApksHelper(binDir, build_type, builderName === 'ant' ? null : arch));
|
||||
}, [])
|
||||
.sort(apkSorter);
|
||||
};
|
||||
|
||||
GenericBuilder.prototype.readProjectProperties = function () {
|
||||
function findAllUniq(data, r) {
|
||||
var s = {};
|
||||
var m;
|
||||
while ((m = r.exec(data))) {
|
||||
s[m[1]] = 1;
|
||||
}
|
||||
return Object.keys(s);
|
||||
}
|
||||
|
||||
var data = fs.readFileSync(path.join(this.root, 'project.properties'), 'utf8');
|
||||
return {
|
||||
libs: findAllUniq(data, /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg),
|
||||
gradleIncludes: findAllUniq(data, /^\s*cordova\.gradle\.include\.\d+=(.*)(?:\s|$)/mg),
|
||||
systemLibs: findAllUniq(data, /^\s*cordova\.system\.library\.\d+=(.*)(?:\s|$)/mg)
|
||||
};
|
||||
};
|
||||
|
||||
GenericBuilder.prototype.extractRealProjectNameFromManifest = function () {
|
||||
var manifestPath = path.join(this.root, 'AndroidManifest.xml');
|
||||
var manifestData = fs.readFileSync(manifestPath, 'utf8');
|
||||
var m = /<manifest[\s\S]*?package\s*=\s*"(.*?)"/i.exec(manifestData);
|
||||
if (!m) {
|
||||
throw new CordovaError('Could not find package name in ' + manifestPath);
|
||||
}
|
||||
|
||||
var packageName=m[1];
|
||||
var lastDotIndex = packageName.lastIndexOf('.');
|
||||
return packageName.substring(lastDotIndex + 1);
|
||||
};
|
||||
|
||||
module.exports = GenericBuilder;
|
||||
|
||||
function apkSorter(fileA, fileB) {
|
||||
var timeDiff = fs.statSync(fileA).mtime - fs.statSync(fileB).mtime;
|
||||
return timeDiff === 0 ? fileA.length - fileB.length : timeDiff;
|
||||
}
|
||||
|
||||
function findOutputApksHelper(dir, build_type, arch) {
|
||||
var shellSilent = shell.config.silent;
|
||||
shell.config.silent = true;
|
||||
|
||||
var ret = shell.ls(path.join(dir, '*.apk'))
|
||||
.filter(function(candidate) {
|
||||
var apkName = path.basename(candidate);
|
||||
// Need to choose between release and debug .apk.
|
||||
if (build_type === 'debug') {
|
||||
return /-debug/.exec(apkName) && !/-unaligned|-unsigned/.exec(apkName);
|
||||
}
|
||||
if (build_type === 'release') {
|
||||
return /-release/.exec(apkName) && !/-unaligned/.exec(apkName);
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.sort(apkSorter);
|
||||
|
||||
shellSilent = shellSilent;
|
||||
|
||||
if (ret.length === 0) {
|
||||
return ret;
|
||||
}
|
||||
// Assume arch-specific build if newest apk has -x86 or -arm.
|
||||
var archSpecific = !!/-x86|-arm/.exec(path.basename(ret[0]));
|
||||
// And show only arch-specific ones (or non-arch-specific)
|
||||
ret = ret.filter(function(p) {
|
||||
/*jshint -W018 */
|
||||
return !!/-x86|-arm/.exec(path.basename(p)) == archSpecific;
|
||||
/*jshint +W018 */
|
||||
});
|
||||
if (archSpecific && ret.length > 1) {
|
||||
ret = ret.filter(function(p) {
|
||||
return path.basename(p).indexOf('-' + arch) != -1;
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
213
bin/templates/cordova/lib/builders/GradleBuilder.js
vendored
213
bin/templates/cordova/lib/builders/GradleBuilder.js
vendored
@@ -1,213 +0,0 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var Q = require('q');
|
||||
var fs = require('fs');
|
||||
var util = require('util');
|
||||
var path = require('path');
|
||||
var shell = require('shelljs');
|
||||
var spawn = require('cordova-common').superspawn.spawn;
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
var check_reqs = require('../check_reqs');
|
||||
|
||||
var GenericBuilder = require('./GenericBuilder');
|
||||
|
||||
var MARKER = 'YOUR CHANGES WILL BE ERASED!';
|
||||
var SIGNING_PROPERTIES = '-signing.properties';
|
||||
var TEMPLATE =
|
||||
'# This file is automatically generated.\n' +
|
||||
'# Do not modify this file -- ' + MARKER + '\n';
|
||||
|
||||
function GradleBuilder (projectRoot) {
|
||||
GenericBuilder.call(this, projectRoot);
|
||||
|
||||
this.binDirs = {gradle: this.binDirs.gradle};
|
||||
}
|
||||
|
||||
util.inherits(GradleBuilder, GenericBuilder);
|
||||
|
||||
GradleBuilder.prototype.getArgs = function(cmd, opts) {
|
||||
if (cmd == 'release') {
|
||||
cmd = 'cdvBuildRelease';
|
||||
} else if (cmd == 'debug') {
|
||||
cmd = 'cdvBuildDebug';
|
||||
}
|
||||
var args = [cmd, '-b', path.join(this.root, 'build.gradle')];
|
||||
if (opts.arch) {
|
||||
args.push('-PcdvBuildArch=' + opts.arch);
|
||||
}
|
||||
|
||||
// 10 seconds -> 6 seconds
|
||||
args.push('-Dorg.gradle.daemon=true');
|
||||
args.push.apply(args, opts.extraArgs);
|
||||
// Shaves another 100ms, but produces a "try at own risk" warning. Not worth it (yet):
|
||||
// args.push('-Dorg.gradle.parallel=true');
|
||||
return args;
|
||||
};
|
||||
|
||||
// Makes the project buildable, minus the gradle wrapper.
|
||||
GradleBuilder.prototype.prepBuildFiles = function() {
|
||||
// Update the version of build.gradle in each dependent library.
|
||||
var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle');
|
||||
var propertiesObj = this.readProjectProperties();
|
||||
var subProjects = propertiesObj.libs;
|
||||
for (var i = 0; i < subProjects.length; ++i) {
|
||||
if (subProjects[i] !== 'CordovaLib') {
|
||||
shell.cp('-f', pluginBuildGradle, path.join(this.root, subProjects[i], 'build.gradle'));
|
||||
}
|
||||
}
|
||||
|
||||
var name = this.extractRealProjectNameFromManifest();
|
||||
//Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149
|
||||
var settingsGradlePaths = subProjects.map(function(p){
|
||||
var realDir=p.replace(/[/\\]/g, ':');
|
||||
var libName=realDir.replace(name+'-','');
|
||||
var str='include ":'+libName+'"\n';
|
||||
if(realDir.indexOf(name+'-')!==-1)
|
||||
str+='project(":'+libName+'").projectDir = new File("'+p+'")\n';
|
||||
return str;
|
||||
});
|
||||
|
||||
// Write the settings.gradle file.
|
||||
fs.writeFileSync(path.join(this.root, 'settings.gradle'),
|
||||
'// GENERATED FILE - DO NOT EDIT\n' +
|
||||
'include ":"\n' + settingsGradlePaths.join(''));
|
||||
// Update dependencies within build.gradle.
|
||||
var buildGradle = fs.readFileSync(path.join(this.root, 'build.gradle'), 'utf8');
|
||||
var depsList = '';
|
||||
subProjects.forEach(function(p) {
|
||||
var libName=p.replace(/[/\\]/g, ':').replace(name+'-','');
|
||||
depsList += ' debugCompile project(path: "' + libName + '", configuration: "debug")\n';
|
||||
depsList += ' releaseCompile project(path: "' + libName + '", configuration: "release")\n';
|
||||
});
|
||||
// For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390
|
||||
var SYSTEM_LIBRARY_MAPPINGS = [
|
||||
[/^\/?extras\/android\/support\/(.*)$/, 'com.android.support:support-$1:+'],
|
||||
[/^\/?google\/google_play_services\/libproject\/google-play-services_lib\/?$/, 'com.google.android.gms:play-services:+']
|
||||
];
|
||||
propertiesObj.systemLibs.forEach(function(p) {
|
||||
var mavenRef;
|
||||
// It's already in gradle form if it has two ':'s
|
||||
if (/:.*:/.exec(p)) {
|
||||
mavenRef = p;
|
||||
} else {
|
||||
for (var i = 0; i < SYSTEM_LIBRARY_MAPPINGS.length; ++i) {
|
||||
var pair = SYSTEM_LIBRARY_MAPPINGS[i];
|
||||
if (pair[0].exec(p)) {
|
||||
mavenRef = p.replace(pair[0], pair[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!mavenRef) {
|
||||
throw new CordovaError('Unsupported system library (does not work with gradle): ' + p);
|
||||
}
|
||||
}
|
||||
depsList += ' compile "' + mavenRef + '"\n';
|
||||
});
|
||||
buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + ' $2');
|
||||
var includeList = '';
|
||||
propertiesObj.gradleIncludes.forEach(function(includePath) {
|
||||
includeList += 'apply from: "' + includePath + '"\n';
|
||||
});
|
||||
buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + includeList + '$2');
|
||||
fs.writeFileSync(path.join(this.root, 'build.gradle'), buildGradle);
|
||||
};
|
||||
|
||||
GradleBuilder.prototype.prepEnv = function(opts) {
|
||||
var self = this;
|
||||
return check_reqs.check_gradle()
|
||||
.then(function() {
|
||||
return self.prepBuildFiles();
|
||||
}).then(function() {
|
||||
// Copy the gradle wrapper on each build so that:
|
||||
// A) we don't require the Android SDK at project creation time, and
|
||||
// B) we always use the SDK's latest version of it.
|
||||
// check_reqs ensures that this is set.
|
||||
/*jshint -W069 */
|
||||
var sdkDir = process.env['ANDROID_HOME'];
|
||||
/*jshint +W069 */
|
||||
var wrapperDir = path.join(sdkDir, 'tools', 'templates', 'gradle', 'wrapper');
|
||||
if (process.platform == 'win32') {
|
||||
shell.rm('-f', path.join(self.root, 'gradlew.bat'));
|
||||
shell.cp(path.join(wrapperDir, 'gradlew.bat'), self.root);
|
||||
} else {
|
||||
shell.rm('-f', path.join(self.root, 'gradlew'));
|
||||
shell.cp(path.join(wrapperDir, 'gradlew'), self.root);
|
||||
}
|
||||
shell.rm('-rf', path.join(self.root, 'gradle', 'wrapper'));
|
||||
shell.mkdir('-p', path.join(self.root, 'gradle'));
|
||||
shell.cp('-r', path.join(wrapperDir, 'gradle', 'wrapper'), path.join(self.root, 'gradle'));
|
||||
|
||||
// If the gradle distribution URL is set, make sure it points to version we want.
|
||||
// If it's not set, do nothing, assuming that we're using a future version of gradle that we don't want to mess with.
|
||||
// For some reason, using ^ and $ don't work. This does the job, though.
|
||||
var distributionUrlRegex = /distributionUrl.*zip/;
|
||||
/*jshint -W069 */
|
||||
var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'http\\://services.gradle.org/distributions/gradle-2.2.1-all.zip';
|
||||
/*jshint +W069 */
|
||||
var gradleWrapperPropertiesPath = path.join(self.root, 'gradle', 'wrapper', 'gradle-wrapper.properties');
|
||||
shell.chmod('u+w', gradleWrapperPropertiesPath);
|
||||
shell.sed('-i', distributionUrlRegex, 'distributionUrl='+distributionUrl, gradleWrapperPropertiesPath);
|
||||
|
||||
var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
|
||||
var propertiesFilePath = path.join(self.root, propertiesFile);
|
||||
if (opts.packageInfo) {
|
||||
fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
|
||||
} else if (isAutoGenerated(propertiesFilePath)) {
|
||||
shell.rm('-f', propertiesFilePath);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Builds the project with gradle.
|
||||
* Returns a promise.
|
||||
*/
|
||||
GradleBuilder.prototype.build = function(opts) {
|
||||
var wrapper = path.join(this.root, 'gradlew');
|
||||
var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);
|
||||
return Q().then(function() {
|
||||
return spawn(wrapper, args, {stdio: 'inherit'});
|
||||
});
|
||||
};
|
||||
|
||||
GradleBuilder.prototype.clean = function(opts) {
|
||||
var builder = this;
|
||||
var wrapper = path.join(this.root, 'gradlew');
|
||||
var args = builder.getArgs('clean', opts);
|
||||
return Q().then(function() {
|
||||
return spawn(wrapper, args, {stdio: 'inherit'});
|
||||
})
|
||||
.then(function () {
|
||||
shell.rm('-rf', path.join(builder.root, 'out'));
|
||||
|
||||
['debug', 'release'].forEach(function(config) {
|
||||
var propertiesFilePath = path.join(builder.root, config + SIGNING_PROPERTIES);
|
||||
if(isAutoGenerated(propertiesFilePath)){
|
||||
shell.rm('-f', propertiesFilePath);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = GradleBuilder;
|
||||
|
||||
function isAutoGenerated(file) {
|
||||
return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
|
||||
}
|
||||
75
bin/templates/cordova/lib/device.js
vendored
75
bin/templates/cordova/lib/device.js
vendored
@@ -19,30 +19,42 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var Q = require('q'),
|
||||
build = require('./build');
|
||||
var path = require('path');
|
||||
var Adb = require('./Adb');
|
||||
var AndroidManifest = require('./AndroidManifest');
|
||||
var spawn = require('cordova-common').superspawn.spawn;
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
var events = require('cordova-common').events;
|
||||
var exec = require('./exec'),
|
||||
Q = require('q'),
|
||||
path = require('path'),
|
||||
os = require('os'),
|
||||
build = require('./build'),
|
||||
appinfo = require('./appinfo'),
|
||||
ROOT = path.join(__dirname, '..', '..');
|
||||
|
||||
/**
|
||||
* Returns a promise for the list of the device ID's found
|
||||
* @param lookHarder When true, try restarting adb if no devices are found.
|
||||
*/
|
||||
module.exports.list = function(lookHarder) {
|
||||
return Adb.devices()
|
||||
function helper() {
|
||||
return exec('adb devices', os.tmpdir())
|
||||
.then(function(output) {
|
||||
var response = output.split('\n');
|
||||
var device_list = [];
|
||||
for (var i = 1; i < response.length; i++) {
|
||||
if (response[i].match(/\w+\tdevice/) && !response[i].match(/emulator/)) {
|
||||
device_list.push(response[i].replace(/\tdevice/, '').replace('\r', ''));
|
||||
}
|
||||
}
|
||||
return device_list;
|
||||
});
|
||||
}
|
||||
return helper()
|
||||
.then(function(list) {
|
||||
if (list.length === 0 && lookHarder) {
|
||||
// adb kill-server doesn't seem to do the trick.
|
||||
// Could probably find a x-platform version of killall, but I'm not actually
|
||||
// sure that this scenario even happens on non-OSX machines.
|
||||
return spawn('killall', ['adb'])
|
||||
return exec('killall adb')
|
||||
.then(function() {
|
||||
events.emit('verbose', 'Restarting adb to see if more devices are detected.');
|
||||
return Adb.devices();
|
||||
console.log('Restarting adb to see if more devices are detected.');
|
||||
return helper();
|
||||
}, function() {
|
||||
// For non-killall OS's.
|
||||
return list;
|
||||
@@ -50,13 +62,13 @@ module.exports.list = function(lookHarder) {
|
||||
}
|
||||
return list;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
module.exports.resolveTarget = function(target) {
|
||||
return this.list(true)
|
||||
.then(function(device_list) {
|
||||
if (!device_list || !device_list.length) {
|
||||
return Q.reject(new CordovaError('Failed to deploy to device, no devices found.'));
|
||||
return Q.reject('ERROR: Failed to deploy to device, no devices found.');
|
||||
}
|
||||
// default device
|
||||
target = target || device_list[0];
|
||||
@@ -85,22 +97,27 @@ module.exports.install = function(target, buildResults) {
|
||||
return module.exports.resolveTarget(target);
|
||||
}).then(function(resolvedTarget) {
|
||||
var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);
|
||||
var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
|
||||
var pkgName = manifest.getPackageId();
|
||||
var launchName = pkgName + '/.' + manifest.getActivity().getName();
|
||||
events.emit('log', 'Using apk: ' + apk_path);
|
||||
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app
|
||||
// or the app doesn't installed at all, so no error catching needed.
|
||||
return Adb.uninstall(resolvedTarget.target, pkgName)
|
||||
.then(function() {
|
||||
return Adb.install(resolvedTarget.target, apk_path, {replace: true});
|
||||
}).then(function() {
|
||||
var launchName = appinfo.getActivityName();
|
||||
console.log('Using apk: ' + apk_path);
|
||||
console.log('Installing app on device...');
|
||||
var cmd = 'adb -s ' + resolvedTarget.target + ' install -r "' + apk_path + '"';
|
||||
return exec(cmd, os.tmpdir())
|
||||
.then(function(output) {
|
||||
if (output.match(/Failure/)) return Q.reject('ERROR: Failed to install apk to device: ' + output);
|
||||
|
||||
//unlock screen
|
||||
return Adb.shell(resolvedTarget.target, 'input keyevent 82');
|
||||
var cmd = 'adb -s ' + resolvedTarget.target + ' shell input keyevent 82';
|
||||
return exec(cmd, os.tmpdir());
|
||||
}, function(err) { return Q.reject('ERROR: Failed to install apk to device: ' + err); })
|
||||
.then(function() {
|
||||
// launch the application
|
||||
console.log('Launching application...');
|
||||
var cmd = 'adb -s ' + resolvedTarget.target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName;
|
||||
return exec(cmd, os.tmpdir());
|
||||
}).then(function() {
|
||||
return Adb.start(resolvedTarget.target, launchName);
|
||||
}).then(function() {
|
||||
events.emit('log', 'LAUNCH SUCCESS');
|
||||
console.log('LAUNCH SUCCESS');
|
||||
}, function(err) {
|
||||
return Q.reject('ERROR: Failed to launch application on device: ' + err);
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
308
bin/templates/cordova/lib/emulator.js
vendored
308
bin/templates/cordova/lib/emulator.js
vendored
@@ -19,28 +19,17 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
/* jshint sub:true */
|
||||
|
||||
var retry = require('./retry');
|
||||
var build = require('./build');
|
||||
var shell = require('shelljs'),
|
||||
exec = require('./exec'),
|
||||
Q = require('q'),
|
||||
path = require('path'),
|
||||
os = require('os'),
|
||||
appinfo = require('./appinfo'),
|
||||
build = require('./build'),
|
||||
ROOT = path.join(__dirname, '..', '..'),
|
||||
child_process = require('child_process'),
|
||||
new_emulator = 'cordova_emulator';
|
||||
var check_reqs = require('./check_reqs');
|
||||
var path = require('path');
|
||||
var Adb = require('./Adb');
|
||||
var AndroidManifest = require('./AndroidManifest');
|
||||
var events = require('cordova-common').events;
|
||||
var spawn = require('cordova-common').superspawn.spawn;
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
|
||||
var Q = require('q');
|
||||
var os = require('os');
|
||||
var child_process = require('child_process');
|
||||
|
||||
// constants
|
||||
var ONE_SECOND = 1000; // in milliseconds
|
||||
var ONE_MINUTE = 60 * ONE_SECOND; // in milliseconds
|
||||
var INSTALL_COMMAND_TIMEOUT = 5 * ONE_MINUTE; // in milliseconds
|
||||
var NUM_INSTALL_RETRIES = 3;
|
||||
var EXEC_KILL_SIGNAL = 'SIGKILL';
|
||||
|
||||
/**
|
||||
* Returns a Promise for a list of emulator images in the form of objects
|
||||
@@ -53,7 +42,7 @@ var EXEC_KILL_SIGNAL = 'SIGKILL';
|
||||
}
|
||||
*/
|
||||
module.exports.list_images = function() {
|
||||
return spawn('android', ['list', 'avds'])
|
||||
return exec('android list avds')
|
||||
.then(function(output) {
|
||||
var response = output.split('\n');
|
||||
var emulator_list = [];
|
||||
@@ -89,7 +78,7 @@ module.exports.list_images = function() {
|
||||
}
|
||||
return emulator_list;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Will return the closest avd to the projects target
|
||||
@@ -97,38 +86,45 @@ module.exports.list_images = function() {
|
||||
* Returns a promise.
|
||||
*/
|
||||
module.exports.best_image = function() {
|
||||
var project_target = check_reqs.get_target().replace('android-', '');
|
||||
return this.list_images()
|
||||
.then(function(images) {
|
||||
// Just return undefined if there is no images
|
||||
if (images.length === 0) return;
|
||||
|
||||
var closest = 9999;
|
||||
var best = images[0];
|
||||
var project_target = check_reqs.get_target().replace('android-', '');
|
||||
for (var i in images) {
|
||||
for (i in images) {
|
||||
var target = images[i].target;
|
||||
if(target) {
|
||||
var num = target.split('(API level ')[1].replace(')', '');
|
||||
if (num == project_target) {
|
||||
return images[i];
|
||||
} else if (project_target - num < closest && project_target > num) {
|
||||
closest = project_target - num;
|
||||
var closest = project_target - num;
|
||||
best = images[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return best;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// Returns a promise.
|
||||
module.exports.list_started = function() {
|
||||
return Adb.devices({emulators: true});
|
||||
};
|
||||
return exec('adb devices', os.tmpdir())
|
||||
.then(function(output) {
|
||||
var response = output.split('\n');
|
||||
var started_emulator_list = [];
|
||||
for (var i = 1; i < response.length; i++) {
|
||||
if (response[i].match(/device/) && response[i].match(/emulator/)) {
|
||||
started_emulator_list.push(response[i].replace(/\tdevice/, '').replace('\r', ''));
|
||||
}
|
||||
}
|
||||
return started_emulator_list;
|
||||
});
|
||||
}
|
||||
|
||||
// Returns a promise.
|
||||
module.exports.list_targets = function() {
|
||||
return spawn('android', ['list', 'targets'], {cwd: os.tmpdir()})
|
||||
return exec('android list targets', os.tmpdir())
|
||||
.then(function(output) {
|
||||
var target_out = output.split('\n');
|
||||
var targets = [];
|
||||
@@ -139,101 +135,106 @@ module.exports.list_targets = function() {
|
||||
}
|
||||
return targets;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Starts an emulator with the given ID,
|
||||
* and returns the started ID of that emulator.
|
||||
* If no ID is given it will use the first image available,
|
||||
* If no ID is given it will used the first image available,
|
||||
* if no image is available it will error out (maybe create one?).
|
||||
*
|
||||
* Returns a promise.
|
||||
*/
|
||||
module.exports.start = function(emulator_ID) {
|
||||
var self = this;
|
||||
var emulator_id, num_started, started_emulators;
|
||||
|
||||
return Q().then(function() {
|
||||
if (emulator_ID) return Q(emulator_ID);
|
||||
|
||||
return self.best_image()
|
||||
.then(function(best) {
|
||||
if (best && best.name) {
|
||||
events.emit('warn', 'No emulator specified, defaulting to ' + best.name);
|
||||
return best.name;
|
||||
}
|
||||
|
||||
var androidCmd = check_reqs.getAbsoluteAndroidCmd();
|
||||
return Q.reject(new CordovaError('No emulator images (avds) found.\n' +
|
||||
'1. Download desired System Image by running: ' + androidCmd + ' sdk\n' +
|
||||
'2. Create an AVD by running: ' + androidCmd + ' avd\n' +
|
||||
'HINT: For a faster emulator, use an Intel System Image and install the HAXM device driver\n'));
|
||||
});
|
||||
}).then(function(emulatorId) {
|
||||
var uuid = 'cordova_emulator_' + new Date().getTime();
|
||||
var uuidProp = 'emu.uuid=' + uuid;
|
||||
var args = ['-avd', emulatorId, '-prop', uuidProp];
|
||||
// Don't wait for it to finish, since the emulator will probably keep running for a long time.
|
||||
child_process
|
||||
.spawn('emulator', args, { stdio: 'inherit', detached: true })
|
||||
.unref();
|
||||
|
||||
return self.list_started()
|
||||
.then(function(list) {
|
||||
started_emulators = list;
|
||||
num_started = started_emulators.length;
|
||||
if (!emulator_ID) {
|
||||
return self.list_images()
|
||||
.then(function(emulator_list) {
|
||||
if (emulator_list.length > 0) {
|
||||
return self.best_image()
|
||||
.then(function(best) {
|
||||
emulator_ID = best.name;
|
||||
console.log('WARNING : no emulator specified, defaulting to ' + emulator_ID);
|
||||
return emulator_ID;
|
||||
});
|
||||
} else {
|
||||
var androidCmd = check_reqs.getAbsoluteAndroidCmd();
|
||||
return Q.reject('ERROR : No emulator images (avds) found.\n' +
|
||||
'1. Download desired System Image by running: ' + androidCmd + ' sdk\n' +
|
||||
'2. Create an AVD by running: ' + androidCmd + ' avd\n' +
|
||||
'HINT: For a faster emulator, use an Intel System Image and install the HAXM device driver\n');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return Q(emulator_ID);
|
||||
}
|
||||
}).then(function() {
|
||||
var cmd = 'emulator';
|
||||
var args = ['-avd', emulator_ID];
|
||||
var proc = child_process.spawn(cmd, args, { stdio: 'inherit', detached: true });
|
||||
proc.unref(); // Don't wait for it to finish, since the emulator will probably keep running for a long time.
|
||||
}).then(function() {
|
||||
// wait for emulator to start
|
||||
events.emit('log', 'Waiting for emulator...');
|
||||
return self.wait_for_emulator(uuid);
|
||||
}).then(function(emulatorId) {
|
||||
if (!emulatorId)
|
||||
return Q.reject(new CordovaError('Failed to start emulator'));
|
||||
console.log('Waiting for emulator...');
|
||||
return self.wait_for_emulator(num_started);
|
||||
}).then(function(new_started) {
|
||||
if (new_started.length > 1) {
|
||||
for (i in new_started) {
|
||||
if (started_emulators.indexOf(new_started[i]) < 0) {
|
||||
emulator_id = new_started[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
emulator_id = new_started[0];
|
||||
}
|
||||
if (!emulator_id) return Q.reject('ERROR : Failed to start emulator, could not find new emulator');
|
||||
|
||||
//wait for emulator to boot up
|
||||
process.stdout.write('Booting up emulator (this may take a while)...');
|
||||
return self.wait_for_boot(emulatorId)
|
||||
.then(function() {
|
||||
events.emit('log','BOOT COMPLETE');
|
||||
//unlock screen
|
||||
return Adb.shell(emulatorId, 'input keyevent 82');
|
||||
}).then(function() {
|
||||
//return the new emulator id for the started emulators
|
||||
return emulatorId;
|
||||
});
|
||||
return self.wait_for_boot(emulator_id);
|
||||
}).then(function() {
|
||||
console.log('BOOT COMPLETE');
|
||||
|
||||
//unlock screen
|
||||
return exec('adb -s ' + emulator_id + ' shell input keyevent 82', os.tmpdir());
|
||||
}).then(function() {
|
||||
//return the new emulator id for the started emulators
|
||||
return emulator_id;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Waits for an emulator with given uuid to apear on the started-emulator list.
|
||||
* Returns a promise with this emulator's ID.
|
||||
* Waits for the new emulator to apear on the started-emulator list.
|
||||
* Returns a promise with a list of newly started emulators' IDs.
|
||||
*/
|
||||
module.exports.wait_for_emulator = function(uuid) {
|
||||
module.exports.wait_for_emulator = function(num_running) {
|
||||
var self = this;
|
||||
return self.list_started()
|
||||
.then(function(new_started) {
|
||||
var emulator_id = null;
|
||||
var promises = [];
|
||||
|
||||
new_started.forEach(function (emulator) {
|
||||
promises.push(
|
||||
Adb.shell(emulator, 'getprop emu.uuid')
|
||||
.then(function (output) {
|
||||
if (output.indexOf(uuid) >= 0) {
|
||||
emulator_id = emulator;
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
return Q.all(promises).then(function () {
|
||||
return emulator_id || self.wait_for_emulator(uuid);
|
||||
});
|
||||
});
|
||||
};
|
||||
if (new_started.length > num_running) {
|
||||
return new_started;
|
||||
} else {
|
||||
return Q.delay(1000).then(function() {
|
||||
return self.wait_for_emulator(num_running);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Waits for the core android process of the emulator to start
|
||||
* Waits for the boot animation property of the emulator to switch to 'stopped'
|
||||
*/
|
||||
module.exports.wait_for_boot = function(emulator_id) {
|
||||
var self = this;
|
||||
return Adb.shell(emulator_id, 'ps')
|
||||
return exec('adb -s ' + emulator_id + ' shell getprop init.svc.bootanim', os.tmpdir())
|
||||
.then(function(output) {
|
||||
if (output.match(/android\.process\.acore/)) {
|
||||
if (output.match(/stopped/)) {
|
||||
return;
|
||||
} else {
|
||||
process.stdout.write('.');
|
||||
@@ -242,7 +243,7 @@ module.exports.wait_for_boot = function(emulator_id) {
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Create avd
|
||||
@@ -252,15 +253,15 @@ module.exports.wait_for_boot = function(emulator_id) {
|
||||
module.exports.create_image = function(name, target) {
|
||||
console.log('Creating avd named ' + name);
|
||||
if (target) {
|
||||
return spawn('android', ['create', 'avd', '--name', name, '--target', target])
|
||||
return exec('android create avd --name ' + name + ' --target ' + target)
|
||||
.then(null, function(error) {
|
||||
console.error('ERROR : Failed to create emulator image : ');
|
||||
console.error(' Do you have the latest android targets including ' + target + '?');
|
||||
console.error(error);
|
||||
console.error(create.output);
|
||||
});
|
||||
} else {
|
||||
console.log('WARNING : Project target not found, creating avd with a different target but the project may fail to install.');
|
||||
return spawn('android', ['create', 'avd', '--name', name, '--target', this.list_targets()[0]])
|
||||
return exec('android create avd --name ' + name + ' --target ' + this.list_targets()[0])
|
||||
.then(function() {
|
||||
// TODO: This seems like another error case, even though it always happens.
|
||||
console.error('ERROR : Unable to create an avd emulator, no targets found.');
|
||||
@@ -271,7 +272,7 @@ module.exports.create_image = function(name, target) {
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports.resolveTarget = function(target) {
|
||||
return this.list_started()
|
||||
@@ -299,74 +300,37 @@ module.exports.resolveTarget = function(target) {
|
||||
* If no started emulators are found, error out.
|
||||
* Returns a promise.
|
||||
*/
|
||||
module.exports.install = function(givenTarget, buildResults) {
|
||||
|
||||
var target;
|
||||
var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
|
||||
var pkgName = manifest.getPackageId();
|
||||
|
||||
// resolve the target emulator
|
||||
return Q().then(function () {
|
||||
if (givenTarget && typeof givenTarget == 'object') {
|
||||
return givenTarget;
|
||||
} else {
|
||||
return module.exports.resolveTarget(givenTarget);
|
||||
module.exports.install = function(target, buildResults) {
|
||||
return Q().then(function() {
|
||||
if (target && typeof target == 'object') {
|
||||
return target;
|
||||
}
|
||||
|
||||
// set the resolved target
|
||||
}).then(function (resolvedTarget) {
|
||||
target = resolvedTarget;
|
||||
|
||||
// install the app
|
||||
}).then(function () {
|
||||
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app
|
||||
// or the app doesn't installed at all, so no error catching needed.
|
||||
return Adb.uninstall(target.target, pkgName)
|
||||
.then(function() {
|
||||
|
||||
var apk_path = build.findBestApkForArchitecture(buildResults, target.arch);
|
||||
var execOptions = {
|
||||
cwd: os.tmpdir(),
|
||||
timeout: INSTALL_COMMAND_TIMEOUT, // in milliseconds
|
||||
killSignal: EXEC_KILL_SIGNAL
|
||||
};
|
||||
|
||||
events.emit('log', 'Using apk: ' + apk_path);
|
||||
events.emit('verbose', 'Installing app on emulator...');
|
||||
|
||||
function exec(command, opts) {
|
||||
return Q.promise(function (resolve, reject) {
|
||||
child_process.exec(command, opts, function(err, stdout, stderr) {
|
||||
if (err) reject(new CordovaError('Error executing "' + command + '": ' + stderr));
|
||||
else resolve(stdout);
|
||||
});
|
||||
});
|
||||
return module.exports.resolveTarget(target);
|
||||
}).then(function(resolvedTarget) {
|
||||
var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);
|
||||
console.log('Installing app on emulator...');
|
||||
console.log('Using apk: ' + apk_path);
|
||||
return exec('adb -s ' + resolvedTarget.target + ' install -r "' + apk_path + '"', os.tmpdir())
|
||||
.then(function(output) {
|
||||
if (output.match(/Failure/)) {
|
||||
return Q.reject('Failed to install apk to emulator: ' + output);
|
||||
}
|
||||
|
||||
var retriedInstall = retry.retryPromise(
|
||||
NUM_INSTALL_RETRIES,
|
||||
exec, 'adb -s ' + target.target + ' install -r "' + apk_path + '"', execOptions
|
||||
);
|
||||
|
||||
return retriedInstall.then(function (output) {
|
||||
if (output.match(/Failure/)) {
|
||||
return Q.reject(new CordovaError('Failed to install apk to emulator: ' + output));
|
||||
} else {
|
||||
events.emit('log', 'INSTALL SUCCESS');
|
||||
}
|
||||
}, function (err) {
|
||||
return Q.reject(new CordovaError('Failed to install apk to emulator: ' + err));
|
||||
});
|
||||
return Q();
|
||||
}, function(err) {
|
||||
return Q.reject('Failed to install apk to emulator: ' + err);
|
||||
}).then(function() {
|
||||
//unlock screen
|
||||
return exec('adb -s ' + resolvedTarget.target + ' shell input keyevent 82', os.tmpdir());
|
||||
}).then(function() {
|
||||
// launch the application
|
||||
console.log('Launching application...');
|
||||
var launchName = appinfo.getActivityName();
|
||||
cmd = 'adb -s ' + resolvedTarget.target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName;
|
||||
return exec(cmd, os.tmpdir());
|
||||
}).then(function(output) {
|
||||
console.log('LAUNCH SUCCESS');
|
||||
}, function(err) {
|
||||
return Q.reject('Failed to launch app on emulator: ' + err);
|
||||
});
|
||||
// unlock screen
|
||||
}).then(function () {
|
||||
|
||||
events.emit('verbose', 'Unlocking screen...');
|
||||
return Adb.shell(target.target, 'input keyevent 82');
|
||||
}).then(function () {
|
||||
Adb.start(target.target, pkgName + '/.' + manifest.getActivity().getName());
|
||||
// report success or failure
|
||||
}).then(function (output) {
|
||||
events.emit('log', 'LAUNCH SUCCESS');
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
41
bin/templates/cordova/lib/exec.js
vendored
Normal file
41
bin/templates/cordova/lib/exec.js
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var child_process = require('child_process'),
|
||||
Q = require('q');
|
||||
|
||||
// Takes a command and optional current working directory.
|
||||
// Returns a promise that either resolves with the stdout, or
|
||||
// rejects with an error message and the stderr.
|
||||
module.exports = function(cmd, opt_cwd) {
|
||||
var d = Q.defer();
|
||||
try {
|
||||
child_process.exec(cmd, {cwd: opt_cwd, maxBuffer: 1024000}, function(err, stdout, stderr) {
|
||||
if (err) d.reject('Error executing "' + cmd + '": ' + stderr);
|
||||
else d.resolve(stdout);
|
||||
});
|
||||
} catch(e) {
|
||||
console.error('error caught: ' + e);
|
||||
d.reject(e);
|
||||
}
|
||||
return d.promise;
|
||||
}
|
||||
|
||||
8
bin/templates/cordova/lib/log.js
vendored
8
bin/templates/cordova/lib/log.js
vendored
@@ -19,7 +19,8 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var path = require('path'),
|
||||
var shell = require('shelljs'),
|
||||
path = require('path'),
|
||||
os = require('os'),
|
||||
Q = require('q'),
|
||||
child_process = require('child_process'),
|
||||
@@ -30,6 +31,7 @@ var path = require('path'),
|
||||
* Returns a promise.
|
||||
*/
|
||||
module.exports.run = function() {
|
||||
var cmd = 'adb logcat | grep -v nativeGetEnabledTags';
|
||||
var d = Q.defer();
|
||||
var adb = child_process.spawn('adb', ['logcat'], {cwd: os.tmpdir()});
|
||||
|
||||
@@ -47,10 +49,10 @@ module.exports.run = function() {
|
||||
});
|
||||
|
||||
return d.promise;
|
||||
};
|
||||
}
|
||||
|
||||
module.exports.help = function() {
|
||||
console.log('Usage: ' + path.relative(process.cwd(), path.join(ROOT, 'cordova', 'log')));
|
||||
console.log('Gives the logcat output on the command line.');
|
||||
process.exit(0);
|
||||
};
|
||||
}
|
||||
|
||||
252
bin/templates/cordova/lib/pluginHandlers.js
vendored
252
bin/templates/cordova/lib/pluginHandlers.js
vendored
@@ -1,252 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2013 Anis Kadri
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
/* jshint unused: vars */
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var shell = require('shelljs');
|
||||
var events = require('cordova-common').events;
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
|
||||
var handlers = {
|
||||
'source-file':{
|
||||
install:function(obj, plugin, project, options) {
|
||||
if (!obj.src) throw new CordovaError('<source-file> element is missing "src" attribute for plugin: ' + plugin.id);
|
||||
if (!obj.targetDir) throw new CordovaError('<source-file> element is missing "target-dir" attribute for plugin: ' + plugin.id);
|
||||
var dest = path.join(obj.targetDir, path.basename(obj.src));
|
||||
copyNewFile(plugin.dir, obj.src, project.projectDir, dest, options && options.link);
|
||||
},
|
||||
uninstall:function(obj, plugin, project, options) {
|
||||
var dest = path.join(obj.targetDir, path.basename(obj.src));
|
||||
deleteJava(project.projectDir, dest);
|
||||
}
|
||||
},
|
||||
'lib-file':{
|
||||
install:function(obj, plugin, project, options) {
|
||||
var dest = path.join('libs', path.basename(obj.src));
|
||||
copyFile(plugin.dir, obj.src, project.projectDir, dest, options && options.link);
|
||||
},
|
||||
uninstall:function(obj, plugin, project, options) {
|
||||
var dest = path.join('libs', path.basename(obj.src));
|
||||
removeFile(project.projectDir, dest);
|
||||
}
|
||||
},
|
||||
'resource-file':{
|
||||
install:function(obj, plugin, project, options) {
|
||||
copyFile(plugin.dir, obj.src, project.projectDir, path.normalize(obj.target), options && options.link);
|
||||
},
|
||||
uninstall:function(obj, plugin, project, options) {
|
||||
removeFile(project.projectDir, path.normalize(obj.target));
|
||||
}
|
||||
},
|
||||
'framework': {
|
||||
install:function(obj, plugin, project, options) {
|
||||
var src = obj.src;
|
||||
if (!src) throw new CordovaError('src not specified in <framework> for plugin: ' + plugin.id);
|
||||
|
||||
events.emit('verbose', 'Installing Android library: ' + src);
|
||||
var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;
|
||||
var subDir;
|
||||
|
||||
if (obj.custom) {
|
||||
var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);
|
||||
copyNewFile(plugin.dir, src, project.projectDir, subRelativeDir, options && options.link);
|
||||
subDir = path.resolve(project.projectDir, subRelativeDir);
|
||||
} else {
|
||||
obj.type = 'sys';
|
||||
subDir = src;
|
||||
}
|
||||
|
||||
if (obj.type == 'gradleReference') {
|
||||
project.addGradleReference(parentDir, subDir);
|
||||
} else if (obj.type == 'sys') {
|
||||
project.addSystemLibrary(parentDir, subDir);
|
||||
} else {
|
||||
project.addSubProject(parentDir, subDir);
|
||||
}
|
||||
},
|
||||
uninstall:function(obj, plugin, project, options) {
|
||||
var src = obj.src;
|
||||
if (!src) throw new CordovaError('src not specified in <framework> for plugin: ' + plugin.id);
|
||||
|
||||
events.emit('verbose', 'Uninstalling Android library: ' + src);
|
||||
var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;
|
||||
var subDir;
|
||||
|
||||
if (obj.custom) {
|
||||
var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);
|
||||
removeFile(project.projectDir, subRelativeDir);
|
||||
subDir = path.resolve(project.projectDir, subRelativeDir);
|
||||
// If it's the last framework in the plugin, remove the parent directory.
|
||||
var parDir = path.dirname(subDir);
|
||||
if (fs.readdirSync(parDir).length === 0) {
|
||||
fs.rmdirSync(parDir);
|
||||
}
|
||||
} else {
|
||||
obj.type = 'sys';
|
||||
subDir = src;
|
||||
}
|
||||
|
||||
if (obj.type == 'gradleReference') {
|
||||
project.removeGradleReference(parentDir, subDir);
|
||||
} else if (obj.type == 'sys') {
|
||||
project.removeSystemLibrary(parentDir, subDir);
|
||||
} else {
|
||||
project.removeSubProject(parentDir, subDir);
|
||||
}
|
||||
}
|
||||
},
|
||||
asset:{
|
||||
install:function(obj, plugin, project, options) {
|
||||
if (!obj.src) {
|
||||
throw new CordovaError('<asset> tag without required "src" attribute. plugin=' + plugin.dir);
|
||||
}
|
||||
if (!obj.target) {
|
||||
throw new CordovaError('<asset> tag without required "target" attribute');
|
||||
}
|
||||
|
||||
var www = options.usePlatformWww ? project.platformWww : project.www;
|
||||
copyFile(plugin.dir, obj.src, www, obj.target);
|
||||
},
|
||||
uninstall:function(obj, plugin, project, options) {
|
||||
var target = obj.target || obj.src;
|
||||
|
||||
if (!target) throw new CordovaError('<asset> tag without required "target" attribute');
|
||||
|
||||
var www = options.usePlatformWww ? project.platformWww : project.www;
|
||||
removeFile(www, target);
|
||||
removeFileF(path.resolve(www, 'plugins', plugin.id));
|
||||
}
|
||||
},
|
||||
'js-module': {
|
||||
install: function (obj, plugin, project, options) {
|
||||
// Copy the plugin's files into the www directory.
|
||||
var moduleSource = path.resolve(plugin.dir, obj.src);
|
||||
var moduleName = plugin.id + '.' + (obj.name || path.parse(obj.src).name);
|
||||
|
||||
// Read in the file, prepend the cordova.define, and write it back out.
|
||||
var scriptContent = fs.readFileSync(moduleSource, 'utf-8').replace(/^\ufeff/, ''); // Window BOM
|
||||
if (moduleSource.match(/.*\.json$/)) {
|
||||
scriptContent = 'module.exports = ' + scriptContent;
|
||||
}
|
||||
scriptContent = 'cordova.define("' + moduleName + '", function(require, exports, module) {\n' + scriptContent + '\n});\n';
|
||||
|
||||
var www = options.usePlatformWww ? project.platformWww : project.www;
|
||||
var moduleDestination = path.resolve(www, 'plugins', plugin.id, obj.src);
|
||||
shell.mkdir('-p', path.dirname(moduleDestination));
|
||||
fs.writeFileSync(moduleDestination, scriptContent, 'utf-8');
|
||||
},
|
||||
uninstall: function (obj, plugin, project, options) {
|
||||
var pluginRelativePath = path.join('plugins', plugin.id, obj.src);
|
||||
var www = options.usePlatformWww ? project.platformWww : project.www;
|
||||
removeFileAndParents(www, pluginRelativePath);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.getInstaller = function (type) {
|
||||
if (handlers[type] && handlers[type].install) {
|
||||
return handlers[type].install;
|
||||
}
|
||||
|
||||
events.emit('verbose', '<' + type + '> is not supported for android plugins');
|
||||
};
|
||||
|
||||
module.exports.getUninstaller = function(type) {
|
||||
if (handlers[type] && handlers[type].uninstall) {
|
||||
return handlers[type].uninstall;
|
||||
}
|
||||
|
||||
events.emit('verbose', '<' + type + '> is not supported for android plugins');
|
||||
};
|
||||
|
||||
function copyFile (plugin_dir, src, project_dir, dest, link) {
|
||||
src = path.resolve(plugin_dir, src);
|
||||
if (!fs.existsSync(src)) throw new CordovaError('"' + src + '" not found!');
|
||||
|
||||
// check that src path is inside plugin directory
|
||||
var real_path = fs.realpathSync(src);
|
||||
var real_plugin_path = fs.realpathSync(plugin_dir);
|
||||
if (real_path.indexOf(real_plugin_path) !== 0)
|
||||
throw new CordovaError('"' + src + '" not located within plugin!');
|
||||
|
||||
dest = path.resolve(project_dir, dest);
|
||||
|
||||
// check that dest path is located in project directory
|
||||
if (dest.indexOf(project_dir) !== 0)
|
||||
throw new CordovaError('"' + dest + '" not located within project!');
|
||||
|
||||
shell.mkdir('-p', path.dirname(dest));
|
||||
|
||||
if (link) {
|
||||
fs.symlinkSync(path.relative(path.dirname(dest), src), dest);
|
||||
} else if (fs.statSync(src).isDirectory()) {
|
||||
// XXX shelljs decides to create a directory when -R|-r is used which sucks. http://goo.gl/nbsjq
|
||||
shell.cp('-Rf', src+'/*', dest);
|
||||
} else {
|
||||
shell.cp('-f', src, dest);
|
||||
}
|
||||
}
|
||||
|
||||
// Same as copy file but throws error if target exists
|
||||
function copyNewFile (plugin_dir, src, project_dir, dest, link) {
|
||||
var target_path = path.resolve(project_dir, dest);
|
||||
if (fs.existsSync(target_path))
|
||||
throw new CordovaError('"' + target_path + '" already exists!');
|
||||
|
||||
copyFile(plugin_dir, src, project_dir, dest, !!link);
|
||||
}
|
||||
|
||||
// checks if file exists and then deletes. Error if doesn't exist
|
||||
function removeFile (project_dir, src) {
|
||||
var file = path.resolve(project_dir, src);
|
||||
shell.rm('-Rf', file);
|
||||
}
|
||||
|
||||
// deletes file/directory without checking
|
||||
function removeFileF (file) {
|
||||
shell.rm('-Rf', file);
|
||||
}
|
||||
|
||||
// Sometimes we want to remove some java, and prune any unnecessary empty directories
|
||||
function deleteJava (project_dir, destFile) {
|
||||
removeFileAndParents(project_dir, destFile, 'src');
|
||||
}
|
||||
|
||||
function removeFileAndParents (baseDir, destFile, stopper) {
|
||||
stopper = stopper || '.';
|
||||
var file = path.resolve(baseDir, destFile);
|
||||
if (!fs.existsSync(file)) return;
|
||||
|
||||
removeFileF(file);
|
||||
|
||||
// check if directory is empty
|
||||
var curDir = path.dirname(file);
|
||||
|
||||
while(curDir !== path.resolve(baseDir, stopper)) {
|
||||
if(fs.existsSync(curDir) && fs.readdirSync(curDir).length === 0) {
|
||||
fs.rmdirSync(curDir);
|
||||
curDir = path.resolve(curDir, '..');
|
||||
} else {
|
||||
// directory not empty...do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
379
bin/templates/cordova/lib/prepare.js
vendored
379
bin/templates/cordova/lib/prepare.js
vendored
@@ -1,379 +0,0 @@
|
||||
/**
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var Q = require('q');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var shell = require('shelljs');
|
||||
var events = require('cordova-common').events;
|
||||
var AndroidManifest = require('./AndroidManifest');
|
||||
var xmlHelpers = require('cordova-common').xmlHelpers;
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
var ConfigParser = require('cordova-common').ConfigParser;
|
||||
|
||||
module.exports.prepare = function (cordovaProject) {
|
||||
|
||||
var self = this;
|
||||
|
||||
this._config = updateConfigFilesFrom(cordovaProject.projectConfig,
|
||||
this._munger, this.locations);
|
||||
|
||||
// Update own www dir with project's www assets and plugins' assets and js-files
|
||||
return Q.when(updateWwwFrom(cordovaProject, this.locations))
|
||||
.then(function () {
|
||||
// update project according to config.xml changes.
|
||||
return updateProjectAccordingTo(self._config, self.locations);
|
||||
})
|
||||
.then(function () {
|
||||
handleIcons(cordovaProject.projectConfig, self.root);
|
||||
handleSplashes(cordovaProject.projectConfig, self.root);
|
||||
})
|
||||
.then(function () {
|
||||
self.events.emit('verbose', 'updated project successfully');
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates config files in project based on app's config.xml and config munge,
|
||||
* generated by plugins.
|
||||
*
|
||||
* @param {ConfigParser} sourceConfig A project's configuration that will
|
||||
* be merged into platform's config.xml
|
||||
* @param {ConfigChanges} configMunger An initialized ConfigChanges instance
|
||||
* for this platform.
|
||||
* @param {Object} locations A map of locations for this platform
|
||||
*
|
||||
* @return {ConfigParser} An instance of ConfigParser, that
|
||||
* represents current project's configuration. When returned, the
|
||||
* configuration is already dumped to appropriate config.xml file.
|
||||
*/
|
||||
function updateConfigFilesFrom(sourceConfig, configMunger, locations) {
|
||||
events.emit('verbose', 'Generating config.xml from defaults for platform "android"');
|
||||
|
||||
// First cleanup current config and merge project's one into own
|
||||
// Overwrite platform config.xml with defaults.xml.
|
||||
shell.cp('-f', locations.defaultConfigXml, locations.configXml);
|
||||
|
||||
// Then apply config changes from global munge to all config files
|
||||
// in project (including project's config)
|
||||
configMunger.reapply_global_munge().save_all();
|
||||
|
||||
// Merge changes from app's config.xml into platform's one
|
||||
var config = new ConfigParser(locations.configXml);
|
||||
xmlHelpers.mergeXml(sourceConfig.doc.getroot(),
|
||||
config.doc.getroot(), 'android', /*clobber=*/true);
|
||||
|
||||
config.write();
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates platform 'www' directory by replacing it with contents of
|
||||
* 'platform_www' and app www. Also copies project's overrides' folder into
|
||||
* the platform 'www' folder
|
||||
*
|
||||
* @param {Object} cordovaProject An object which describes cordova project.
|
||||
* @param {Object} destinations An object that contains destination
|
||||
* paths for www files.
|
||||
*/
|
||||
function updateWwwFrom(cordovaProject, destinations) {
|
||||
shell.rm('-rf', destinations.www);
|
||||
shell.mkdir('-p', destinations.www);
|
||||
// Copy source files from project's www directory
|
||||
shell.cp('-rf', path.join(cordovaProject.locations.www, '*'), destinations.www);
|
||||
// Override www sources by files in 'platform_www' directory
|
||||
shell.cp('-rf', path.join(destinations.platformWww, '*'), destinations.www);
|
||||
|
||||
// If project contains 'merges' for our platform, use them as another overrides
|
||||
var merges_path = path.join(cordovaProject.root, 'merges', 'android');
|
||||
if (fs.existsSync(merges_path)) {
|
||||
events.emit('verbose', 'Found "merges" for android platform. Copying over existing "www" files.');
|
||||
var overrides = path.join(merges_path, '*');
|
||||
shell.cp('-rf', overrides, destinations.www);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates project structure and AndroidManifest according to project's configuration.
|
||||
*
|
||||
* @param {ConfigParser} platformConfig A project's configuration that will
|
||||
* be used to update project
|
||||
* @param {Object} locations A map of locations for this platform
|
||||
*/
|
||||
function updateProjectAccordingTo(platformConfig, locations) {
|
||||
// Update app name by editing res/values/strings.xml
|
||||
var name = platformConfig.name();
|
||||
var strings = xmlHelpers.parseElementtreeSync(locations.strings);
|
||||
strings.find('string[@name="app_name"]').text = name;
|
||||
fs.writeFileSync(locations.strings, strings.write({indent: 4}), 'utf-8');
|
||||
events.emit('verbose', 'Wrote out Android application name to "' + name + '"');
|
||||
|
||||
// Java packages cannot support dashes
|
||||
var pkg = (platformConfig.android_packageName() || platformConfig.packageName()).replace(/-/g, '_');
|
||||
|
||||
var manifest = new AndroidManifest(locations.manifest);
|
||||
var orig_pkg = manifest.getPackageId();
|
||||
|
||||
manifest.getActivity()
|
||||
.setOrientation(findOrientationValue(platformConfig))
|
||||
.setLaunchMode(findAndroidLaunchModePreference(platformConfig));
|
||||
|
||||
manifest.setVersionName(platformConfig.version())
|
||||
.setVersionCode(platformConfig.android_versionCode() || default_versionCode(platformConfig.version()))
|
||||
.setPackageId(pkg)
|
||||
.setMinSdkVersion(platformConfig.getPreference('android-minSdkVersion', 'android'))
|
||||
.setMaxSdkVersion(platformConfig.getPreference('android-maxSdkVersion', 'android'))
|
||||
.setTargetSdkVersion(platformConfig.getPreference('android-targetSdkVersion', 'android'))
|
||||
.write();
|
||||
|
||||
var javaPattern = path.join(locations.root, 'src', orig_pkg.replace(/\./g, '/'), '*.java');
|
||||
var java_files = shell.ls(javaPattern).filter(function(f) {
|
||||
return shell.grep(/extends\s+CordovaActivity/g, f);
|
||||
});
|
||||
|
||||
if (java_files.length === 0) {
|
||||
throw new CordovaError('No Java files found which extend CordovaActivity.');
|
||||
} else if(java_files.length > 1) {
|
||||
events.emit('log', 'Multiple candidate Java files (.java files which extend CordovaActivity) found. Guessing at the first one, ' + java_files[0]);
|
||||
}
|
||||
|
||||
var destFile = path.join(locations.root, 'src', pkg.replace(/\./g, '/'), path.basename(java_files[0]));
|
||||
shell.mkdir('-p', path.dirname(destFile));
|
||||
shell.sed(/package [\w\.]*;/, 'package ' + pkg + ';', java_files[0]).to(destFile);
|
||||
events.emit('verbose', 'Wrote out Android package name to "' + pkg + '"');
|
||||
|
||||
if (orig_pkg !== pkg) {
|
||||
// If package was name changed we need to remove old java with main activity
|
||||
shell.rm('-Rf',java_files[0]);
|
||||
// remove any empty directories
|
||||
var currentDir = path.dirname(java_files[0]);
|
||||
var sourcesRoot = path.resolve(locations.root, 'src');
|
||||
while(currentDir !== sourcesRoot) {
|
||||
if(fs.existsSync(currentDir) && fs.readdirSync(currentDir).length === 0) {
|
||||
fs.rmdirSync(currentDir);
|
||||
currentDir = path.resolve(currentDir, '..');
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Consturct the default value for versionCode as
|
||||
// PATCH + MINOR * 100 + MAJOR * 10000
|
||||
// see http://developer.android.com/tools/publishing/versioning.html
|
||||
function default_versionCode(version) {
|
||||
var nums = version.split('-')[0].split('.');
|
||||
var versionCode = 0;
|
||||
if (+nums[0]) {
|
||||
versionCode += +nums[0] * 10000;
|
||||
}
|
||||
if (+nums[1]) {
|
||||
versionCode += +nums[1] * 100;
|
||||
}
|
||||
if (+nums[2]) {
|
||||
versionCode += +nums[2];
|
||||
}
|
||||
return versionCode;
|
||||
}
|
||||
|
||||
function copyImage(src, resourcesDir, density, name) {
|
||||
var destFolder = path.join(resourcesDir, (density ? 'drawable-': 'drawable') + density);
|
||||
var isNinePatch = !!/\.9\.png$/.exec(src);
|
||||
var ninePatchName = name.replace(/\.png$/, '.9.png');
|
||||
|
||||
// default template does not have default asset for this density
|
||||
if (!fs.existsSync(destFolder)) {
|
||||
fs.mkdirSync(destFolder);
|
||||
}
|
||||
|
||||
var destFilePath = path.join(destFolder, isNinePatch ? ninePatchName : name);
|
||||
events.emit('verbose', 'copying image from ' + src + ' to ' + destFilePath);
|
||||
shell.cp('-f', src, destFilePath);
|
||||
}
|
||||
|
||||
function handleSplashes(projectConfig, platformRoot) {
|
||||
var resources = projectConfig.getSplashScreens('android');
|
||||
// if there are "splash" elements in config.xml
|
||||
if (resources.length > 0) {
|
||||
deleteDefaultResourceAt(platformRoot, 'screen.png');
|
||||
events.emit('verbose', 'splash screens: ' + JSON.stringify(resources));
|
||||
|
||||
// The source paths for icons and splashes are relative to
|
||||
// project's config.xml location, so we use it as base path.
|
||||
var projectRoot = path.dirname(projectConfig.path);
|
||||
var destination = path.join(platformRoot, 'res');
|
||||
|
||||
var hadMdpi = false;
|
||||
resources.forEach(function (resource) {
|
||||
if (!resource.density) {
|
||||
return;
|
||||
}
|
||||
if (resource.density == 'mdpi') {
|
||||
hadMdpi = true;
|
||||
}
|
||||
copyImage(path.join(projectRoot, resource.src), destination, resource.density, 'screen.png');
|
||||
});
|
||||
// There's no "default" drawable, so assume default == mdpi.
|
||||
if (!hadMdpi && resources.defaultResource) {
|
||||
copyImage(path.join(projectRoot, resources.defaultResource.src), destination, 'mdpi', 'screen.png');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleIcons(projectConfig, platformRoot) {
|
||||
var icons = projectConfig.getIcons('android');
|
||||
|
||||
// if there are icon elements in config.xml
|
||||
if (icons.length === 0) {
|
||||
events.emit('verbose', 'This app does not have launcher icons defined');
|
||||
return;
|
||||
}
|
||||
|
||||
deleteDefaultResourceAt(platformRoot, 'icon.png');
|
||||
|
||||
var android_icons = {};
|
||||
var default_icon;
|
||||
// http://developer.android.com/design/style/iconography.html
|
||||
var sizeToDensityMap = {
|
||||
36: 'ldpi',
|
||||
48: 'mdpi',
|
||||
72: 'hdpi',
|
||||
96: 'xhdpi',
|
||||
144: 'xxhdpi',
|
||||
192: 'xxxhdpi'
|
||||
};
|
||||
// find the best matching icon for a given density or size
|
||||
// @output android_icons
|
||||
var parseIcon = function(icon, icon_size) {
|
||||
// do I have a platform icon for that density already
|
||||
var density = icon.density || sizeToDensityMap[icon_size];
|
||||
if (!density) {
|
||||
// invalid icon defition ( or unsupported size)
|
||||
return;
|
||||
}
|
||||
var previous = android_icons[density];
|
||||
if (previous && previous.platform) {
|
||||
return;
|
||||
}
|
||||
android_icons[density] = icon;
|
||||
};
|
||||
|
||||
// iterate over all icon elements to find the default icon and call parseIcon
|
||||
for (var i=0; i<icons.length; i++) {
|
||||
var icon = icons[i];
|
||||
var size = icon.width;
|
||||
if (!size) {
|
||||
size = icon.height;
|
||||
}
|
||||
if (!size && !icon.density) {
|
||||
if (default_icon) {
|
||||
events.emit('verbose', 'more than one default icon: ' + JSON.stringify(icon));
|
||||
} else {
|
||||
default_icon = icon;
|
||||
}
|
||||
} else {
|
||||
parseIcon(icon, size);
|
||||
}
|
||||
}
|
||||
|
||||
// The source paths for icons and splashes are relative to
|
||||
// project's config.xml location, so we use it as base path.
|
||||
var projectRoot = path.dirname(projectConfig.path);
|
||||
var destination = path.join(platformRoot, 'res');
|
||||
for (var density in android_icons) {
|
||||
copyImage(path.join(projectRoot, android_icons[density].src), destination, density, 'icon.png');
|
||||
}
|
||||
// There's no "default" drawable, so assume default == mdpi.
|
||||
if (default_icon && !android_icons.mdpi) {
|
||||
copyImage(path.join(projectRoot, default_icon.src), destination, 'mdpi', 'icon.png');
|
||||
}
|
||||
}
|
||||
|
||||
// remove the default resource name from all drawable folders
|
||||
function deleteDefaultResourceAt(baseDir, resourceName) {
|
||||
shell.ls(path.join(baseDir, 'res/drawable-*'))
|
||||
.forEach(function (drawableFolder) {
|
||||
var imagePath = path.join(drawableFolder, resourceName);
|
||||
shell.rm('-f', [imagePath, imagePath.replace(/\.png$/, '.9.png')]);
|
||||
events.emit('verbose', 'Deleted ' + imagePath);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets and validates 'AndroidLaunchMode' prepference from config.xml. Returns
|
||||
* preference value and warns if it doesn't seems to be valid
|
||||
*
|
||||
* @param {ConfigParser} platformConfig A configParser instance for
|
||||
* platform.
|
||||
*
|
||||
* @return {String} Preference's value from config.xml or
|
||||
* default value, if there is no such preference. The default value is
|
||||
* 'singleTop'
|
||||
*/
|
||||
function findAndroidLaunchModePreference(platformConfig) {
|
||||
var launchMode = platformConfig.getPreference('AndroidLaunchMode');
|
||||
if (!launchMode) {
|
||||
// Return a default value
|
||||
return 'singleTop';
|
||||
}
|
||||
|
||||
var expectedValues = ['standard', 'singleTop', 'singleTask', 'singleInstance'];
|
||||
var valid = expectedValues.indexOf(launchMode) >= 0;
|
||||
if (!valid) {
|
||||
// Note: warn, but leave the launch mode as developer wanted, in case the list of options changes in the future
|
||||
events.emit('warn', 'Unrecognized value for AndroidLaunchMode preference: ' +
|
||||
launchMode + '. Expected values are: ' + expectedValues.join(', '));
|
||||
}
|
||||
|
||||
return launchMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries ConfigParser object for the orientation <preference> value. Warns if
|
||||
* global preference value is not supported by platform.
|
||||
*
|
||||
* @param {Object} platformConfig ConfigParser object
|
||||
*
|
||||
* @return {String} Global/platform-specific orientation in lower-case
|
||||
* (or empty string if both are undefined).
|
||||
*/
|
||||
function findOrientationValue(platformConfig) {
|
||||
|
||||
var ORIENTATION_DEFAULT = 'default';
|
||||
|
||||
var orientation = platformConfig.getPreference('orientation');
|
||||
if (!orientation) {
|
||||
return ORIENTATION_DEFAULT;
|
||||
}
|
||||
|
||||
var GLOBAL_ORIENTATIONS = ['default', 'portrait','landscape'];
|
||||
function isSupported(orientation) {
|
||||
return GLOBAL_ORIENTATIONS.indexOf(orientation.toLowerCase()) >= 0;
|
||||
}
|
||||
|
||||
// Check if the given global orientation is supported
|
||||
if (orientation && isSupported(orientation)) {
|
||||
return orientation;
|
||||
}
|
||||
|
||||
events.emit('warn', 'Unsupported global orientation: ' + orientation +
|
||||
'. Defaulting to value: ' + ORIENTATION_DEFAULT);
|
||||
return ORIENTATION_DEFAULT;
|
||||
}
|
||||
68
bin/templates/cordova/lib/retry.js
vendored
68
bin/templates/cordova/lib/retry.js
vendored
@@ -1,68 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
/* jshint node: true */
|
||||
|
||||
'use strict';
|
||||
|
||||
var events = require('cordova-common').events;
|
||||
|
||||
/*
|
||||
* Retry a promise-returning function a number of times, propagating its
|
||||
* results on success or throwing its error on a failed final attempt.
|
||||
*
|
||||
* @arg {Number} attemts_left - The number of times to retry the passed call.
|
||||
* @arg {Function} promiseFunction - A function that returns a promise.
|
||||
* @arg {...} - Arguments to pass to promiseFunction.
|
||||
*
|
||||
* @returns {Promise}
|
||||
*/
|
||||
module.exports.retryPromise = function (attemts_left, promiseFunction) {
|
||||
|
||||
// NOTE:
|
||||
// get all trailing arguments, by skipping the first two (attemts_left and
|
||||
// promiseFunction) because they shouldn't get passed to promiseFunction
|
||||
var promiseFunctionArguments = Array.prototype.slice.call(arguments, 2);
|
||||
|
||||
return promiseFunction.apply(undefined, promiseFunctionArguments).then(
|
||||
|
||||
// on success pass results through
|
||||
function onFulfilled(value) {
|
||||
return value;
|
||||
},
|
||||
|
||||
// on rejection either retry, or throw the error
|
||||
function onRejected(error) {
|
||||
|
||||
attemts_left -= 1;
|
||||
|
||||
if (attemts_left < 1) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
events.emit('verbose', 'A retried call failed. Retrying ' + attemts_left + ' more time(s).');
|
||||
|
||||
// retry call self again with the same arguments, except attemts_left is now lower
|
||||
var fullArguments = [attemts_left, promiseFunction].concat(promiseFunctionArguments);
|
||||
return module.exports.retryPromise.apply(undefined, fullArguments);
|
||||
}
|
||||
);
|
||||
};
|
||||
90
bin/templates/cordova/lib/run.js
vendored
90
bin/templates/cordova/lib/run.js
vendored
@@ -19,31 +19,67 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
/* jshint loopfunc:true */
|
||||
|
||||
var path = require('path'),
|
||||
build = require('./build'),
|
||||
emulator = require('./emulator'),
|
||||
device = require('./device'),
|
||||
shell = require('shelljs'),
|
||||
Q = require('q');
|
||||
|
||||
/**
|
||||
* Runs the application on a device if available. If no device is found, it will
|
||||
* use a started emulator. If no started emulators are found it will attempt
|
||||
* to start an avd. If no avds are found it will error out.
|
||||
*
|
||||
* @param {Object} runOptions various run/build options. See Api.js build/run
|
||||
* methods for reference.
|
||||
*
|
||||
* @return {Promise}
|
||||
/*
|
||||
* Runs the application on a device if available.
|
||||
* If no device is found, it will use a started emulator.
|
||||
* If no started emulators are found it will attempt to start an avd.
|
||||
* If no avds are found it will error out.
|
||||
* Returns a promise.
|
||||
*/
|
||||
module.exports.run = function(runOptions) {
|
||||
module.exports.run = function(args) {
|
||||
var buildFlags = [];
|
||||
var install_target;
|
||||
var list = false;
|
||||
|
||||
var self = this;
|
||||
for (var i=2; i<args.length; i++) {
|
||||
if (/^--(debug|release|ant|gradle|nobuild|versionCode=|minSdkVersion=|gradleArg=)/.exec(args[i])) {
|
||||
buildFlags.push(args[i]);
|
||||
} else if (args[i] == '--device') {
|
||||
install_target = '--device';
|
||||
} else if (args[i] == '--emulator') {
|
||||
install_target = '--emulator';
|
||||
} else if (/^--target=/.exec(args[i])) {
|
||||
install_target = args[i].substring(9, args[i].length);
|
||||
} else if (args[i] == '--list') {
|
||||
list = true;
|
||||
} else {
|
||||
console.warn('Option \'' + args[i] + '\' not recognized (ignoring).');
|
||||
}
|
||||
}
|
||||
|
||||
var install_target = runOptions.device ? '--device' :
|
||||
runOptions.emulator ? '--emulator' :
|
||||
runOptions.target;
|
||||
if (list) {
|
||||
var output = '';
|
||||
var temp = '';
|
||||
if (!install_target) {
|
||||
output += 'Available Android Devices:\n';
|
||||
temp = shell.exec(path.join(__dirname, 'list-devices'), {silent:true}).output;
|
||||
temp = temp.replace(/^(?=[^\s])/gm, '\t');
|
||||
output += temp;
|
||||
output += 'Available Android Virtual Devices:\n';
|
||||
temp = shell.exec(path.join(__dirname, 'list-emulator-images'), {silent:true}).output;
|
||||
temp = temp.replace(/^(?=[^\s])/gm, '\t');
|
||||
output += temp;
|
||||
} else if (install_target == '--emulator') {
|
||||
output += 'Available Android Virtual Devices:\n';
|
||||
temp = shell.exec(path.join(__dirname, 'list-emulator-images'), {silent:true}).output;
|
||||
temp = temp.replace(/^(?=[^\s])/gm, '\t');
|
||||
output += temp;
|
||||
} else if (install_target == '--device') {
|
||||
output += 'Available Android Devices:\n';
|
||||
temp = shell.exec(path.join(__dirname, 'list-devices'), {silent:true}).output;
|
||||
temp = temp.replace(/^(?=[^\s])/gm, '\t');
|
||||
output += temp;
|
||||
}
|
||||
console.log(output);
|
||||
return;
|
||||
}
|
||||
|
||||
return Q()
|
||||
.then(function() {
|
||||
@@ -52,10 +88,10 @@ var path = require('path'),
|
||||
return device.list()
|
||||
.then(function(device_list) {
|
||||
if (device_list.length > 0) {
|
||||
self.events.emit('warn', 'No target specified, deploying to device \'' + device_list[0] + '\'.');
|
||||
console.log('WARNING : No target specified, deploying to device \'' + device_list[0] + '\'.');
|
||||
install_target = device_list[0];
|
||||
} else {
|
||||
self.events.emit('warn', 'No target specified, deploying to emulator');
|
||||
console.log('WARNING : No target specified, deploying to emulator');
|
||||
install_target = '--emulator';
|
||||
}
|
||||
});
|
||||
@@ -86,7 +122,7 @@ var path = require('path'),
|
||||
return emulator.list_images()
|
||||
.then(function(avds) {
|
||||
// if target emulator isn't started, then start it.
|
||||
for (var avd in avds) {
|
||||
for (avd in avds) {
|
||||
if (avds[avd].name == install_target) {
|
||||
return emulator.start(install_target)
|
||||
.then(function(emulatorId) {
|
||||
@@ -99,22 +135,14 @@ var path = require('path'),
|
||||
});
|
||||
});
|
||||
}).then(function(resolvedTarget) {
|
||||
// Better just call self.build, but we're doing some processing of
|
||||
// build results (according to platformApi spec) so they are in different
|
||||
// format than emulator.install expects.
|
||||
// TODO: Update emulator/device.install to handle this change
|
||||
return build.run.call(self, runOptions, resolvedTarget)
|
||||
.then(function(buildResults) {
|
||||
return build.run(buildFlags, resolvedTarget).then(function(buildResults) {
|
||||
if (resolvedTarget.isEmulator) {
|
||||
return emulator.wait_for_boot(resolvedTarget.target)
|
||||
.then(function () {
|
||||
return emulator.install(resolvedTarget, buildResults);
|
||||
});
|
||||
return emulator.install(resolvedTarget, buildResults);
|
||||
}
|
||||
return device.install(resolvedTarget, buildResults);
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
module.exports.help = function(args) {
|
||||
console.log('Usage: ' + path.relative(process.cwd(), args[1]) + ' [options]');
|
||||
@@ -127,4 +155,4 @@ module.exports.help = function(args) {
|
||||
console.log(' --emulator : Will deploy the built project to an emulator if one exists');
|
||||
console.log(' --target=<target_id> : Installs to the target with the specified id.');
|
||||
process.exit(0);
|
||||
};
|
||||
}
|
||||
|
||||
50
bin/templates/cordova/lib/spawn.js
vendored
Normal file
50
bin/templates/cordova/lib/spawn.js
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var child_process = require('child_process'),
|
||||
Q = require('q');
|
||||
var isWindows = process.platform.slice(0, 3) == 'win';
|
||||
|
||||
// Takes a command and optional current working directory.
|
||||
module.exports = function(cmd, args, opt_cwd) {
|
||||
var d = Q.defer();
|
||||
var opts = { cwd: opt_cwd, stdio: 'inherit' };
|
||||
try {
|
||||
// Work around spawn not being able to find .bat files.
|
||||
if (isWindows) {
|
||||
args = [['/s', '/c', '"' + [cmd].concat(args).map(function(a){if (/^[^"].* .*[^"]/.test(a)) return '"' + a + '"'; return a;}).join(' ')+'"'].join(' ')];
|
||||
cmd = 'cmd';
|
||||
opts.windowsVerbatimArguments = true;
|
||||
}
|
||||
var child = child_process.spawn(cmd, args, opts);
|
||||
child.on('exit', function(code) {
|
||||
if (code) {
|
||||
d.reject('Error code ' + code + ' for command: ' + cmd + ' with args: ' + args);
|
||||
} else {
|
||||
d.resolve();
|
||||
}
|
||||
});
|
||||
} catch(e) {
|
||||
console.error('error caught: ' + e);
|
||||
d.reject(e);
|
||||
}
|
||||
return d.promise;
|
||||
};
|
||||
@@ -19,33 +19,19 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var Api = require('./Api');
|
||||
var nopt = require('nopt');
|
||||
var path = require('path');
|
||||
var run = require('./lib/run'),
|
||||
reqs = require('./lib/check_reqs'),
|
||||
args = process.argv;
|
||||
|
||||
// Support basic help commands
|
||||
if(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0)
|
||||
require('./lib/run').help();
|
||||
|
||||
// Do some basic argument parsing
|
||||
var runOpts = nopt({
|
||||
'verbose' : Boolean,
|
||||
'silent' : Boolean,
|
||||
'debug' : Boolean,
|
||||
'release' : Boolean,
|
||||
'nobuild': Boolean,
|
||||
'buildConfig' : path,
|
||||
'archs' : String,
|
||||
'device' : Boolean,
|
||||
'emulator': Boolean,
|
||||
'target' : String
|
||||
}, { 'd' : '--verbose' });
|
||||
|
||||
// Make runOptions compatible with PlatformApi run method spec
|
||||
runOpts.argv = runOpts.argv.remain;
|
||||
|
||||
new Api().run(runOpts)
|
||||
.catch(function(err) {
|
||||
console.error(err, err.stack);
|
||||
process.exit(2);
|
||||
});
|
||||
if (args[2] == '--help' || args[2] == '/?' || args[2] == '-h' ||
|
||||
args[2] == 'help' || args[2] == '-help' || args[2] == '/help') {
|
||||
run.help(args);
|
||||
} else {
|
||||
reqs.run().done(function() {
|
||||
return run.run(args);
|
||||
}, function(err) {
|
||||
console.error('ERROR: ' + err);
|
||||
process.exit(2);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -20,10 +20,6 @@
|
||||
*/
|
||||
|
||||
// Coho updates this line:
|
||||
var VERSION = "5.0.0";
|
||||
var VERSION = "3.7.2";
|
||||
|
||||
module.exports.version = VERSION;
|
||||
|
||||
if (!module.parent) {
|
||||
console.log(VERSION);
|
||||
}
|
||||
console.log(VERSION);
|
||||
|
||||
@@ -28,6 +28,7 @@ public class __ACTIVITY__ extends CordovaActivity
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
super.init();
|
||||
// Set by <content src="index.html" /> in config.xml
|
||||
loadUrl(launchUrl);
|
||||
}
|
||||
|
||||
@@ -45,5 +45,5 @@
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="__APILEVEL__"/>
|
||||
<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="__APILEVEL__"/>
|
||||
</manifest>
|
||||
|
||||
@@ -19,20 +19,10 @@
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
Customize this policy to fit your own app's needs. For more guidance, see:
|
||||
https://github.com/apache/cordova-plugin-whitelist/blob/master/README.md#content-security-policy
|
||||
Some notes:
|
||||
* gap: is required only on iOS (when using UIWebView) and is needed for JS->native communication
|
||||
* https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly
|
||||
* Disables use of inline scripts in order to mitigate risk of XSS vulnerabilities. To change this:
|
||||
* Enable inline JS: add 'unsafe-inline' to default-src
|
||||
-->
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="msapplication-tap-highlight" content="no">
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
|
||||
<link rel="stylesheet" type="text/css" href="css/index.css">
|
||||
<meta charset="utf-8" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
|
||||
<link rel="stylesheet" type="text/css" href="css/index.css" />
|
||||
<title>Hello World</title>
|
||||
</head>
|
||||
<body>
|
||||
@@ -45,5 +35,8 @@
|
||||
</div>
|
||||
<script type="text/javascript" src="cordova.js"></script>
|
||||
<script type="text/javascript" src="js/index.js"></script>
|
||||
<script type="text/javascript">
|
||||
app.initialize();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -47,5 +47,3 @@ var app = {
|
||||
console.log('Received Event: ' + id);
|
||||
}
|
||||
};
|
||||
|
||||
app.initialize();
|
||||
165
bin/templates/project/assets/www/main.js
Normal file
165
bin/templates/project/assets/www/main.js
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
var deviceInfo = function() {
|
||||
document.getElementById("platform").innerHTML = device.platform;
|
||||
document.getElementById("version").innerHTML = device.version;
|
||||
document.getElementById("uuid").innerHTML = device.uuid;
|
||||
document.getElementById("name").innerHTML = device.name;
|
||||
document.getElementById("width").innerHTML = screen.width;
|
||||
document.getElementById("height").innerHTML = screen.height;
|
||||
document.getElementById("colorDepth").innerHTML = screen.colorDepth;
|
||||
};
|
||||
|
||||
var getLocation = function() {
|
||||
var suc = function(p) {
|
||||
alert(p.coords.latitude + " " + p.coords.longitude);
|
||||
};
|
||||
var locFail = function() {
|
||||
};
|
||||
navigator.geolocation.getCurrentPosition(suc, locFail);
|
||||
};
|
||||
|
||||
var beep = function() {
|
||||
navigator.notification.beep(2);
|
||||
};
|
||||
|
||||
var vibrate = function() {
|
||||
navigator.notification.vibrate(0);
|
||||
};
|
||||
|
||||
function roundNumber(num) {
|
||||
var dec = 3;
|
||||
var result = Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec);
|
||||
return result;
|
||||
}
|
||||
|
||||
var accelerationWatch = null;
|
||||
|
||||
function updateAcceleration(a) {
|
||||
document.getElementById('x').innerHTML = roundNumber(a.x);
|
||||
document.getElementById('y').innerHTML = roundNumber(a.y);
|
||||
document.getElementById('z').innerHTML = roundNumber(a.z);
|
||||
}
|
||||
|
||||
var toggleAccel = function() {
|
||||
if (accelerationWatch !== null) {
|
||||
navigator.accelerometer.clearWatch(accelerationWatch);
|
||||
updateAcceleration({
|
||||
x : "",
|
||||
y : "",
|
||||
z : ""
|
||||
});
|
||||
accelerationWatch = null;
|
||||
} else {
|
||||
var options = {};
|
||||
options.frequency = 1000;
|
||||
accelerationWatch = navigator.accelerometer.watchAcceleration(
|
||||
updateAcceleration, function(ex) {
|
||||
alert("accel fail (" + ex.name + ": " + ex.message + ")");
|
||||
}, options);
|
||||
}
|
||||
};
|
||||
|
||||
var preventBehavior = function(e) {
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
function dump_pic(data) {
|
||||
var viewport = document.getElementById('viewport');
|
||||
console.log(data);
|
||||
viewport.style.display = "";
|
||||
viewport.style.position = "absolute";
|
||||
viewport.style.top = "10px";
|
||||
viewport.style.left = "10px";
|
||||
document.getElementById("test_img").src = data;
|
||||
}
|
||||
|
||||
function fail(msg) {
|
||||
alert(msg);
|
||||
}
|
||||
|
||||
function show_pic() {
|
||||
navigator.camera.getPicture(dump_pic, fail, {
|
||||
quality : 50
|
||||
});
|
||||
}
|
||||
|
||||
function close() {
|
||||
var viewport = document.getElementById('viewport');
|
||||
viewport.style.position = "relative";
|
||||
viewport.style.display = "none";
|
||||
}
|
||||
|
||||
function contacts_success(contacts) {
|
||||
alert(contacts.length
|
||||
+ ' contacts returned.'
|
||||
+ (contacts[2] && contacts[2].name ? (' Third contact is ' + contacts[2].name.formatted)
|
||||
: ''));
|
||||
}
|
||||
|
||||
function get_contacts() {
|
||||
var obj = new ContactFindOptions();
|
||||
obj.filter = "";
|
||||
obj.multiple = true;
|
||||
navigator.contacts.find(
|
||||
[ "displayName", "name" ], contacts_success,
|
||||
fail, obj);
|
||||
}
|
||||
|
||||
function check_network() {
|
||||
var networkState = navigator.network.connection.type;
|
||||
|
||||
var states = {};
|
||||
states[Connection.UNKNOWN] = 'Unknown connection';
|
||||
states[Connection.ETHERNET] = 'Ethernet connection';
|
||||
states[Connection.WIFI] = 'WiFi connection';
|
||||
states[Connection.CELL_2G] = 'Cell 2G connection';
|
||||
states[Connection.CELL_3G] = 'Cell 3G connection';
|
||||
states[Connection.CELL_4G] = 'Cell 4G connection';
|
||||
states[Connection.NONE] = 'No network connection';
|
||||
|
||||
confirm('Connection type:\n ' + states[networkState]);
|
||||
}
|
||||
|
||||
var watchID = null;
|
||||
|
||||
function updateHeading(h) {
|
||||
document.getElementById('h').innerHTML = h.magneticHeading;
|
||||
}
|
||||
|
||||
function toggleCompass() {
|
||||
if (watchID !== null) {
|
||||
navigator.compass.clearWatch(watchID);
|
||||
watchID = null;
|
||||
updateHeading({ magneticHeading : "Off"});
|
||||
} else {
|
||||
var options = { frequency: 1000 };
|
||||
watchID = navigator.compass.watchHeading(updateHeading, function(e) {
|
||||
alert('Compass Error: ' + e.code);
|
||||
}, options);
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
// the next line makes it impossible to see Contacts on the HTC Evo since it
|
||||
// doesn't have a scroll button
|
||||
// document.addEventListener("touchmove", preventBehavior, false);
|
||||
document.addEventListener("deviceready", deviceInfo, true);
|
||||
}
|
||||
116
bin/templates/project/assets/www/master.css
Normal file
116
bin/templates/project/assets/www/master.css
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
|
||||
body {
|
||||
background:#222 none repeat scroll 0 0;
|
||||
color:#666;
|
||||
font-family:Helvetica;
|
||||
font-size:72%;
|
||||
line-height:1.5em;
|
||||
margin:0;
|
||||
border-top:1px solid #393939;
|
||||
}
|
||||
|
||||
#info{
|
||||
background:#ffa;
|
||||
border: 1px solid #ffd324;
|
||||
-webkit-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
clear:both;
|
||||
margin:15px 6px 0;
|
||||
width:295px;
|
||||
padding:4px 0px 2px 10px;
|
||||
}
|
||||
|
||||
#info > h4{
|
||||
font-size:.95em;
|
||||
margin:5px 0;
|
||||
}
|
||||
|
||||
#stage.theme{
|
||||
padding-top:3px;
|
||||
}
|
||||
|
||||
/* Definition List */
|
||||
#stage.theme > dl{
|
||||
padding-top:10px;
|
||||
clear:both;
|
||||
margin:0;
|
||||
list-style-type:none;
|
||||
padding-left:10px;
|
||||
overflow:auto;
|
||||
}
|
||||
|
||||
#stage.theme > dl > dt{
|
||||
font-weight:bold;
|
||||
float:left;
|
||||
margin-left:5px;
|
||||
}
|
||||
|
||||
#stage.theme > dl > dd{
|
||||
width:45px;
|
||||
float:left;
|
||||
color:#a87;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
/* Content Styling */
|
||||
#stage.theme > h1, #stage.theme > h2, #stage.theme > p{
|
||||
margin:1em 0 .5em 13px;
|
||||
}
|
||||
|
||||
#stage.theme > h1{
|
||||
color:#eee;
|
||||
font-size:1.6em;
|
||||
text-align:center;
|
||||
margin:0;
|
||||
margin-top:15px;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
#stage.theme > h2{
|
||||
clear:both;
|
||||
margin:0;
|
||||
padding:3px;
|
||||
font-size:1em;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
/* Stage Buttons */
|
||||
#stage.theme a.btn{
|
||||
border: 1px solid #555;
|
||||
-webkit-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
text-align:center;
|
||||
display:block;
|
||||
float:left;
|
||||
background:#444;
|
||||
width:150px;
|
||||
color:#9ab;
|
||||
font-size:1.1em;
|
||||
text-decoration:none;
|
||||
padding:1.2em 0;
|
||||
margin:3px 0px 3px 5px;
|
||||
}
|
||||
#stage.theme a.btn.large{
|
||||
width:308px;
|
||||
padding:1.2em 0;
|
||||
}
|
||||
|
||||
@@ -60,11 +60,11 @@ ext {
|
||||
apply from: 'CordovaLib/cordova.gradle'
|
||||
// The value for android.compileSdkVersion.
|
||||
if (!project.hasProperty('cdvCompileSdkVersion')) {
|
||||
cdvCompileSdkVersion = null;
|
||||
cdvCompileSdkVersion = privateHelpers.getProjectTarget()
|
||||
}
|
||||
// The value for android.buildToolsVersion.
|
||||
if (!project.hasProperty('cdvBuildToolsVersion')) {
|
||||
cdvBuildToolsVersion = null;
|
||||
cdvBuildToolsVersion = privateHelpers.findLatestInstalledBuildTools()
|
||||
}
|
||||
// Sets the versionCode to the given value.
|
||||
if (!project.hasProperty('cdvVersionCode')) {
|
||||
@@ -76,7 +76,7 @@ ext {
|
||||
}
|
||||
// Whether to build architecture-specific APKs.
|
||||
if (!project.hasProperty('cdvBuildMultipleApks')) {
|
||||
cdvBuildMultipleApks = null
|
||||
cdvBuildMultipleApks = false
|
||||
}
|
||||
// .properties files to use for release signing.
|
||||
if (!project.hasProperty('cdvReleaseSigningPropertiesFile')) {
|
||||
@@ -90,38 +90,13 @@ ext {
|
||||
if (!project.hasProperty('cdvBuildArch')) {
|
||||
cdvBuildArch = null
|
||||
}
|
||||
|
||||
// Plugin gradle extensions can append to this to have code run at the end.
|
||||
cdvPluginPostBuildExtras = []
|
||||
}
|
||||
|
||||
// PLUGIN GRADLE EXTENSIONS START
|
||||
// PLUGIN GRADLE EXTENSIONS END
|
||||
|
||||
def hasBuildExtras = file('build-extras.gradle').exists()
|
||||
if (hasBuildExtras) {
|
||||
apply from: 'build-extras.gradle'
|
||||
}
|
||||
|
||||
// Set property defaults after extension .gradle files.
|
||||
if (ext.cdvCompileSdkVersion == null) {
|
||||
ext.cdvCompileSdkVersion = privateHelpers.getProjectTarget()
|
||||
}
|
||||
if (ext.cdvBuildToolsVersion == null) {
|
||||
ext.cdvBuildToolsVersion = privateHelpers.findLatestInstalledBuildTools()
|
||||
}
|
||||
if (ext.cdvDebugSigningPropertiesFile == null && file('debug-signing.properties').exists()) {
|
||||
ext.cdvDebugSigningPropertiesFile = 'debug-signing.properties'
|
||||
}
|
||||
if (ext.cdvReleaseSigningPropertiesFile == null && file('release-signing.properties').exists()) {
|
||||
ext.cdvReleaseSigningPropertiesFile = 'release-signing.properties'
|
||||
}
|
||||
|
||||
// Cast to appropriate types.
|
||||
ext.cdvBuildMultipleApks = cdvBuildMultipleApks == null ? false : cdvBuildMultipleApks.toBoolean();
|
||||
ext.cdvMinSdkVersion = cdvMinSdkVersion == null ? null : Integer.parseInt('' + cdvMinSdkVersion)
|
||||
ext.cdvVersionCode = cdvVersionCode == null ? null : Integer.parseInt('' + cdvVersionCode)
|
||||
|
||||
def computeBuildTargetName(debugBuild) {
|
||||
def ret = 'assemble'
|
||||
if (cdvBuildMultipleApks && cdvBuildArch) {
|
||||
@@ -152,11 +127,17 @@ task cdvPrintProps << {
|
||||
println('cdvDebugSigningPropertiesFile=' + cdvDebugSigningPropertiesFile)
|
||||
println('cdvBuildArch=' + cdvBuildArch)
|
||||
println('computedVersionCode=' + android.defaultConfig.versionCode)
|
||||
android.productFlavors.each { flavor ->
|
||||
println('computed' + flavor.name.capitalize() + 'VersionCode=' + flavor.versionCode)
|
||||
if (android.productFlavors.has('armv7')) {
|
||||
println('computedArmv7VersionCode=' + android.productFlavors.armv7.versionCode)
|
||||
}
|
||||
if (android.productFlavors.has('x86')) {
|
||||
println('computedx86VersionCode=' + android.productFlavors.x86.versionCode)
|
||||
}
|
||||
}
|
||||
|
||||
// PLUGIN GRADLE EXTENSIONS START
|
||||
// PLUGIN GRADLE EXTENSIONS END
|
||||
|
||||
android {
|
||||
sourceSets {
|
||||
main {
|
||||
@@ -167,14 +148,16 @@ android {
|
||||
renderscript.srcDirs = ['src']
|
||||
res.srcDirs = ['res']
|
||||
assets.srcDirs = ['assets']
|
||||
jniLibs.srcDirs = ['libs']
|
||||
}
|
||||
}
|
||||
|
||||
def versionCodeOverride = cdvVersionCode ? Integer.parseInt(cdvVersionCode) : null
|
||||
def minSdkVersionOverride = cdvMinSdkVersion ? Integer.parseInt(cdvMinSdkVersion) : null
|
||||
|
||||
defaultConfig {
|
||||
versionCode cdvVersionCode ?: Integer.parseInt("" + privateHelpers.extractIntFromManifest("versionCode") + "0")
|
||||
if (cdvMinSdkVersion != null) {
|
||||
minSdkVersion cdvMinSdkVersion
|
||||
versionCode versionCodeOverride ?: Integer.parseInt("" + privateHelpers.extractIntFromManifest("versionCode") + "0")
|
||||
if (minSdkVersionOverride != null) {
|
||||
minSdkVersion minSdkVersionOverride
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,13 +167,13 @@ android {
|
||||
if (Boolean.valueOf(cdvBuildMultipleApks)) {
|
||||
productFlavors {
|
||||
armv7 {
|
||||
versionCode defaultConfig.versionCode + 2
|
||||
versionCode versionCodeOverride ?: defaultConfig.versionCode + 2
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", ""
|
||||
}
|
||||
}
|
||||
x86 {
|
||||
versionCode defaultConfig.versionCode + 4
|
||||
versionCode versionCodeOverride ?: defaultConfig.versionCode + 4
|
||||
ndk {
|
||||
abiFilters "x86", ""
|
||||
}
|
||||
@@ -201,8 +184,8 @@ android {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (!cdvVersionCode) {
|
||||
def minSdkVersion = cdvMinSdkVersion ?: privateHelpers.extractIntFromManifest("minSdkVersion")
|
||||
} else if (!versionCodeOverride) {
|
||||
def minSdkVersion = minSdkVersionOverride ?: privateHelpers.extractIntFromManifest("minSdkVersion")
|
||||
// Vary versionCode by the two most common API levels:
|
||||
// 14 is ICS, which is the lowest API level for many apps.
|
||||
// 20 is Lollipop, which is the lowest API level for the updatable system webview.
|
||||
@@ -272,32 +255,27 @@ def addSigningProps(propsFilePath, signingConfig) {
|
||||
propsFile.withReader { reader ->
|
||||
props.load(reader)
|
||||
}
|
||||
|
||||
def storeFile = new File(props.get('key.store') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'storeFile'))
|
||||
def storeFile = new File(privateHelpers.ensureValueExists(propsFilePath, props, 'storeFile'))
|
||||
if (!storeFile.isAbsolute()) {
|
||||
storeFile = RelativePath.parse(true, storeFile.toString()).getFile(propsFile.getParentFile())
|
||||
}
|
||||
if (!storeFile.exists()) {
|
||||
throw new FileNotFoundException('Keystore file does not exist: ' + storeFile.getAbsolutePath())
|
||||
}
|
||||
signingConfig.keyAlias = props.get('key.alias') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'keyAlias')
|
||||
signingConfig.keyPassword = props.get('keyPassword', props.get('key.alias.password', signingConfig.keyPassword))
|
||||
signingConfig.keyAlias = privateHelpers.ensureValueExists(propsFilePath, props, 'keyAlias')
|
||||
signingConfig.keyPassword = props.get('keyPassword', signingConfig.keyPassword)
|
||||
signingConfig.storeFile = storeFile
|
||||
signingConfig.storePassword = props.get('storePassword', props.get('key.store.password', signingConfig.storePassword))
|
||||
def storeType = props.get('storeType', props.get('key.store.type', ''))
|
||||
signingConfig.storePassword = props.get('storePassword', signingConfig.storePassword)
|
||||
def storeType = props.get('storeType')
|
||||
if (!storeType) {
|
||||
def filename = storeFile.getName().toLowerCase();
|
||||
if (filename.endsWith('.p12') || filename.endsWith('.pfx')) {
|
||||
storeType = 'pkcs12'
|
||||
} else {
|
||||
storeType = signingConfig.storeType // "jks"
|
||||
}
|
||||
}
|
||||
signingConfig.storeType = storeType
|
||||
}
|
||||
|
||||
for (def func : cdvPluginPostBuildExtras) {
|
||||
func()
|
||||
if (storeType) {
|
||||
signingConfig.storeType = storeType
|
||||
}
|
||||
}
|
||||
|
||||
// This can be defined within build-extras.gradle as:
|
||||
|
||||
22
bin/templates/project/custom_rules.xml
Normal file
22
bin/templates/project/custom_rules.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project>
|
||||
<target name="-pre-compile">
|
||||
<!-- Fix library references due to bug in build.xml: See: https://groups.google.com/forum/#!topic/android-developers/0ivH-YqCjzg -->
|
||||
<pathconvert property="fixedJarsPath" refid="project.all.jars.path">
|
||||
<filtermapper>
|
||||
<replacestring from="/bin/" to="/ant-build/"/>
|
||||
<replacestring from="\bin\" to="\ant-build\"/>
|
||||
</filtermapper>
|
||||
</pathconvert>
|
||||
<path id="project.all.jars.path">
|
||||
<pathelement path="${fixedJarsPath}"/>
|
||||
</path>
|
||||
<echo message="Set jars path to: ${toString:project.all.jars.path}"/>
|
||||
</target>
|
||||
<!-- Rename AndroidManifest.xml so that Eclipse's import wizard doesn't detect ant-build as a project -->
|
||||
<target name="-post-build">
|
||||
<move file="ant-build/AndroidManifest.xml" tofile="ant-build/AndroidManifest.cordova.xml" failonerror="false" overwrite="true" />
|
||||
<move file="CordovaLib/ant-build/AndroidManifest.xml" tofile="CordovaLib/ant-build/AndroidManifest.cordova.xml" failonerror="false" overwrite="true" />
|
||||
</target>
|
||||
</project>
|
||||
|
||||
45
bin/templates/project/eclipse-project
Normal file
45
bin/templates/project/eclipse-project
Normal file
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>__NAME__</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
<filteredResources>
|
||||
<filter>
|
||||
<id>1388696068187</id>
|
||||
<name></name>
|
||||
<type>10</type>
|
||||
<matcher>
|
||||
<id>org.eclipse.ui.ide.multiFilter</id>
|
||||
<arguments>1.0-name-matches-false-true-CordovaLib|platform_www|cordova</arguments>
|
||||
</matcher>
|
||||
</filter>
|
||||
</filteredResources>
|
||||
</projectDescription>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user