in deploy-runner-agent/src/main/java/jetbrains/buildServer/deployer/agent/ftp/FtpBuildProcessAdapter.java [86:213]
public BuildFinishedStatus runProcess() {
FTPClient clientToDisconnect = null;
try {
final URL targetUrl = new URL(myTarget);
final String host = targetUrl.getHost();
final int port = targetUrl.getPort();
final String encodedPath = targetUrl.getPath();
final String path;
if (encodedPath.length() > 0) {
path = URLDecoder.decode(encodedPath.substring(1), "UTF-8");
} else {
path = "";
}
final FTPClient client = createClient();
clientToDisconnect = client;
if (port > 0) {
client.connect(host, port);
} else {
client.connect(host);
}
client.addProtocolCommandListener(new BuildLogCommandListener(myLogger));
if (myIsActive) {
client.enterLocalActiveMode();
} else {
client.enterLocalPassiveMode();
}
final boolean loginSuccessful = client.login(myUsername, myPassword);
if (!loginSuccessful) {
logBuildProblem(myLogger, "Failed to login. Reply was: " + client.getReplyString());
return BuildFinishedStatus.FINISHED_FAILED;
}
boolean isAutoType = false;
if (FTPRunnerConstants.TRANSFER_MODE_BINARY.equals(myTransferMode)) {
client.setFileType(FTP.BINARY_FILE_TYPE);
} else if (FTPRunnerConstants.TRANSFER_MODE_ASCII.equals(myTransferMode)) {
client.setFileType(FTP.ASCII_FILE_TYPE);
} else {
isAutoType = true;
}
AtomicReference<BuildFinishedStatus> processResult = new AtomicReference<BuildFinishedStatus>(BuildFinishedStatus.FINISHED_SUCCESS);
final Runnable interruptibleBody = new InterruptibleUploadProcess(client, myLogger, myArtifacts, isAutoType, path, processResult) {
public boolean checkIsInterrupted() {
return FtpBuildProcessAdapter.this.isInterrupted();
}
};
AtomicReference<IOException> exceptionAtomicReference = new AtomicReference<>();
final Thread uploadThread = new Thread(() -> {
try {
interruptibleBody.run();
} catch (RetryWithPrivateSettingsException e) {
try {
enableDataChannelProtection(client, DataChannelProtection.PRIVATE);
interruptibleBody.run();
} catch (IOException e1) {
exceptionAtomicReference.set(e1);
}
}
});
if (exceptionAtomicReference.get() != null)
throw exceptionAtomicReference.get();
myLogger.message("Starting upload via " + mySecureMode.name() + " to " + myTarget);
uploadThread.start();
new WaitFor(Long.MAX_VALUE, 1000) {
@Override
protected boolean condition() {
if (uploadThread.getState() == Thread.State.TERMINATED) {
return true;
}
try {
if (isInterrupted()) {
client.abort();
uploadThread.join();
return true;
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return false;
}
};
if (uploadThread.getState() != Thread.State.TERMINATED) {
LOG.warn("Ftp upload thread did not reach termination state after wait operation, trying to join");
try {
uploadThread.join();
} catch (InterruptedException e) {
LOG.warnAndDebugDetails("Interrupted while waiting for FTP upload thread to join.", e);
}
LOG.warn("thread joined.");
}
return processResult.get();
} catch (UploadInterruptedException e) {
myLogger.warning("Ftp upload interrupted.");
return BuildFinishedStatus.FINISHED_FAILED;
} catch (SSLException e) {
if (e.getMessage().contains("unable to find valid certification path to requested target")) {
logBuildProblem(myLogger,"Failed to setup SSL connection. Looks like target's certificate is not trusted.\n" +
"See Oracle's documentation on how to import the certificate as a Trusted Certificate.");
}
LOG.warnAndDebugDetails("SSL error executing FTP command", e);
return BuildFinishedStatus.FINISHED_FAILED;
} catch (IOException e) {
logBuildProblem(myLogger, e.getMessage());
LOG.warnAndDebugDetails("Error executing FTP command", e);
return BuildFinishedStatus.FINISHED_FAILED;
} finally {
try {
if (clientToDisconnect != null && clientToDisconnect.isConnected()) {
clientToDisconnect.disconnect();
}
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
}
}