diff --git a/bin/ns-bundle b/bin/ns-bundle old mode 100644 new mode 100755 index 09a7a542..bc482c98 --- a/bin/ns-bundle +++ b/bin/ns-bundle @@ -3,8 +3,10 @@ const { spawn } = require("child_process"); const { resolve: pathResolve, join } = require("path"); const { existsSync } = require("fs"); + +const semver = require("semver"); + const { getPackageJson } = require("../projectHelpers"); -const { isVersionGte } = require("../utils"); const PROJECT_DIR = pathResolve(__dirname, "../../../"); const packageJson = getPackageJson(PROJECT_DIR); @@ -79,7 +81,8 @@ function cleanBuildArtefacts(platform) { getTnsVersion().then(version => { // the android build artefacts should be cleaned manually // for nativescript-cli v3.0.1 and below or if using uglify - if (!isVersionGte(version, "3.0.1") || shouldUglify()) { + + if (!semver.gte(version, "3.0.1") || shouldUglify()) { gradlewClean().then(resolve).catch(throwError); } else { return resolve(); @@ -114,7 +117,7 @@ function getTnsVersion() { return new Promise((resolve, reject) => { const childProcess = spawn("tns", ["--version"], { shell: true }); - childProcess.stdout.on("data", resolve); + childProcess.stdout.on("data", version => resolve(version.toString())); childProcess.on("close", code => { if (code) { @@ -127,12 +130,6 @@ function getTnsVersion() { }); } -function versionToNumber(version) { - const VERSION_MATCHER = /(\d+)\.(\d+)\.(\d+)/; - - return Number(VERSION_MATCHER.exec(version).splice(1).join("")); -} - // Clear platform/**/app folder contents function cleanApp(platform) { return new Promise((resolve, reject) => { diff --git a/index.js b/index.js index 187863a9..298d1414 100644 --- a/index.js +++ b/index.js @@ -2,7 +2,6 @@ const path = require("path"); const { existsSync } = require("fs"); const { getPackageJson, isAngular } = require("./projectHelpers"); -const { sanitize } = require("./utils"); const PROJECT_DIR = path.dirname(path.dirname(__dirname)); const APP_DIR = path.join(PROJECT_DIR, "app"); @@ -38,6 +37,11 @@ exports.getAppPath = platform => { } }; +const sanitize = name => name + .split("") + .filter(char => /[a-zA-Z0-9]/.test(char)) + .join(""); + function getPackageJsonEntry() { const packageJsonSource = getPackageJson(APP_DIR); const entry = packageJsonSource.main; diff --git a/package.json b/package.json index feba7670..1f2708f2 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "generate-android-snapshot": "./bin/generate-android-snapshot" }, "dependencies": { + "semver": "^5.4.1", "shelljs": "^0.6.0" }, "devDependencies": {} diff --git a/snapshot/android/project-snapshot-generator.js b/snapshot/android/project-snapshot-generator.js index 89a6032c..72fade35 100644 --- a/snapshot/android/project-snapshot-generator.js +++ b/snapshot/android/project-snapshot-generator.js @@ -1,15 +1,18 @@ const { join, isAbsolute, resolve } = require("path"); const fs = require("fs"); -const shelljs = require("shelljs"); const os = require("os"); +const shelljs = require("shelljs"); +const semver = require("semver"); + const SnapshotGenerator = require("./snapshot-generator"); const TnsJavaClassesGenerator = require("./tns-java-classes-generator"); -const { isVersionGte } = require("../../utils"); +const { getJsonFile } = require("./utils"); const { getPackageJson } = require("../../projectHelpers"); const MIN_ANDROID_RUNTIME_VERSION = "3.0.0"; const VALID_ANDROID_RUNTIME_TAGS = Object.freeze(["next", "rc"]); +const V8_VERSIONS_URL = "https://raw.githubusercontent.com/NativeScript/android-runtime/master/v8-versions.json"; const resolveRelativePath = (path) => { if (path) @@ -95,23 +98,23 @@ ProjectSnapshotGenerator.installSnapshotArtefacts = function(projectRoot) { } } -ProjectSnapshotGenerator.prototype.getV8Version = function() { - const runtimeVersion = this.getAndroidRuntimeVersion(); - - if (!runtimeVersion) { - return; - } else if ( - VALID_ANDROID_RUNTIME_TAGS.includes(runtimeVersion) || - isVersionGte(runtimeVersion, "3.2.0") - ) { - return "5.9.211"; - } else if (isVersionGte(runtimeVersion, "3.1.0")) { - return "5.5.372"; - } else if (isVersionGte(runtimeVersion, "2.4.0")) { - return "5.2.361"; - } else if (isVersionGte(runtimeVersion, "2.0.0")) { - return "4.7.80"; - } +ProjectSnapshotGenerator.prototype.getV8Version = function(generationOptions) { + return new Promise((resolve, reject) => { + const maybeV8Version = generationOptions.v8Version; + if (maybeV8Version) { + return resolve(maybeV8Version); + } + + getJsonFile(V8_VERSIONS_URL).then(v8VersionsMap => { + const runtimeVersion = this.getAndroidRuntimeVersion().replace(/-.*/, ""); + + const runtimeRange = Object.keys(v8VersionsMap) + .find(range => semver.satisfies(runtimeVersion, range)); + const v8Version = v8VersionsMap[runtimeRange]; + + return resolve(v8Version); + }).catch(reject); + }); } ProjectSnapshotGenerator.prototype.validateAndroidRuntimeVersion = function() { @@ -124,7 +127,7 @@ ProjectSnapshotGenerator.prototype.validateAndroidRuntimeVersion = function() { } if (!VALID_ANDROID_RUNTIME_TAGS.includes(currentRuntimeVersion) && - !isVersionGte(currentRuntimeVersion, MIN_ANDROID_RUNTIME_VERSION)) { + !semver.gte(currentRuntimeVersion, MIN_ANDROID_RUNTIME_VERSION)) { throw new Error("In order to support heap snapshots, you must have at least tns-android@" + MIN_ANDROID_RUNTIME_VERSION + " installed. Current Android Runtime version is: " + currentRuntimeVersion + "."); @@ -178,23 +181,29 @@ ProjectSnapshotGenerator.prototype.generate = function(generationOptions) { // Generate snapshots const generator = new SnapshotGenerator({ buildPath: this.getBuildPath() }); - return generator.generate({ - snapshotToolsPath, - inputFile: generationOptions.inputFile || join(this.options.projectRoot, "__snapshot.js"), - targetArchs: generationOptions.targetArchs || ["arm", "arm64", "ia32"], - v8Version: generationOptions.v8Version || this.getV8Version(), - preprocessedInputFile: generationOptions.preprocessedInputFile, - useLibs: generationOptions.useLibs || false, - androidNdkPath - }).then(() => { - console.log("Snapshots build finished succesfully!"); - - if (generationOptions.install) { - ProjectSnapshotGenerator.cleanSnapshotArtefacts(this.options.projectRoot); - ProjectSnapshotGenerator.installSnapshotArtefacts(this.options.projectRoot); - console.log(generationOptions.useLibs ? - "Snapshot is included in the app as dynamically linked library (.so file)." : - "Snapshot is included in the app as binary .blob file. The more space-efficient option is to embed it in a dynamically linked library (.so file)."); - } + + return this.getV8Version(generationOptions).then(v8Version => { + return generator.generate({ + snapshotToolsPath, + inputFile: generationOptions.inputFile || join(this.options.projectRoot, "__snapshot.js"), + targetArchs: generationOptions.targetArchs || ["arm", "arm64", "ia32"], + v8Version: generationOptions.v8Version || this.getV8Version(), + preprocessedInputFile: generationOptions.preprocessedInputFile, + useLibs: generationOptions.useLibs || false, + androidNdkPath + }).then(() => { + console.log("Snapshots build finished succesfully!"); + + if (generationOptions.install) { + ProjectSnapshotGenerator.cleanSnapshotArtefacts(this.options.projectRoot); + ProjectSnapshotGenerator.installSnapshotArtefacts(this.options.projectRoot); + console.log(generationOptions.useLibs ? + "Snapshot is included in the app as dynamically linked library (.so file)." : + "Snapshot is included in the app as binary .blob file. The more space-efficient option is to embed it in a dynamically linked library (.so file)."); + } + }); + }).catch(error => { + throw new Error(`Cannot find suitable v8 version! Original error: ${error.message || error}`); }); } + diff --git a/snapshot/android/snapshot-generator.js b/snapshot/android/snapshot-generator.js index a097601a..36e1838c 100644 --- a/snapshot/android/snapshot-generator.js +++ b/snapshot/android/snapshot-generator.js @@ -1,9 +1,11 @@ const fs = require("fs"); -const shelljs = require("shelljs"); const { join, dirname } = require("path"); const os = require("os"); const child_process = require("child_process"); -const https = require("https"); + +const shelljs = require("shelljs"); + +const { downloadFile } = require("./utils"); const NDK_BUILD_SEED_PATH = join(__dirname, "snapshot-generator-tools/ndk-build"); const BUNDLE_PREAMBLE_PATH = join(__dirname, "snapshot-generator-tools/bundle-preamble.js"); @@ -61,45 +63,10 @@ SnapshotGenerator.prototype.downloadMksnapshotTool = function(snapshotToolsPath, return snapshotToolsDownloads[mksnapshotToolPath]; const downloadUrl = MKSNAPSHOT_TOOLS_DOWNLOAD_ROOT_URL + mksnapshotToolRelativePath; - snapshotToolsDownloads[mksnapshotToolPath] = this.downloadExecFile(downloadUrl, mksnapshotToolPath); + snapshotToolsDownloads[mksnapshotToolPath] = downloadFile(downloadUrl, mksnapshotToolPath); return snapshotToolsDownloads[mksnapshotToolPath]; } -SnapshotGenerator.prototype.downloadExecFile = function(url, destinationFilePath) { - return new Promise((resolve, reject) => { - const request = https.get(url, (response) => { - switch (response.statusCode) { - case 200: - shelljs.mkdir("-p", dirname(destinationFilePath)); - const file = fs.createWriteStream(destinationFilePath); - file.on('error', function (error) { - return reject(error); - }); - file.on("finish", function() { - file.close(); - fs.chmodSync(destinationFilePath, 0755); - return resolve(destinationFilePath); - }); - response.pipe(file); - break; - case 301: - case 302: - case 303: - const redirectUrl = response.headers.location; - return this.downloadExecFile(redirectUrl, destinationFilePath); - default: - return reject(new Error("Unable to download file at " + url + ". Status code: " + response.statusCode)); - } - }); - - request.end(); - - request.on('error', function(err) { - return reject(err); - }); - }); -} - SnapshotGenerator.prototype.convertToAndroidArchName = function(archName) { switch (archName) { case "arm": return "armeabi-v7a"; @@ -205,4 +172,4 @@ SnapshotGenerator.prototype.generate = function(options) { } return this.buildPath; }); -} \ No newline at end of file +} diff --git a/snapshot/android/utils.js b/snapshot/android/utils.js new file mode 100644 index 00000000..13e4ba6b --- /dev/null +++ b/snapshot/android/utils.js @@ -0,0 +1,58 @@ +const https = require("https"); + +const shelljs = require("shelljs"); + +const downloadFile = (url, destinationFilePath) => + new Promise((resolve, reject) => { + const request = https.get(url, response => { + switch (response.statusCode) { + case 200: + shelljs.mkdir("-p", dirname(destinationFilePath)); + const file = fs.createWriteStream(destinationFilePath); + file.on('error', function (error) { + return reject(error); + }); + file.on("finish", function() { + file.close(); + fs.chmodSync(destinationFilePath, 0755); + return resolve(destinationFilePath); + }); + response.pipe(file); + break; + case 301: + case 302: + case 303: + const redirectUrl = response.headers.location; + return this.downloadExecFile(redirectUrl, destinationFilePath); + default: + return reject(new Error("Unable to download file at " + url + ". Status code: " + response.statusCode)); + } + }); + + request.end(); + + request.on('error', function(err) { + return reject(err); + }); + }); + +const getJsonFile = url => + new Promise((resolve, reject) => { + https.get(url, res => { + let body = ""; + res.on("data", chunk => { + body += chunk; + }) + + res.on("end", () => { + const data = JSON.parse(body); + return resolve(data); + }); + }).on("error", reject); + }); + +module.exports = { + downloadFile, + getJsonFile, +}; + diff --git a/utils.js b/utils.js deleted file mode 100644 index d6d7a85d..00000000 --- a/utils.js +++ /dev/null @@ -1,34 +0,0 @@ -const VERSION_MATCHER = /(\d+)\.(\d+)\.(\d+)/; -const parseVersion = version => { - const semver = VERSION_MATCHER.exec(version); - - return semver && semver.length> 3 && semver.splice(1).map(Number); -}; - -const isVersionValid = version => !!parseVersion(version); - -const isVersionGte = (first, second) => { - if (!isVersionValid(first) || !isVersionValid(second)) { - return false; - } - - const [ fMajor, fMinor, fPatch ] = parseVersion(first); - const [ sMajor, sMinor, sPatch ] = parseVersion(second); - - return ( - fMajor - sMajor || - fMinor - sMinor || - fPatch - sPatch - )>= 0; -} - -const sanitize = name => name - .split("") - .filter(char => /[a-zA-Z0-9]/.test(char)) - .join(""); - -module.exports = { - isVersionGte, - sanitize, -}; -