buildframework/helium/sf/java/environment/src/com/nokia/helium/environment/Environment.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/buildframework/helium/sf/java/environment/src/com/nokia/helium/environment/Environment.java Fri Aug 13 14:59:05 2010 +0300
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * This component and the accompanying materials are made available
+ * under the terms of the License "Eclipse Public License v1.0"
+ * which accompanies this distribution, and is available
+ * at the URL "http://www.eclipse.org/legal/epl-v10.html".
+ *
+ * Initial Contributors:
+ * Nokia Corporation - initial contribution.
+ *
+ * Contributors:
+ *
+ * Description:
+ *
+ */
+
+package com.nokia.helium.environment;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.tools.ant.Project;
+
+import com.nokia.helium.environment.ant.types.ExecutableInfo;
+
+/**
+ * Represents the environment of the computer in terms of executables, etc. Typically scans for
+ * executables that have been run during the build.
+ */
+public class Environment {
+ private static final String[] WINDOWS_EXE_EXTENSIONS = { ".exe", ".bat", ".cmd" };
+ private static final String STDERR_OUTPUT = "stderr";
+ private static final String[] DEFAULT_EXECUTABLES = { "java", "ant" };
+
+ private Project project;
+ /** List of known executables. */
+ private List<Executable> executables = new ArrayList<Executable>();
+ /** List of meta information about executables. */
+ private Map<String, ExecutableInfo> defs = new HashMap<String, ExecutableInfo>();
+
+ public Environment(Project project) {
+ this.project = project;
+ }
+
+ public void setExecutableDefs(List<ExecutableInfo> executableDefs) {
+ for (Iterator<ExecutableInfo> iterator = executableDefs.iterator(); iterator.hasNext();) {
+ ExecutableInfo execDef = (ExecutableInfo) iterator.next();
+ defs.put(execDef.getName(), execDef);
+ }
+ }
+
+ public List<Executable> getExecutables() {
+ return executables;
+ }
+
+ public void scan(List<String> execCalls) throws IOException {
+ addDefaultExecutables();
+ parseExecLog(execCalls);
+ addExecsWithInfo();
+ populateExecutables(executables);
+ }
+
+ /**
+ * Adds default executables to the list that must have been run because Ant is running.
+ */
+ private void addDefaultExecutables() {
+
+ for (int i = 0; i < DEFAULT_EXECUTABLES.length; i++) {
+ Executable exe = new Executable(DEFAULT_EXECUTABLES[i]);
+ exe.setExecuted(true);
+ executables.add(exe);
+ }
+ }
+
+ /**
+ * Parses a log of calls to executables in CSV format.
+ *
+ * @param execLog
+ * @throws IOException
+ */
+ private void parseExecLog(List<String> execCalls) throws IOException {
+ for (Iterator<String> iterator = execCalls.iterator(); iterator.hasNext();) {
+ String execCall = (String) iterator.next();
+
+ File execFile = new File(execCall);
+ String name = execFile.getName();
+ String path = null;
+ // See if the full path is available in the exec call
+ if (execFile.getParentFile() != null) {
+ path = execFile.getCanonicalPath();
+ }
+ Executable runExec = new Executable(name);
+ runExec.setPath(path);
+ runExec.setExecuted(true);
+ if (!executables.contains(runExec)) {
+ executables.add(runExec);
+ }
+ }
+ }
+
+ /**
+ * Adds executables to the list based on the meta-information given in the configuration.
+ */
+ private void addExecsWithInfo() {
+ for (Iterator<String> iterator = defs.keySet().iterator(); iterator.hasNext();) {
+ String execName = (String) iterator.next();
+ Executable exec = new Executable(execName);
+ if (!executables.contains(exec)) {
+ executables.add(exec);
+ }
+ }
+ }
+
+ private void populateExecutables(List<Executable> executables) throws IOException {
+ for (Iterator<Executable> iterator = executables.iterator(); iterator.hasNext();) {
+ Executable exec = (Executable) iterator.next();
+ project.log("Checking executable: " + exec.toString(), Project.MSG_INFO);
+ File executableFile = findExecutableFile(exec);
+
+ if (executableFile != null) {
+ if (!findVersion(exec)) {
+ calculateAdditionalVersioningInfo(exec);
+ }
+ }
+ else {
+ project.log("Cannot find path for executable: " + exec.toString(), Project.MSG_DEBUG);
+ }
+ }
+ }
+
+ /**
+ * Finds an executable file based on the executable definition.
+ *
+ * @param exec An executable definition.
+ * @return The executable file.
+ * @throws IOException
+ */
+ private File findExecutableFile(final Executable exec) throws IOException {
+ File executableFile = null;
+
+ // See if the executable has a full path
+ String path = exec.getPath();
+ if (path != null) {
+ File file = new File(path);
+ executableFile = file;
+ exec.setPath(executableFile.getCanonicalPath());
+ }
+ // Or search the PATH
+ else {
+ String[] pathDirs = getPaths();
+ // Filter object to match executable filenames
+ FileFilter filter = new FileFilter() {
+ public boolean accept(File file) {
+ if (isFileExecutable(file)) {
+ // Find the first file in the directory that has the same start of the name
+ String exeNameNoExt = exec.getNameNoExt();
+
+ String name = file.getName();
+ if (name.contains(".")) {
+ name = name.substring(0, name.indexOf("."));
+ }
+
+ if (name.equals(exeNameNoExt) || name.startsWith(exeNameNoExt + ".")) {
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+ for (int i = 0; i < pathDirs.length; i++) {
+ File pathDir = new File(pathDirs[i]);
+ File[] executableFiles = pathDir.listFiles(filter);
+ if (executableFiles != null && executableFiles.length > 0) {
+ executableFile = executableFiles[0];
+ exec.setPath(executableFile.getCanonicalPath());
+ }
+ }
+ }
+ return executableFile;
+ }
+
+ private boolean isFileExecutable(File file) {
+ if (file.canExecute()) {
+ String os = System.getProperty("os.name").toLowerCase();
+ if (os.contains("windows") || os.contains("win32")) {
+ for (int i = 0; i < WINDOWS_EXE_EXTENSIONS.length; i++) {
+ if (file.getName().endsWith(WINDOWS_EXE_EXTENSIONS[i])) {
+ return true;
+ }
+ }
+ }
+ else {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private String[] getPaths() {
+ String pathEnvVar = System.getenv("Path");
+ String[] pathDirs = null;
+ if (pathEnvVar == null) {
+ pathEnvVar = System.getenv("PATH");
+ }
+ if (pathEnvVar != null) {
+ pathDirs = pathEnvVar.split(File.pathSeparator);
+ }
+ else {
+ pathDirs = new String[0];
+ }
+ return pathDirs;
+ }
+
+ private boolean findVersion(Executable exec) throws IOException {
+ // Get the executable additional data for this execution
+ ExecutableInfo def = defs.get(exec.getNameNoExt());
+ if (def != null && def.getVersionArgs() != null) {
+ String path = exec.getPath();
+ if (path == null) {
+ path = "";
+ }
+ String[] versionArgs = def.getVersionArgs().split(" ");
+ String[] commands = new String[versionArgs.length + 1];
+ commands[0] = path;
+ for (int i = 0; i < versionArgs.length; i++) {
+ commands[i + 1] = versionArgs[i].trim();
+ }
+ Process commandProcess = Runtime.getRuntime().exec(commands);
+
+ String output = def.getOutput();
+ StringBuilder text = new StringBuilder();
+ int dataRead = 0;
+ char[] chars = new char[1000];
+ if (output == null || !output.equals(STDERR_OUTPUT)) {
+ InputStream in = commandProcess.getInputStream();
+ InputStreamReader textIn = new InputStreamReader(in);
+ while (dataRead != -1) {
+ dataRead = textIn.read(chars, 0, chars.length);
+ if (dataRead != -1) {
+ text.append(chars, 0, dataRead);
+ }
+ }
+ }
+ InputStream err = commandProcess.getErrorStream();
+ InputStreamReader textErr = new InputStreamReader(err);
+ dataRead = 0;
+ while (dataRead != -1) {
+ dataRead = textErr.read(chars, 0, chars.length);
+ if (dataRead != -1) {
+ text.append(chars, 0, dataRead);
+ }
+ }
+ String versionText = text.toString();
+ if (def.getVersionRegex() != null) {
+ Pattern versionPattern = Pattern.compile(def.getVersionRegex());
+ Matcher versionMatch = versionPattern.matcher(versionText);
+ if (versionMatch.find()) {
+ String version = versionMatch.group(1);
+ exec.setVersion(version);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Calculate extra versioning info for the executable file. Used if cannot find a version value.
+ *
+ * @param exec The executable.
+ * @throws IOException If file cannot be read.
+ */
+ private void calculateAdditionalVersioningInfo(Executable exec) throws IOException {
+ calculateHash(exec);
+ File file = new File(exec.getPath());
+ exec.setLastModified(file.lastModified());
+ exec.setLength(file.length());
+ }
+
+ /**
+ * Calculate a hash value for the executable file.
+ *
+ * @param exec The executable.
+ * @throws IOException If file cannot be read.
+ */
+ private void calculateHash(Executable exec) throws IOException {
+ FileInputStream in = new FileInputStream(exec.getPath());
+ byte[] bytes = new byte[1000];
+ ByteArrayOutputStream fileBytes = new ByteArrayOutputStream();
+ int bytesRead = 0;
+ bytesRead = in.read(bytes);
+ while (bytesRead != -1) {
+ fileBytes.write(bytes, 0, bytesRead);
+ bytesRead = in.read(bytes);
+ }
+ MessageDigest digest;
+ String hash = "";
+ try {
+ digest = MessageDigest.getInstance("MD5");
+ digest.update(fileBytes.toByteArray());
+ byte[] hashBytes = digest.digest();
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < hashBytes.length; i++) {
+ builder.append(Byte.toString(hashBytes[i]));
+ }
+ hash = new String(builder.toString());
+ exec.setHash(hash);
+
+ }
+ catch (NoSuchAlgorithmException e) {
+ // Not expected to occur
+ e.printStackTrace();
+ }
+ }
+}