summaryrefslogtreecommitdiff
path: root/StoneIsland/platforms/android/cordova/lib/builders
diff options
context:
space:
mode:
authorJules Laplace <jules@okfoc.us>2017-02-16 01:24:12 +0100
committerJules Laplace <jules@okfoc.us>2017-02-16 01:24:12 +0100
commit30c49550c89c1b69c680170d2dc247eac76bd463 (patch)
tree8732652298b630b9ba15def97e59738f1c9bf7b6 /StoneIsland/platforms/android/cordova/lib/builders
parent8f1f626384e6ba75f4fb24c27e0973260a74421b (diff)
push plugin
Diffstat (limited to 'StoneIsland/platforms/android/cordova/lib/builders')
-rw-r--r--StoneIsland/platforms/android/cordova/lib/builders/AntBuilder.js156
-rw-r--r--StoneIsland/platforms/android/cordova/lib/builders/GenericBuilder.js147
-rw-r--r--StoneIsland/platforms/android/cordova/lib/builders/GradleBuilder.js266
-rw-r--r--StoneIsland/platforms/android/cordova/lib/builders/builders.js47
4 files changed, 616 insertions, 0 deletions
diff --git a/StoneIsland/platforms/android/cordova/lib/builders/AntBuilder.js b/StoneIsland/platforms/android/cordova/lib/builders/AntBuilder.js
new file mode 100644
index 00000000..4e0f71ab
--- /dev/null
+++ b/StoneIsland/platforms/android/cordova/lib/builders/AntBuilder.js
@@ -0,0 +1,156 @@
+/*
+ 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(this.root)) {
+ 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. Use gradle instead.');
+ }
+
+ 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(this.root)) {
+ // 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: 'pipe'});
+ }).progress(function (stdio){
+ if (stdio.stderr) {
+ process.stderr.write(stdio.stderr);
+ } else {
+ process.stdout.write(stdio.stdout);
+ }
+ }).catch(function (error) {
+ if (error.toString().indexOf('Unable to resolve project target') >= 0) {
+ return check_reqs.check_android_target(error).then(function() {
+ // If due to some odd reason - check_android_target succeeds
+ // we should still fail here.
+ return Q.reject(error);
+ });
+ }
+ return Q.reject(error);
+ });
+};
+
+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;
+}
diff --git a/StoneIsland/platforms/android/cordova/lib/builders/GenericBuilder.js b/StoneIsland/platforms/android/cordova/lib/builders/GenericBuilder.js
new file mode 100644
index 00000000..362da431
--- /dev/null
+++ b/StoneIsland/platforms/android/cordova/lib/builders/GenericBuilder.js
@@ -0,0 +1,147 @@
+/*
+ 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) {
+ // De-prioritize unsigned builds
+ var unsignedRE = /-unsigned/;
+ if (unsignedRE.exec(fileA)) {
+ return 1;
+ } else if (unsignedRE.exec(fileB)) {
+ return -1;
+ }
+
+ 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 && arch) {
+ ret = ret.filter(function(p) {
+ return path.basename(p).indexOf('-' + arch) != -1;
+ });
+ }
+
+ return ret;
+}
diff --git a/StoneIsland/platforms/android/cordova/lib/builders/GradleBuilder.js b/StoneIsland/platforms/android/cordova/lib/builders/GradleBuilder.js
new file mode 100644
index 00000000..f415646e
--- /dev/null
+++ b/StoneIsland/platforms/android/cordova/lib/builders/GradleBuilder.js
@@ -0,0 +1,266 @@
+/*
+ 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');
+ // to allow dex in process
+ args.push('-Dorg.gradle.jvmargs=-Xmx2048m');
+ // allow NDK to be used - required by Gradle 1.5 plugin
+ args.push('-Pandroid.useDeprecatedNdk=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;
+ var checkAndCopy = function(subProject, root) {
+ var subProjectGradle = path.join(root, subProject, 'build.gradle');
+ // This is the future-proof way of checking if a file exists
+ // This must be synchronous to satisfy a Travis test
+ try {
+ fs.accessSync(subProjectGradle, fs.F_OK);
+ } catch (e) {
+ shell.cp('-f', pluginBuildGradle, subProjectGradle);
+ }
+ };
+ for (var i = 0; i < subProjects.length; ++i) {
+ if (subProjects[i] !== 'CordovaLib') {
+ checkAndCopy(subProjects[i], this.root);
+ }
+ }
+ 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 = '';
+ var root = this.root;
+ var insertExclude = function(p) {
+ var gradlePath = path.join(root, p, 'build.gradle');
+ var projectGradleFile = fs.readFileSync(gradlePath, 'utf-8');
+ if(projectGradleFile.indexOf('CordovaLib') != -1) {
+ depsList += '{\n exclude module:("CordovaLib")\n }\n';
+ }
+ else {
+ depsList +='\n';
+ }
+ };
+ subProjects.forEach(function(p) {
+ console.log('Subproject Path: ' + p);
+ var libName=p.replace(/[/\\]/g, ':').replace(name+'-','');
+ depsList += ' debugCompile(project(path: "' + libName + '", configuration: "debug"))';
+ insertExclude(p);
+ depsList += ' releaseCompile(project(path: "' + libName + '", configuration: "release"))';
+ insertExclude(p);
+ });
+ // 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'] || 'https\\://services.gradle.org/distributions/gradle-2.14.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 spawn(wrapper, args, {stdio: 'pipe'})
+ .progress(function (stdio){
+ if (stdio.stderr) {
+ /*
+ * Workaround for the issue with Java printing some unwanted information to
+ * stderr instead of stdout.
+ * This function suppresses 'Picked up _JAVA_OPTIONS' message from being
+ * printed to stderr. See https://issues.apache.org/jira/browse/CB-9971 for
+ * explanation.
+ */
+ var suppressThisLine = /^Picked up _JAVA_OPTIONS: /i.test(stdio.stderr.toString());
+ if (suppressThisLine) {
+ return;
+ }
+ process.stderr.write(stdio.stderr);
+ } else {
+ process.stdout.write(stdio.stdout);
+ }
+ }).catch(function (error) {
+ if (error.toString().indexOf('failed to find target with hash string') >= 0) {
+ return check_reqs.check_android_target(error).then(function() {
+ // If due to some odd reason - check_android_target succeeds
+ // we should still fail here.
+ return Q.reject(error);
+ });
+ }
+ return Q.reject(error);
+ });
+};
+
+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;
+}
diff --git a/StoneIsland/platforms/android/cordova/lib/builders/builders.js b/StoneIsland/platforms/android/cordova/lib/builders/builders.js
new file mode 100644
index 00000000..4921c49a
--- /dev/null
+++ b/StoneIsland/platforms/android/cordova/lib/builders/builders.js
@@ -0,0 +1,47 @@
+/*
+ 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 CordovaError = require('cordova-common').CordovaError;
+
+var knownBuilders = {
+ ant: 'AntBuilder',
+ gradle: 'GradleBuilder',
+ none: 'GenericBuilder'
+};
+
+/**
+ * Helper method that instantiates and returns a builder for specified build
+ * type.
+ *
+ * @param {String} builderType Builder name to construct and return. Must
+ * be one of 'ant', 'gradle' or 'none'
+ *
+ * @return {Builder} A builder instance for specified build type.
+ */
+module.exports.getBuilder = function (builderType, projectRoot) {
+ if (!knownBuilders[builderType])
+ throw new CordovaError('Builder ' + builderType + ' is not supported.');
+
+ try {
+ var Builder = require('./' + knownBuilders[builderType]);
+ return new Builder(projectRoot);
+ } catch (err) {
+ throw new CordovaError('Failed to instantiate ' + knownBuilders[builderType] + ' builder: ' + err);
+ }
+};