Added basic clone code and ssh authentication code using Apache SSHD
This commit is contained in:
parent
ef39c6f6d5
commit
54f013d291
6 changed files with 207 additions and 0 deletions
|
@ -21,6 +21,7 @@ repositories {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(compose.desktop.currentOs)
|
implementation(compose.desktop.currentOs)
|
||||||
implementation("org.eclipse.jgit:org.eclipse.jgit:5.13.0.202109080827-r")
|
implementation("org.eclipse.jgit:org.eclipse.jgit:5.13.0.202109080827-r")
|
||||||
|
implementation("org.apache.sshd:sshd-core:2.7.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<KotlinCompile>() {
|
tasks.withType<KotlinCompile>() {
|
||||||
|
|
11
src/main/kotlin/credentials/CredentialsStateManager.kt
Normal file
11
src/main/kotlin/credentials/CredentialsStateManager.kt
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
class CredentialsStateManager {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class CredentialsState {
|
||||||
|
object CredentialsRequested: CredentialsState()
|
||||||
|
object CredentialsDenied: CredentialsState()
|
||||||
|
data class CredentialsAccepted(val user: String, val password: String): CredentialsState()
|
||||||
|
}
|
65
src/main/kotlin/credentials/GProcess.kt
Normal file
65
src/main/kotlin/credentials/GProcess.kt
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
import org.apache.sshd.client.channel.ChannelExec
|
||||||
|
import org.apache.sshd.client.session.ClientSession
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
|
import java.io.PipedInputStream
|
||||||
|
import java.io.PipedOutputStream
|
||||||
|
|
||||||
|
class GProcess : Process() {
|
||||||
|
private lateinit var channel: ChannelExec
|
||||||
|
private val outputStream = PipedOutputStream()
|
||||||
|
private val inputStream = PipedInputStream()
|
||||||
|
private val errorOutputStream = PipedOutputStream()
|
||||||
|
private val pipedInputStream = PipedInputStream(outputStream)
|
||||||
|
private val pipedOutputStream = PipedOutputStream(inputStream)
|
||||||
|
private val pipedErrorInputStream = PipedInputStream(errorOutputStream)
|
||||||
|
|
||||||
|
override fun getOutputStream(): OutputStream {
|
||||||
|
return pipedOutputStream
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getInputStream(): InputStream {
|
||||||
|
return pipedInputStream
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getErrorStream(): InputStream {
|
||||||
|
return pipedErrorInputStream
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun waitFor(): Int {
|
||||||
|
if (isRunning())
|
||||||
|
Thread.sleep(100)
|
||||||
|
|
||||||
|
return exitValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun exitValue(): Int {
|
||||||
|
check(!isRunning())
|
||||||
|
|
||||||
|
return channel.exitStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun destroy() {
|
||||||
|
if (channel.isOpen) {
|
||||||
|
channel.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isRunning(): Boolean {
|
||||||
|
return channel.exitStatus < 0 && channel.isOpen
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setup(session: ClientSession, commandName: String) {
|
||||||
|
val channel = session.createExecChannel(commandName)
|
||||||
|
channel.out = outputStream
|
||||||
|
channel.err = errorOutputStream
|
||||||
|
channel.`in` = inputStream
|
||||||
|
|
||||||
|
channel.open().verify()
|
||||||
|
|
||||||
|
this.channel = channel
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
45
src/main/kotlin/credentials/GRemoteSession.kt
Normal file
45
src/main/kotlin/credentials/GRemoteSession.kt
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
import org.apache.sshd.client.SshClient
|
||||||
|
import org.apache.sshd.client.future.ConnectFuture
|
||||||
|
import org.eclipse.jgit.transport.RemoteSession
|
||||||
|
import org.eclipse.jgit.transport.URIish
|
||||||
|
import java.io.PipedInputStream
|
||||||
|
import java.io.PipedOutputStream
|
||||||
|
|
||||||
|
private const val DEFAULT_SSH_PORT = 22
|
||||||
|
|
||||||
|
class GRemoteSession : RemoteSession {
|
||||||
|
private val client = SshClient.setUpDefaultClient()
|
||||||
|
|
||||||
|
private var connectFuture: ConnectFuture? = null
|
||||||
|
|
||||||
|
override fun exec(commandName: String, timeout: Int): Process {
|
||||||
|
println(commandName)
|
||||||
|
val connectFuture = checkNotNull(connectFuture)
|
||||||
|
val session = connectFuture.clientSession
|
||||||
|
session.auth().verify()
|
||||||
|
|
||||||
|
val process = GProcess()
|
||||||
|
process.setup(session, commandName)
|
||||||
|
return process
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun disconnect() {
|
||||||
|
client.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setup(uri: URIish) {
|
||||||
|
client.open()
|
||||||
|
|
||||||
|
val port = if (uri.port == -1) {
|
||||||
|
DEFAULT_SSH_PORT
|
||||||
|
} else
|
||||||
|
uri.port
|
||||||
|
|
||||||
|
val connectFuture = client.connect(uri.user, uri.host, port)
|
||||||
|
connectFuture.await()
|
||||||
|
|
||||||
|
this.connectFuture = connectFuture
|
||||||
|
}
|
||||||
|
}
|
29
src/main/kotlin/credentials/GSessionManager.kt
Normal file
29
src/main/kotlin/credentials/GSessionManager.kt
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
import org.eclipse.jgit.transport.CredentialsProvider
|
||||||
|
import org.eclipse.jgit.transport.RemoteSession
|
||||||
|
import org.eclipse.jgit.transport.SshSessionFactory
|
||||||
|
import org.eclipse.jgit.transport.URIish
|
||||||
|
import org.eclipse.jgit.util.FS
|
||||||
|
|
||||||
|
class GSessionManager {
|
||||||
|
fun generateSshSessionFactory(): SshSessionFactory {
|
||||||
|
return object : SshSessionFactory() {
|
||||||
|
override fun getSession(
|
||||||
|
uri: URIish,
|
||||||
|
credentialsProvider: CredentialsProvider?,
|
||||||
|
fs: FS?,
|
||||||
|
tms: Int
|
||||||
|
): RemoteSession {
|
||||||
|
val remoteSession = GRemoteSession()
|
||||||
|
remoteSession.setup(uri)
|
||||||
|
return remoteSession
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getType(): String {
|
||||||
|
return "ssh" //TODO What should be the value of this?
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
56
src/main/kotlin/git/CloneManager.kt
Normal file
56
src/main/kotlin/git/CloneManager.kt
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package git
|
||||||
|
|
||||||
|
import credentials.GRemoteSession
|
||||||
|
import credentials.GSessionManager
|
||||||
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.transport.*
|
||||||
|
import org.eclipse.jgit.util.FS
|
||||||
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
private const val REMOTE_URL = ""
|
||||||
|
|
||||||
|
class CloneManager {
|
||||||
|
private val sessionManager = GSessionManager()
|
||||||
|
|
||||||
|
|
||||||
|
fun cloneTest() {
|
||||||
|
// prepare a new folder for the cloned repository
|
||||||
|
|
||||||
|
// prepare a new folder for the cloned repository
|
||||||
|
val localPath = File.createTempFile("TestGitRepository", "")
|
||||||
|
if (!localPath.delete()) {
|
||||||
|
throw IOException("Could not delete temporary file $localPath")
|
||||||
|
}
|
||||||
|
|
||||||
|
Git.cloneRepository()
|
||||||
|
.setURI(REMOTE_URL)
|
||||||
|
.setDirectory(localPath)
|
||||||
|
.setTransportConfigCallback {
|
||||||
|
if (it is SshTransport) {
|
||||||
|
it.sshSessionFactory = sessionManager.generateSshSessionFactory()
|
||||||
|
} else if (it is HttpTransport) {
|
||||||
|
it.credentialsProvider = object : CredentialsProvider() {
|
||||||
|
override fun isInteractive(): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun supports(vararg items: CredentialItem?): Boolean {
|
||||||
|
println(items)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun get(uri: URIish?, vararg items: CredentialItem?): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.call().use { result ->
|
||||||
|
// Note: the call() returns an opened repository already which needs to be closed to avoid file handle leaks!
|
||||||
|
println("Having repository: " + result.repository.directory)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue