/******************************************************************************* * Copyright (c) 2008, 2011 Thomas Holland (thomas@innot.de) and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Thomas Holland - initial API and implementation *******************************************************************************/ package de.innot.avreclipse.core.paths.posix; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import org.eclipse.cdt.utils.spawner.ProcessFactory; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import de.innot.avreclipse.core.paths.AVRPath; import de.innot.avreclipse.core.paths.SystemPathHelper; /** * Gets the actual system paths to the AVR-GCC Toolchain and some config files. * * As these path can be almost everywhere (or not exist at all), this class tries to get the * location with the following methods: * <ol> * <li><code>which</code> command to look in the current $PATH</li> * <li><code>find</code> command to search certain parts of the filesystem. Currently the * following paths are checked (in this order) * <ul> * <li><code>/usr/bin</code></li> * <li><code>/usr/lib</code></li> * <li><code>disabled /usr/</code></li> * <li><code>/opt/</code></li> * <li><code>/usr/local/bin</code></li> * <li><code>/usr/local/lib</code></li> * <li><code>/usr/local/</code></li> * <li><code>~/</code></li> * <li><code>disabled /home</code></li> * <li><code>/etc/</code></li> * </ul> * </li> * </ol> * <p> * Finding a path can be quite expensive on large systems. Therefore the caller ({@link SystemPathHelper}) * should cache any paths found. * </p> * * @author Thomas Holland * @since 2.1 */ public class SystemPathsPosix { private final static IPath fEmptyPath = new Path(""); /** Paths to be searched in order. */ // /etc/ was used to find the avrdude.conf file. While this is currently not // required I leave it in just in case we will be looking for some other // configuration file in a future version of the plugin. // TODO Perhaps we can make this list configurable. Volunteers? private final static String[] fSearchPaths = { "/usr/bin", "/usr/lib", "/usr/avr", // Arch Linux, Fedora // no "/usr", "/opt/", "/usr/local/bin", "/usr/local/lib", "/usr/local/", "~/", // "/home/", "/etc/", }; private SystemPathsPosix() { // prevent instantiation } /** * Find the system path for the given {@link AVRPath} enum value. * * @param avrpath * @return a valid path or <code>null</code> if no path could be found. */ public static IPath getSystemPath(AVRPath avrpath) { IPath path = fEmptyPath; String test = avrpath.getTest(); path = which(test); if (path.isEmpty()) { path = find("*/" + test); } if (!path.isEmpty()) { // remove the number of segments of the test from // the path. This makes a test like "avr/io.h" work path = path.removeLastSegments(new Path(test).segmentCount()); } return path; } /** * Use the posix 'which' command to find the given file. * * @param file * Name of the file * @return <code>IPath</code> to the file. May be an empty path if the file could not be found * with the 'which' command. */ private static IPath which(String file) { IPath path = executeCommand("which " + file); return path; } /** * Use the posix 'find' command to find the given file. * <p> * This method will search the paths in the order given by the {@link #fSearchPaths} array of * path names. * </p> * * @param file * Name of the file * @return <code>IPath</code> to the file. May be an empty path if the file could not be found * with the 'find' command. */ private static IPath find(String file) { for (String findpath : fSearchPaths) { // TODO: use -ipath instead of -path to be case insensitive. // -ipath is a GNU extension to the Posix find, so this might not be as // compatible across all platforms. For the time we leave // -path until someone complains. IPath testpath = executeCommand("find " + findpath + " -path " + file); if (!testpath.isEmpty()) { return testpath; } } // nothing found: return an empty path return fEmptyPath; } /** * Execute the given command and read its output until a line with a valid path is found, which * is returned. * * @param command * @return A valid <code>IPath</code> or an empty path if the command did not return a valid * path. */ public static IPath executeCommand(String command) { IPath path = fEmptyPath; Process cmdproc = null; InputStream is = null; InputStreamReader isr = null; BufferedReader br = null; try { cmdproc = ProcessFactory.getFactory().exec(command); is = cmdproc.getInputStream(); isr = new InputStreamReader(is); br = new BufferedReader(isr); String line; while ((line = br.readLine()) != null) { if (line.length() > 1) { // non-empty line should have the path + file if (path.isValidPath(line)) { path = new Path(line); break; } } } } catch (IOException e) { e.printStackTrace(); } finally { try { if (br != null) br.close(); if (isr != null) isr.close(); if (is != null) is.close(); } catch (IOException e) { // can't do anything about it } try { if (cmdproc != null) { cmdproc.waitFor(); } } catch (InterruptedException e) { } } return path; } }