Skip to content

Commit

Permalink
Merge pull request #435 from ringo/ringo-admin
Browse files Browse the repository at this point in the history
New ringo-admin
  • Loading branch information
botic authored Jan 12, 2022
2 parents 57c2bb9 + 2c03100 commit 934f9cc
Show file tree
Hide file tree
Showing 59 changed files with 1,487 additions and 656 deletions.
181 changes: 181 additions & 0 deletions tools/admin/commands/create.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
const log = require("ringo/logging").getLogger(module.id);
const fs = require("fs");
const {Parser} = require("ringo/args");
const term = require("ringo/term");

const packages = require("../utils/packages");
const shell = require("../utils/shell");
const install = require("./install");

const parser = new Parser();
parser.addOption("a", "app-source", "[DIR]", "Copy application from [DIR] instead of skeleton");
parser.addOption("g", "google-app-engine", null, "Create a new Google App Engine application");
parser.addOption("p", "ringo-package", null, "Create a new Ringo package");
parser.addOption("s", "symlink", null, "Create symbolic links for jar and module files");
parser.addOption("w", "java-web-app", null, "Create a new Java Web application (WAR)");
parser.addOption("h", "help", null, "Print help message and exit");

/** @ignore */
exports.description = "Create a new RingoJS web application or package";

exports.help = [
"\n" + exports.description + "\n",
"Usage:",
" ringo-admin create [path]",
"\nOptions:",
parser.help(),
""
].join("\n");

/**
* Create a new RingoJS web application at the given path.
* @param {String} path The path where to create the application
* @param {Object} options Options defining the application to create
*/
const createApplication = (path, options) => {
log.debug("Creating application in {} (options: {}) ...", path, JSON.stringify(options));
const home = packages.getRingoHome();
const skeletons = fs.join(home, "tools/admin/skeletons");
const appSource = options.appSource || fs.join(skeletons, "app");
const appTemplate = options.googleAppEngine ? "appengine" :
options.javaWebApp ? "webapp" : null;
if (appTemplate) {
const symlink = Boolean(options.symlink);
copyTree(fs.join(skeletons, appTemplate), path);
// symlink app source if requested unless it's the skeleton app
if (!options.googleAppengine) {
copyTree(appSource, fs.join(path, "WEB-INF/app"), symlink && options.appSource);
}
copyTree(fs.join(home, "modules"), fs.join(path, "WEB-INF/modules"), symlink);
createAppEngineDirs(path);
copyJars(home, path, symlink);
} else if (copyTree(appSource, path)) {
if (!options.appSource) {
const descriptor = packages.getDescriptor(path);
term.writeln("Installing dependencies ...");
const packagesDirectory = fs.join(path, "packages");
if (!fs.exists(packagesDirectory)) {
fs.makeDirectory(packagesDirectory);
}
install.installDependencies(descriptor, packagesDirectory);
}
}
log.debug("Created application in", path);
term.writeln(term.GREEN, "Created application in", path, term.RESET);
};

/**
* Create a new RingoJS package at the given path.
* @param {String} path The path where to create the package
*/
const createPackage = (path) => {
log.debug("Creating package in", path);
const home = packages.getRingoHome();
const source = fs.join(home, "tools/admin/skeletons/package");
copyTree(source, path);
log.debug("Created package in", path);
term.writeln(term.GREEN, "Created RingoJS package in", path, term.RESET);
};

const copyTree = (source, destination, asSymLink) => {
if (!fs.exists(source) || !fs.isDirectory(source)) {
throw new Error("Source directory " + source + " doesn't exist");
}
term.write((asSymLink ? "Linking" : "Copying"), source, "to", destination, "... ");
if (asSymLink) {
log.debug("Linking {} to {} ...", source, destination);
fs.symbolicLink(source, destination);
} else {
log.debug("Copying tree {} to {} ...", source, destination);
fs.copyTree(source, destination);
}
log.debug("done");
term.writeln("done");
return true;
};

