buildframework/helium/sf/java/environment/src/com/nokia/helium/environment/Environment.java
changeset 628 7c4a911dc066
child 645 b8d81fa19e7d
--- /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();
+        }
+    }
+}