📄 symlink.java
字号:
/* * 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. * *//* * Since the initial version of this file was developed 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.PrintStream;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.FileNotFoundException;import java.util.Vector;import java.util.HashSet;import java.util.Iterator;import java.util.Hashtable;import java.util.Properties;import org.apache.tools.ant.Project;import org.apache.tools.ant.BuildException;import org.apache.tools.ant.DirectoryScanner;import org.apache.tools.ant.dispatch.DispatchTask;import org.apache.tools.ant.dispatch.DispatchUtils;import org.apache.tools.ant.taskdefs.Execute;import org.apache.tools.ant.taskdefs.LogOutputStream;import org.apache.tools.ant.types.FileSet;import org.apache.tools.ant.types.Commandline;import org.apache.tools.ant.util.FileUtils;/** * Creates, Deletes, 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 attribute to * a resource specified in the resource attribute. The second usage of this * task is to traverse 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 associated resource. * * <p> Usage examples: * * <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 its 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 canonical 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 command line * 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>. * */public class Symlink extends DispatchTask { private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); private String resource; private String link; private Vector fileSets = new Vector(); private String linkFileName; private boolean overwrite; private boolean failonerror; private boolean executing = false; /** * Initialize the task. * @throws BuildException on error. */ public void init() throws BuildException { super.init(); setDefaults(); } /** * The standard method for executing any task. * @throws BuildException on error. */ public synchronized void execute() throws BuildException { if (executing) { throw new BuildException( "Infinite recursion detected in Symlink.execute()"); } try { executing = true; DispatchUtils.execute(this); } finally { executing = false; } } /** * Create a symlink. * @throws BuildException on error. * @since Ant 1.7 */ public void single() throws BuildException { try { if (resource == null) { handleError("Must define the resource to symlink to!"); return; } if (link == null) { handleError("Must define the link name for symlink!"); return; } doLink(resource, link); } finally { setDefaults(); } } /** * Delete a symlink. * @throws BuildException on error. * @since Ant 1.7 */ public void delete() throws BuildException { try { if (link == null) { handleError("Must define the link name for symlink!"); return; } log("Removing symlink: " + link); deleteSymlink(link); } catch (FileNotFoundException fnfe) { handleError(fnfe.toString()); } catch (IOException ioe) { handleError(ioe.toString()); } finally { setDefaults(); } } /** * Restore symlinks. * @throws BuildException on error. * @since Ant 1.7 */ public void recreate() throws BuildException { try { if (fileSets.isEmpty()) { handleError("File set identifying link file(s) " + "required for action recreate"); return; } Properties links = loadLinks(fileSets); for (Iterator kitr = links.keySet().iterator(); kitr.hasNext();) { String lnk = (String) kitr.next(); String res = links.getProperty(lnk); // handle the case where lnk points to a directory (bug 25181) try { File test = new File(lnk); if (!FILE_UTILS.isSymbolicLink(null, lnk)) { doLink(res, lnk); } else if (!test.getCanonicalPath().equals( new File(res).getCanonicalPath())) { deleteSymlink(lnk); doLink(res, lnk); } // else lnk exists, do nothing } catch (IOException ioe) { handleError("IO exception while creating link"); } } } finally { setDefaults(); } } /** * Record symlinks. * @throws BuildException on error. * @since Ant 1.7 */ public void record() throws BuildException { try { if (fileSets.isEmpty()) { handleError("Fileset identifying links to record required"); return; } if (linkFileName == null) { handleError("Name of file to record links in required"); return; } // create a hashtable to group them by parent directory: Hashtable byDir = new Hashtable(); // get an Iterator of file objects representing links (canonical): for (Iterator litr = findLinks(fileSets).iterator(); litr.hasNext();) { File thisLink = (File) litr.next(); File parent = thisLink.getParentFile(); Vector v = (Vector) byDir.get(parent); if (v == null) { v = new Vector(); byDir.put(parent, v); } v.addElement(thisLink); } // write a Properties file in each directory: for (Iterator dirs = byDir.keySet().iterator(); dirs.hasNext();) { File dir = (File) dirs.next(); Vector linksInDir = (Vector) byDir.get(dir); Properties linksToStore = new Properties(); // fill up a Properties object with link and resource names: for (Iterator dlnk = linksInDir.iterator(); dlnk.hasNext();) { File lnk = (File) dlnk.next(); try { linksToStore.put(lnk.getName(), lnk.getCanonicalPath()); } catch (IOException ioe) { handleError("Couldn't get canonical name of parent link"); } } writePropertyFile(linksToStore, dir); } } finally { setDefaults(); } } /** * Return all variables to their default state for the next invocation. * @since Ant 1.7 */ private void setDefaults() { resource = null; link = null; linkFileName = null; failonerror = true; // default behavior is to fail on an error overwrite = false; // default behavior is to not overwrite setAction("single"); // default behavior is make a single link fileSets.clear(); } /**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -