mirror of
https://github.com/apache/cordova-android.git
synced 2025-05-15 00:01:29 +08:00
CB-12546: more specs for android_sdk and check_reqs. added fixtures for sdk targets. refactored target listing.
This commit is contained in:
parent
f7687a2567
commit
3554267adf
77
bin/templates/cordova/lib/android_sdk.js
vendored
77
bin/templates/cordova/lib/android_sdk.js
vendored
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
@ -44,51 +44,68 @@ module.exports.version_string_to_api_level = {
|
|||||||
'7.1.1': 25
|
'7.1.1': 25
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.list_targets = function() {
|
module.exports.list_targets_with_android = function() {
|
||||||
return superspawn.spawn('android', ['list', 'targets'])
|
return superspawn.spawn('android', ['list', 'targets'])
|
||||||
.then(function(stdout) {
|
.then(function(stdout) {
|
||||||
var target_out = stdout.split('\n');
|
var target_out = stdout.split('\n');
|
||||||
var targets = [];
|
var targets = [];
|
||||||
for (var i = target_out.length; i >= 0; i--) {
|
for (var i = target_out.length - 1; i >= 0; i--) {
|
||||||
if(target_out[i].match(/id:/)) {
|
if(target_out[i].match(/id:/)) {
|
||||||
targets.push(targets[i].split(' ')[1]);
|
targets.push(target_out[i].match(/"(.+)"/)[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return targets;
|
return targets;
|
||||||
}).catch(function(err) {
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.list_targets_with_sdkmanager = function() {
|
||||||
|
return superspawn.spawn('sdkmanager', ['--list'])
|
||||||
|
.then(function(stdout) {
|
||||||
|
var parsing_installed_packages = false;
|
||||||
|
var lines = stdout.split('\n');
|
||||||
|
var targets = [];
|
||||||
|
for (var i = 0, l = lines.length; i < l; i++) {
|
||||||
|
var line = lines[i];
|
||||||
|
if (line.match(/Installed packages/)) {
|
||||||
|
parsing_installed_packages = true;
|
||||||
|
} else if (line.match(/Available Packages/) || line.match(/Available Updates/)) {
|
||||||
|
// we are done working through installed packages, exit
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (parsing_installed_packages) {
|
||||||
|
// Match stock android platform
|
||||||
|
if (line.match(/platforms;android-\d+/)) {
|
||||||
|
targets.push(line.match(/(android-\d+)/)[1]);
|
||||||
|
}
|
||||||
|
// Match Google APIs
|
||||||
|
if (line.match(/addon-google_apis-google-\d+/)) {
|
||||||
|
var description = lines[i + 1];
|
||||||
|
// munge description to match output from old android sdk tooling
|
||||||
|
var api_level = description.match(/Android (\d+)/); //[1];
|
||||||
|
if (api_level) {
|
||||||
|
targets.push('Google Inc.:Google APIs:' + api_level[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: match anything else?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return targets;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.list_targets = function() {
|
||||||
|
return module.exports.list_targets_with_android()
|
||||||
|
.catch(function(err) {
|
||||||
// there's a chance `android` no longer works.
|
// there's a chance `android` no longer works.
|
||||||
// lets see if `sdkmanager` is available and we can figure it out
|
// lets see if `sdkmanager` is available and we can figure it out
|
||||||
var avail_regex = /android command is no longer available/;
|
var avail_regex = /android command is no longer available/;
|
||||||
if (err.code && (err.stdout.match(avail_regex) || err.stderr.match(avail_regex))) {
|
if (err.code && (err.stdout.match(avail_regex) || err.stderr.match(avail_regex))) {
|
||||||
return superspawn.spawn('sdkmanager', ['--list'])
|
return module.exports.list_targets_with_sdkmanager();
|
||||||
.then(function(stdout) {
|
|
||||||
var parsing_installed_packages = false;
|
|
||||||
var lines = stdout.split('\n');
|
|
||||||
var targets = [];
|
|
||||||
for (var i = 0, l = lines.length; i < l; i++) {
|
|
||||||
var line = lines[i];
|
|
||||||
if (line.match(/Installed packages/)) {
|
|
||||||
parsing_installed_packages = true;
|
|
||||||
} else if (line.match(/Available Packages/) || line.match(/Available Updates/)) {
|
|
||||||
// we are done working through installed packages, exit
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (parsing_installed_packages && line.match(/platforms;android-\d+/)) {
|
|
||||||
targets.push(line.match(/android-\d+/)[0].split('-')[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return targets;
|
|
||||||
});
|
|
||||||
} else throw err;
|
} else throw err;
|
||||||
}).then(function(targets) {
|
}).then(function(targets) {
|
||||||
if (targets.length === 0) {
|
if (targets.length === 0) {
|
||||||
return Q.reject(new Error('No android targets (SDKs) installed!'));
|
return Q.reject(new Error('No android targets (SDKs) installed!'));
|
||||||
} else {
|
|
||||||
// Ensure we are working with integers
|
|
||||||
targets = targets.map(function(t) { return parseInt(t); });
|
|
||||||
// Sort them in descending order.
|
|
||||||
targets.sort(function(a, b) { return b-a; });
|
|
||||||
return targets;
|
|
||||||
}
|
}
|
||||||
|
return targets;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
3
bin/templates/cordova/lib/check_reqs.js
vendored
3
bin/templates/cordova/lib/check_reqs.js
vendored
@ -317,8 +317,7 @@ module.exports.check_android_target = function(originalError) {
|
|||||||
// android-L
|
// android-L
|
||||||
// Google Inc.:Google APIs:20
|
// Google Inc.:Google APIs:20
|
||||||
// Google Inc.:Glass Development Kit Preview:20
|
// Google Inc.:Glass Development Kit Preview:20
|
||||||
var desired_api_level = parseInt(module.exports.get_target().replace(/android-/, ''));
|
var desired_api_level = module.exports.get_target();
|
||||||
// Changing "targets" to "target" is stupid and makes more code. Thanks Google!
|
|
||||||
return android_sdk.list_targets()
|
return android_sdk.list_targets()
|
||||||
.then(function(targets) {
|
.then(function(targets) {
|
||||||
if (targets.indexOf(desired_api_level) >= 0) {
|
if (targets.indexOf(desired_api_level) >= 0) {
|
||||||
|
116
spec/fixtures/android_list_targets.txt
vendored
Normal file
116
spec/fixtures/android_list_targets.txt
vendored
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
Available Android targets:
|
||||||
|
----------
|
||||||
|
id: 1 or "android-20"
|
||||||
|
Name: Android 4.4W.2
|
||||||
|
Type: Platform
|
||||||
|
API level: 20
|
||||||
|
Revision: 2
|
||||||
|
Skins: HVGA, QVGA, WQVGA400, WQVGA432, WSVGA, WVGA800 (default), WVGA854, WXGA720, WXGA800, WXGA800-7in
|
||||||
|
Tag/ABIs : no ABIs.
|
||||||
|
----------
|
||||||
|
id: 2 or "android-21"
|
||||||
|
Name: Android 5.0.1
|
||||||
|
Type: Platform
|
||||||
|
API level: 21
|
||||||
|
Revision: 2
|
||||||
|
Skins: HVGA, QVGA, WQVGA400, WQVGA432, WSVGA, WVGA800 (default), WVGA854, WXGA720, WXGA800, WXGA800-7in
|
||||||
|
Tag/ABIs : android-tv/armeabi-v7a, android-tv/x86, default/armeabi-v7a, default/x86, default/x86_64
|
||||||
|
----------
|
||||||
|
id: 3 or "android-22"
|
||||||
|
Name: Android 5.1.1
|
||||||
|
Type: Platform
|
||||||
|
API level: 22
|
||||||
|
Revision: 2
|
||||||
|
Skins: HVGA, QVGA, WQVGA400, WQVGA432, WSVGA, WVGA800 (default), WVGA854, WXGA720, WXGA800, WXGA800-7in
|
||||||
|
Tag/ABIs : android-tv/armeabi-v7a, android-tv/x86, default/armeabi-v7a, default/x86, default/x86_64
|
||||||
|
----------
|
||||||
|
id: 4 or "android-MNC"
|
||||||
|
Name: Android M (Preview)
|
||||||
|
Type: Platform
|
||||||
|
API level: MNC
|
||||||
|
Revision: 1
|
||||||
|
Skins: HVGA, QVGA, WQVGA400, WQVGA432, WSVGA, WVGA800 (default), WVGA854, WXGA720, WXGA800, WXGA800-7in
|
||||||
|
Tag/ABIs : no ABIs.
|
||||||
|
----------
|
||||||
|
id: 5 or "android-23"
|
||||||
|
Name: Android 6.0
|
||||||
|
Type: Platform
|
||||||
|
API level: 23
|
||||||
|
Revision: 3
|
||||||
|
Skins: HVGA, QVGA, WQVGA400, WQVGA432, WSVGA, WVGA800 (default), WVGA854, WXGA720, WXGA800, WXGA800-7in
|
||||||
|
Tag/ABIs : android-tv/armeabi-v7a, android-tv/x86, default/x86, default/x86_64
|
||||||
|
----------
|
||||||
|
id: 6 or "android-N"
|
||||||
|
Name: Android N (Preview)
|
||||||
|
Type: Platform
|
||||||
|
API level: N
|
||||||
|
Revision: 3
|
||||||
|
Skins: HVGA, QVGA, WQVGA400, WQVGA432, WSVGA, WVGA800 (default), WVGA854, WXGA720, WXGA800, WXGA800-7in
|
||||||
|
Tag/ABIs : no ABIs.
|
||||||
|
----------
|
||||||
|
id: 7 or "android-24"
|
||||||
|
Name: Android 7.0
|
||||||
|
Type: Platform
|
||||||
|
API level: 24
|
||||||
|
Revision: 2
|
||||||
|
Skins: HVGA, QVGA, WQVGA400, WQVGA432, WSVGA, WVGA800 (default), WVGA854, WXGA720, WXGA800, WXGA800-7in
|
||||||
|
Tag/ABIs : android-tv/x86, default/x86, default/x86_64
|
||||||
|
----------
|
||||||
|
id: 8 or "android-25"
|
||||||
|
Name: Android 7.1.1
|
||||||
|
Type: Platform
|
||||||
|
API level: 25
|
||||||
|
Revision: 3
|
||||||
|
Skins: HVGA, QVGA, WQVGA400, WQVGA432, WSVGA, WVGA800 (default), WVGA854, WXGA720, WXGA800, WXGA800-7in
|
||||||
|
Tag/ABIs : android-tv/x86, google_apis/x86, google_apis/x86_64
|
||||||
|
----------
|
||||||
|
id: 9 or "Google Inc.:Google APIs:21"
|
||||||
|
Name: Google APIs
|
||||||
|
Type: Add-On
|
||||||
|
Vendor: Google Inc.
|
||||||
|
Revision: 1
|
||||||
|
Description: Android + Google APIs
|
||||||
|
Based on Android 5.0.1 (API level 21)
|
||||||
|
Libraries:
|
||||||
|
* com.android.future.usb.accessory (usb.jar)
|
||||||
|
API for USB Accessories
|
||||||
|
* com.google.android.media.effects (effects.jar)
|
||||||
|
Collection of video effects
|
||||||
|
* com.google.android.maps (maps.jar)
|
||||||
|
API for Google Maps
|
||||||
|
Skins: HVGA, QVGA, WQVGA400, WQVGA432, WSVGA, WVGA800 (default), WVGA854, WXGA720, WXGA800, WXGA800-7in
|
||||||
|
Tag/ABIs : google_apis/armeabi-v7a, google_apis/x86, google_apis/x86_64
|
||||||
|
----------
|
||||||
|
id: 10 or "Google Inc.:Google APIs:22"
|
||||||
|
Name: Google APIs
|
||||||
|
Type: Add-On
|
||||||
|
Vendor: Google Inc.
|
||||||
|
Revision: 1
|
||||||
|
Description: Android + Google APIs
|
||||||
|
Based on Android 5.1.1 (API level 22)
|
||||||
|
Libraries:
|
||||||
|
* com.android.future.usb.accessory (usb.jar)
|
||||||
|
API for USB Accessories
|
||||||
|
* com.google.android.media.effects (effects.jar)
|
||||||
|
Collection of video effects
|
||||||
|
* com.google.android.maps (maps.jar)
|
||||||
|
API for Google Maps
|
||||||
|
Skins: HVGA, QVGA, WQVGA400, WQVGA432, WSVGA, WVGA800 (default), WVGA854, WXGA720, WXGA800, WXGA800-7in
|
||||||
|
Tag/ABIs : google_apis/armeabi-v7a, google_apis/x86, google_apis/x86_64
|
||||||
|
----------
|
||||||
|
id: 11 or "Google Inc.:Google APIs:23"
|
||||||
|
Name: Google APIs
|
||||||
|
Type: Add-On
|
||||||
|
Vendor: Google Inc.
|
||||||
|
Revision: 1
|
||||||
|
Description: Android + Google APIs
|
||||||
|
Based on Android 6.0 (API level 23)
|
||||||
|
Libraries:
|
||||||
|
* com.android.future.usb.accessory (usb.jar)
|
||||||
|
API for USB Accessories
|
||||||
|
* com.google.android.media.effects (effects.jar)
|
||||||
|
Collection of video effects
|
||||||
|
* com.google.android.maps (maps.jar)
|
||||||
|
API for Google Maps
|
||||||
|
Skins: HVGA, QVGA, WQVGA400, WQVGA432, WSVGA, WVGA800 (default), WVGA854, WXGA720, WXGA800, WXGA800-7in
|
||||||
|
Tag/ABIs : google_apis/armeabi-v7a, google_apis/x86, google_apis/x86_64
|
1137
spec/fixtures/sdkmanager_list.txt
vendored
Normal file
1137
spec/fixtures/sdkmanager_list.txt
vendored
Normal file
File diff suppressed because it is too large
Load Diff
122
spec/unit/android_sdk.spec.js
Normal file
122
spec/unit/android_sdk.spec.js
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
/**
|
||||||
|
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 laxcomma:true */
|
||||||
|
|
||||||
|
var android_sdk = require("../../bin/templates/cordova/lib/android_sdk");
|
||||||
|
var superspawn = require("cordova-common").superspawn;
|
||||||
|
var fs = require("fs");
|
||||||
|
var path = require("path");
|
||||||
|
var Q = require("q");
|
||||||
|
|
||||||
|
describe("android_sdk", function () {
|
||||||
|
describe("list_targets_with_android", function() {
|
||||||
|
it("should parse and return results from `android list targets` command", function(done) {
|
||||||
|
var deferred = Q.defer();
|
||||||
|
spyOn(superspawn, "spawn").and.returnValue(deferred.promise);
|
||||||
|
deferred.resolve(fs.readFileSync(path.join("spec", "fixtures", "android_list_targets.txt"), "utf-8"));
|
||||||
|
return android_sdk.list_targets_with_android()
|
||||||
|
.then(function(list) {
|
||||||
|
[ "Google Inc.:Google APIs:23",
|
||||||
|
"Google Inc.:Google APIs:22",
|
||||||
|
"Google Inc.:Google APIs:21",
|
||||||
|
"android-25",
|
||||||
|
"android-24",
|
||||||
|
"android-N",
|
||||||
|
"android-23",
|
||||||
|
"android-MNC",
|
||||||
|
"android-22",
|
||||||
|
"android-21",
|
||||||
|
"android-20" ].forEach(function(target) {
|
||||||
|
expect(list).toContain(target);
|
||||||
|
});
|
||||||
|
}).fail(function(err) {
|
||||||
|
console.log(err);
|
||||||
|
expect(err).toBeUndefined();
|
||||||
|
}).fin(function() {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe("list_targets_with_sdkmanager", function() {
|
||||||
|
it("should parse and return results from `sdkmanager --list` command", function(done) {
|
||||||
|
var deferred = Q.defer();
|
||||||
|
spyOn(superspawn, "spawn").and.returnValue(deferred.promise);
|
||||||
|
deferred.resolve(fs.readFileSync(path.join("spec", "fixtures", "sdkmanager_list.txt"), "utf-8"));
|
||||||
|
return android_sdk.list_targets_with_sdkmanager()
|
||||||
|
.then(function(list) {
|
||||||
|
[ "Google Inc.:Google APIs:19",
|
||||||
|
"Google Inc.:Google APIs:21",
|
||||||
|
"Google Inc.:Google APIs:22",
|
||||||
|
"Google Inc.:Google APIs:23",
|
||||||
|
"Google Inc.:Google APIs:24",
|
||||||
|
"android-19",
|
||||||
|
"android-21",
|
||||||
|
"android-22",
|
||||||
|
"android-23",
|
||||||
|
"android-24",
|
||||||
|
"android-25" ].forEach(function(target) {
|
||||||
|
expect(list).toContain(target);
|
||||||
|
});
|
||||||
|
}).fail(function(err) {
|
||||||
|
console.log(err);
|
||||||
|
expect(err).toBeUndefined();
|
||||||
|
}).fin(function() {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe("list_targets", function() {
|
||||||
|
it("should parse Android SDK installed target information with `android` command first", function() {
|
||||||
|
var deferred = Q.defer();
|
||||||
|
var android_spy = spyOn(android_sdk, "list_targets_with_android").and.returnValue(deferred.promise);
|
||||||
|
android_sdk.list_targets();
|
||||||
|
expect(android_spy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
it("should parse Android SDK installed target information with `avdmanager` command if list_targets_with_android fails due to `android` command being obsolete", function(done) {
|
||||||
|
var deferred = Q.defer();
|
||||||
|
spyOn(android_sdk, "list_targets_with_android").and.returnValue(deferred.promise);
|
||||||
|
deferred.reject({
|
||||||
|
code: 1,
|
||||||
|
stdout: "The android command is no longer available."
|
||||||
|
});
|
||||||
|
var twoferred = Q.defer();
|
||||||
|
twoferred.resolve(["target1"]);
|
||||||
|
var sdkmanager_spy = spyOn(android_sdk, "list_targets_with_sdkmanager").and.returnValue(twoferred.promise);
|
||||||
|
return android_sdk.list_targets()
|
||||||
|
.then(function(targets) {
|
||||||
|
expect(sdkmanager_spy).toHaveBeenCalled();
|
||||||
|
expect(targets[0]).toEqual("target1");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("should throw an error if no Android targets were found.", function(done) {
|
||||||
|
var deferred = Q.defer();
|
||||||
|
spyOn(android_sdk, "list_targets_with_android").and.returnValue(deferred.promise);
|
||||||
|
deferred.resolve([]);
|
||||||
|
return android_sdk.list_targets()
|
||||||
|
.then(function(targets) {
|
||||||
|
done.fail();
|
||||||
|
}).catch(function(err) {
|
||||||
|
expect(err).toBeDefined();
|
||||||
|
expect(err.message).toContain("No android targets (SDKs) installed!");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -19,9 +19,11 @@
|
|||||||
/* jshint laxcomma:true */
|
/* jshint laxcomma:true */
|
||||||
|
|
||||||
var check_reqs = require("../../bin/templates/cordova/lib/check_reqs");
|
var check_reqs = require("../../bin/templates/cordova/lib/check_reqs");
|
||||||
|
var android_sdk = require("../../bin/templates/cordova/lib/android_sdk");
|
||||||
var shelljs = require("shelljs");
|
var shelljs = require("shelljs");
|
||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
var path = require("path");
|
var path = require("path");
|
||||||
|
var Q = require("q");
|
||||||
|
|
||||||
describe("check_reqs", function () {
|
describe("check_reqs", function () {
|
||||||
var original_env;
|
var original_env;
|
||||||
@ -218,4 +220,32 @@ describe("check_reqs", function () {
|
|||||||
expect(target).toContain("android-");
|
expect(target).toContain("android-");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe("check_android_target", function() {
|
||||||
|
it("should should return full list of supported targets if there is a match to ideal api level", function(done) {
|
||||||
|
var deferred = Q.defer();
|
||||||
|
spyOn(android_sdk, "list_targets").and.returnValue(deferred.promise);
|
||||||
|
var fake_targets = ["you are my fire", "my one desire"];
|
||||||
|
deferred.resolve(fake_targets);
|
||||||
|
spyOn(check_reqs, "get_target").and.returnValue("you are my fire");
|
||||||
|
return check_reqs.check_android_target()
|
||||||
|
.then(function(targets) {
|
||||||
|
expect(targets).toBeDefined();
|
||||||
|
expect(targets).toEqual(fake_targets);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("should error out if there is no match between ideal api level and installed targets", function(done) {
|
||||||
|
var deferred = Q.defer();
|
||||||
|
spyOn(android_sdk, "list_targets").and.returnValue(deferred.promise);
|
||||||
|
var fake_targets = ["you are my fire", "my one desire"];
|
||||||
|
deferred.resolve(fake_targets);
|
||||||
|
spyOn(check_reqs, "get_target").and.returnValue("and i knowwwwwwwwwwww");
|
||||||
|
return check_reqs.check_android_target()
|
||||||
|
.catch(function(err) {
|
||||||
|
expect(err).toBeDefined();
|
||||||
|
expect(err.message).toContain("Please install Android target");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user