| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * Copyright (c) 2002-2003 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, if |
| * any, must include the following acknowlegement: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowlegement may appear in the software itself, |
| * if and wherever such third-party acknowlegements normally appear. |
| * |
| * 4. The names "Ant" and "Apache Software |
| * Foundation" must not be used to endorse or promote products derived |
| * from this software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache" |
| * nor may "Apache" appear in their names without prior written |
| * permission of the Apache Group. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| |
| /* |
| * Since the initial version of this file was deveolped on the clock on |
| * an NSF grant I should say the following boilerplate: |
| * |
| * This material is based upon work supported by the National Science |
| * Foundaton under Grant No. EIA-0196404. Any opinions, findings, and |
| * conclusions or recommendations expressed in this material are those |
| * of the author and do not necessarily reflect the views of the |
| * National Science Foundation. |
| */ |
| |
| package org.apache.tools.ant.taskdefs.optional.unix; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.FileNotFoundException; |
| |
| import java.util.Vector; |
| import java.util.Properties; |
| import java.util.Enumeration; |
| import java.util.Hashtable; |
| |
| import org.apache.tools.ant.Task; |
| import org.apache.tools.ant.BuildException; |
| import org.apache.tools.ant.DirectoryScanner; |
| |
| import org.apache.tools.ant.util.FileUtils; |
| |
| import org.apache.tools.ant.types.FileSet; |
| |
| import org.apache.tools.ant.taskdefs.Execute; |
| |
| /** |
| * Creates, Records and Restores Symlinks. |
| * |
| * <p> This task performs several related operations. In the most trivial, |
| * and default usage, it creates a link specified in the link atribute to |
| * a resource specified in the resource atribute. The second usage of this |
| * task is to traverses a directory structure specified by a fileset, |
| * and write a properties file in each included directory describing the |
| * links found in that directory. The third usage is to traverse a |
| * directory structure specified by a fileset, looking for properties files |
| * (also specified as included in the fileset) and recreate the links |
| * that have been previously recorded for each directory. Finally, it can be |
| * used to remove a symlink without deleting the file or directory it points |
| * to. |
| * |
| * <p> Examples of use: |
| * |
| * <p> Make a link named "foo" to a resource named "bar.foo" in subdir: |
| * <pre> |
| * <symlink link="${dir.top}/foo" resource="${dir.top}/subdir/bar.foo"/> |
| * </pre> |
| * |
| * <p> Record all links in subdir and it's descendants in files named |
| * "dir.links" |
| * <pre> |
| * <symlink action="record" linkfilename="dir.links"> |
| * <fileset dir="${dir.top}" includes="subdir/**" /> |
| * </symlink> |
| * </pre> |
| * |
| * <p> Recreate the links recorded in the previous example: |
| * <pre> |
| * <symlink action="recreate"> |
| * <fileset dir="${dir.top}" includes="subdir/**/dir.links" /> |
| * </symlink> |
| * </pre> |
| * |
| * <p> Delete a link named "foo" to a resource named "bar.foo" in subdir: |
| * <pre> |
| * <symlink action="delete" link="${dir.top}/foo"/> |
| * </pre> |
| * |
| * <p><strong>LIMITATIONS:</strong> Because Java has no direct support for |
| * handling symlinks this task divines them by comparing canoniacal and |
| * absolute paths. On non-unix systems this may cause false positives. |
| * Furthermore, any operating system on which the command |
| * <code>ln -s link resource</code> is not a valid command on the comandline |
| * will not be able to use action= "delete", action="single" or |
| * action="recreate", but action="record" should still work. Finally, the |
| * lack of support for symlinks in Java means that all links are recorded |
| * as links to the <strong>canonical</strong> resource name. Therefore |
| * the link: <code>link --> subdir/dir/../foo.bar</code> will be recorded |
| * as <code>link=subdir/foo.bar</code> and restored as |
| * <code>link --> subdir/foo.bar</code> |
| * |
| * @version $Revision$ |
| * @author <a href="mailto:gus.heck@olin.edu">Patrick G. Heck</a> |
| */ |
| |
| public class Symlink extends Task { |
| |
| // Atributes with setter methods |
| private String resource; |
| private String link; |
| private String action; |
| private Vector fileSets = new Vector(); |
| private String linkFileName; |
| private boolean overwrite; |
| private boolean failonerror; |
| |
| /** Initialize the task. */ |
| |
| public void init() throws BuildException { |
| super.init(); |
| failonerror = true; // default behavior is to fail on an error |
| overwrite = false; // devault behavior is to not overwrite |
| action = "single"; // default behavior is make a single link |
| fileSets = new Vector(); |
| } |
| |
| /** The standard method for executing any task. */ |
| |
| public void execute() throws BuildException { |
| try { |
| if (action.equals("single")) { |
| doLink(resource, link); |
| } else if (action.equals("delete")) { |
| try { |
| log("Removing symlink: " + link); |
| Symlink.deleteSymlink(link); |
| } catch (FileNotFoundException fnfe) { |
| handleError(fnfe.toString()); |
| } catch (IOException ioe) { |
| handleError(ioe.toString()); |
| } |
| } else if (action.equals("recreate")) { |
| Properties listOfLinks; |
| Enumeration keys; |
| |
| if (fileSets.size() == 0) { |
| handleError("File set identifying link file(s) " |
| + "required for action recreate"); |
| return; |
| } |
| |
| listOfLinks = loadLinks(fileSets); |
| |
| keys = listOfLinks.keys(); |
| |
| while (keys.hasMoreElements()) { |
| link = (String) keys.nextElement(); |
| resource = listOfLinks.getProperty(link); |
| doLink(resource, link); |
| } |
| } else if (action.equals("record")) { |
| Vector vectOfLinks; |
| Hashtable byDir = new Hashtable(); |
| Enumeration links, dirs; |
| |
| if (fileSets.size() == 0) { |
| handleError("File set identifying links to " |
| + "record required"); |
| return; |
| } |
| |
| if (linkFileName == null) { |
| handleError("Name of file to record links in " |
| + "required"); |
| return; |
| } |
| |
| // fill our vector with file objects representing |
| // links (canonical) |
| vectOfLinks = findLinks(fileSets); |
| |
| // create a hashtable to group them by parent directory |
| links = vectOfLinks.elements(); |
| while (links.hasMoreElements()) { |
| File thisLink = (File) links.nextElement(); |
| String parent = thisLink.getParent(); |
| if (byDir.containsKey(parent)) { |
| ((Vector) byDir.get(parent)).addElement(thisLink); |
| } else { |
| byDir.put(parent, new Vector()); |
| ((Vector) byDir.get(parent)).addElement(thisLink); |
| } |
| } |
| |
| // write a Properties file in each directory |
| dirs = byDir.keys(); |
| while (dirs.hasMoreElements()) { |
| String dir = (String) dirs.nextElement(); |
| Vector linksInDir = (Vector) byDir.get(dir); |
| Properties linksToStore = new Properties(); |
| Enumeration eachlink = linksInDir.elements(); |
| File writeTo; |
| |
| // fill up a Properties object with link and resource |
| // names |
| while (eachlink.hasMoreElements()) { |
| File alink = (File) eachlink.nextElement(); |
| try { |
| linksToStore.put(alink.getName(), |
| alink.getCanonicalPath()); |
| } catch (IOException ioe) { |
| handleError("Couldn't get canonical " |
| + "name of a parent link"); |
| } |
| } |
| |
| |
| // Get a place to record what we are about to write |
| writeTo = new File(dir + File.separator |
| + linkFileName); |
| |
| writePropertyFile(linksToStore, writeTo, |
| "Symlinks from " + writeTo.getParent()); |
| } |
| } else { |
| handleError("Invalid action specified in symlink"); |
| } |
| } finally { |
| // return all variables to their default state, |
| // ready for the next invocation. |
| resource = null; |
| link = null; |
| action = "single"; |
| fileSets = new Vector(); |
| linkFileName = null; |
| overwrite = false; |
| failonerror = true; |
| } |
| } |
| |
| /* ********************************************************** * |
| * Begin Atribute Setter Methods * |
| * ********************************************************** */ |
| |
| /** |
| * The setter for the overwrite atribute. If set to false (default) |
| * the task will not overwrite existing links, and may stop the build |
| * if a link already exists depending on the setting of failonerror. |
| * |
| * @param owrite If true overwrite existing links. |
| */ |
| public void setOverwrite(boolean owrite) { |
| this.overwrite = owrite; |
| } |
| |
| /** |
| * The setter for the failonerror atribute. If set to true (default) |
| * the entire build fails upon error. If set to false, the error is |
| * logged and the build will continue. |
| * |
| * @param foe If true throw build exception on error else log it. |
| */ |
| public void setFailOnError(boolean foe) { |
| this.failonerror = foe; |
| } |
| |
| |
| /** |
| * The setter for the "action" attribute. May be "single" "multi" |
| * or "record" |
| * |
| * @param typ The action of action to perform |
| */ |
| public void setAction(String typ) { |
| this.action = typ; |
| } |
| |
| /** |
| * The setter for the "link" attribute. Only used for action = single. |
| * |
| * @param lnk The name for the link |
| */ |
| public void setLink(String lnk) { |
| this.link = lnk; |
| } |
| |
| /** |
| * The setter for the "resource" attribute. Only used for action = single. |
| * |
| * @param src The source of the resource to be linked. |
| */ |
| public void setResource(String src) { |
| this.resource = src; |
| } |
| |
| /** |
| * The setter for the "linkfilename" attribute. Only used for action=record. |
| * |
| * @param lf The name of the file to write links to. |
| */ |
| public void setLinkfilename(String lf) { |
| this.linkFileName = lf; |
| } |
| |
| /** |
| * Adds a fileset to this task. |
| * |
| * @param set The fileset to add. |
| */ |
| public void addFileset(FileSet set) { |
| fileSets.addElement(set); |
| } |
| |
| /* ********************************************************** * |
| * Begin Public Utility Methods * |
| * ********************************************************** */ |
| |
| /** |
| * Deletes a symlink without deleteing the resource it points to. |
| * |
| * <p>This is a convenience method that simply invokes |
| * <code>deleteSymlink(java.io.File)</code> |
| * |
| * @param path A string containing the path of the symlink to delete |
| * |
| * @throws FileNotFoundException When the path results in a |
| * <code>File</code> that doesn't exist. |
| * @throws IOException If calls to <code>File.rename</code> |
| * or <code>File.delete</code> fail. |
| */ |
| |
| public static void deleteSymlink(String path) |
| throws IOException, FileNotFoundException { |
| |
| File linkfil = new File(path); |
| deleteSymlink(linkfil); |
| } |
| |
| /** |
| * Deletes a symlink without deleteing the resource it points to. |
| * |
| * <p>This is a utility method that removes a unix symlink without removing |
| * the resource that the symlink points to. If it is accidentally invoked |
| * on a real file, the real file will not be harmed, but an exception |
| * will be thrown when the deletion is attempted. This method works by |
| * getting the canonical path of the link, using the canonical path to |
| * rename the resource (breaking the link) and then deleting the link. |
| * The resource is then returned to it's original name inside a finally |
| * block to ensure that the resource is unharmed even in the event of |
| * an exception. |
| * |
| * @param linkfil A <code>File</code> object of the symlink to delete |
| * |
| * @throws FileNotFoundException When the path results in a |
| * <code>File</code> that doesn't exist. |
| * @throws IOException If calls to <code>File.rename</code>, |
| * <code>File.delete</code> or |
| * <code>File.getCanonicalPath</code> |
| * fail. |
| */ |
| |
| public static void deleteSymlink(File linkfil) |
| throws IOException, FileNotFoundException { |
| |
| if (!linkfil.exists()) { |
| throw new FileNotFoundException("No such symlink: " + linkfil); |
| } |
| |
| // find the resource of the existing link |
| String canstr = linkfil.getCanonicalPath(); |
| File canfil = new File(canstr); |
| |
| // rename the resource, thus breaking the link |
| String parentStr = canfil.getParent(); |
| File parentDir = new File(parentStr); |
| FileUtils fu = FileUtils.newFileUtils(); |
| File temp = fu.createTempFile("symlink", ".tmp", parentDir); |
| temp.deleteOnExit(); |
| try { |
| try { |
| fu.rename(canfil, temp); |
| } catch (IOException e) { |
| throw new IOException("Couldn't rename resource when " |
| + "attempting to delete " + linkfil); |
| } |
| |
| // delete the (now) broken link |
| if (!linkfil.delete()) { |
| throw new IOException("Couldn't delete symlink: " + linkfil |
| + " (was it a real file? is this not a " |
| + "UNIX system?)"); |
| } |
| } finally { |
| // return the resource to its original name. |
| try { |
| fu.rename(temp, canfil); |
| } catch (IOException e) { |
| throw new IOException("Couldn't return resource " + temp |
| + " to its original name: " + canstr |
| + "\n THE RESOURCE'S NAME ON DISK HAS " |
| + "BEEN CHANGED BY THIS ERROR!\n"); |
| } |
| } |
| } |
| |
| |
| /* ********************************************************** * |
| * Begin Private Methods * |
| * ********************************************************** */ |
| |
| /** |
| * Writes a properties file. |
| * |
| * This method use <code>Properties.store</code> |
| * and thus report exceptions that occur while writing the file. |
| * |
| * This is not jdk 1.1 compatible, but ant 1.6 is not anymore. |
| * |
| * @param properties The properties object to be written. |
| * @param propertyfile The File to write to. |
| * @param comment The comment to place at the head of the file. |
| */ |
| |
| private void writePropertyFile(Properties properties, |
| File propertyfile, |
| String comment) |
| throws BuildException { |
| |
| FileOutputStream fos = null; |
| try { |
| fos = new FileOutputStream(propertyfile); |
| properties.store(fos, comment); |
| |
| } catch (IOException ioe) { |
| throw new BuildException(ioe, getLocation()); |
| } finally { |
| if (fos != null) { |
| try { |
| fos.close(); |
| } catch (IOException ioex) { |
| log("Failed to close output stream"); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Handles errors correctly based on the setting of failonerror. |
| * |
| * @param msg The message to log, or include in the |
| * <code>BuildException</code> |
| */ |
| |
| private void handleError(String msg) { |
| if (failonerror) { |
| throw new BuildException(msg); |
| } else { |
| log(msg); |
| } |
| } |
| |
| |
| /** |
| * Conducts the actual construction of a link. |
| * |
| * <p> The link is constructed by calling <code>Execute.runCommand</code>. |
| * |
| * @param resource The path of the resource we are linking to. |
| * @param link The name of the link we wish to make |
| */ |
| |
| private void doLink(String resource, String link) throws BuildException { |
| |
| if (resource == null) { |
| handleError("Must define the resource to symlink to!"); |
| return; |
| } |
| if (link == null) { |
| handleError("Must define the link " |
| + "name for symlink!"); |
| return; |
| } |
| |
| File linkfil = new File(link); |
| |
| String[] cmd = new String[4]; |
| cmd[0] = "ln"; |
| cmd[1] = "-s"; |
| cmd[2] = resource; |
| cmd[3] = link; |
| |
| try { |
| if (overwrite && linkfil.exists()) { |
| deleteSymlink(linkfil); |
| } |
| } catch (FileNotFoundException fnfe) { |
| handleError("Symlink dissapeared before it was deleted:" + link); |
| } catch (IOException ioe) { |
| handleError("Unable to overwrite preexisting link " + link); |
| } |
| |
| log(cmd[0] + " " + cmd[1] + " " + cmd[2] + " " + cmd[3]); |
| Execute.runCommand(this, cmd); |
| } |
| |
| |
| /** |
| * Simultaneously get included directories and included files. |
| * |
| * @param ds The scanner with which to get the files and directories. |
| * @return A vector of <code>String</code> objects containing the |
| * included file names and directory names. |
| */ |
| |
| private Vector scanDirsAndFiles(DirectoryScanner ds) { |
| String[] files, dirs; |
| Vector list = new Vector(); |
| |
| ds.scan(); |
| |
| files = ds.getIncludedFiles(); |
| dirs = ds.getIncludedDirectories(); |
| |
| for (int i = 0; i < files.length; i++) { |
| list.addElement(files[i]); |
| } |
| for (int i = 0; i < dirs.length; i++) { |
| list.addElement(dirs[i]); |
| } |
| |
| return list; |
| } |
| |
| /** |
| * Finds all the links in all supplied filesets. |
| * |
| * <p> This method is invoked when the action atribute is is "record". |
| * This means that filesets are interpreted as the directories in |
| * which links may be found. |
| * |
| * <p> The basic method follwed here is, for each file set: |
| * <ol> |
| * <li> Compile a list of all matches </li> |
| * <li> Convert matches to <code>File</code> objects </li> |
| * <li> Remove all non-symlinks using |
| * <code>FileUtils.isSymbolicLink</code> </li> |
| * <li> Convert all parent directories to the canonical form </li> |
| * <li> Add the remaining links from each file set to a |
| * master list of links unless the link is already recorded |
| * in the list</li> |
| * </ol> |
| * |
| * @param fileSets The filesets specified by the user. |
| * @return A vector of <code>File</code> objects containing the |
| * links (with canonical parent directories) |
| */ |
| |
| private Vector findLinks(Vector fileSets) { |
| Vector result = new Vector(); |
| |
| // loop through the supplied file sets |
| FSLoop: for (int i = 0; i < fileSets.size(); i++) { |
| FileSet fsTemp = (FileSet) fileSets.elementAt(i); |
| String workingDir = null; |
| Vector links = new Vector(); |
| Vector linksFiles = new Vector(); |
| Enumeration enumLinks; |
| |
| DirectoryScanner ds; |
| |
| File tmpfil = null; |
| try { |
| tmpfil = fsTemp.getDir(this.getProject()); |
| workingDir = tmpfil.getCanonicalPath(); |
| } catch (IOException ioe) { |
| handleError("Exception caught getting " |
| + "canonical path of working dir " + tmpfil |
| + " in a FileSet passed to the symlink " |
| + "task. Further processing of this " |
| + "fileset skipped"); |
| continue FSLoop; |
| } |
| |
| // Get a vector of String with file names that match |
| // the pattern |
| ds = fsTemp.getDirectoryScanner(this.getProject()); |
| links = scanDirsAndFiles(ds); |
| |
| // Now convert the strings to File Objects |
| // using the canonical version of the working dir |
| enumLinks = links.elements(); |
| |
| while (enumLinks.hasMoreElements()) { |
| linksFiles.addElement(new File(workingDir |
| + File.separator |
| + (String) enumLinks |
| .nextElement())); |
| } |
| |
| // Now loop through and remove the non-links |
| |
| enumLinks = linksFiles.elements(); |
| |
| File parentNext, next; |
| String nameParentNext; |
| FileUtils fu = FileUtils.newFileUtils(); |
| Vector removals = new Vector(); |
| while (enumLinks.hasMoreElements()) { |
| next = (File) enumLinks.nextElement(); |
| nameParentNext = next.getParent(); |
| |
| parentNext = new File(nameParentNext); |
| try { |
| if (!fu.isSymbolicLink(parentNext, next.getName())) { |
| removals.addElement(next); |
| } |
| } catch (IOException ioe) { |
| handleError("Failed checking " + next |
| + " for symbolic link. FileSet skipped."); |
| continue FSLoop; |
| // Otherwise this file will be falsely recorded as a link, |
| // if failonerror = false, hence the warn and skip. |
| } |
| } |
| |
| enumLinks = removals.elements(); |
| |
| while (enumLinks.hasMoreElements()) { |
| linksFiles.removeElement(enumLinks.nextElement()); |
| } |
| |
| // Now we have what we want so add it to results, ensuring that |
| // no link is returned twice and we have a canonical reference |
| // to the link. (no symlinks in the parent dir) |
| |
| enumLinks = linksFiles.elements(); |
| while (enumLinks.hasMoreElements()) { |
| File temp, parent; |
| next = (File) enumLinks.nextElement(); |
| try { |
| parent = new File(next.getParent()); |
| parent = new File(parent.getCanonicalPath()); |
| temp = new File(parent, next.getName()); |
| if (!result.contains(temp)) { |
| result.addElement(temp); |
| } |
| } catch (IOException ioe) { |
| handleError("IOException: " + next + " omitted"); |
| } |
| } |
| |
| // Note that these links are now specified with a full |
| // canonical path irrespective of the working dir of the |
| // file set so it is ok to mix them in the same vector. |
| |
| } |
| return result; |
| } |
| |
| /** |
| * Load the links from a properties file. |
| * |
| * <p> This method is only invoked when the action atribute is set to |
| * "multi". The filesets passed in are assumed to specify the names |
| * of the property files with the link information and the |
| * subdirectories in which to look for them. |
| * |
| * <p> The basic method follwed here is, for each file set: |
| * <ol> |
| * <li> Get the canonical version of the dir atribute </li> |
| * <li> Scan for properties files </li> |
| * <li> load the contents of each properties file found. </li> |
| * </ol> |
| * |
| * @param fileSets The <code>FileSet</code>s for this task |
| * @return The links to be made. |
| */ |
| |
| private Properties loadLinks(Vector fileSets) { |
| Properties finalList = new Properties(); |
| Enumeration keys; |
| String key, value; |
| String[] includedFiles; |
| |
| // loop through the supplied file sets |
| FSLoop: for (int i = 0; i < fileSets.size(); i++) { |
| String workingDir; |
| FileSet fsTemp = (FileSet) fileSets.elementAt(i); |
| |
| DirectoryScanner ds; |
| |
| try { |
| File linelength = fsTemp.getDir(this.getProject()); |
| workingDir = linelength.getCanonicalPath(); |
| } catch (IOException ioe) { |
| handleError("Exception caught getting " |
| + "canonical path of working dir " |
| + "of a FileSet passed to symlink " |
| + "task. FileSet skipped."); |
| continue FSLoop; |
| } |
| |
| ds = fsTemp.getDirectoryScanner(this.getProject()); |
| ds.setFollowSymlinks(false); |
| ds.scan(); |
| includedFiles = ds.getIncludedFiles(); |
| |
| // loop through the files identified by each file set |
| // and load their contents. |
| for (int j = 0; j < includedFiles.length; j++) { |
| File inc = new File(workingDir + File.separator |
| + includedFiles[j]); |
| String inDir; |
| Properties propTemp = new Properties(); |
| |
| try { |
| propTemp.load(new FileInputStream(inc)); |
| inDir = inc.getParent(); |
| inDir = (new File(inDir)).getCanonicalPath(); |
| } catch (FileNotFoundException fnfe) { |
| handleError("Unable to find " + includedFiles[j] |
| + "FileSet skipped."); |
| continue FSLoop; |
| } catch (IOException ioe) { |
| handleError("Unable to open " + includedFiles[j] |
| + " or it's parent dir" |
| + "FileSet skipped."); |
| continue FSLoop; |
| } |
| |
| keys = propTemp.keys(); |
| propTemp.list(System.out); |
| // Write the contents to our master list of links |
| |
| // This method assumes that all links are defined in |
| // terms of absolute paths, or paths relative to the |
| // working directory |
| while (keys.hasMoreElements()) { |
| key = (String) keys.nextElement(); |
| value = propTemp.getProperty(key); |
| finalList.put(inDir + File.separator + key, value); |
| } |
| } |
| } |
| return finalList; |
| } |
| } |