const createAppEngineDirs = (destination) => {
const webInf = fs.join(destination, "WEB-INF");
fs.makeDirectory(fs.join(webInf, "lib"));
fs.makeDirectory(fs.join(webInf, "packages"));
const staticDir = fs.join(webInf, "app/static");
if (fs.exists(staticDir)) {
fs.move(staticDir, fs.join(destination, "static"));
}
};

const copyJars = (home, destination, asSymLink) => {
log.debug("Copying .jar files from {} to {} (as symlink: {}) ...", home, destination, asSymLink);
term.write("Copying .jar files ... ");
const jars = [
"ringo-core.jar",
fs.list(fs.join(packages.getRingoHome(), "lib")).find(jar => {
return jar.startsWith("rhino") && jar.endsWith(".jar")
})
];
const libSource = fs.join(home, "lib");
const libDestination = fs.join(destination, "WEB-INF/lib");
term.writeln(" +", (asSymLink ? "Linking" : "Copying"), "jar files to", libDestination, "... ");
jars.forEach(jar => {
if (asSymLink) {
fs.symbolicLink(fs.join(libSource, jar), fs.join(libDestination, fs.base(jar)));
} else {
fs.copy(fs.join(libSource, jar), fs.join(libDestination, fs.base(jar)));
}
});
log.debug("done");
term.writeln("done");
};

/**
* Create a new RingoJS web application from the command line.
* @param args
*/
exports.run = (args) => {
const options = parser.parse(args);
if (options.help) {
term.writeln(exports.help);
return;
} else if (!!options.googleAppengine + !!options.ringoPackage + !!options.javaWebapp > 1) {
term.writeln(term.RED, "Options are mutually exclusive.", term.RESET);
}

const type = options.googleAppEngine ? "Google App Engine app":
options.ringoPackage ? "Ringo package" :
options.javaWebApp ? "Java web application" :
"Ringo web application";

const path = fs.absolute(args[0] || shell.readln("Path for new " + type + ": "));
if (prepare(path, type)) {
term.writeln(term.GREEN, "Creating", type, "in", path, term.RESET);
if (options.ringoPackage) {
createPackage(path);
} else {
createApplication(path, options);
}
}
};

const prepare = (path, type) => {
if (fs.exists(path)) {
if (fs.isDirectory(path)) {
if (fs.list(path).length > 0) {
log.warn("Destination path {} exists, but is not a directory", path);
term.writeln(term.RED, path, "exists, but is not empty");
return false;
}
} else {
log.warn("Destination directory {} exists, but is not empty", path);
term.writeln(term.RED, path, "exists, but is not a directory");
return false;
}
} else {
if (shell.prompt("Create " + type + " in " + path + " ?", ["y", "n"], "n") !== "y") {
log.debug("User aborted creation of {} in {}", type, path);
term.writeln("Aborted");
return false;
}
fs.makeTree(path);
}
return true;
};
33 changes: 33 additions & 0 deletions tools/admin/commands/help.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const fs = require("fs");
const term = require("ringo/term");

exports.description = "Display command usage details";

exports.help = [
"\n" + exports.description + "\n",
"Usage:",
" ringo-admin help <command>",
""
].join("\n")

exports.run = ([name]) => {
if (name != null) {
try {
term.writeln(require("./" + name).help);
} catch (e if e instanceof InternalError) {
term.writeln(term.RED, "Unknown command '" + name +
"', use 'help' to get a list of available commands",
term.RESET);
}
} else {
// print short info about available modules
term.writeln();
term.writeln(term.GREEN, "Available commands:", term.RESET);
fs.list(module.directory).sort().forEach(file => {
const cmd = file.slice(0, fs.extension(file).length * -1);
const {description} = require(module.resolve(file));
term.writeln(term.BOLD, " ", cmd, term.RESET, "-", description || "(no description)");
});
term.writeln();
}
};
Loading

0 comments on commit 934f9cc

Please sign in to comment.