/* * Copyright 2014-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.liquigraph.cli; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import org.liquigraph.core.api.Liquigraph; import org.liquigraph.core.configuration.ConfigurationBuilder; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static com.google.common.base.Throwables.propagate; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; public class LiquigraphCli { private static final Logger LOGGER = LoggerFactory.getLogger(LiquigraphCli.class); @Parameter( names = {"--help", "-h"}, description = "Get this help", help = true ) private boolean help; @Parameter( names = {"--version", "-v"}, description = "Show the version", help = true ) private boolean version; @Parameter( names = {"--changelog", "-c"}, description = "Master Liquigraph changelog location.\n" + "\t Prefix with 'classpath:' if location is in classpath", required = true ) private String changelog; @Parameter( names = {"--graph-db-uri", "-g"}, description = "Graph JDBC URI:\n" + "\t- jdbc:neo4j:http://host:port/\n" + "\t- jdbc:neo4j:https://host:port/\n" + "\t- jdbc:neo4j:bolt://host:port/\n", required = true ) private String graphDbUri; @Parameter( names = {"--username", "-u"}, description = "Graph DB username (remote only)" ) private String username; @Parameter( names = {"--password", "-p"}, description = "Graph DB password (remote only)", password = true ) private String password; @Parameter( names = {"--execution-contexts", "-x"}, description = "Comma-separated list of Liquigraph execution contexts" ) private String executionContexts = ""; @Parameter( names = {"--dry-run-output-directory", "-d"}, description = "Output directory path into which changeset queries will be written. " + "Not setting this option will trigger RUN mode." ) private String dryRunOutputDirectory; public static void main(String[] args) { LiquigraphCli cli = new LiquigraphCli(); JCommander commander = new JCommander(cli, args); commander.setProgramName("liquigraph"); if (cli.help) { commander.usage(); return; } if (cli.version) { printVersion(); return; } ConfigurationBuilder builder = new ConfigurationBuilder() .withMasterChangelogLocation(fileName(cli.changelog)) .withUri(cli.graphDbUri) .withUsername(cli.username) .withPassword(cli.password) .withExecutionContexts(executionContexts(cli.executionContexts)) .withClassLoader(classloader(parentFolder(cli.changelog), cli.dryRunOutputDirectory)); String outputDirectory = cli.dryRunOutputDirectory; if (outputDirectory != null) { builder.withDryRunMode(Paths.get(outputDirectory)); } else { builder.withRunMode(); } new Liquigraph().runMigrations( builder.build() ); } private static void printVersion() { Optional<String> version = getVersion(); System.out.println(version.or("Unknown version!")); } private static Optional<String> getVersion() { try (InputStream propsIs = LiquigraphCli.class.getResourceAsStream("/liquigraph-cli.properties")) { if (propsIs != null) { Properties props = new Properties(); props.load(propsIs); return Optional.fromNullable(props.getProperty("liquigraph.version")); } } catch (IOException e) { LOGGER.error("An exception occurred while loading the properties", e); } return Optional.absent(); } private static String fileName(String changelog) { return new File(changelog).getName(); } private static String parentFolder(String changelog) { try { return new File(changelog).getCanonicalFile().getParent(); } catch (IOException e) { throw new RuntimeException(e.getMessage(), e); } } private static Collection<String> executionContexts(String executionContexts) { if (executionContexts.isEmpty()) { return emptyList(); } Collection<String> result = new ArrayList<>(); for (String context : asList(executionContexts.split(","))) { result.add(context.trim()); } return result; } private static ClassLoader classloader(String changelog, String dryRunOutputDirectory) { ImmutableList.Builder<URL> resources = ImmutableList.builder(); try { resources.add(toUrl(changelog)); if (dryRunOutputDirectory != null) { resources.add(toUrl(dryRunOutputDirectory)); } } catch (MalformedURLException e) { throw propagate(e); } Collection<URL> urls = resources.build(); return new URLClassLoader(urls.toArray(new URL[urls.size()])); } private static URL toUrl(String location) throws MalformedURLException { return new File(location).toURI().toURL(); } }