Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New ringo-admin #435

Merged
merged 26 commits into from
Jan 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5f29d26
feat: initial commit of new ringo-admin tool
grob Aug 13, 2021
64e596f
reworked app skeleton to use stick and reinhardt
grob Aug 14, 2021
4d4ecfb
refactored create command
grob Aug 14, 2021
82df6c2
added module search path to start command
grob Aug 14, 2021
2bdb309
refactor: replaced var with const
grob Aug 14, 2021
b1b55c6
refactor: changed to arrow functions where possible
grob Aug 14, 2021
beb910c
made package speck checks more specific, changed github spec to allow…
grob Aug 14, 2021
42238be
fix: newGitHubSpec didn't handle absolute github urls correctly
grob Aug 14, 2021
8a0eff4
changed constant value TYPE_ARCHIVE, added test for specs.get()
grob Aug 14, 2021
5f36dbf
guard agains archive entries that are not within the destination dire…
grob Aug 14, 2021
9c772fe
fix: archive.getBasePath() now returns a normalized path
grob Aug 14, 2021
1279565
added tests for archive.getEntries() and archive.extract()
grob Aug 14, 2021
127c744
added cumulative test
grob Aug 14, 2021
4e38594
improved usage help
grob Aug 14, 2021
9ce4bff
added lots of logging into <ringo.home>.ringo-admin.log
grob Aug 14, 2021
b8c0deb
unify help options
grob Aug 15, 2021
927d757
added option -n (--no-deps) to skip installing package dependencies
grob Aug 15, 2021
601affa
switched all log messages to debug level
grob Aug 15, 2021
bea64a4
improved logging/console output of git errors
grob Aug 15, 2021
4159d88
added install option `-s` to save installed packages as dependencies …
grob Aug 16, 2021
bd9aabd
added `--refs` to git ls-remote to avoid those refs ending with "^{}"
grob Aug 16, 2021
4ae139c
log process errors with debug level to avoid cluttering test output (…
grob Aug 16, 2021
a015769
added tests for git module
grob Aug 16, 2021
c52dd56
added test repo
grob Aug 16, 2021
09611c3
map custom git schemes to their supported one
grob Aug 16, 2021
2c03100
refactor: removed constants module (most of these were unused) and un…
grob Sep 25, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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