1 18 19 29 30 package org.apache.tools.ant.taskdefs.optional.unix; 31 32 import java.io.File ; 33 import java.io.IOException ; 34 import java.io.PrintStream ; 35 import java.io.FileInputStream ; 36 import java.io.FileOutputStream ; 37 import java.io.BufferedInputStream ; 38 import java.io.BufferedOutputStream ; 39 import java.io.FileNotFoundException ; 40 41 import java.util.Vector ; 42 import java.util.HashSet ; 43 import java.util.Iterator ; 44 import java.util.Hashtable ; 45 import java.util.Properties ; 46 47 import org.apache.tools.ant.Project; 48 import org.apache.tools.ant.BuildException; 49 import org.apache.tools.ant.DirectoryScanner; 50 import org.apache.tools.ant.dispatch.DispatchTask; 51 import org.apache.tools.ant.dispatch.DispatchUtils; 52 import org.apache.tools.ant.taskdefs.Execute; 53 import org.apache.tools.ant.taskdefs.LogOutputStream; 54 import org.apache.tools.ant.types.FileSet; 55 import org.apache.tools.ant.types.Commandline; 56 import org.apache.tools.ant.util.FileUtils; 57 58 115 public class Symlink extends DispatchTask { 116 private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); 117 118 private String resource; 119 private String link; 120 private Vector fileSets = new Vector (); 121 private String linkFileName; 122 private boolean overwrite; 123 private boolean failonerror; 124 private boolean executing = false; 125 126 130 public void init() throws BuildException { 131 super.init(); 132 setDefaults(); 133 } 134 135 139 public synchronized void execute() throws BuildException { 140 if (executing) { 141 throw new BuildException( 142 "Infinite recursion detected in Symlink.execute()"); 143 } 144 try { 145 executing = true; 146 DispatchUtils.execute(this); 147 } finally { 148 executing = false; 149 } 150 } 151 152 157 public void single() throws BuildException { 158 try { 159 if (resource == null) { 160 handleError("Must define the resource to symlink to!"); 161 return; 162 } 163 if (link == null) { 164 handleError("Must define the link name for symlink!"); 165 return; 166 } 167 doLink(resource, link); 168 } finally { 169 setDefaults(); 170 } 171 } 172 173 178 public void delete() throws BuildException { 179 try { 180 if (link == null) { 181 handleError("Must define the link name for symlink!"); 182 return; 183 } 184 log("Removing symlink: " + link); 185 deleteSymlink(link); 186 } catch (FileNotFoundException fnfe) { 187 handleError(fnfe.toString()); 188 } catch (IOException ioe) { 189 handleError(ioe.toString()); 190 } finally { 191 setDefaults(); 192 } 193 } 194 195 200 public void recreate() throws BuildException { 201 try { 202 if (fileSets.isEmpty()) { 203 handleError("File set identifying link file(s) " 204 + "required for action recreate"); 205 return; 206 } 207 Properties links = loadLinks(fileSets); 208 209 for (Iterator kitr = links.keySet().iterator(); kitr.hasNext();) { 210 String lnk = (String ) kitr.next(); 211 String res = links.getProperty(lnk); 212 try { 214 File test = new File (lnk); 215 if (!FILE_UTILS.isSymbolicLink(null, lnk)) { 216 doLink(res, lnk); 217 } else if (!test.getCanonicalPath().equals( 218 new File (res).getCanonicalPath())) { 219 deleteSymlink(lnk); 220 doLink(res, lnk); 221 } } catch (IOException ioe) { 223 handleError("IO exception while creating link"); 224 } 225 } 226 } finally { 227 setDefaults(); 228 } 229 } 230 231 236 public void record() throws BuildException { 237 try { 238 if (fileSets.isEmpty()) { 239 handleError("Fileset identifying links to record required"); 240 return; 241 } 242 if (linkFileName == null) { 243 handleError("Name of file to record links in required"); 244 return; 245 } 246 Hashtable byDir = new Hashtable (); 248 249 for (Iterator litr = findLinks(fileSets).iterator(); 251 litr.hasNext();) { 252 File thisLink = (File ) litr.next(); 253 File parent = thisLink.getParentFile(); 254 Vector v = (Vector ) byDir.get(parent); 255 if (v == null) { 256 v = new Vector (); 257 byDir.put(parent, v); 258 } 259 v.addElement(thisLink); 260 } 261 for (Iterator dirs = byDir.keySet().iterator(); dirs.hasNext();) { 263 File dir = (File ) dirs.next(); 264 Vector linksInDir = (Vector ) byDir.get(dir); 265 Properties linksToStore = new Properties (); 266 267 for (Iterator dlnk = linksInDir.iterator(); dlnk.hasNext();) { 269 File lnk = (File ) dlnk.next(); 270 try { 271 linksToStore.put(lnk.getName(), lnk.getCanonicalPath()); 272 } catch (IOException ioe) { 273 handleError("Couldn't get canonical name of parent link"); 274 } 275 } 276 writePropertyFile(linksToStore, dir); 277 } 278 } finally { 279 setDefaults(); 280 } 281 } 282 283 287 private void setDefaults() { 288 resource = null; 289 link = null; 290 linkFileName = null; 291 failonerror = true; overwrite = false; setAction("single"); fileSets.clear(); 295 } 296 297 304 public void setOverwrite(boolean owrite) { 305 this.overwrite = owrite; 306 } 307 308 314 public void setFailOnError(boolean foe) { 315 this.failonerror = foe; 316 } 317 318 324 public void setAction(String action) { 325 super.setAction(action); 326 } 327 328 333 public void setLink(String lnk) { 334 this.link = lnk; 335 } 336 337 343 public void setResource(String src) { 344 this.resource = src; 345 } 346 347 353 public void setLinkfilename(String lf) { 354 this.linkFileName = lf; 355 } 356 357 362 public void addFileset(FileSet set) { 363 fileSets.addElement(set); 364 } 365 366 379 public static void deleteSymlink(String path) 380 throws IOException , FileNotFoundException { 381 deleteSymlink(new File (path)); 382 } 383 384 406 public static void deleteSymlink(File linkfil) 407 throws IOException , FileNotFoundException { 408 if (!linkfil.exists()) { 409 throw new FileNotFoundException ("No such symlink: " + linkfil); 410 } 411 File canfil = linkfil.getCanonicalFile(); 413 414 File temp = FILE_UTILS.createTempFile("symlink", ".tmp", 416 canfil.getParentFile()); 417 try { 418 try { 419 FILE_UTILS.rename(canfil, temp); 420 } catch (IOException e) { 421 throw new IOException ( 422 "Couldn't rename resource when attempting to delete " 423 + linkfil); 424 } 425 if (!linkfil.delete()) { 427 throw new IOException ("Couldn't delete symlink: " + linkfil 428 + " (was it a real file? is this not a UNIX system?)"); 429 } 430 } finally { 431 try { 433 FILE_UTILS.rename(temp, canfil); 434 } catch (IOException e) { 435 throw new IOException ("Couldn't return resource " + temp 436 + " to its original name: " + canfil.getAbsolutePath() 437 + "\n THE RESOURCE'S NAME ON DISK HAS " 438 + "BEEN CHANGED BY THIS ERROR!\n"); 439 } 440 } 441 } 442 443 450 private void writePropertyFile(Properties properties, File dir) 451 throws BuildException { 452 BufferedOutputStream bos = null; 453 try { 454 bos = new BufferedOutputStream ( 455 new FileOutputStream (new File (dir, linkFileName))); 456 properties.store(bos, "Symlinks from " + dir); 457 } catch (IOException ioe) { 458 throw new BuildException(ioe, getLocation()); 459 } finally { 460 FileUtils.close(bos); 461 } 462 } 463 464 470 private void handleError(String msg) { 471 if (failonerror) { 472 throw new BuildException(msg); 473 } 474 log(msg); 475 } 476 477 485 private void doLink(String res, String lnk) throws BuildException { 486 File linkfil = new File (lnk); 487 if (overwrite && linkfil.exists()) { 488 try { 489 deleteSymlink(linkfil); 490 } catch (FileNotFoundException fnfe) { 491 handleError("Symlink disappeared before it was deleted: " + lnk); 492 } catch (IOException ioe) { 493 handleError("Unable to overwrite preexisting link: " + lnk); 494 } 495 } 496 String [] cmd = new String [] {"ln", "-s", res, lnk}; 497 log(Commandline.toString(cmd)); 498 Execute.runCommand(this, cmd); 499 } 500 501 512 private HashSet findLinks(Vector v) { 513 HashSet result = new HashSet (); 514 for (int i = 0; i < v.size(); i++) { 515 FileSet fs = (FileSet) v.get(i); 516 DirectoryScanner ds = fs.getDirectoryScanner(getProject()); 517 String [][] fnd = new String [][] 518 {ds.getIncludedFiles(), ds.getIncludedDirectories()}; 519 File dir = fs.getDir(getProject()); 520 for (int j = 0; j < fnd.length; j++) { 521 for (int k = 0; k < fnd[j].length; k++) { 522 try { 523 File f = new File (dir, fnd[j][k]); 524 File pf = f.getParentFile(); 525 String name = f.getName(); 526 if (FILE_UTILS.isSymbolicLink(pf, name)) { 527 result.add(new File (pf.getCanonicalFile(), name)); 528 } 529 } catch (IOException e) { 530 handleError("IOException: " + fnd[j][k] + " omitted"); 531 } 532 } 533 } 534 } 535 return result; 536 } 537 538 549 private Properties loadLinks(Vector v) { 550 Properties finalList = new Properties (); 551 for (int i = 0; i < v.size(); i++) { 553 FileSet fs = (FileSet) v.elementAt(i); 554 DirectoryScanner ds = new DirectoryScanner(); 555 fs.setupDirectoryScanner(ds, getProject()); 556 ds.setFollowSymlinks(false); 557 ds.scan(); 558 String [] incs = ds.getIncludedFiles(); 559 File dir = fs.getDir(getProject()); 560 561 for (int j = 0; j < incs.length; j++) { 563 File inc = new File (dir, incs[j]); 564 File pf = inc.getParentFile(); 565 Properties lnks = new Properties (); 566 try { 567 lnks.load(new BufferedInputStream (new FileInputStream (inc))); 568 pf = pf.getCanonicalFile(); 569 } catch (FileNotFoundException fnfe) { 570 handleError("Unable to find " + incs[j] + "; skipping it."); 571 continue; 572 } catch (IOException ioe) { 573 handleError("Unable to open " + incs[j] 574 + " or its parent dir; skipping it."); 575 continue; 576 } 577 lnks.list(new PrintStream ( 578 new LogOutputStream(this, Project.MSG_INFO))); 579 for (Iterator kitr = lnks.keySet().iterator(); kitr.hasNext();) { 584 String key = (String ) kitr.next(); 585 finalList.put(new File (pf, key).getAbsolutePath(), 586 lnks.getProperty(key)); 587 } 588 } 589 } 590 return finalList; 591 } 592 } 593 | Popular Tags |