You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SshSupport.java 3.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. /*
  2. * Copyright (C) 2018, Markus Duft <markus.duft@ssi-schaefer.com> and others
  3. *
  4. * This program and the accompanying materials are made available under the
  5. * terms of the Eclipse Distribution License v. 1.0 which is available at
  6. * https://www.eclipse.org/org/documents/edl-v10.php.
  7. *
  8. * SPDX-License-Identifier: BSD-3-Clause
  9. */
  10. package org.eclipse.jgit.util;
  11. import java.io.IOException;
  12. import java.text.MessageFormat;
  13. import org.eclipse.jgit.annotations.Nullable;
  14. import org.eclipse.jgit.errors.CommandFailedException;
  15. import org.eclipse.jgit.internal.JGitText;
  16. import org.eclipse.jgit.transport.CredentialsProvider;
  17. import org.eclipse.jgit.transport.RemoteSession;
  18. import org.eclipse.jgit.transport.SshSessionFactory;
  19. import org.eclipse.jgit.transport.URIish;
  20. import org.eclipse.jgit.util.io.MessageWriter;
  21. import org.eclipse.jgit.util.io.StreamCopyThread;
  22. /**
  23. * Extra utilities to support usage of SSH.
  24. *
  25. * @since 5.0
  26. */
  27. public class SshSupport {
  28. /**
  29. * Utility to execute a remote SSH command and read the first line of
  30. * output.
  31. *
  32. * @param sshUri
  33. * the SSH remote URI
  34. * @param provider
  35. * the {@link CredentialsProvider} or <code>null</code>.
  36. * @param fs
  37. * the {@link FS} implementation passed to
  38. * {@link SshSessionFactory}
  39. * @param command
  40. * the remote command to execute.
  41. * @param timeout
  42. * a timeout in seconds. The timeout may be exceeded in corner
  43. * cases.
  44. * @return The entire output read from stdout.
  45. * @throws IOException
  46. * @throws CommandFailedException
  47. * if the ssh command execution failed, error message contains
  48. * the content of stderr.
  49. */
  50. public static String runSshCommand(URIish sshUri,
  51. @Nullable CredentialsProvider provider, FS fs, String command,
  52. int timeout) throws IOException, CommandFailedException {
  53. RemoteSession session = null;
  54. Process process = null;
  55. StreamCopyThread errorThread = null;
  56. StreamCopyThread outThread = null;
  57. CommandFailedException failure = null;
  58. @SuppressWarnings("resource")
  59. MessageWriter stderr = new MessageWriter();
  60. String out;
  61. try (MessageWriter stdout = new MessageWriter()) {
  62. session = SshSessionFactory.getInstance().getSession(sshUri,
  63. provider, fs, 1000 * timeout);
  64. process = session.exec(command, 0);
  65. errorThread = new StreamCopyThread(process.getErrorStream(),
  66. stderr.getRawStream());
  67. errorThread.start();
  68. outThread = new StreamCopyThread(process.getInputStream(),
  69. stdout.getRawStream());
  70. outThread.start();
  71. try {
  72. // waitFor with timeout has a bug - JSch' exitValue() throws the
  73. // wrong exception type :(
  74. if (process.waitFor() == 0) {
  75. out = stdout.toString();
  76. } else {
  77. out = null; // still running after timeout
  78. }
  79. } catch (InterruptedException e) {
  80. out = null; // error
  81. }
  82. } finally {
  83. if (errorThread != null) {
  84. try {
  85. errorThread.halt();
  86. } catch (InterruptedException e) {
  87. // Stop waiting and return anyway.
  88. } finally {
  89. errorThread = null;
  90. }
  91. }
  92. if (outThread != null) {
  93. try {
  94. outThread.halt();
  95. } catch (InterruptedException e) {
  96. // Stop waiting and return anyway.
  97. } finally {
  98. outThread = null;
  99. }
  100. }
  101. if (process != null) {
  102. if (process.exitValue() != 0) {
  103. failure = new CommandFailedException(process.exitValue(),
  104. MessageFormat.format(
  105. JGitText.get().sshCommandFailed, command,
  106. stderr.toString()));
  107. }
  108. process.destroy();
  109. }
  110. stderr.close();
  111. if (session != null) {
  112. SshSessionFactory.getInstance().releaseSession(session);
  113. }
  114. }
  115. if (failure != null) {
  116. throw failure;
  117. }
  118. return out;
  119. }
  120. }