Skip to content

Commit

Permalink
Implement version restriction
Browse files Browse the repository at this point in the history
See #1
  • Loading branch information
devappd committed Jan 3, 2021
1 parent 775d063 commit 3f5dc6e
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 69 deletions.
29 changes: 17 additions & 12 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,20 @@ By default, it does not disturb the user's global Emscripten configuration. You
```sh
npm install --save-dev git+https://github.com/devappd/emsdk-npm.git
npx emsdk-checkout
npx emsdk install latest
npx emsdk activate latest
npx emsdk install <version>
npx emsdk activate <version>
npx emsdk-run emcc test/test.c -o test/test.html
```

You can choose a specific release of emscripten to install by changing the `emsdk` parameters from "`latest`".
See "Version Selection", below, for rules on selecting the SDK version.

## Module usage

```js
const emsdk = require('emsdk-npm');

// Optionally, you can call emsdk.update() first to
// pre-emptively retrieve the latest emsdk version.
//
// Both emsdk.update() and emsdk.install() will call
// `emsdk-checkout`.

emsdk.install('latest')
.then(() => emsdk.activate('latest'))
emsdk.install(version)
.then(() => emsdk.activate(version))
.then(() => emsdk.run(
'emcc',
[
Expand All @@ -44,7 +38,18 @@ emsdk.install('latest')
});
```

As with command line usage, you can choose a specific release of emscripten to install by changing the "`latest`" parameter.
Optionally, you may call `emsdk.update()` first to retrieve the latest SDK tags.

See below for rules on selecting the SDK version.

## Version selection

If you install the `emscripten-sdk` package, then the SDK version is selected for you via the NPM
package version. Change the version you need by editing your `package.json`. You do not need to
specify anything for the `version` parameter in the CLI or JS API.

If you install the `emscripten-sdk-npm` package or checkout from Git, then you will specify the
SDK version as the `version` parameter in the CLI or JS API. To select the most recent version, you must specify `latest`.

## Install

Expand Down
57 changes: 56 additions & 1 deletion src/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
// DEALINGS IN THE SOFTWARE.

const path = require('path');
const fs = require('fs');
const GetEmsdkPath = require('./path.js');
const spawn = require('cross-spawn-promise');

Expand Down Expand Up @@ -52,8 +53,62 @@ function run(command, args, opts = {}) {
);
}

////////////////////////////////////////////////////////////////////////
// install() helpers
// Retrieve release tags and detect whether our requested version
// is already active as indicated by `.emsdk_version`
////////////////////////////////////////////////////////////////////////

function getReleaseTags() {
let tagsFile = path.join(common.emsdkBase(), 'emscripten-releases-tags.txt');
let rawData = fs.readFileSync(tagsFile);
return JSON.parse(rawData);
}

function getTotHash() {
let totFile = path.join(common.emsdkBase(), 'emscripten-releases-tot.txt');
return fs.readFileSync(totFile);
}

function getInstalled(version) {
// Set lookup defaults in case of exception
let which = (version.includes('fastcomp')) ? 'fastcomp' : 'upstream';
let hash = version;
let versionData = '';

try {
// Get hash from version
// Version hash is the same regardless if -fastcomp is in the string
if (version.includes('tot'))
hash = getTotHash();
else {
let tags = getReleaseTags();

if (version.includes('latest'))
hash = tags.releases[tags.latest];
else {
let versionTest = version.replace('-fastcomp', '');
if (versionTest in tags.releases)
hash = tags.releases[versionTest];
// else, user may have passed a complete hash string already
}
}

// Get currently installed hash
let versionFile = path.join(common.emsdkBase(), which, '.emsdk_version');
versionData = fs.readFileSync(versionFile);
} catch (e) {
console.warn('Error retrieving installed EMSDK version: ' + e.message);
}

return versionData.includes(hash);
}

module.exports = {
moduleBase: moduleBase,
emsdkBase: emsdkBase,
run: run
run: run,
getReleaseTags: getReleaseTags,
getTotHash: getTotHash,
getInstalled: getInstalled
};
3 changes: 2 additions & 1 deletion src/emsdk.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

const path = require('path');
const common = require('./common.js');
const version = require('./version.js');

