From 8ee3a73dd1fbedaa3cd9fd9478b2fbd14f83258d Mon Sep 17 00:00:00 2001 From: Gearoid M Date: Thu, 28 Jun 2018 08:53:36 +0900 Subject: [PATCH 1/3] Remove unused builders and add unit tests --- bin/templates/cordova/Api.js | 28 +- .../cordova/lib/builders/GenericBuilder.js | 122 ------- .../cordova/lib/builders/GradleBuilder.js | 329 ------------------ .../{StudioBuilder.js => ProjectBuilder.js} | 121 +++++-- .../cordova/lib/builders/builders.js | 35 +- spec/unit/builders/GradleBuilder.spec.js | 28 -- spec/unit/builders/ProjectBuilder.spec.js | 289 +++++++++++++++ spec/unit/builders/builders.spec.js | 54 +++ test/run_java_unit_tests.js | 4 +- 9 files changed, 465 insertions(+), 545 deletions(-) delete mode 100644 bin/templates/cordova/lib/builders/GenericBuilder.js delete mode 100644 bin/templates/cordova/lib/builders/GradleBuilder.js rename bin/templates/cordova/lib/builders/{StudioBuilder.js => ProjectBuilder.js} (76%) delete mode 100644 spec/unit/builders/GradleBuilder.spec.js create mode 100644 spec/unit/builders/ProjectBuilder.spec.js create mode 100644 spec/unit/builders/builders.spec.js diff --git a/bin/templates/cordova/Api.js b/bin/templates/cordova/Api.js index ae4d17bd..c669983e 100644 --- a/bin/templates/cordova/Api.js +++ b/bin/templates/cordova/Api.js @@ -56,7 +56,7 @@ function setupEvents (externalEventEmitter) { function Api (platform, platformRootDir, events) { this.platform = PLATFORM; this.root = path.resolve(__dirname, '..'); - this.builder = 'gradle'; + this.builder = 'studio'; setupEvents(events); @@ -64,33 +64,19 @@ function Api (platform, platformRootDir, events) { this.locations = { root: self.root, - www: path.join(self.root, 'assets/www'), - res: path.join(self.root, 'res'), + www: path.join(self.root, 'app/src/main/assets/www'), + res: path.join(self.root, 'app/src/main/res'), platformWww: path.join(self.root, 'platform_www'), - configXml: path.join(self.root, 'res/xml/config.xml'), + configXml: path.join(self.root, 'app/src/main/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'), + strings: path.join(self.root, 'app/src/main/res/values/strings.xml'), + manifest: path.join(self.root, 'app/src/main/AndroidManifest.xml'), build: path.join(self.root, 'build'), - javaSrc: path.join(self.root, 'src'), + javaSrc: path.join(self.root, 'app/src/main/java/'), // NOTE: Due to platformApi spec we need to return relative paths here cordovaJs: 'bin/templates/project/assets/www/cordova.js', cordovaJsSrc: 'cordova-js-src' }; - - // XXX Override some locations for Android Studio projects - if (AndroidStudio.isAndroidStudioProject(self.root) === true) { - selfEvents.emit('log', 'Android Studio project detected'); - this.builder = 'studio'; - this.android_studio = true; - this.locations.configXml = path.join(self.root, 'app/src/main/res/xml/config.xml'); - this.locations.strings = path.join(self.root, 'app/src/main/res/values/strings.xml'); - this.locations.manifest = path.join(self.root, 'app/src/main/AndroidManifest.xml'); - // We could have Java Source, we could have other languages - this.locations.javaSrc = path.join(self.root, 'app/src/main/java/'); - this.locations.www = path.join(self.root, 'app/src/main/assets/www'); - this.locations.res = path.join(self.root, 'app/src/main/res'); - } } /** diff --git a/bin/templates/cordova/lib/builders/GenericBuilder.js b/bin/templates/cordova/lib/builders/GenericBuilder.js deleted file mode 100644 index 33c40ea2..00000000 --- a/bin/templates/cordova/lib/builders/GenericBuilder.js +++ /dev/null @@ -1,122 +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. -*/ -/* eslint no-self-assign: 0 */ -/* eslint no-unused-vars: 0 */ - -var Q = require('q'); -var fs = require('fs'); -var path = require('path'); -var shell = require('shelljs'); -var events = require('cordova-common').events; - -function GenericBuilder (projectDir) { - this.root = projectDir || path.resolve(__dirname, '../../..'); - this.binDirs = { - studio: path.join(this.root, 'app', 'build', 'outputs', 'apk'), - gradle: path.join(this.root, 'build', 'outputs', 'apk') - }; -} - -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); -}; - -module.exports = GenericBuilder; - -function apkSorter (fileA, fileB) { - // De-prioritize arch specific builds - var archSpecificRE = /-x86|-arm/; - if (archSpecificRE.exec(fileA)) { - return 1; - } else if (archSpecificRE.exec(fileB)) { - return -1; - } - - // De-prioritize unsigned builds - var unsignedRE = /-unsigned/; - if (unsignedRE.exec(fileA)) { - return 1; - } else if (unsignedRE.exec(fileB)) { - return -1; - } - - var timeDiff = fs.statSync(fileB).mtime - fs.statSync(fileA).mtime; - return timeDiff === 0 ? fileA.length - fileB.length : timeDiff; -} - -function findOutputApksHelper (dir, build_type, arch) { - var shellSilent = shell.config.silent; - shell.config.silent = true; - - // list directory recursively - var ret = shell.ls('-R', dir).map(function (file) { - // ls does not include base directory - return path.join(dir, file); - }).filter(function (file) { - // find all APKs - return file.match(/\.apk?$/i); - }).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) { - return !!/-x86|-arm/.exec(path.basename(p)) === archSpecific; - }); - - if (archSpecific && ret.length > 1 && arch) { - ret = ret.filter(function (p) { - return path.basename(p).indexOf('-' + arch) !== -1; - }); - } - - return ret; -} diff --git a/bin/templates/cordova/lib/builders/GradleBuilder.js b/bin/templates/cordova/lib/builders/GradleBuilder.js deleted file mode 100644 index cec20791..00000000 --- a/bin/templates/cordova/lib/builders/GradleBuilder.js +++ /dev/null @@ -1,329 +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 superspawn = require('cordova-common').superspawn; -var CordovaError = require('cordova-common').CordovaError; -var events = require('cordova-common').events; -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; -}; - -/* - * This returns a promise - */ - -GradleBuilder.prototype.runGradleWrapper = function (gradle_cmd, gradle_file) { - var gradlePath = path.join(this.root, 'gradlew'); - gradle_file = path.join(this.root, (gradle_file || 'wrapper.gradle')); - if (fs.existsSync(gradlePath)) { - // Literally do nothing, for some reason this works, while !fs.existsSync didn't on Windows - } else { - return superspawn.spawn(gradle_cmd, ['-p', this.root, 'wrapper', '-b', gradle_file], { stdio: 'pipe' }) - .progress(function (stdio) { - suppressJavaOptionsInfo(stdio); - }); - } -}; - -/* - * We need to kill this in a fire. - */ - -GradleBuilder.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) - }; -}; - -GradleBuilder.prototype.extractRealProjectNameFromManifest = function () { - var manifestPath = path.join(this.root, 'AndroidManifest.xml'); - var manifestData = fs.readFileSync(manifestPath, 'utf8'); - var m = /= 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 superspawn.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 suppressJavaOptionsInfo (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); - } -} - -function isAutoGenerated (file) { - return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0; -} diff --git a/bin/templates/cordova/lib/builders/StudioBuilder.js b/bin/templates/cordova/lib/builders/ProjectBuilder.js similarity index 76% rename from bin/templates/cordova/lib/builders/StudioBuilder.js rename to bin/templates/cordova/lib/builders/ProjectBuilder.js index 81d9240f..db1253d5 100644 --- a/bin/templates/cordova/lib/builders/StudioBuilder.js +++ b/bin/templates/cordova/lib/builders/ProjectBuilder.js @@ -16,10 +16,11 @@ specific language governing permissions and limitations under the License. */ +/* eslint no-self-assign: 0 */ +/* eslint no-unused-vars: 0 */ 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; @@ -27,23 +28,21 @@ var events = require('cordova-common').events; 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 = +const MARKER = 'YOUR CHANGES WILL BE ERASED!'; +const SIGNING_PROPERTIES = '-signing.properties'; +const TEMPLATE = '# This file is automatically generated.\n' + '# Do not modify this file -- ' + MARKER + '\n'; -function StudioBuilder (projectRoot) { - GenericBuilder.call(this, projectRoot); - - this.binDirs = {gradle: this.binDirs.studio}; +function ProjectBuilder (projectRoot) { + this.root = projectRoot || path.resolve(__dirname, '../../..'); + this.binDirs = { + studio: path.join(this.root, 'app', 'build', 'outputs', 'apk'), + gradle: path.join(this.root, 'app', 'build', 'outputs', 'apk') + }; } -util.inherits(StudioBuilder, GenericBuilder); - -StudioBuilder.prototype.getArgs = function (cmd, opts) { +ProjectBuilder.prototype.getArgs = function (cmd, opts) { if (cmd === 'release') { cmd = 'cdvBuildRelease'; } else if (cmd === 'debug') { @@ -70,18 +69,17 @@ StudioBuilder.prototype.getArgs = function (cmd, opts) { * This returns a promise */ -StudioBuilder.prototype.runGradleWrapper = function (gradle_cmd) { +ProjectBuilder.prototype.runGradleWrapper = function (gradle_cmd) { var gradlePath = path.join(this.root, 'gradlew'); var wrapperGradle = path.join(this.root, 'wrapper.gradle'); if (fs.existsSync(gradlePath)) { // Literally do nothing, for some reason this works, while !fs.existsSync didn't on Windows } else { - return spawn(gradle_cmd, ['-p', this.root, 'wrapper', '-b', wrapperGradle], {stdio: 'inherit'}); + return spawn(gradle_cmd, ['-p', this.root, 'wrapper', '-b', wrapperGradle], { stdio: 'inherit' }); } }; -StudioBuilder.prototype.readProjectProperties = function () { - +ProjectBuilder.prototype.readProjectProperties = function () { function findAllUniq (data, r) { var s = {}; var m; @@ -99,7 +97,7 @@ StudioBuilder.prototype.readProjectProperties = function () { }; }; -StudioBuilder.prototype.extractRealProjectNameFromManifest = function () { +ProjectBuilder.prototype.extractRealProjectNameFromManifest = function () { var manifestPath = path.join(this.root, 'app', 'src', 'main', 'AndroidManifest.xml'); var manifestData = fs.readFileSync(manifestPath, 'utf8'); var m = / 1 && arch) { + ret = ret.filter(function (p) { + return path.basename(p).indexOf('-' + arch) !== -1; + }); + } + + return ret; +} function isAutoGenerated (file) { return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0; diff --git a/bin/templates/cordova/lib/builders/builders.js b/bin/templates/cordova/lib/builders/builders.js index aedf9be5..bc2ca5b9 100644 --- a/bin/templates/cordova/lib/builders/builders.js +++ b/bin/templates/cordova/lib/builders/builders.js @@ -1,28 +1,27 @@ /* - 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 + 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 + 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. + 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 = { - gradle: 'GradleBuilder', - studio: 'StudioBuilder', - none: 'GenericBuilder' + gradle: 'ProjectBuilder', + studio: 'ProjectBuilder' }; /** @@ -30,7 +29,7 @@ var knownBuilders = { * type. * * @param {String} builderType Builder name to construct and return. Must - * be one of 'ant', 'gradle' or 'none' + * be one of gradle' or 'studio' * * @return {Builder} A builder instance for specified build type. */ diff --git a/spec/unit/builders/GradleBuilder.spec.js b/spec/unit/builders/GradleBuilder.spec.js deleted file mode 100644 index f8ad1a4f..00000000 --- a/spec/unit/builders/GradleBuilder.spec.js +++ /dev/null @@ -1,28 +0,0 @@ - -var Gradle_builder = require('../../../bin/templates/cordova/lib/builders/GradleBuilder.js'); -var fs = require('fs'); -var Q = require('q'); -var superspawn = require('cordova-common').superspawn; -var builder; - -describe('Gradle Builder', function () { - beforeEach(function () { - spyOn(fs, 'existsSync').and.returnValue(true); - builder = new Gradle_builder('/root'); - var deferred = Q.defer(); - spyOn(superspawn, 'spawn').and.returnValue(deferred.promise); - }); - - describe('runGradleWrapper method', function () { - it('should run the provided gradle command if a gradle wrapper does not already exist', function () { - fs.existsSync.and.returnValue(false); - builder.runGradleWrapper('/my/sweet/gradle'); - expect(superspawn.spawn).toHaveBeenCalledWith('/my/sweet/gradle', jasmine.any(Array), jasmine.any(Object)); - }); - it('should do nothing if a gradle wrapper exists in the project directory', function () { - fs.existsSync.and.returnValue(true); - builder.runGradleWrapper('/my/sweet/gradle'); - expect(superspawn.spawn).not.toHaveBeenCalledWith('/my/sweet/gradle', jasmine.any(Array), jasmine.any(Object)); - }); - }); -}); diff --git a/spec/unit/builders/ProjectBuilder.spec.js b/spec/unit/builders/ProjectBuilder.spec.js new file mode 100644 index 00000000..7db85517 --- /dev/null +++ b/spec/unit/builders/ProjectBuilder.spec.js @@ -0,0 +1,289 @@ +/* + 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. +*/ + +const fs = require('fs'); +const path = require('path'); +const Q = require('q'); +const rewire = require('rewire'); + +const CordovaError = require('cordova-common').CordovaError; + +describe('ProjectBuilder', () => { + const rootDir = '/root'; + + let builder; + let ProjectBuilder; + let spawnSpy; + + beforeEach(() => { + spawnSpy = jasmine.createSpy('spawn').and.returnValue(Q.defer().promise); + ProjectBuilder = rewire('../../../bin/templates/cordova/lib/builders/ProjectBuilder'); + ProjectBuilder.__set__('spawn', spawnSpy); + + builder = new ProjectBuilder(rootDir); + }); + + describe('constructor', () => { + it('should set the project directory to the passed argument', () => { + expect(builder.root).toBe(rootDir); + }); + + it('should set the project directory to three folders up', () => { + ProjectBuilder.__set__('__dirname', 'projecttest/platforms/android/app'); + builder = new ProjectBuilder(); + expect(builder.root).toMatch(/projecttest$/); + }); + }); + + describe('getArgs', () => { + beforeEach(() => { + spyOn(fs, 'existsSync').and.returnValue(true); + }); + + it('should set release argument', () => { + const args = builder.getArgs('release', {}); + expect(args[0]).toBe('cdvBuildRelease'); + }); + + it('should set debug argument', () => { + const args = builder.getArgs('debug', {}); + expect(args[0]).toBe('cdvBuildDebug'); + }); + + it('should add architecture if it is passed', () => { + const arch = 'unittest'; + const args = builder.getArgs('debug', { arch }); + + expect(args).toContain(`-PcdvBuildArch=${arch}`); + }); + }); + + describe('runGradleWrapper', () => { + it('should run the provided gradle command if a gradle wrapper does not already exist', () => { + spyOn(fs, 'existsSync').and.returnValue(false); + builder.runGradleWrapper('/my/sweet/gradle'); + expect(spawnSpy).toHaveBeenCalledWith('/my/sweet/gradle', jasmine.any(Array), jasmine.any(Object)); + }); + + it('should do nothing if a gradle wrapper exists in the project directory', () => { + spyOn(fs, 'existsSync').and.returnValue(true); + builder.runGradleWrapper('/my/sweet/gradle'); + expect(spawnSpy).not.toHaveBeenCalledWith('/my/sweet/gradle', jasmine.any(Array), jasmine.any(Object)); + }); + }); + + describe('extractRealProjectNameFromManifest', () => { + it('should get the project name from the Android Manifest', () => { + const projectName = 'unittestproject'; + const projectId = `io.cordova.${projectName}`; + const manifest = ` + `; + + spyOn(fs, 'readFileSync').and.returnValue(manifest); + + expect(builder.extractRealProjectNameFromManifest()).toBe(projectName); + }); + + it('should throw an error if there is no package in the Android manifest', () => { + const manifest = ` + `; + + spyOn(fs, 'readFileSync').and.returnValue(manifest); + + expect(() => builder.extractRealProjectNameFromManifest()).toThrow(jasmine.any(CordovaError)); + }); + }); + + describe('build', () => { + beforeEach(() => { + spyOn(builder, 'getArgs'); + }); + + it('should set build type to debug', () => { + const opts = { buildType: 'debug' }; + builder.build(opts); + expect(builder.getArgs).toHaveBeenCalledWith('debug', opts); + }); + + it('should set build type to release', () => { + const opts = { buildType: 'release' }; + builder.build(opts); + expect(builder.getArgs).toHaveBeenCalledWith('release', opts); + }); + + it('should default build type to release', () => { + const opts = {}; + builder.build(opts); + expect(builder.getArgs).toHaveBeenCalledWith('release', opts); + }); + + it('should spawn gradle with correct args', () => { + const testArgs = ['test', 'args', '-c']; + builder.getArgs.and.returnValue(testArgs); + + builder.build({}); + + expect(spawnSpy).toHaveBeenCalledWith(path.join(rootDir, 'gradlew'), testArgs, jasmine.anything()); + }); + + it('should reject if the spawn fails', () => { + const errorMessage = 'ERROR: Failed to spawn'; + spawnSpy.and.returnValue(Q.reject(errorMessage)); + + return builder.build({}).then( + () => fail('Unexpectedly resolved'), + err => { + expect(err).toBe(errorMessage); + } + ); + }); + + it('should check the Android target if failed to find target', () => { + const checkReqsSpy = jasmine.createSpyObj('check_reqs', ['check_android_target']); + const errorMessage = 'ERROR: failed to find target with hash string'; + + ProjectBuilder.__set__('check_reqs', checkReqsSpy); + checkReqsSpy.check_android_target.and.returnValue(Q.resolve()); + spawnSpy.and.returnValue(Q.reject(errorMessage)); + + return builder.build({}).then( + () => fail('Unexpectedly resolved'), + err => { + expect(checkReqsSpy.check_android_target).toHaveBeenCalledWith(errorMessage); + expect(err).toBe(errorMessage); + } + ); + }); + }); + + describe('clean', () => { + let shellSpy; + + beforeEach(() => { + shellSpy = jasmine.createSpyObj('shell', ['rm']); + ProjectBuilder.__set__('shell', shellSpy); + spyOn(builder, 'getArgs'); + spawnSpy.and.returnValue(Promise.resolve()); + }); + + it('should get arguments for cleaning', () => { + const opts = {}; + builder.clean(opts); + + expect(builder.getArgs).toHaveBeenCalledWith('clean', opts); + }); + + it('should spawn gradle', () => { + const opts = {}; + const gradleArgs = ['test', 'args', '-f']; + builder.getArgs.and.returnValue(gradleArgs); + + return builder.clean(opts).then(() => { + expect(spawnSpy).toHaveBeenCalledWith(path.join(rootDir, 'gradlew'), gradleArgs, jasmine.anything()); + }); + }); + + it('should remove "out" folder', () => { + return builder.clean({}).then(() => { + expect(shellSpy.rm).toHaveBeenCalledWith('-rf', path.join(rootDir, 'out')); + }); + }); + + it('should remove signing files if they are autogenerated', () => { + const debugSigningFile = path.join(rootDir, 'debug-signing.properties'); + const releaseSigningFile = path.join(rootDir, 'release-signing.properties'); + + const isAutoGeneratedSpy = jasmine.createSpy('isAutoGenerated'); + ProjectBuilder.__set__('isAutoGenerated', isAutoGeneratedSpy); + isAutoGeneratedSpy.and.returnValue(true); + + return builder.clean({}).then(() => { + expect(shellSpy.rm).toHaveBeenCalledWith(jasmine.any(String), debugSigningFile); + expect(shellSpy.rm).toHaveBeenCalledWith(jasmine.any(String), releaseSigningFile); + }); + }); + + it('should not remove signing files if they are not autogenerated', () => { + const debugSigningFile = path.join(rootDir, 'debug-signing.properties'); + const releaseSigningFile = path.join(rootDir, 'release-signing.properties'); + + const isAutoGeneratedSpy = jasmine.createSpy('isAutoGenerated'); + ProjectBuilder.__set__('isAutoGenerated', isAutoGeneratedSpy); + isAutoGeneratedSpy.and.returnValue(false); + + return builder.clean({}).then(() => { + expect(shellSpy.rm).not.toHaveBeenCalledWith(jasmine.any(String), debugSigningFile); + expect(shellSpy.rm).not.toHaveBeenCalledWith(jasmine.any(String), releaseSigningFile); + }); + }); + }); + + describe('apkSorter', () => { + it('should sort APKs from most recent to oldest, deprioritising unsigned arch-specific builds', () => { + const APKs = { + 'app-debug.apk': new Date('2018-04-20'), + 'app-release.apk': new Date('2018-05-20'), + 'app-debug-x86.apk': new Date('2018-06-01'), + 'app-release-x86.apk': new Date('2018-06-20'), + 'app-debug-arm.apk': new Date('2018-05-24'), + 'app-release-arm.apk': new Date('2018-06-24'), + 'app-release-unsigned.apk': new Date('2018-06-28') + }; + + const expectedResult = ['app-release.apk', 'app-debug.apk', 'app-release-unsigned.apk', + 'app-release-arm.apk', 'app-debug-arm.apk', 'app-release-x86.apk', 'app-debug-x86.apk']; + + const fsSpy = jasmine.createSpyObj('fs', ['statSync']); + fsSpy.statSync.and.callFake(filename => { + return { mtime: APKs[filename].getTime() }; + }); + ProjectBuilder.__set__('fs', fsSpy); + + const apkArray = Object.keys(APKs); + const sortedApks = apkArray.sort(ProjectBuilder.__get__('apkSorter')); + + expect(sortedApks).toEqual(expectedResult); + }); + }); + + describe('isAutoGenerated', () => { + let fsSpy; + + beforeEach(() => { + fsSpy = jasmine.createSpyObj('fs', ['existsSync', 'readFileSync']); + fsSpy.existsSync.and.returnValue(true); + ProjectBuilder.__set__('fs', fsSpy); + }); + + it('should return true if the file contains the autogenerated marker', () => { + const fileContents = `# DO NOT MODIFY - YOUR CHANGES WILL BE ERASED!`; + fsSpy.readFileSync.and.returnValue(fileContents); + + expect(ProjectBuilder.__get__('isAutoGenerated')()).toBe(true); + }); + + it('should return false if the file does not contain the autogenerated marker', () => { + const fileContents = `# My modified file`; + fsSpy.readFileSync.and.returnValue(fileContents); + + expect(ProjectBuilder.__get__('isAutoGenerated')()).toBe(false); + }); + }); +}); diff --git a/spec/unit/builders/builders.spec.js b/spec/unit/builders/builders.spec.js new file mode 100644 index 00000000..0709d9e6 --- /dev/null +++ b/spec/unit/builders/builders.spec.js @@ -0,0 +1,54 @@ +/** + 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. +*/ + +const rewire = require('rewire'); + +const CordovaError = require('cordova-common').CordovaError; +const ProjectBuilder = require('../../../bin/templates/cordova/lib/builders/ProjectBuilder'); + +describe('builders', () => { + let builders; + + beforeEach(() => { + builders = rewire('../../../bin/templates/cordova/lib/builders/builders'); + }); + + describe('getBuilder', () => { + it('should return an instance of ProjectBuilder when gradle is requested', () => { + const newBuilder = builders.getBuilder('gradle'); + expect(newBuilder).toEqual(jasmine.any(ProjectBuilder)); + }); + + it('should return an instance of ProjectBuilder when studio is requested', () => { + const newBuilder = builders.getBuilder('studio'); + expect(newBuilder).toEqual(jasmine.any(ProjectBuilder)); + }); + + it('should throw an error if the selected builder does not exist', () => { + expect(() => builders.getBuilder('NonExistentBuilder')).toThrow(jasmine.any(CordovaError)); + }); + + it('should throw an error if a builder cannot be instantiated', () => { + const requireSpy = jasmine.createSpy('require').and.throwError(); + builders.__set__('require', requireSpy); + + expect(() => builders.getBuilder('gradle')).toThrow(jasmine.any(CordovaError)); + }); + }); +}); diff --git a/test/run_java_unit_tests.js b/test/run_java_unit_tests.js index 8f8a14b6..3f99d282 100644 --- a/test/run_java_unit_tests.js +++ b/test/run_java_unit_tests.js @@ -22,11 +22,11 @@ var Q = require('q'); var path = require('path'); var superspawn = require('cordova-common').superspawn; -var GradleBuilder = require('../bin/templates/cordova/lib/builders/GradleBuilder'); +var ProjectBuilder = require('../bin/templates/cordova/lib/builders/ProjectBuilder'); Q.resolve() .then(_ => console.log('Preparing Gradle wrapper for Java unit tests.')) - .then(_ => new GradleBuilder(__dirname).runGradleWrapper('gradle')) + .then(_ => new ProjectBuilder(__dirname).runGradleWrapper('gradle')) .then(_ => gradlew('--version')) .then(_ => console.log('Gradle wrapper is ready. Running tests now.')) From 350d35fb24aae039fd720b4cae23cd44613bdf58 Mon Sep 17 00:00:00 2001 From: Gearoid M Date: Fri, 29 Jun 2018 09:16:57 +0900 Subject: [PATCH 2/3] Refactor ProjectBuilder to use class instead of prototype --- .../cordova/lib/builders/ProjectBuilder.js | 485 +++++++++--------- 1 file changed, 243 insertions(+), 242 deletions(-) diff --git a/bin/templates/cordova/lib/builders/ProjectBuilder.js b/bin/templates/cordova/lib/builders/ProjectBuilder.js index db1253d5..bba971d5 100644 --- a/bin/templates/cordova/lib/builders/ProjectBuilder.js +++ b/bin/templates/cordova/lib/builders/ProjectBuilder.js @@ -34,273 +34,274 @@ const TEMPLATE = '# This file is automatically generated.\n' + '# Do not modify this file -- ' + MARKER + '\n'; -function ProjectBuilder (projectRoot) { - this.root = projectRoot || path.resolve(__dirname, '../../..'); - this.binDirs = { - studio: path.join(this.root, 'app', 'build', 'outputs', 'apk'), - gradle: path.join(this.root, 'app', 'build', 'outputs', 'apk') - }; -} - -ProjectBuilder.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); +class ProjectBuilder { + constructor (projectRoot) { + this.root = projectRoot || path.resolve(__dirname, '../../..'); + this.binDirs = { + studio: path.join(this.root, 'app', 'build', 'outputs', 'apk'), + gradle: path.join(this.root, 'app', 'build', 'outputs', 'apk') + }; } - // 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; -}; - -/* - * This returns a promise - */ - -ProjectBuilder.prototype.runGradleWrapper = function (gradle_cmd) { - var gradlePath = path.join(this.root, 'gradlew'); - var wrapperGradle = path.join(this.root, 'wrapper.gradle'); - if (fs.existsSync(gradlePath)) { - // Literally do nothing, for some reason this works, while !fs.existsSync didn't on Windows - } else { - return spawn(gradle_cmd, ['-p', this.root, 'wrapper', '-b', wrapperGradle], { stdio: 'inherit' }); - } -}; - -ProjectBuilder.prototype.readProjectProperties = function () { - function findAllUniq (data, r) { - var s = {}; - var m; - while ((m = r.exec(data))) { - s[m[1]] = 1; + getArgs (cmd, opts) { + if (cmd === 'release') { + cmd = 'cdvBuildRelease'; + } else if (cmd === 'debug') { + cmd = 'cdvBuildDebug'; } - return Object.keys(s); + 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; } - 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) - }; -}; - -ProjectBuilder.prototype.extractRealProjectNameFromManifest = function () { - var manifestPath = path.join(this.root, 'app', 'src', 'main', 'AndroidManifest.xml'); - var manifestData = fs.readFileSync(manifestPath, 'utf8'); - var m = /= 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); - }); + }; + subProjects.forEach(function (p) { + events.emit('log', 'Subproject Path: ' + p); + var libName = p.replace(/[/\\]/g, ':').replace(name + '-', ''); + if (libName !== 'app') { + depsList += ' implementation(project(path: ":' + libName + '"))'; + insertExclude(p); } - return Q.reject(error); }); -}; + // 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:+'] + ]; -ProjectBuilder.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')); + 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'; + }); - ['debug', 'release'].forEach(function (config) { - var propertiesFilePath = path.join(builder.root, config + SIGNING_PROPERTIES); - if (isAutoGenerated(propertiesFilePath)) { + 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'); + // This needs to be stored in the app gradle, not the root grade + fs.writeFileSync(path.join(this.root, 'app', 'build.gradle'), buildGradle); + } + + prepEnv (opts) { + var self = this; + return check_reqs.check_gradle() + .then(function (gradlePath) { + return self.runGradleWrapper(gradlePath); + }).then(function () { + return self.prepBuildFiles(); + }).then(function () { + // 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 = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'https\\://services.gradle.org/distributions/gradle-4.4-all.zip'; + 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); } }); - }); -}; + } -ProjectBuilder.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); -}; + /* + * Builds the project with gradle. + * Returns a promise. + */ + build (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); + }); + } + + clean (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); + } + }); + }); + } + + findOutputApks (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); + } +} module.exports = ProjectBuilder; From 4b0725dfc23540c8fb1e5c9000fa4ed13b7dfc4e Mon Sep 17 00:00:00 2001 From: Gearoid M Date: Fri, 29 Jun 2018 10:11:27 +0900 Subject: [PATCH 3/3] Remove no longer needed AndroidStudio.js --- bin/templates/cordova/Api.js | 17 ----------------- bin/templates/cordova/lib/AndroidProject.js | 11 ++--------- bin/templates/cordova/lib/AndroidStudio.js | 9 --------- spec/unit/AndroidStudio.spec.js | 11 ----------- 4 files changed, 2 insertions(+), 46 deletions(-) delete mode 100644 bin/templates/cordova/lib/AndroidStudio.js delete mode 100644 spec/unit/AndroidStudio.spec.js diff --git a/bin/templates/cordova/Api.js b/bin/templates/cordova/Api.js index c669983e..1cbef764 100644 --- a/bin/templates/cordova/Api.js +++ b/bin/templates/cordova/Api.js @@ -21,7 +21,6 @@ var path = require('path'); var Q = require('q'); var AndroidProject = require('./lib/AndroidProject'); -var AndroidStudio = require('./lib/AndroidStudio'); var PluginManager = require('cordova-common').PluginManager; var CordovaLogger = require('cordova-common').CordovaLogger; @@ -214,22 +213,6 @@ Api.prototype.addPlugin = function (plugin, installOptions) { } return Q().then(function () { - // CB-11964: Do a clean when installing the plugin code to get around - // the Gradle bug introduced by the Android Gradle Plugin Version 2.2 - // TODO: Delete when the next version of Android Gradle plugin comes out - // Since clean doesn't just clean the build, it also wipes out www, we need - // to pass additional options. - - // Do some basic argument parsing - var opts = {}; - - // Skip cleaning prepared files when not invoking via cordova CLI. - opts.noPrepare = true; - - if (!AndroidStudio.isAndroidStudioProject(self.root) && !project.isClean()) { - return self.clean(opts); - } - }).then(function () { return PluginManager.get(self.platform, self.locations, project).addPlugin(plugin, installOptions); }).then(function () { if (plugin.getFrameworks(this.platform).length === 0) return; diff --git a/bin/templates/cordova/lib/AndroidProject.js b/bin/templates/cordova/lib/AndroidProject.js index bf55cad1..3c2586a3 100644 --- a/bin/templates/cordova/lib/AndroidProject.js +++ b/bin/templates/cordova/lib/AndroidProject.js @@ -21,7 +21,6 @@ var fs = require('fs'); var path = require('path'); var properties_parser = require('properties-parser'); var AndroidManifest = require('./AndroidManifest'); -var AndroidStudio = require('./AndroidStudio'); var pluginHandlers = require('./pluginHandlers'); var projectFileCache = {}; @@ -62,10 +61,7 @@ function AndroidProject (projectDir) { this._dirty = false; this.projectDir = projectDir; this.platformWww = path.join(this.projectDir, 'platform_www'); - this.www = path.join(this.projectDir, 'assets/www'); - if (AndroidStudio.isAndroidStudioProject(projectDir) === true) { - this.www = path.join(this.projectDir, 'app/src/main/assets/www'); - } + this.www = path.join(this.projectDir, 'app/src/main/assets/www'); } AndroidProject.getProjectFile = function (projectDir) { @@ -92,10 +88,7 @@ AndroidProject.purgeCache = function (projectDir) { * @return {String} The name of the package */ AndroidProject.prototype.getPackageName = function () { - var manifestPath = path.join(this.projectDir, 'AndroidManifest.xml'); - if (AndroidStudio.isAndroidStudioProject(this.projectDir) === true) { - manifestPath = path.join(this.projectDir, 'app/src/main/AndroidManifest.xml'); - } + var manifestPath = path.join(this.projectDir, 'app/src/main/AndroidManifest.xml'); return new AndroidManifest(manifestPath).getPackageId(); }; diff --git a/bin/templates/cordova/lib/AndroidStudio.js b/bin/templates/cordova/lib/AndroidStudio.js deleted file mode 100644 index e04d8a8b..00000000 --- a/bin/templates/cordova/lib/AndroidStudio.js +++ /dev/null @@ -1,9 +0,0 @@ -/* - * This is a simple routine that checks if project is an Android Studio Project - * - * @param {String} root Root folder of the project - */ - -module.exports.isAndroidStudioProject = function isAndroidStudioProject (root) { - return true; -}; diff --git a/spec/unit/AndroidStudio.spec.js b/spec/unit/AndroidStudio.spec.js deleted file mode 100644 index 11d46752..00000000 --- a/spec/unit/AndroidStudio.spec.js +++ /dev/null @@ -1,11 +0,0 @@ - -var path = require('path'); -var AndroidStudio = require('../../bin/templates/cordova/lib/AndroidStudio'); - -describe('AndroidStudio module', function () { - it('should return true for Android Studio project', function () { - var root = path.join(__dirname, '../fixtures/android_studio_project/'); - var isAndStud = AndroidStudio.isAndroidStudioProject(root); - expect(isAndStud).toBe(true); - }); -});