1 package hudson; 2 3 import hudson.remoting.Callable; 4 import hudson.remoting.Channel; 5 import hudson.remoting.Pipe; 6 import hudson.remoting.RemoteOutputStream; 7 import hudson.remoting.VirtualChannel; 8 import hudson.remoting.DelegatingCallable; 9 import hudson.util.IOException2; 10 import hudson.model.Hudson; 11 import org.apache.tools.ant.BuildException; 12 import org.apache.tools.ant.DirectoryScanner; 13 import org.apache.tools.ant.taskdefs.Copy; 14 import org.apache.tools.ant.types.FileSet; 15 16 import java.io.File ; 17 import java.io.FileFilter ; 18 import java.io.FileInputStream ; 19 import java.io.FileOutputStream ; 20 import java.io.FileWriter ; 21 import java.io.IOException ; 22 import java.io.InputStream ; 23 import java.io.ObjectInputStream ; 24 import java.io.ObjectOutputStream ; 25 import java.io.OutputStream ; 26 import java.io.Serializable ; 27 import java.io.Writer ; 28 import java.util.ArrayList ; 29 import java.util.List ; 30 import java.net.URI ; 31 32 93 public final class FilePath implements Serializable { 94 107 private transient VirtualChannel channel; 108 109 private final String remote; 111 112 public FilePath(VirtualChannel channel, String remote) { 113 this.channel = channel; 114 this.remote = remote; 115 } 116 117 120 public FilePath(File localPath) { 121 this.channel = null; 122 this.remote = localPath.getPath(); 123 } 124 125 public FilePath(FilePath base, String rel) { 126 this.channel = base.channel; 127 if(base.isUnix()) { 128 this.remote = base.remote+'/'+rel; 129 } else { 130 this.remote = base.remote+'\\'+rel; 131 } 132 } 133 134 137 private boolean isUnix() { 138 return remote.indexOf("\\")==-1; 141 } 142 143 public String getRemote() { 144 return remote; 145 } 146 147 153 public static interface FileCallable<T> extends Serializable { 154 163 T invoke(File f, VirtualChannel channel) throws IOException ; 164 } 165 166 170 public <T> T act(final FileCallable<T> callable) throws IOException , InterruptedException { 171 if(channel!=null) { 172 try { 174 return channel.call(new DelegatingCallable<T,IOException >() { 175 public T call() throws IOException { 176 return callable.invoke(new File (remote), Channel.current()); 177 } 178 179 public ClassLoader getClassLoader() { 180 return callable.getClass().getClassLoader(); 181 } 182 183 private static final long serialVersionUID = 1L; 184 }); 185 } catch (IOException e) { 186 throw new IOException2("remote file operation failed",e); 188 } 189 } else { 190 return callable.invoke(new File (remote), Hudson.MasterComputer.localChannel); 192 } 193 } 194 195 199 public <V,E extends Throwable > V act(Callable<V,E> callable) throws IOException , InterruptedException , E { 200 if(channel!=null) { 201 return channel.call(callable); 203 } else { 204 return callable.call(); 206 } 207 } 208 209 213 public URI toURI() throws IOException , InterruptedException { 214 return act(new FileCallable<URI >() { 215 public URI invoke(File f, VirtualChannel channel) { 216 return f.toURI(); 217 } 218 }); 219 } 220 221 224 public void mkdirs() throws IOException , InterruptedException { 225 if(act(new FileCallable<Boolean >() { 226 public Boolean invoke(File f, VirtualChannel channel) throws IOException { 227 return !f.mkdirs() && !f.exists(); 228 } 229 })) 230 throw new IOException ("Failed to mkdirs: "+remote); 231 } 232 233 236 public void deleteRecursive() throws IOException , InterruptedException { 237 act(new FileCallable<Void >() { 238 public Void invoke(File f, VirtualChannel channel) throws IOException { 239 Util.deleteRecursive(f); 240 return null; 241 } 242 }); 243 } 244 245 248 public void deleteContents() throws IOException , InterruptedException { 249 act(new FileCallable<Void >() { 250 public Void invoke(File f, VirtualChannel channel) throws IOException { 251 Util.deleteContentsRecursive(f); 252 return null; 253 } 254 }); 255 } 256 257 262 public String getName() { 263 int len = remote.length()-1; 264 while(len>=0) { 265 char ch = remote.charAt(len); 266 if(ch=='\\' || ch=='/') 267 break; 268 len--; 269 } 270 271 return remote.substring(len+1); 272 } 273 274 277 public FilePath child(String rel) { 278 return new FilePath(this,rel); 279 } 280 281 284 public FilePath getParent() { 285 int len = remote.length()-1; 286 while(len>=0) { 287 char ch = remote.charAt(len); 288 if(ch=='\\' || ch=='/') 289 break; 290 len--; 291 } 292 293 return new FilePath( channel, remote.substring(0,len) ); 294 } 295 296 299 public FilePath createTempFile(final String prefix, final String suffix) throws IOException , InterruptedException { 300 try { 301 return new FilePath(this,act(new FileCallable<String >() { 302 public String invoke(File dir, VirtualChannel channel) throws IOException { 303 File f = File.createTempFile(prefix, suffix, dir); 304 return f.getName(); 305 } 306 })); 307 } catch (IOException e) { 308 throw new IOException2("Failed to create a temp file on "+remote,e); 309 } 310 } 311 312 316 public FilePath createTextTempFile(final String prefix, final String suffix, final String contents) throws IOException , InterruptedException { 317 return createTextTempFile(prefix,suffix,contents,true); 318 } 319 320 324 public FilePath createTextTempFile(final String prefix, final String suffix, final String contents, final boolean inThisDirectory) throws IOException , InterruptedException { 325 try { 326 return new FilePath(channel,act(new FileCallable<String >() { 327 public String invoke(File dir, VirtualChannel channel) throws IOException { 328 if(!inThisDirectory) 329 dir = null; 330 File f = File.createTempFile(prefix, suffix, dir); 331 332 Writer w = new FileWriter (f); 333 w.write(contents); 334 w.close(); 335 336 return f.getAbsolutePath(); 337 } 338 })); 339 } catch (IOException e) { 340 throw new IOException2("Failed to create a temp file on "+remote,e); 341 } 342 } 343 344 347 public boolean delete() throws IOException , InterruptedException { 348 return act(new FileCallable<Boolean >() { 349 public Boolean invoke(File f, VirtualChannel channel) throws IOException { 350 return f.delete(); 351 } 352 }); 353 } 354 355 358 public boolean exists() throws IOException , InterruptedException { 359 return act(new FileCallable<Boolean >() { 360 public Boolean invoke(File f, VirtualChannel channel) throws IOException { 361 return f.exists(); 362 } 363 }); 364 } 365 366 372 public long lastModified() throws IOException , InterruptedException { 373 return act(new FileCallable<Long >() { 374 public Long invoke(File f, VirtualChannel channel) throws IOException { 375 return f.lastModified(); 376 } 377 }); 378 } 379 380 383 public boolean isDirectory() throws IOException , InterruptedException { 384 return act(new FileCallable<Boolean >() { 385 public Boolean invoke(File f, VirtualChannel channel) throws IOException { 386 return f.isDirectory(); 387 } 388 }); 389 } 390 391 400 public List <FilePath> list(final FileFilter filter) throws IOException , InterruptedException { 401 return act(new FileCallable<List <FilePath>>() { 402 public List <FilePath> invoke(File f, VirtualChannel channel) throws IOException { 403 File [] children = f.listFiles(filter); 404 if(children ==null) return null; 405 406 ArrayList <FilePath> r = new ArrayList <FilePath>(children.length); 407 for (File child : children) 408 r.add(new FilePath(child)); 409 410 return r; 411 } 412 }); 413 } 414 415 421 public FilePath[] list(final String includes) throws IOException , InterruptedException { 422 return act(new FileCallable<FilePath[]>() { 423 public FilePath[] invoke(File f, VirtualChannel channel) throws IOException { 424 FileSet fs = new FileSet(); 425 fs.setDir(f); 426 fs.setIncludes(includes); 427 428 DirectoryScanner ds = fs.getDirectoryScanner(new org.apache.tools.ant.Project()); 429 String [] files = ds.getIncludedFiles(); 430 431 FilePath[] r = new FilePath[files.length]; 432 for( int i=0; i<r.length; i++ ) 433 r[i] = new FilePath(new File (f,files[i])); 434 435 return r; 436 } 437 }); 438 } 439 440 443 public InputStream read() throws IOException { 444 if(channel==null) 445 return new FileInputStream (new File (remote)); 446 447 final Pipe p = Pipe.createRemoteToLocal(); 448 channel.callAsync(new Callable<Void ,IOException >() { 449 public Void call() throws IOException { 450 FileInputStream fis = new FileInputStream (new File (remote)); 451 Util.copyStream(fis,p.getOut()); 452 fis.close(); 453 p.getOut().close(); 454 return null; 455 } 456 }); 457 458 return p.getIn(); 459 } 460 461 466 public OutputStream write() throws IOException , InterruptedException { 467 if(channel==null) { 468 File f = new File (remote); 469 f.getParentFile().mkdirs(); 470 return new FileOutputStream (f); 471 } 472 473 return channel.call(new Callable<OutputStream,IOException >() { 474 public OutputStream call() throws IOException { 475 File f = new File (remote); 476 f.getParentFile().mkdirs(); 477 FileOutputStream fos = new FileOutputStream (f); 478 return new RemoteOutputStream(fos); 479 } 480 }); 481 } 482 483 486 public String digest() throws IOException , InterruptedException { 487 return act(new FileCallable<String >() { 488 public String invoke(File f, VirtualChannel channel) throws IOException { 489 return Util.getDigestOf(new FileInputStream (f)); 490 } 491 }); 492 } 493 494 497 public void copyTo(FilePath target) throws IOException , InterruptedException { 498 OutputStream out = target.write(); 499 try { 500 copyTo(out); 501 } finally { 502 out.close(); 503 } 504 } 505 506 509 public void copyTo(OutputStream os) throws IOException , InterruptedException { 510 final OutputStream out = new RemoteOutputStream(os); 511 512 act(new FileCallable<Void >() { 513 public Void invoke(File f, VirtualChannel channel) throws IOException { 514 FileInputStream fis = new FileInputStream (f); 515 Util.copyStream(fis,out); 516 fis.close(); 517 out.close(); 518 return null; 519 } 520 }); 521 } 522 523 528 interface RemoteCopier { 529 533 void open(String fileName) throws IOException ; 534 void write(byte[] buf, int len) throws IOException ; 535 void close() throws IOException ; 536 } 537 538 public int copyRecursiveTo(String fileMask, FilePath target) throws IOException , InterruptedException { 539 return copyRecursiveTo(fileMask,null,target); 540 } 541 542 550 public int copyRecursiveTo(final String fileMask, final String excludes, final FilePath target) throws IOException , InterruptedException { 551 if(this.channel==target.channel) { 552 return act(new FileCallable<Integer >() { 554 public Integer invoke(File base, VirtualChannel channel) throws IOException { 555 assert target.channel==null; 556 557 try { 558 class CopyImpl extends Copy { 559 private int copySize; 560 561 public CopyImpl() { 562 setProject(new org.apache.tools.ant.Project()); 563 } 564 565 protected void doFileOperations() { 566 copySize = super.fileCopyMap.size(); 567 super.doFileOperations(); 568 } 569 570 public int getNumCopied() { 571 return copySize; 572 } 573 } 574 575 CopyImpl copyTask = new CopyImpl(); 576 copyTask.setTodir(new File (target.remote)); 577 FileSet src = new FileSet(); 578 src.setDir(base); 579 src.setIncludes(fileMask); 580 src.setExcludes(excludes); 581 copyTask.addFileset(src); 582 583 copyTask.execute(); 584 return copyTask.getNumCopied(); 585 } catch (BuildException e) { 586 throw new IOException2("Failed to copy "+base+"/"+fileMask+" to "+target,e); 587 } 588 } 589 }); 590 } else { 591 final FilePath src = this; 593 594 return target.act(new FileCallable<Integer >() { 595 public Integer invoke(final File dest, VirtualChannel channel) throws IOException { 597 final RemoteCopier copier = src.getChannel().export( 598 RemoteCopier.class, 599 new RemoteCopier() { 600 private OutputStream os; 601 public void open(String fileName) throws IOException { 602 File file = new File (dest, fileName); 603 file.getParentFile().mkdirs(); 604 os = new FileOutputStream (file); 605 } 606 607 public void write(byte[] buf, int len) throws IOException { 608 os.write(buf,0,len); 609 } 610 611 public void close() throws IOException { 612 os.close(); 613 os = null; 614 } 615 }); 616 617 try { 618 return src.act(new FileCallable<Integer >() { 619 public Integer invoke(File base, VirtualChannel channel) throws IOException { 620 FileSet fs = new FileSet(); 622 fs.setDir(base); 623 fs.setIncludes(fileMask); 624 625 byte[] buf = new byte[8192]; 626 627 DirectoryScanner ds = fs.getDirectoryScanner(new org.apache.tools.ant.Project()); 628 String [] files = ds.getIncludedFiles(); 629 for( String f : files) { 630 File file = new File (base, f); 631 632 if(Functions.isWindows()) 633 f = f.replace('\\','/'); 634 copier.open(f); 635 636 FileInputStream in = new FileInputStream (file); 637 int len; 638 while((len=in.read(buf))>=0) 639 copier.write(buf,len); 640 in.close(); 641 642 copier.close(); 643 } 644 return files.length; 645 } 646 }); 647 } catch (InterruptedException e) { 648 throw new IOException2("Copy operation interrupted",e); 649 } 650 } 651 }); 652 } 653 } 654 655 @Deprecated 656 public String toString() { 657 return remote; 659 } 660 661 public VirtualChannel getChannel() { 662 if(channel!=null) return channel; 663 else return Hudson.MasterComputer.localChannel; 664 } 665 666 private void writeObject(ObjectOutputStream oos) throws IOException { 667 Channel target = Channel.current(); 668 669 if(channel!=null && channel!=target) 670 throw new IllegalStateException ("Can't send a remote FilePath to a different remote channel"); 671 672 oos.defaultWriteObject(); 673 oos.writeBoolean(channel==null); 674 } 675 676 private void readObject(ObjectInputStream ois) throws IOException , ClassNotFoundException { 677 Channel channel = Channel.current(); 678 assert channel!=null; 679 680 ois.defaultReadObject(); 681 if(ois.readBoolean()) { 682 this.channel = channel; 683 } else { 684 this.channel = null; 685 } 686 } 687 688 private static final long serialVersionUID = 1L; 689 } 690 | Popular Tags |