function emsdk(args, opts = {}) {
const emsdkArgs = ['--embedded'].concat(args);
Expand All @@ -32,7 +33,7 @@ function emsdk(args, opts = {}) {
}

if (require.main === module) {
const args = process.argv.slice(2);
const args = version.restrictVersionInArgs(process.argv.slice(2));

emsdk(args).then(function () {
process.exit(0);
Expand Down
68 changes: 13 additions & 55 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,61 +24,15 @@ const emsdkCheckout = require('./emsdk-checkout.js');
const emsdkRun = require('./emsdk-run.js');
const emsdkPull = require('./emsdk-pull.js');
const shelljs = require('shelljs');
const path = require('path');
const common = require('./common.js');
const getEmsdkPath = require('./path.js');
const fs = require('fs');

////////////////////////////////////////////////////////////////////////
// install() helpers
// Retrieve release tags and detect whether our requested version
// is already active as indicated by `.emsdk_version`
////////////////////////////////////////////////////////////////////////

function _getReleaseTags() {
let tagsFile = path.join(common.emsdkBase(), 'emscripten-releases-tags.txt');
let rawData = fs.readFileSync(tagsFile);
return JSON.parse(rawData);
}

function _getTotHash() {
let totFile = path.join(common.emsdkBase(), 'emscripten-releases-tot.txt');
return fs.readFileSync(totFile);
}

function getInstalled(version) {
// Set lookup defaults in case of exception
let which = (version.includes('fastcomp')) ? 'fastcomp' : 'upstream';
let hash = version;
let versionData = '';

try {
// Get hash from version
// Version hash is the same regardless if -fastcomp is in the string
if (version.includes('tot'))
hash = _getTotHash();
else {
let tags = _getReleaseTags();

if (version.includes('latest'))
hash = tags.releases[tags.latest];
else {
let versionTest = version.replace('-fastcomp', '');
if (versionTest in tags.releases)
hash = tags.releases[versionTest];
// else, user may have passed a complete hash string already
}
}

// Get currently installed hash
let versionFile = path.join(common.emsdkBase(), which, '.emsdk_version');
versionData = fs.readFileSync(versionFile);
} catch (e) {
console.warn('Error retrieving installed EMSDK version: ' + e.message);
}

return versionData.includes(hash);
}
// This property restricts the version to be installed.
// If hardVersion is null, then the installable version is unrestricted.
const versionTools = require('./version.js');
const hardVersion = versionTools.version;
const defaultVersion = (hardVersion || 'latest');

////////////////////////////////////////////////////////////////////////
// JS API
Expand Down Expand Up @@ -123,11 +77,13 @@ function update() {
})
}

function install(version = 'latest', force = false) {
function install(version = defaultVersion, force = false) {
version = versionTools.validateVersion(version);

// Check if requested EMSDK version is installed.
// Only one version can be installed at a time, and no other
// versions are cached.
if (!force && getInstalled(version))
if (!force && common.getInstalled(version))
return Promise.resolve();

return checkout().then(function () {
Expand All @@ -138,7 +94,9 @@ function install(version = 'latest', force = false) {
});
}

function activate(version = 'latest') {
function activate(version = defaultVersion) {
version = versionTools.validateVersion(version);

return emsdk.run([
'activate',
version
Expand All @@ -156,5 +114,5 @@ module.exports = {
activate: activate,
run: run,
getEmsdkPath: getEmsdkPath,
getInstalled: getInstalled
getInstalled: common.getInstalled
};
104 changes: 104 additions & 0 deletions src/version.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// emsdk-npm - version.js
// Copyright 2019-2020 Brion Vibber and the emsdk-npm contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
////////////////////////////////////////////////////////////////////////
//
// Hardcoded Emscripten SDK version to install with this package.
//
// If `version` is `null`, then the allowed version to install is
// unrestricted.

const common = require('./common.js');

const version = null;

function restrictVersionInArgs(args) {
if (version
&& Array.isArray(args)
&& args.length
&& ['install','activate'].includes(args[0])
) {
// Count number of args that are not -- parameters
let versionCount = args.filter((val, idx) => {
// Skip first element
return (idx && !val.startsWith('-'));
}).length;

// If no version is specified, then add our hardcoded version
if (!versionCount)
args.push(version);
// Else, validate all specified versions
else
args = args.map((val, idx) => {
// Skip first element and -- parameters
if (!idx || val.startsWith('-'))
return val;
// Assume every other arg is a version ("tool")
else
return validateVersion(versionInput);
});
}

return args;
}

function validateVersion(versionInput) {
if (!version)
return versionInput;

// Allow `${version}`, 'fastcomp', `${version}-fastcomp`, and any
// string with version's hash
if (versionInput === 'fastcomp')
return `${version}-fastcomp`;
else if(versionInput === `${version-fastcomp}`
|| versionInput === version)
return versionInput;
else {
// Validate by version hash
let hash;
try {
let tags = common.getReleaseTags();
hash = tags.releases[versionInput] || null;
if (versionInput.includes(hash))
return versionInput;
} catch(e) {
// Fail silently
}

throw new RangeError(`
Input version "${inputVersion}" is not accepted! Accepted versions are:
* ${version}
* ${version}-fastcomp
* "fastcomp" (installs ${version} legacy backend)
${(hash ? `* Any string containing "${hash}"
` : '' )}
To install another SDK version, update your "emscripten-sdk" NPM package
to the corresponding version. Or, install "emscripten-sdk-npm" to enable
installing of all versions.
`.trimLeft())
}
}

module.exports = {
version: version,
restrictVersionInArgs: restrictVersionInArgs,
validateVersion: validateVersion
};

0 comments on commit 3f5dc6e

Please sign in to comment.