1
1
package com.jetpackduba.gitnuro.lfs
2
2
3
+ import com.jetpackduba.gitnuro.Result
3
4
import com.jetpackduba.gitnuro.credentials.CredentialsAccepted
4
5
import com.jetpackduba.gitnuro.credentials.CredentialsRequest
5
6
import com.jetpackduba.gitnuro.credentials.CredentialsStateManager
7
+ import com.jetpackduba.gitnuro.logging.printLog
6
8
import com.jetpackduba.gitnuro.models.lfs.LfsObjectBatch
9
+ import com.jetpackduba.gitnuro.models.lfs.LfsObjects
7
10
import com.jetpackduba.gitnuro.models.lfs.LfsPrepareUploadObjectBatch
8
- import com.jetpackduba.gitnuro.models.lfs.LfsRef
9
11
import io.ktor.client.*
10
12
import io.ktor.client.engine.cio.*
11
13
import io.ktor.client.plugins.contentnegotiation.*
@@ -15,13 +17,9 @@ import io.ktor.http.*
15
17
import io.ktor.serialization.kotlinx.json.*
16
18
import io.ktor.util.cio.*
17
19
import kotlinx.coroutines.runBlocking
18
- import kotlinx.serialization.encodeToString
19
- import kotlinx.serialization.json.Json
20
20
import org.eclipse.jgit.annotations.Nullable
21
- import org.eclipse.jgit.api.Git
22
21
import org.eclipse.jgit.attributes.Attribute
23
- import org.eclipse.jgit.errors.IncorrectObjectTypeException
24
- import org.eclipse.jgit.errors.MissingObjectException
22
+ import org.eclipse.jgit.attributes.FilterCommandRegistry
25
23
import org.eclipse.jgit.hooks.PrePushHook
26
24
import org.eclipse.jgit.lfs.*
27
25
import org.eclipse.jgit.lib.*
@@ -32,24 +30,33 @@ import org.eclipse.jgit.util.LfsFactory
32
30
import java.io.IOException
33
31
import java.io.InputStream
34
32
import java.io.PrintStream
35
- import java.security.cert.X509Certificate
36
33
import java.util.*
37
34
import java.util.concurrent.CancellationException
38
35
import javax.inject.Inject
39
36
import javax.inject.Singleton
40
- import javax.net.ssl.X509TrustManager
41
- import javax.swing.text.AbstractDocument.Content
42
37
38
+ private const val TAG = " GLfsFactory"
43
39
44
40
@Singleton
45
41
class GLfsFactory @Inject constructor(
46
42
private val lfsRepository : LfsRepository ,
47
43
private val credentialsStateManager : CredentialsStateManager ,
48
44
) : LfsFactory() {
45
+ init {
46
+ FilterCommandRegistry .register(" jgit://builtin/lfs/smudge" ) { repository, input, out ->
47
+ LfsSmudgeFilter (lfsRepository, credentialsStateManager, input, out , repository)
48
+ }
49
+ FilterCommandRegistry .register(" jgit://builtin/lfs/clean" ) { db, `in `, out ->
50
+ LfsCleanFilter (db, `in `, out )
51
+ }
52
+ }
53
+
54
+
49
55
fun register () {
50
56
setInstance(this )
51
57
}
52
58
59
+
53
60
override fun isAvailable (): Boolean {
54
61
return true
55
62
}
@@ -65,7 +72,7 @@ class GLfsFactory @Inject constructor(
65
72
66
73
@Throws(IOException ::class )
67
74
override fun applyCleanFilter (
68
- db : Repository ? ,
75
+ db : Repository ,
69
76
input : InputStream ? ,
70
77
length : Long ,
71
78
attribute : Attribute ?
@@ -121,6 +128,18 @@ class GLfsFactory @Inject constructor(
121
128
}
122
129
}
123
130
131
+ // class GSmudgeFilter(
132
+ // repository: Repository,
133
+ // input: InputStream?,
134
+ // output: OutputStream?,
135
+ // ) : SmudgeFilter(
136
+ // repository,
137
+ // input,
138
+ // output,
139
+ // ) {
140
+ //
141
+ // }
142
+
124
143
class GLfsPrePushHook (
125
144
repository : Repository ,
126
145
outputStream : PrintStream ? ,
@@ -212,70 +231,101 @@ class GLfsPrePushHook(
212
231
return Constants .R_REMOTES + remoteName
213
232
}
214
233
215
- fun getLfsRepositoryUrl (repository : Repository ): String {
216
- // TODO Obtain proper url
217
- return " https://localhost:8080"
218
- }
219
-
220
234
override fun call (): String = runBlocking {
221
235
val toPush = findObjectsToPush()
222
236
if (toPush.isEmpty()) {
223
237
return @runBlocking " "
224
238
}
225
239
226
- val uploadBatch = LfsPrepareUploadObjectBatch (
227
- operation = " upload" ,
228
- objects = toPush.map {
229
- LfsObjectBatch (it.oid.name(), it.size)
230
- },
231
- transfers = listOf (
232
- " lfs-standalone-file" ,
233
- " basic" ,
234
- " ssh" ,
235
- ),
236
- ref = LfsRef (repository.fullBranch),
237
- hashAlgo = " sha256" ,
238
- )
239
-
240
240
if (! isDryRun) {
241
- val lfsServerUrl = getLfsRepositoryUrl(repository)
242
- val requiresAuth = lfsRepository.requiresAuthForBatchObjects(lfsServerUrl)
241
+ val lfsServerUrl = lfsRepository.getLfsRepositoryUrl(repository)
243
242
244
- var username : String? = null
245
- var password : String? = null
246
-
247
- if (requiresAuth) {
248
- credentialsStateManager.requestCredentials( CredentialsRequest . LfsCredentialsRequest )
243
+ val lfsPrepareUploadObjectBatch = createLfsPrepareUploadObjectBatch(
244
+ OperationType . UPLOAD ,
245
+ branch = repository.fullBranch,
246
+ objects = toPush.map { LfsObjectBatch (it.oid.name(), it.size) },
247
+ )
249
248
250
- var credentials = credentialsStateManager.currentCredentialsState
251
- while (credentials is CredentialsRequest ) {
252
- credentials = credentialsStateManager.currentCredentialsState
249
+ when ( val lfsObjects = getLfsObjects(lfsServerUrl, lfsPrepareUploadObjectBatch)) {
250
+ is Result . Err -> {
251
+ throw Exception ( " LFS Error ${lfsObjects.error} " )
253
252
}
254
253
255
- if (credentials !is CredentialsAccepted .LfsCredentialsAccepted )
256
- throw CancellationException (" Credentials cancelled" )
257
- else {
258
- username = credentials.user
259
- password = credentials.password
254
+ is Result .Ok -> for (p in toPush) {
255
+ val lfs = Lfs (repository)
256
+
257
+ printLog(" LFS" , " Requesting credentials for objects upload" )
258
+ val credentials = requestLfsCredentials()
259
+
260
+ lfsObjects.value.objects.forEach { obj ->
261
+ val uploadUrl = obj.actions.upload?.href
262
+
263
+ if (uploadUrl != null ) {
264
+ lfsRepository.uploadObject(
265
+ uploadUrl,
266
+ p.oid.name(),
267
+ lfs.getMediaFile(p.oid),
268
+ p.size,
269
+ credentials.user,
270
+ credentials.password,
271
+ )
272
+ }
273
+ }
260
274
}
261
275
}
276
+ }
262
277
263
- lfsRepository.batchObjects(lfsServerUrl, uploadBatch, username, password)
278
+ return @runBlocking " "
279
+ }
264
280
265
- for (p in toPush) {
266
- val lfs = Lfs (repository)
281
+ private suspend fun getLfsObjects (
282
+ lfsServerUrl : String ,
283
+ lfsPrepareUploadObjectBatch : LfsPrepareUploadObjectBatch ,
284
+ ): Result <LfsObjects , LfsError > {
267
285
268
- lfsRepository.uploadObject(
269
- lfsServerUrl,
270
- p.oid.name(),
271
- lfs.getMediaFile(p.oid),
272
- p.size,
273
- username,
274
- password,
275
- )
286
+ var lfsObjects: Result <LfsObjects , LfsError >
287
+ var requiresAuth: Boolean
288
+
289
+ var username: String? = null
290
+ var password: String? = null
291
+
292
+
293
+ do {
294
+ val newLfsObjects = lfsRepository.postBatchObjects(
295
+ lfsServerUrl,
296
+ lfsPrepareUploadObjectBatch,
297
+ username,
298
+ password,
299
+ )
300
+
301
+ requiresAuth = newLfsObjects is Result .Err &&
302
+ newLfsObjects.error is LfsError .HttpError &&
303
+ newLfsObjects.error.code == HttpStatusCode .Unauthorized
304
+
305
+ if (requiresAuth) {
306
+ val credentials = requestLfsCredentials()
307
+ username = credentials.user
308
+ password = credentials.password
276
309
}
310
+
311
+ lfsObjects = newLfsObjects
312
+ } while (requiresAuth)
313
+
314
+ return lfsObjects
315
+ }
316
+
317
+ private fun requestLfsCredentials (): CredentialsAccepted .LfsCredentialsAccepted {
318
+ credentialsStateManager.requestCredentials(CredentialsRequest .LfsCredentialsRequest )
319
+
320
+ var credentials = credentialsStateManager.currentCredentialsState
321
+ while (credentials is CredentialsRequest ) {
322
+ credentials = credentialsStateManager.currentCredentialsState
277
323
}
278
324
279
- return @runBlocking " "
325
+ if (credentials !is CredentialsAccepted .LfsCredentialsAccepted ) {
326
+ throw CancellationException (" Credentials cancelled" ) // TODO Improve this error
327
+ }
328
+
329
+ return credentials
280
330
}
281
331
}
0 commit comments