96
96
import java.util.zip.GZIPInputStream;
98
98
import com.sun.jna.Native;
99
import hudson.os.PosixException;
99
100
import java.util.Enumeration;
100
101
import java.util.logging.Logger;
101
102
import org.apache.tools.ant.taskdefs.Chmod;
495
private void unzip(File dir, InputStream in) throws IOException {
496
private static void unzip(File dir, InputStream in) throws IOException {
496
497
File tmpFile = File.createTempFile("tmpzip", null); // uses java.io.tmpdir
499
// XXX why does this not simply use ZipInputStream?
498
500
IOUtils.copy(in, tmpFile);
499
501
unzip(dir,tmpFile);
506
private void unzip(File dir, File zipFile) throws IOException {
508
static private void unzip(File dir, File zipFile) throws IOException {
507
509
dir = dir.getAbsoluteFile(); // without absolutization, getParentFile below seems to fail
508
510
ZipFile zip = new ZipFile(zipFile);
509
511
@SuppressWarnings("unchecked")
543
545
public FilePath absolutize() throws IOException, InterruptedException {
544
546
return new FilePath(channel,act(new FileCallable<String>() {
547
private static final long serialVersionUID = 1L;
545
548
public String invoke(File f, VirtualChannel channel) throws IOException {
546
549
return f.getAbsolutePath();
560
563
public void symlinkTo(final String target, final TaskListener listener) throws IOException, InterruptedException {
561
564
act(new FileCallable<Void>() {
565
private static final long serialVersionUID = 1L;
562
566
public Void invoke(File f, VirtualChannel channel) throws IOException, InterruptedException {
563
567
Util.createSymlink(f.getParentFile(),target,f.getName(),listener);
576
580
public String readLink() throws IOException, InterruptedException {
577
581
return act(new FileCallable<String>() {
582
private static final long serialVersionUID = 1L;
578
583
public String invoke(File f, VirtualChannel channel) throws IOException, InterruptedException {
579
584
return Util.resolveSymlink(f);
720
725
if(listener!=null)
721
726
listener.getLogger().println(message);
729
// First try to download from the slave machine.
731
act(new Unpack(archive));
732
timestamp.touch(sourceTimestamp);
734
} catch (IOException x) {
735
if (listener != null) {
736
x.printStackTrace(listener.error("Failed to download " + archive + " from slave; will retry from master"));
723
741
// for HTTP downloads, enable automatic retry for added resilience
724
742
InputStream in = archive.getProtocol().startsWith("http") ? ProxyConfiguration.getInputStream(archive) : con.getInputStream();
725
743
CountingInputStream cis = new CountingInputStream(in);
760
private static final class Unpack implements FileCallable<Void> {
761
private final URL archive;
762
Unpack(URL archive) {
763
this.archive = archive;
765
@Override public Void invoke(File dir, VirtualChannel channel) throws IOException, InterruptedException {
766
InputStream in = archive.openStream();
768
CountingInputStream cis = new CountingInputStream(in);
770
if (archive.toExternalForm().endsWith(".zip")) {
773
readFromTar("input stream", dir, GZIP.extract(cis));
775
} catch (IOException x) {
776
throw new IOException2(String.format("Failed to unpack %s (%d bytes read)", archive, cis.getByteCount()), x);
743
786
* Reads the URL on the current VM, and writes all the data to this {@link FilePath}
744
787
* (this is different from resolving URL remotely.)
838
881
if(channel!=null) {
839
882
// run this on a remote system
841
return channel.call(new FileCallableWrapper<T>(callable,cl));
884
DelegatingCallable<T,IOException> wrapper = new FileCallableWrapper<T>(callable, cl);
885
Jenkins instance = Jenkins.getInstance();
886
if (instance != null) { // this happens during unit tests
887
ExtensionList<FileCallableWrapperFactory> factories = instance.getExtensionList(FileCallableWrapperFactory.class);
888
for (FileCallableWrapperFactory factory : factories) {
889
wrapper = factory.wrap(wrapper);
893
return channel.call(wrapper);
842
894
} catch (TunneledInterruptedException e) {
843
895
throw (InterruptedException)new InterruptedException(e.getMessage()).initCause(e);
844
896
} catch (AbortException e) {
909
* This extension point allows to contribute a wrapper around a fileCallable so that a plugin can "intercept" a
911
* <p>The {@link #wrap(hudson.remoting.DelegatingCallable)} method itself will be executed on master
912
* (and may collect contextual data if needed) and the returned wrapper will be executed on remote.
915
* @see AbstractInterceptorCallableWrapper
917
public static abstract class FileCallableWrapperFactory implements ExtensionPoint {
919
public abstract <T> DelegatingCallable<T,IOException> wrap(DelegatingCallable<T,IOException> callable);
924
* Abstract {@link DelegatingCallable} that exposes an Before/After pattern for
925
* {@link hudson.FilePath.FileCallableWrapperFactory} that want to implement AOP-style interceptors
928
public static abstract class AbstractInterceptorCallableWrapper<T> implements DelegatingCallable<T, IOException> {
929
private static final long serialVersionUID = 1L;
931
private final DelegatingCallable<T, IOException> callable;
933
public AbstractInterceptorCallableWrapper(DelegatingCallable<T, IOException> callable) {
934
this.callable = callable;
938
public final ClassLoader getClassLoader() {
939
return callable.getClassLoader();
942
public final T call() throws IOException {
945
return callable.call();
952
* Executed before the actual FileCallable is invoked. This code will run on remote
954
protected void before() {}
957
* Executed after the actual FileCallable is invoked (even if this one failed). This code will run on remote
959
protected void after() {}
857
964
* Executes some program on the machine that this {@link FilePath} exists,
858
965
* so that one can perform local file operations.
860
967
public <T> Future<T> actAsync(final FileCallable<T> callable) throws IOException, InterruptedException {
969
DelegatingCallable<T,IOException> wrapper = new FileCallableWrapper<T>(callable);
970
Jenkins instance = Jenkins.getInstance();
971
if (instance != null) { // this happens during unit tests
972
ExtensionList<FileCallableWrapperFactory> factories = instance.getExtensionList(FileCallableWrapperFactory.class);
973
for (FileCallableWrapperFactory factory : factories) {
974
wrapper = factory.wrap(wrapper);
862
978
return (channel!=null ? channel : Jenkins.MasterComputer.localChannel)
863
.callAsync(new FileCallableWrapper<T>(callable));
864
980
} catch (IOException e) {
865
981
// wrap it into a new IOException so that we get the caller's stack trace as well.
866
982
throw new IOException2("remote file operation failed",e);
899
1016
public void mkdirs() throws IOException, InterruptedException {
900
1017
if(!act(new FileCallable<Boolean>() {
1018
private static final long serialVersionUID = 1L;
901
1019
public Boolean invoke(File f, VirtualChannel channel) throws IOException, InterruptedException {
902
1020
if(f.mkdirs() || f.exists())
903
1021
return true; // OK
917
1035
public void deleteRecursive() throws IOException, InterruptedException {
918
1036
act(new FileCallable<Void>() {
1037
private static final long serialVersionUID = 1L;
919
1038
public Void invoke(File f, VirtualChannel channel) throws IOException {
920
1039
Util.deleteRecursive(f);
929
1048
public void deleteContents() throws IOException, InterruptedException {
930
1049
act(new FileCallable<Void>() {
1050
private static final long serialVersionUID = 1L;
931
1051
public Void invoke(File f, VirtualChannel channel) throws IOException {
932
1052
Util.deleteContentsRecursive(f);
1021
1141
public FilePath createTempFile(final String prefix, final String suffix) throws IOException, InterruptedException {
1023
1143
return new FilePath(this,act(new FileCallable<String>() {
1144
private static final long serialVersionUID = 1L;
1024
1145
public String invoke(File dir, VirtualChannel channel) throws IOException {
1025
1146
File f = File.createTempFile(prefix, suffix, dir);
1026
1147
return f.getName();
1076
1197
public FilePath createTextTempFile(final String prefix, final String suffix, final String contents, final boolean inThisDirectory) throws IOException, InterruptedException {
1078
1199
return new FilePath(channel,act(new FileCallable<String>() {
1200
private static final long serialVersionUID = 1L;
1079
1201
public String invoke(File dir, VirtualChannel channel) throws IOException {
1080
1202
if(!inThisDirectory)
1081
1203
dir = new File(System.getProperty("java.io.tmpdir"));
1118
1240
public FilePath createTempDir(final String prefix, final String suffix) throws IOException, InterruptedException {
1120
1242
return new FilePath(this,act(new FileCallable<String>() {
1243
private static final long serialVersionUID = 1L;
1121
1244
public String invoke(File dir, VirtualChannel channel) throws IOException {
1122
1245
File f = File.createTempFile(prefix, suffix, dir);
1138
1261
public boolean delete() throws IOException, InterruptedException {
1139
1262
act(new FileCallable<Void>() {
1263
private static final long serialVersionUID = 1L;
1140
1264
public Void invoke(File f, VirtualChannel channel) throws IOException {
1141
1265
Util.deleteFile(f);
1151
1275
public boolean exists() throws IOException, InterruptedException {
1152
1276
return act(new FileCallable<Boolean>() {
1277
private static final long serialVersionUID = 1L;
1153
1278
public Boolean invoke(File f, VirtualChannel channel) throws IOException {
1154
1279
return f.exists();
1166
1291
public long lastModified() throws IOException, InterruptedException {
1167
1292
return act(new FileCallable<Long>() {
1293
private static final long serialVersionUID = 1L;
1168
1294
public Long invoke(File f, VirtualChannel channel) throws IOException {
1169
1295
return f.lastModified();
1217
1343
public boolean isDirectory() throws IOException, InterruptedException {
1218
1344
return act(new FileCallable<Boolean>() {
1345
private static final long serialVersionUID = 1L;
1219
1346
public Boolean invoke(File f, VirtualChannel channel) throws IOException {
1220
1347
return f.isDirectory();
1230
1357
public long length() throws IOException, InterruptedException {
1231
1358
return act(new FileCallable<Long>() {
1359
private static final long serialVersionUID = 1L;
1232
1360
public Long invoke(File f, VirtualChannel channel) throws IOException {
1233
1361
return f.length();
1253
1381
public void chmod(final int mask) throws IOException, InterruptedException {
1254
1382
if(!isUnix() || mask==-1) return;
1255
1383
act(new FileCallable<Void>() {
1384
private static final long serialVersionUID = 1L;
1256
1385
public Void invoke(File f, VirtualChannel channel) throws IOException {
1257
1386
_chmod(f, mask);
1301
1430
* @see #chmod(int)
1303
public int mode() throws IOException, InterruptedException {
1432
public int mode() throws IOException, InterruptedException, PosixException {
1304
1433
if(!isUnix()) return -1;
1305
1434
return act(new FileCallable<Integer>() {
1435
private static final long serialVersionUID = 1L;
1306
1436
public Integer invoke(File f, VirtualChannel channel) throws IOException {
1307
1437
return IOUtils.mode(f);
1349
1479
throw new IllegalArgumentException("Non-serializable filter of " + filter.getClass());
1351
1481
return act(new FileCallable<List<FilePath>>() {
1482
private static final long serialVersionUID = 1L;
1352
1483
public List<FilePath> invoke(File f, VirtualChannel channel) throws IOException {
1353
1484
File[] children = f.listFiles(filter);
1354
1485
if(children ==null) return null;
1402
1533
public FilePath[] list(final String includes, final String excludes, final boolean defaultExcludes) throws IOException, InterruptedException {
1403
1534
return act(new FileCallable<FilePath[]>() {
1535
private static final long serialVersionUID = 1L;
1404
1536
public FilePath[] invoke(File f, VirtualChannel channel) throws IOException {
1405
1537
String[] files = glob(f, includes, excludes, defaultExcludes);
1439
1571
final Pipe p = Pipe.createRemoteToLocal();
1440
1572
channel.callAsync(new Callable<Void,IOException>() {
1573
private static final long serialVersionUID = 1L;
1441
1574
public Void call() throws IOException {
1442
1575
FileInputStream fis=null;
1491
1624
return channel.call(new Callable<OutputStream,IOException>() {
1625
private static final long serialVersionUID = 1L;
1492
1626
public OutputStream call() throws IOException {
1493
1627
File f = new File(remote).getAbsoluteFile();
1494
1628
f.getParentFile().mkdirs();
1508
1642
public void write(final String content, final String encoding) throws IOException, InterruptedException {
1509
1643
act(new FileCallable<Void>() {
1644
private static final long serialVersionUID = 1L;
1510
1645
public Void invoke(File f, VirtualChannel channel) throws IOException {
1511
1646
f.getParentFile().mkdirs();
1512
1647
FileOutputStream fos = new FileOutputStream(f);
1527
1662
public String digest() throws IOException, InterruptedException {
1528
1663
return act(new FileCallable<String>() {
1664
private static final long serialVersionUID = 1L;
1529
1665
public String invoke(File f, VirtualChannel channel) throws IOException {
1530
1666
return Util.getDigestOf(new FileInputStream(f));
1541
1677
throw new IOException("renameTo target must be on the same host");
1543
1679
act(new FileCallable<Void>() {
1680
private static final long serialVersionUID = 1L;
1544
1681
public Void invoke(File f, VirtualChannel channel) throws IOException {
1545
1682
f.renameTo(new File(target.remote));
1558
1695
throw new IOException("pullUpTo target must be on the same host");
1560
1697
act(new FileCallable<Void>() {
1698
private static final long serialVersionUID = 1L;
1561
1699
public Void invoke(File f, VirtualChannel channel) throws IOException {
1562
1700
File t = new File(target.getRemote());
1710
1848
if(this.channel==target.channel) {
1711
1849
// local to local copy.
1712
1850
return act(new FileCallable<Integer>() {
1851
private static final long serialVersionUID = 1L;
1713
1852
public Integer invoke(File base, VirtualChannel channel) throws IOException {
1714
1853
if(!base.exists()) return 0;
1715
1854
assert target.channel==null;
1752
1891
final Pipe pipe = Pipe.createLocalToRemote();
1754
1893
Future<Void> future = target.actAsync(new FileCallable<Void>() {
1894
private static final long serialVersionUID = 1L;
1755
1895
public Void invoke(File f, VirtualChannel channel) throws IOException {
1757
1897
readFromTar(remote+'/'+fileMask, f,TarCompression.GZIP.extract(pipe.getIn()));
1773
1913
final Pipe pipe = Pipe.createRemoteToLocal();
1775
1915
Future<Integer> future = actAsync(new FileCallable<Integer>() {
1916
private static final long serialVersionUID = 1L;
1776
1917
public Integer invoke(File f, VirtualChannel channel) throws IOException {
1778
1919
return writeToTar(f,fileMask,excludes,TarCompression.GZIP.compress(pipe.getOut()));