TAJO-737: Change version message when daemon starts up. (hyunsik)
Project: http://git-wip-us.apache.org/repos/asf/tajo/repo Commit: http://git-wip-us.apache.org/repos/asf/tajo/commit/bbf2461a Tree: http://git-wip-us.apache.org/repos/asf/tajo/tree/bbf2461a Diff: http://git-wip-us.apache.org/repos/asf/tajo/diff/bbf2461a Branch: refs/heads/window_function Commit: bbf2461a5bddc77b3597030976158e00ee88fe0d Parents: c367377 Author: Hyunsik Choi <[email protected]> Authored: Mon Apr 21 16:38:48 2014 +0900 Committer: Hyunsik Choi <[email protected]> Committed: Mon Apr 21 16:39:15 2014 +0900 ---------------------------------------------------------------------- CHANGES.txt | 2 + pom.xml | 1 + tajo-common/pom.xml | 45 +++ .../java/org/apache/tajo/util/StringUtils.java | 68 ++++ .../java/org/apache/tajo/util/VersionInfo.java | 177 ++++++++++ .../main/resources/tajo-version-info.properties | 26 ++ .../java/org/apache/tajo/master/TajoMaster.java | 2 +- .../java/org/apache/tajo/worker/TajoWorker.java | 2 +- tajo-maven-plugins/pom.xml | 88 +++++ .../tajo/maven/plugin/protoc/ProtocMojo.java | 114 ++++++ .../org/apache/tajo/maven/plugin/util/Exec.java | 117 +++++++ .../tajo/maven/plugin/util/FileSetUtils.java | 61 ++++ .../plugin/versioninfo/VersionInfoMojo.java | 344 +++++++++++++++++++ 13 files changed, 1045 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 7f22b06..7f1b175 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -153,6 +153,8 @@ Release 0.8.0 - unreleased IMPROVEMENTS + TAJO-737: Change version message when daemon starts up. (hyunsik) + TAJO-768: Improve the log4j configuration. (hyoungjunkim via jinho) TAJO-755: ALTER TABLESPACE LOCATION support. (hyunsilk) http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 964d984..6eea5c8 100644 --- a/pom.xml +++ b/pom.xml @@ -78,6 +78,7 @@ </properties> <modules> + <module>tajo-maven-plugins</module> <module>tajo-project</module> <module>tajo-common</module> <module>tajo-algebra</module> http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-common/pom.xml ---------------------------------------------------------------------- diff --git a/tajo-common/pom.xml b/tajo-common/pom.xml index 35ac3e5..f334380 100644 --- a/tajo-common/pom.xml +++ b/tajo-common/pom.xml @@ -46,8 +46,53 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xs </repositories> <build> + <!-- + Include all files in src/main/resources. By default, do not apply property + substitution (filtering=false), but do apply property substitution to + tajo-version-info.properties (filtering=true). This will substitute the + version information correctly, but prevent Maven from altering other files + like tajo-default.xml. + --> + <resources> + <resource> + <directory>${basedir}/src/main/resources</directory> + <excludes> + <exclude>tajo-version-info.properties</exclude> + </excludes> + <filtering>false</filtering> + </resource> + <resource> + <directory>${basedir}/src/main/resources</directory> + <includes> + <include>tajo-version-info.properties</include> + </includes> + <filtering>true</filtering> + </resource> + </resources> <plugins> <plugin> + <groupId>org.apache.tajo</groupId> + <artifactId>tajo-maven-plugins</artifactId> + <executions> + <execution> + <id>version-info</id> + <phase>generate-resources</phase> + <goals> + <goal>version-info</goal> + </goals> + <configuration> + <source> + <directory>${basedir}/src/main</directory> + <includes> + <include>java/**/*.java</include> + <include>proto/**/*.proto</include> + </includes> + </source> + </configuration> + </execution> + </executions> + </plugin> + <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-common/src/main/java/org/apache/tajo/util/StringUtils.java ---------------------------------------------------------------------- diff --git a/tajo-common/src/main/java/org/apache/tajo/util/StringUtils.java b/tajo-common/src/main/java/org/apache/tajo/util/StringUtils.java index 32edc31..ed9014d 100644 --- a/tajo-common/src/main/java/org/apache/tajo/util/StringUtils.java +++ b/tajo-common/src/main/java/org/apache/tajo/util/StringUtils.java @@ -18,9 +18,20 @@ package org.apache.tajo.util; +import org.apache.commons.lang.SystemUtils; +import org.apache.hadoop.util.ShutdownHookManager; +import org.apache.hadoop.util.SignalLogger; + +import java.util.Arrays; + public class StringUtils { /** + * Priority of the StringUtils shutdown hook. + */ + public static final int SHUTDOWN_HOOK_PRIORITY = 0; + + /** * * Given the time in long milliseconds, returns a * String in the format X hrs, Y mins, S sec, M msecs @@ -97,4 +108,61 @@ public class StringUtils { public static String escapeLike(String literal) { return literal.replaceAll(LIKE_SPECIAL_CHARACTERS, "\\\\$1"); } + + /** + * Return a message for logging. + * @param prefix prefix keyword for the message + * @param msg content of the message + * @return a message for logging + */ + private static String toStartupShutdownString(String prefix, String [] msg) { + StringBuilder b = new StringBuilder(prefix); + b.append("\n/************************************************************"); + for(String s : msg) + b.append("\n" + prefix + s); + b.append("\n************************************************************/"); + return b.toString(); + } + + /** + * Print a log message for starting up and shutting down + * @param clazz the class of the server + * @param args arguments + * @param LOG the target log object + */ + public static void startupShutdownMessage(Class<?> clazz, String[] args, + final org.apache.commons.logging.Log LOG) { + final String hostname = org.apache.hadoop.net.NetUtils.getHostname(); + final String classname = clazz.getSimpleName(); + LOG.info( + toStartupShutdownString("STARTUP_MSG: ", new String[] { + "Starting " + classname, + " host = " + hostname, + " args = " + Arrays.asList(args), + " version = " + org.apache.tajo.util.VersionInfo.getVersion(), + " classpath = " + System.getProperty("java.class.path"), + " build = " + org.apache.tajo.util.VersionInfo.getUrl() + " -r " + + org.apache.tajo.util.VersionInfo.getRevision() + + "; compiled by '" + org.apache.tajo.util.VersionInfo.getUser() + + "' on " + org.apache.tajo.util.VersionInfo.getDate(), + " java = " + System.getProperty("java.version") } + ) + ); + + if (SystemUtils.IS_OS_UNIX) { + try { + SignalLogger.INSTANCE.register(LOG); + } catch (Throwable t) { + LOG.warn("failed to register any UNIX signal loggers: ", t); + } + } + ShutdownHookManager.get().addShutdownHook( + new Runnable() { + @Override + public void run() { + LOG.info(toStartupShutdownString("SHUTDOWN_MSG: ", new String[]{ + "Shutting down " + classname + " at " + hostname})); + } + }, SHUTDOWN_HOOK_PRIORITY); + } } http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-common/src/main/java/org/apache/tajo/util/VersionInfo.java ---------------------------------------------------------------------- diff --git a/tajo-common/src/main/java/org/apache/tajo/util/VersionInfo.java b/tajo-common/src/main/java/org/apache/tajo/util/VersionInfo.java new file mode 100644 index 0000000..39e0f54 --- /dev/null +++ b/tajo-common/src/main/java/org/apache/tajo/util/VersionInfo.java @@ -0,0 +1,177 @@ +package org.apache.tajo.util; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import org.apache.hadoop.util.ClassUtil; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +/** + * This class returns build information about Hadoop components. + */ [email protected] [email protected] +public class VersionInfo { + private static final Log LOG = LogFactory.getLog(VersionInfo.class); + + private Properties info; + + protected VersionInfo(String component) { + info = new Properties(); + String versionInfoFile = component + "-version-info.properties"; + try { + InputStream is = Thread.currentThread().getContextClassLoader() + .getResourceAsStream(versionInfoFile); + if (is == null) { + throw new IOException("Resource not found"); + } + info.load(is); + } catch (IOException ex) { + LogFactory.getLog(getClass()).warn("Could not read '" + + versionInfoFile + "', " + ex.toString(), ex); + } + } + + protected String _getVersion() { + return info.getProperty("version", "Unknown"); + } + + protected String _getRevision() { + return info.getProperty("revision", "Unknown"); + } + + protected String _getBranch() { + return info.getProperty("branch", "Unknown"); + } + + protected String _getDate() { + return info.getProperty("date", "Unknown"); + } + + protected String _getUser() { + return info.getProperty("user", "Unknown"); + } + + protected String _getUrl() { + return info.getProperty("url", "Unknown"); + } + + protected String _getSrcChecksum() { + return info.getProperty("srcChecksum", "Unknown"); + } + + protected String _getBuildVersion(){ + return getVersion() + + " from " + _getRevision() + + " by " + _getUser() + + " source checksum " + _getSrcChecksum(); + } + + protected String _getProtocVersion() { + return info.getProperty("protocVersion", "Unknown"); + } + + private static VersionInfo TAJO_VERSION_INFO = new VersionInfo("tajo"); + /** + * Get the Hadoop version. + * @return the Hadoop version string, eg. "0.6.3-dev" + */ + public static String getVersion() { + return TAJO_VERSION_INFO._getVersion(); + } + + /** + * Get the subversion revision number for the root directory + * @return the revision number, eg. "451451" + */ + public static String getRevision() { + return TAJO_VERSION_INFO._getRevision(); + } + + /** + * Get the branch on which this originated. + * @return The branch name, e.g. "trunk" or "branches/branch-0.20" + */ + public static String getBranch() { + return TAJO_VERSION_INFO._getBranch(); + } + + /** + * The date that Hadoop was compiled. + * @return the compilation date in unix date format + */ + public static String getDate() { + return TAJO_VERSION_INFO._getDate(); + } + + /** + * The user that compiled Hadoop. + * @return the username of the user + */ + public static String getUser() { + return TAJO_VERSION_INFO._getUser(); + } + + /** + * Get the subversion URL for the root Hadoop directory. + */ + public static String getUrl() { + return TAJO_VERSION_INFO._getUrl(); + } + + /** + * Get the checksum of the source files from which Hadoop was + * built. + **/ + public static String getSrcChecksum() { + return TAJO_VERSION_INFO._getSrcChecksum(); + } + + /** + * Returns the buildVersion which includes version, + * revision, user and date. + */ + public static String getBuildVersion(){ + return TAJO_VERSION_INFO._getBuildVersion(); + } + + /** + * Returns the protoc version used for the build. + */ + public static String getProtocVersion(){ + return TAJO_VERSION_INFO._getProtocVersion(); + } + + public static void main(String[] args) { + LOG.debug("version: "+ getVersion()); + System.out.println("Tajo " + getVersion()); + System.out.println("Git " + getUrl() + " -r " + getRevision()); + System.out.println("Compiled by " + getUser() + " on " + getDate()); + System.out.println("Compiled with protoc " + getProtocVersion()); + System.out.println("From source with checksum " + getSrcChecksum()); + System.out.println("This command was run using " + ClassUtil.findContainingJar(VersionInfo.class)); + } +} + http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-common/src/main/resources/tajo-version-info.properties ---------------------------------------------------------------------- diff --git a/tajo-common/src/main/resources/tajo-version-info.properties b/tajo-common/src/main/resources/tajo-version-info.properties new file mode 100644 index 0000000..ad9a24d --- /dev/null +++ b/tajo-common/src/main/resources/tajo-version-info.properties @@ -0,0 +1,26 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +version=${pom.version} +revision=${version-info.scm.commit} +branch=${version-info.scm.branch} +user=${user.name} +date=${version-info.build.time} +url=${version-info.scm.uri} +srcChecksum=${version-info.source.md5} +protocVersion=${protobuf.version} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-core/src/main/java/org/apache/tajo/master/TajoMaster.java ---------------------------------------------------------------------- diff --git a/tajo-core/src/main/java/org/apache/tajo/master/TajoMaster.java b/tajo-core/src/main/java/org/apache/tajo/master/TajoMaster.java index 9d54bb5..dfae300 100644 --- a/tajo-core/src/main/java/org/apache/tajo/master/TajoMaster.java +++ b/tajo-core/src/main/java/org/apache/tajo/master/TajoMaster.java @@ -30,7 +30,6 @@ import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.io.IOUtils; import org.apache.hadoop.service.CompositeService; import org.apache.hadoop.util.ShutdownHookManager; -import org.apache.hadoop.util.StringUtils; import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.event.AsyncDispatcher; import org.apache.hadoop.yarn.event.EventHandler; @@ -58,6 +57,7 @@ import org.apache.tajo.storage.StorageManagerFactory; import org.apache.tajo.util.ClassUtil; import org.apache.tajo.util.CommonTestingUtil; import org.apache.tajo.util.NetUtils; +import org.apache.tajo.util.StringUtils; import org.apache.tajo.util.metrics.TajoSystemMetrics; import org.apache.tajo.webapp.QueryExecutorServlet; import org.apache.tajo.webapp.StaticHttpServer; http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-core/src/main/java/org/apache/tajo/worker/TajoWorker.java ---------------------------------------------------------------------- diff --git a/tajo-core/src/main/java/org/apache/tajo/worker/TajoWorker.java b/tajo-core/src/main/java/org/apache/tajo/worker/TajoWorker.java index 0b8d6c2..3768edf 100644 --- a/tajo-core/src/main/java/org/apache/tajo/worker/TajoWorker.java +++ b/tajo-core/src/main/java/org/apache/tajo/worker/TajoWorker.java @@ -27,7 +27,6 @@ import org.apache.hadoop.fs.LocalDirAllocator; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.shell.PathData; import org.apache.hadoop.service.CompositeService; -import org.apache.hadoop.util.StringUtils; import org.apache.hadoop.yarn.util.RackResolver; import org.apache.tajo.QueryId; import org.apache.tajo.TajoConstants; @@ -45,6 +44,7 @@ import org.apache.tajo.rpc.RpcConnectionPool; import org.apache.tajo.rpc.protocolrecords.PrimitiveProtos; import org.apache.tajo.util.CommonTestingUtil; import org.apache.tajo.util.NetUtils; +import org.apache.tajo.util.StringUtils; import org.apache.tajo.util.TajoIdUtils; import org.apache.tajo.util.metrics.TajoSystemMetrics; import org.apache.tajo.webapp.StaticHttpServer; http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-maven-plugins/pom.xml ---------------------------------------------------------------------- diff --git a/tajo-maven-plugins/pom.xml b/tajo-maven-plugins/pom.xml new file mode 100644 index 0000000..7de67ef --- /dev/null +++ b/tajo-maven-plugins/pom.xml @@ -0,0 +1,88 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. See accompanying LICENSE file. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.tajo</groupId> + <artifactId>tajo-project</artifactId> + <version>0.8.0-SNAPSHOT</version> + <relativePath>../tajo-project</relativePath> + </parent> + <groupId>org.apache.tajo</groupId> + <artifactId>tajo-maven-plugins</artifactId> + <packaging>maven-plugin</packaging> + <name>Tajo Maven Plugins</name> + <properties> + <maven.dependency.version>3.0</maven.dependency.version> + </properties> + <dependencies> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-plugin-api</artifactId> + <version>${maven.dependency.version}</version> + </dependency> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-core</artifactId> + <version>${maven.dependency.version}</version> + </dependency> + <dependency> + <groupId>org.apache.maven.plugin-tools</groupId> + <artifactId>maven-plugin-annotations</artifactId> + <version>${maven.dependency.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>3.8.1</version> + <scope>test</scope> + </dependency> + </dependencies> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-plugin-plugin</artifactId> + <version>${maven.dependency.version}</version> + <configuration> + <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound> + </configuration> + <executions> + <execution> + <id>mojo-descriptor</id> + <goals> + <goal>descriptor</goal> + </goals> + </execution> + </executions> + </plugin> + <!-- + Skip Clover instrumentation for this module to prevent error finding Clover + classes during plugin execution when running a build with Clover enabled. + --> + <plugin> + <groupId>com.atlassian.maven.plugins</groupId> + <artifactId>maven-clover2-plugin</artifactId> + <version>3.0.5</version> + <configuration> + <skip>true</skip> + </configuration> + </plugin> + </plugins> + </build> +</project> http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/protoc/ProtocMojo.java ---------------------------------------------------------------------- diff --git a/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/protoc/ProtocMojo.java b/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/protoc/ProtocMojo.java new file mode 100644 index 0000000..498f85d --- /dev/null +++ b/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/protoc/ProtocMojo.java @@ -0,0 +1,114 @@ +/* + * Copyright 2012 The Apache Software Foundation. + * + * 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.apache.tajo.maven.plugin.protoc; + +import org.apache.tajo.maven.plugin.util.Exec; +import org.apache.tajo.maven.plugin.util.FileSetUtils; +import org.apache.maven.model.FileSet; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; +import org.apache.tajo.maven.plugin.util.Exec; +import org.apache.tajo.maven.plugin.util.FileSetUtils; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + + +@Mojo(name="protoc", defaultPhase = LifecyclePhase.GENERATE_SOURCES) +public class ProtocMojo extends AbstractMojo { + + @Parameter(defaultValue="${project}") + private MavenProject project; + + @Parameter + private File[] imports; + + @Parameter(defaultValue="${project.build.directory}/generated-sources/java") + private File output; + + @Parameter(required=true) + private FileSet source; + + @Parameter + private String protocCommand; + + @Parameter(required=true) + private String protocVersion; + + public void execute() throws MojoExecutionException { + try { + if (protocCommand == null || protocCommand.trim().isEmpty()) { + protocCommand = "protoc"; + } + List<String> command = new ArrayList<String>(); + command.add(protocCommand); + command.add("--version"); + Exec exec = new Exec(this); + List<String> out = new ArrayList<String>(); + if (exec.run(command, out) == 127) { + getLog().error("protoc, not found at: " + protocCommand); + throw new MojoExecutionException("protoc failure"); + } else { + if (out.isEmpty()) { + getLog().error("stdout: " + out); + throw new MojoExecutionException( + "'protoc --version' did not return a version"); + } else { + if (!out.get(0).endsWith(protocVersion)) { + throw new MojoExecutionException( + "protoc version is '" + out.get(0) + "', expected version is '" + + protocVersion + "'"); + } + } + } + if (!output.mkdirs()) { + if (!output.exists()) { + throw new MojoExecutionException("Could not create directory: " + + output); + } + } + command = new ArrayList<String>(); + command.add(protocCommand); + command.add("--java_out=" + output.getCanonicalPath()); + if (imports != null) { + for (File i : imports) { + command.add("-I" + i.getCanonicalPath()); + } + } + for (File f : FileSetUtils.convertFileSetToFiles(source)) { + command.add(f.getCanonicalPath()); + } + exec = new Exec(this); + out = new ArrayList<String>(); + if (exec.run(command, out) != 0) { + getLog().error("protoc compiler error"); + for (String s : out) { + getLog().error(s); + } + throw new MojoExecutionException("protoc failure"); + } + } catch (Throwable ex) { + throw new MojoExecutionException(ex.toString(), ex); + } + project.addCompileSourceRoot(output.getAbsolutePath()); + } + +} http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/util/Exec.java ---------------------------------------------------------------------- diff --git a/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/util/Exec.java b/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/util/Exec.java new file mode 100644 index 0000000..89ba6fb --- /dev/null +++ b/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/util/Exec.java @@ -0,0 +1,117 @@ +/* + * Copyright 2012 The Apache Software Foundation. + * + * 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.apache.tajo.maven.plugin.util; + +import org.apache.maven.plugin.Mojo; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; + +/** + * Exec is a helper class for executing an external process from a mojo. + */ +public class Exec { + private Mojo mojo; + + /** + * Creates a new Exec instance for executing an external process from the given + * mojo. + * + * @param mojo Mojo executing external process + */ + public Exec(Mojo mojo) { + this.mojo = mojo; + } + + /** + * Runs the specified command and saves each line of the command's output to + * the given list. + * + * @param command List<String> containing command and all arguments + * @param output List<String> in/out parameter to receive command output + * @return int exit code of command + */ + public int run(List<String> command, List<String> output) { + int retCode = 1; + ProcessBuilder pb = new ProcessBuilder(command); + try { + Process p = pb.start(); + OutputBufferThread stdOut = new OutputBufferThread(p.getInputStream()); + OutputBufferThread stdErr = new OutputBufferThread(p.getErrorStream()); + stdOut.start(); + stdErr.start(); + retCode = p.waitFor(); + if (retCode != 0) { + mojo.getLog().warn(command + " failed with error code " + retCode); + for (String s : stdErr.getOutput()) { + mojo.getLog().debug(s); + } + } + stdOut.join(); + stdErr.join(); + output.addAll(stdOut.getOutput()); + } catch (Exception ex) { + mojo.getLog().warn(command + " failed: " + ex.toString()); + } + return retCode; + } + + /** + * OutputBufferThread is a background thread for consuming and storing output + * of the external process. + */ + private static class OutputBufferThread extends Thread { + private List<String> output; + private BufferedReader reader; + + /** + * Creates a new OutputBufferThread to consume the given InputStream. + * + * @param is InputStream to consume + */ + public OutputBufferThread(InputStream is) { + this.setDaemon(true); + output = new ArrayList<String>(); + reader = new BufferedReader(new InputStreamReader(is)); + } + + @Override + public void run() { + try { + String line = reader.readLine(); + while (line != null) { + output.add(line); + line = reader.readLine(); + } + } catch (IOException ex) { + throw new RuntimeException("make failed with error code " + ex.toString()); + } + } + + /** + * Returns every line consumed from the input. + * + * @return List<String> every line consumed from the input + */ + public List<String> getOutput() { + return output; + } + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/util/FileSetUtils.java ---------------------------------------------------------------------- diff --git a/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/util/FileSetUtils.java b/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/util/FileSetUtils.java new file mode 100644 index 0000000..f034f44 --- /dev/null +++ b/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/util/FileSetUtils.java @@ -0,0 +1,61 @@ +/* + * Copyright 2012 The Apache Software Foundation. + * + * 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.apache.tajo.maven.plugin.util; + +import org.apache.maven.model.FileSet; +import org.codehaus.plexus.util.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +/** + * FileSetUtils contains helper methods for mojo implementations that need to + * work with a Maven FileSet. + */ +public class FileSetUtils { + + /** + * Returns a string containing every element of the given list, with each + * element separated by a comma. + * + * @param list List of all elements + * @return String containing every element, comma-separated + */ + private static String getCommaSeparatedList(List list) { + StringBuilder buffer = new StringBuilder(); + String separator = ""; + for (Object e : list) { + buffer.append(separator).append(e); + separator = ","; + } + return buffer.toString(); + } + + /** + * Converts a Maven FileSet to a list of File objects. + * + * @param source FileSet to convert + * @return List<File> containing every element of the FileSet as a File + * @throws IOException if an I/O error occurs while trying to find the files + */ + @SuppressWarnings("unchecked") + public static List<File> convertFileSetToFiles(FileSet source) throws IOException { + String includes = getCommaSeparatedList(source.getIncludes()); + String excludes = getCommaSeparatedList(source.getExcludes()); + return FileUtils.getFiles(new File(source.getDirectory()), includes, excludes); + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/bbf2461a/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/versioninfo/VersionInfoMojo.java ---------------------------------------------------------------------- diff --git a/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/versioninfo/VersionInfoMojo.java b/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/versioninfo/VersionInfoMojo.java new file mode 100644 index 0000000..5347f40 --- /dev/null +++ b/tajo-maven-plugins/src/main/java/org/apache/tajo/maven/plugin/versioninfo/VersionInfoMojo.java @@ -0,0 +1,344 @@ +/* + * Copyright 2012 The Apache Software Foundation. + * + * 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.apache.tajo.maven.plugin.versioninfo; + +import org.apache.tajo.maven.plugin.util.Exec; +import org.apache.tajo.maven.plugin.util.FileSetUtils; +import org.apache.maven.model.FileSet; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; +import org.apache.tajo.maven.plugin.util.Exec; +import org.apache.tajo.maven.plugin.util.FileSetUtils; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import java.util.TimeZone; + +/** + * VersionInfoMojo calculates information about the current version of the + * codebase and exports the information as properties for further use in a Maven + * build. The version information includes build time, SCM URI, SCM branch, SCM + * commit, and an MD5 checksum of the contents of the files in the codebase. + */ +@Mojo(name="version-info") +public class VersionInfoMojo extends AbstractMojo { + + @Parameter(defaultValue="${project}") + private MavenProject project; + + @Parameter(required=true) + private FileSet source; + + @Parameter(defaultValue="version-info.build.time") + private String buildTimeProperty; + + @Parameter(defaultValue="version-info.source.md5") + private String md5Property; + + @Parameter(defaultValue="version-info.scm.uri") + private String scmUriProperty; + + @Parameter(defaultValue="version-info.scm.branch") + private String scmBranchProperty; + + @Parameter(defaultValue="version-info.scm.commit") + private String scmCommitProperty; + + @Parameter(defaultValue="git") + private String gitCommand; + + @Parameter(defaultValue="svn") + private String svnCommand; + + private enum SCM {NONE, SVN, GIT} + + @Override + public void execute() throws MojoExecutionException { + try { + SCM scm = determineSCM(); + project.getProperties().setProperty(buildTimeProperty, getBuildTime()); + project.getProperties().setProperty(scmUriProperty, getSCMUri(scm)); + project.getProperties().setProperty(scmBranchProperty, getSCMBranch(scm)); + project.getProperties().setProperty(scmCommitProperty, getSCMCommit(scm)); + project.getProperties().setProperty(md5Property, computeMD5()); + } catch (Throwable ex) { + throw new MojoExecutionException(ex.toString(), ex); + } + } + + /** + * Returns a string representing current build time. + * + * @return String representing current build time + */ + private String getBuildTime() { + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + return dateFormat.format(new Date()); + } + private List<String> scmOut; + + /** + * Determines which SCM is in use (Subversion, git, or none) and captures + * output of the SCM command for later parsing. + * + * @return SCM in use for this build + * @throws Exception if any error occurs attempting to determine SCM + */ + private SCM determineSCM() throws Exception { + Exec exec = new Exec(this); + SCM scm = SCM.NONE; + scmOut = new ArrayList<String>(); + int ret = exec.run(Arrays.asList(svnCommand, "info"), scmOut); + if (ret == 0) { + scm = SCM.SVN; + } else { + ret = exec.run(Arrays.asList(gitCommand, "branch"), scmOut); + if (ret == 0) { + ret = exec.run(Arrays.asList(gitCommand, "remote", "-v"), scmOut); + if (ret != 0) { + scm = SCM.NONE; + scmOut = null; + } else { + ret = exec.run(Arrays.asList(gitCommand, "log", "-n", "1"), scmOut); + if (ret != 0) { + scm = SCM.NONE; + scmOut = null; + } else { + scm = SCM.GIT; + } + } + } + } + if (scmOut != null) { + getLog().debug(scmOut.toString()); + } + getLog().info("SCM: " + scm); + return scm; + } + + /** + * Return URI and branch of Subversion repository. + * + * @param str String Subversion info output containing URI and branch + * @return String[] containing URI and branch + */ + private String[] getSvnUriInfo(String str) { + String[] res = new String[]{"Unknown", "Unknown"}; + try { + String path = str; + int index = path.indexOf("trunk"); + if (index > -1) { + res[0] = path.substring(0, index - 1); + res[1] = "trunk"; + } else { + index = path.indexOf("branches"); + if (index > -1) { + res[0] = path.substring(0, index - 1); + int branchIndex = index + "branches".length() + 1; + index = path.indexOf("/", branchIndex); + if (index > -1) { + res[1] = path.substring(branchIndex, index); + } else { + res[1] = path.substring(branchIndex); + } + } + } + } catch (Exception ex) { + getLog().warn("Could not determine URI & branch from SVN URI: " + str); + } + return res; + } + + /** + * Parses SCM output and returns URI of SCM. + * + * @param scm SCM in use for this build + * @return String URI of SCM + */ + private String getSCMUri(SCM scm) { + String uri = "Unknown"; + switch (scm) { + case SVN: + for (String s : scmOut) { + if (s.startsWith("URL:")) { + uri = s.substring(4).trim(); + uri = getSvnUriInfo(uri)[0]; + break; + } + } + break; + case GIT: + for (String s : scmOut) { + if (s.startsWith("origin") && s.endsWith("(fetch)")) { + uri = s.substring("origin".length()); + uri = uri.substring(0, uri.length() - "(fetch)".length()); + break; + } + } + break; + } + return uri.trim(); + } + + /** + * Parses SCM output and returns commit of SCM. + * + * @param scm SCM in use for this build + * @return String commit of SCM + */ + private String getSCMCommit(SCM scm) { + String commit = "Unknown"; + switch (scm) { + case SVN: + for (String s : scmOut) { + if (s.startsWith("Revision:")) { + commit = s.substring("Revision:".length()); + break; + } + } + break; + case GIT: + for (String s : scmOut) { + if (s.startsWith("commit")) { + commit = s.substring("commit".length()); + break; + } + } + break; + } + return commit.trim(); + } + + /** + * Parses SCM output and returns branch of SCM. + * + * @param scm SCM in use for this build + * @return String branch of SCM + */ + private String getSCMBranch(SCM scm) { + String branch = "Unknown"; + switch (scm) { + case SVN: + for (String s : scmOut) { + if (s.startsWith("URL:")) { + branch = s.substring(4).trim(); + branch = getSvnUriInfo(branch)[1]; + break; + } + } + break; + case GIT: + for (String s : scmOut) { + if (s.startsWith("*")) { + branch = s.substring("*".length()); + break; + } + } + break; + } + return branch.trim(); + } + + /** + * Reads and returns the full contents of the specified file. + * + * @param file File to read + * @return byte[] containing full contents of file + * @throws IOException if there is an I/O error while reading the file + */ + private byte[] readFile(File file) throws IOException { + RandomAccessFile raf = new RandomAccessFile(file, "r"); + byte[] buffer = new byte[(int) raf.length()]; + raf.readFully(buffer); + raf.close(); + return buffer; + } + + /** + * Given a list of files, computes and returns an MD5 checksum of the full + * contents of all files. + * + * @param files List<File> containing every file to input into the MD5 checksum + * @return byte[] calculated MD5 checksum + * @throws IOException if there is an I/O error while reading a file + * @throws NoSuchAlgorithmException if the MD5 algorithm is not supported + */ + private byte[] computeMD5(List<File> files) throws IOException, NoSuchAlgorithmException { + MessageDigest md5 = MessageDigest.getInstance("MD5"); + for (File file : files) { + getLog().debug("Computing MD5 for: " + file); + md5.update(readFile(file)); + } + return md5.digest(); + } + + /** + * Converts bytes to a hexadecimal string representation and returns it. + * + * @param array byte[] to convert + * @return String containing hexadecimal representation of bytes + */ + private String byteArrayToString(byte[] array) { + StringBuilder sb = new StringBuilder(); + for (byte b : array) { + sb.append(Integer.toHexString(0xff & b)); + } + return sb.toString(); + } + + /** + * Computes and returns an MD5 checksum of the contents of all files in the + * input Maven FileSet. + * + * @return String containing hexadecimal representation of MD5 checksum + * @throws Exception if there is any error while computing the MD5 checksum + */ + private String computeMD5() throws Exception { + List<File> files = FileSetUtils.convertFileSetToFiles(source); + // File order of MD5 calculation is significant. Sorting is done on + // unix-format names, case-folded, in order to get a platform-independent + // sort and calculate the same MD5 on all platforms. + Collections.sort(files, new Comparator<File>() { + @Override + public int compare(File lhs, File rhs) { + return normalizePath(lhs).compareTo(normalizePath(rhs)); + } + + private String normalizePath(File file) { + return file.getPath().toUpperCase().replaceAll("\\\\", "/"); + } + }); + byte[] md5 = computeMD5(files); + String md5str = byteArrayToString(md5); + getLog().info("Computed MD5: " + md5str); + return md5str; + } +}
