Skip to content

Commit

Permalink
[FEATURE] Add "ui5 use/add" commands (#315)
Browse files Browse the repository at this point in the history
Co-authored-by: Merlin Beutlberger <m.beutlberger@sap.com>
  • Loading branch information
matz3 and RandomByte authored Apr 1, 2020
1 parent 7539675 commit 920fbfc
Show file tree
Hide file tree
Showing 14 changed files with 2,946 additions and 3 deletions.
4 changes: 4 additions & 0 deletions bin/ui5.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ setTimeout(() => {
shouldNotifyInNpmScript: true
}).notify();

cli.parserConfiguration({
"parse-numbers": false
});

// Explicitly set CLI version as the yargs default might
// be wrong in case a local CLI installation is used
// Also add CLI location
Expand Down
88 changes: 88 additions & 0 deletions lib/cli/commands/add.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Add
const addCommand = {
command: "add [--development] [--optional] <framework-libraries..>",
describe: "Add SAPUI5/OpenUI5 framework libraries to the project configuration.",
middlewares: [require("../middlewares/base.js")]
};

addCommand.builder = function(cli) {
return cli
.positional("framework-libraries", {
describe: "Framework library names",
type: "string"
}).option("development", {
describe: "Add as development dependency",
alias: ["D", "dev"],
default: false,
type: "boolean"
}).option("optional", {
describe: "Add as optional dependency",
alias: ["O"],
default: false,
type: "boolean"
})
.example("$0 add sap.ui.core sap.m", "Add the framework libraries sap.ui.core and sap.m as dependencies")
.example("$0 add -D sap.ui.support", "Add the framework library sap.ui.support as development dependency")
.example("$0 add --optional themelib_sap_fiori_3",
"Add the framework library themelib_sap_fiori_3 as optional dependency");
};

addCommand.handler = async function(argv) {
const libraryNames = argv["framework-libraries"] || [];
const development = argv["development"];
const optional = argv["optional"];

if (libraryNames.length === 0) {
// Should not happen via yargs as parameter is mandatory
throw new Error("Missing mandatory parameter framework-libraries");
}

if (development && optional) {
throw new Error("Options 'development' and 'optional' cannot be combined");
}

const normalizerOptions = {
translatorName: argv.translator,
configPath: argv.config
};

const libraries = libraryNames.map((name) => {
const library = {name};
if (optional) {
library.optional = true;
} else if (development) {
library.development = true;
}
return library;
});

const {yamlUpdated} = await require("../../framework/add")({
normalizerOptions,
libraries
});

const library = libraries.length === 1 ? "library": "libraries";
if (!yamlUpdated) {
if (argv.config) {
throw new Error(
`Internal error while adding framework ${library} ${libraryNames.join(" ")} to config at ${argv.config}`
);
} else {
throw new Error(
`Internal error while adding framework ${library} ${libraryNames.join(" ")} to ui5.yaml`
);
}
} else {
console.log(`Updated configuration written to ${argv.config || "ui5.yaml"}`);
let logMessage = `Added framework ${library} ${libraryNames.join(" ")} as`;
if (development) {
logMessage += " development";
} else if (optional) {
logMessage += " optional";
}
logMessage += libraries.length === 1 ? " dependency": " dependencies";
console.log(logMessage);
}
};

module.exports = addCommand;
83 changes: 83 additions & 0 deletions lib/cli/commands/use.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Use
const useCommand = {
command: "use <framework-info>",
describe: "Initialize or update the project's framework configuration.",
middlewares: [require("../middlewares/base.js")]
};

useCommand.builder = function(cli) {
return cli
.positional("framework-info", {
describe: "Framework name, version or both (name@version).\n" +
"Name can be \"SAPUI5\" or \"OpenUI5\" (case-insensitive).\n" +
"Version can be \"latest\", \"1.xx\" or \"1.xx.x\".",
type: "string"
})
.example("$0 use sapui5@latest", "Use SAPUI5 in the latest available version")
.example("$0 use openui5@1.76", "Use OpenUI5 in the latest available 1.76 patch version")
.example("$0 use latest", "Use the latest available version of the configured framework")
.example("$0 use openui5", "Use OpenUI5 without a version (or use existing version)");
};

const versionRegExp = /^(0|[1-9]\d*)\.(0|[1-9]\d*)(?:\.(0|[1-9]\d*))?$/;

function parseFrameworkInfo(frameworkInfo) {
const parts = frameworkInfo.split("@");
if (parts.length > 2) {
// More than one @ sign
throw new Error("Invalid framework info: " + frameworkInfo);
}
if (parts.length === 1) {
// No @ sign, only name or version
const nameOrVersion = parts[0];
if (!nameOrVersion) {
throw new Error("Invalid framework info: " + frameworkInfo);
}
if (nameOrVersion === "latest" || versionRegExp.test(nameOrVersion)) {
return {
name: null,
version: nameOrVersion
};
} else {
return {
name: nameOrVersion,
version: null
};
}
} else {
const [name, version] = parts;
if (!name || !version) {
throw new Error("Invalid framework info: " + frameworkInfo);
}
return {name, version};
}
}

useCommand.handler = async function(argv) {
const frameworkOptions = parseFrameworkInfo(argv["framework-info"]);

const normalizerOptions = {
translatorName: argv.translator,
configPath: argv.config
};

const {usedFramework, usedVersion, yamlUpdated} = await require("../../framework/use")({
normalizerOptions,
frameworkOptions
});

if (!yamlUpdated) {
if (argv.config) {
throw new Error(
`Internal error while updating config at ${argv.config} to ${usedFramework} version ${usedVersion}`
);
} else {
throw new Error(`Internal error while updating ui5.yaml to ${usedFramework} version ${usedVersion}`);
}
} else {
console.log(`Updated configuration written to ${argv.config || "ui5.yaml"}`);
console.log(`This project is now using ${usedFramework} version ${usedVersion}`);
}
};

module.exports = useCommand;
77 changes: 77 additions & 0 deletions lib/framework/add.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
const {getRootProjectConfiguration, getFrameworkResolver, isValidSpecVersion} = require("./utils");

module.exports = async function({normalizerOptions, libraries}) {
const project = await getRootProjectConfiguration({normalizerOptions});

if (!isValidSpecVersion(project.specVersion)) {
throw new Error(
`ui5 add command requires specVersion "2.0" or higher. ` +
`Project ${project.metadata.name} uses specVersion "${project.specVersion}"`
);
}

if (!project.framework) {
throw new Error(
`Project ${project.metadata.name} is missing a framework configuration. ` +
`Please use "ui5 use" to configure a framework and version.`
);
}
if (!project.framework.version) {
throw new Error(
`Project ${project.metadata.name} does not define a framework version configuration. ` +
`Please use "ui5 use" to configure a version.`
);
}

const Resolver = getFrameworkResolver(project.framework.name);

const resolver = new Resolver({
cwd: project.path,
version: project.framework.version
});

// Get metadata of all libraries to verify that they can be installed
await Promise.all(libraries.map(async ({name}) => {
try {
await resolver.getLibraryMetadata(name);
} catch (err) {
throw new Error(`Failed to find ${project.framework.name} framework library ${name}: ` + err.message);
}
}));

// Shallow copy of given libraries to not modify the input parameter when pushing other libraries
const allLibraries = [...libraries];

if (project.framework.libraries) {
project.framework.libraries.forEach((library) => {
// Don't add libraries twice!
if (allLibraries.findIndex(($) => $.name === library.name) === -1) {
allLibraries.push(library);
}
});
}
allLibraries.sort((a, b) => {
return a.name.localeCompare(b.name);
});

// Try to update YAML file but still return with name and resolved version in case it failed
let yamlUpdated = false;
try {
await require("./updateYaml")({
project,
data: {
framework: {
libraries: allLibraries
}
}
});
yamlUpdated = true;
} catch (err) {
if (err.name !== "FrameworkUpdateYamlFailed") {
throw err;
}
}
return {
yamlUpdated
};
};
Loading

0 comments on commit 920fbfc

Please sign in to comment.