1
0
Fork 0
mirror of https://github.com/ethauvin/kobalt.git synced 2025-04-27 00:38:11 -07:00

retrofit the rest of the bintry calls

tweak the output to reflect the current file being uploaded
This commit is contained in:
evanchooly 2016-04-16 16:04:45 -04:00
parent 2c2cd8b16b
commit a84a721412
2 changed files with 104 additions and 123 deletions

View file

@ -10,61 +10,41 @@ import com.beust.kobalt.misc.KobaltExecutors
import com.beust.kobalt.misc.error import com.beust.kobalt.misc.error
import com.beust.kobalt.misc.log import com.beust.kobalt.misc.log
import com.beust.kobalt.misc.warn import com.beust.kobalt.misc.warn
import com.google.common.net.MediaType import com.google.gson.JsonArray
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.google.gson.JsonParser
import com.google.gson.annotations.SerializedName
import com.google.inject.assistedinject.Assisted import com.google.inject.assistedinject.Assisted
import okhttp3.Credentials import okhttp3.Credentials
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.MediaType
import okhttp3.MultipartBody
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Response import okhttp3.RequestBody
import retrofit2.Call import retrofit2.Call
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.Body import retrofit2.http.Body
import retrofit2.http.GET import retrofit2.http.GET
import retrofit2.http.PATCH import retrofit2.http.Headers
import retrofit2.http.Multipart
import retrofit2.http.POST import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Part
import retrofit2.http.Path import retrofit2.http.Path
import java.io.File import java.io.File
import javax.annotation.Nullable import javax.annotation.Nullable
import javax.inject.Inject import javax.inject.Inject
data class BintrayPackage(val jo: JsonObject) { class BintrayResponse()
// @Suppress("UNCHECKED_CAST")
// val latestPublishedVersion = (jo.get("versions") as JsonArray).get(0) as JsonObject).
}
open public class UnauthenticatedBintrayApi @Inject constructor(open val http: Http) { class BintrayApi @Inject constructor(val http: Http,
companion object {
const val BINTRAY_URL_API = "https://api.bintray.com"
const val BINTRAY_URL_API_CONTENT = BINTRAY_URL_API + "/content"
}
class BintrayResponse(val jo: JsonObject?, val errorMessage: String?)
fun parseResponse(r: Response): BintrayResponse {
val networkResponse = r.networkResponse()
if (networkResponse.code() != 200) {
val message = networkResponse.message()
try {
val errorObject = JsonParser().parse(r.body().string()).asJsonObject
return BintrayResponse(null, message + ": " + errorObject.get("message").asString)
} catch(ex: Exception) {
return BintrayResponse(null, message)
}
} else {
return BintrayResponse(JsonParser().parse(r.body().string()).asJsonObject, null)
}
}
}
class BintrayApi @Inject constructor (
@Nullable @Assisted("username") val username: String?, @Nullable @Assisted("username") val username: String?,
@Nullable @Assisted("password") val password: String?, @Nullable @Assisted("password") val password: String?,
@Nullable @Assisted("org") val org: String?, @Nullable @Assisted("org") val org: String?,
override val http: Http, val gpg: Gpg, val executors: KobaltExecutors) : UnauthenticatedBintrayApi(http) { val gpg: Gpg, val executors: KobaltExecutors) {
companion object {
const val BINTRAY_URL_API = "https://api.bintray.com"
}
interface IFactory { interface IFactory {
fun create(@Nullable @Assisted("username") username: String?, fun create(@Nullable @Assisted("username") username: String?,
@ -72,28 +52,37 @@ class BintrayApi @Inject constructor (
@Nullable @Assisted("org") org: String?): BintrayApi @Nullable @Assisted("org") org: String?): BintrayApi
} }
class ReleaseResponse(var id: String? = null, @SerializedName("upload_url") var uploadUrl: String?)
interface Api { interface Api {
@GET("/packages/{owner}/maven/{package}") @GET("/packages/{owner}/maven/{package}")
fun getPackage(@Path("owner") owner: String, fun getPackage(@Path("owner") owner: String,
@Path("package") name: String): Call<BintrayResponse> @Path("package") name: String): Call<BintrayResponse>
@POST("/packages/{owner}/maven/{package}") @POST("/packages/{owner}/maven")
fun createPackage(@Path("owner") owner: String, fun createPackage(@Path("owner") owner: String,
@Path("package") name: String, @Body content: JsonObject): Call<BintrayResponse>
@Body content: String): Call<BintrayResponse>
/* @Multipart
@GET("/repos/{owner}/{repo}/releases") @Headers("Content-Type: application/xml")
fun getReleases(@Path("owner") owner: String, @PUT("/content/{owner}/maven/{repo}/{version}/{group}/{artifact}/{version}/{name}")
fun uploadPom(@Path("owner") owner: String,
@Path("repo") repo: String, @Path("repo") repo: String,
@Query("access_token") accessToken: String): Call<List<ReleasesResponse>> @Path("version") version: String,
@Path("group", encoded = true) group: String,
@Path("artifact") artifact: String,
@Path("name") name: String,
@Part file: MultipartBody.Part): Call<BintrayResponse>
@Multipart
@PUT("/maven/{owner}/maven/{package}/{group}/{artifact}/{version}/{name}")
fun uploadArtifact(@Path("owner") owner: String,
@Path("package") bintrayPackage: String,
@Path("group", encoded = true) group: String,
@Path("artifact") artifact: String,
@Path("version") version: String,
@Path("name") name: String,
@Part file: MultipartBody.Part): Call<BintrayResponse>
@GET("/repos/{owner}/{repo}/releases")
fun getReleasesNoAuth(@Path("owner") owner: String,
@Path("repo") repo: String): Call<List<ReleasesResponse>>
*/
} }
private val service: Api private val service: Api
@ -103,78 +92,57 @@ class BintrayApi @Inject constructor (
builder.interceptors().add(Interceptor { chain -> builder.interceptors().add(Interceptor { chain ->
var original = chain.request(); var original = chain.request();
var requestBuilder = original.newBuilder() chain.proceed(original.newBuilder()
.header("Authorization", Credentials.basic(username, password)) .header("Authorization", Credentials.basic(username, password))
.header("Accept", "application/json") .method(original.method(), original.body())
.method(original.method(), original.body()); .build());
chain.proceed(requestBuilder.build());
}) })
val okHttpClient = builder.build() val okHttpClient = builder.build()
service = Retrofit.Builder() service = Retrofit.Builder()
.client(okHttpClient) .client(okHttpClient)
.baseUrl(UnauthenticatedBintrayApi.BINTRAY_URL_API) .baseUrl(BintrayApi.BINTRAY_URL_API)
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create())
.build() .build()
.create(Api::class.java) .create(Api::class.java)
} }
fun packageExists(project: Project) : Boolean { fun validatePackage(project: Project) {
val url = arrayListOf(UnauthenticatedBintrayApi.BINTRAY_URL_API, "packages", org ?: username!!,
"maven", project.name)
.joinToString("/")
val jcResponse = parseResponse(http.get(username, password, url))
val execute = service.getPackage(org ?: username!!, project.name).execute() val execute = service.getPackage(org ?: username!!, project.name).execute()
if (execute.errorBody()?.string()?.contains("was not found") ?: false) { if (execute.errorBody()?.string()?.contains("'${project.name}' was not found") ?: false) {
warn("Package does not exist on bintray. Creating now.") warn("Package does not exist on bintray. Creating now.")
val content = mapOf( val result = service.createPackage(org ?: username!!, buildPackageInfo(project))
"desc" to project.description, .execute()
"vcs_url" to (project.scm?.url ?: ""),
"licences" to """[ "Apache-2.0" ]""",
"website_url" to (project.url ?: "")
).toString()
val result = service.createPackage(org ?: username!!, project.name, content).execute()
if (result.errorBody() != null) { if (result.errorBody() != null) {
error(" Errors while creating package:\n" + result.errorBody().string()) throw KobaltException("Error while creating package:\n" + result.errorBody().string())
return false }
} }
} }
return jcResponse.jo!!.get("name").asString == project.name private fun buildPackageInfo(project: Project): JsonObject {
val jsonObject = JsonObject()
jsonObject.addNonNull("name", project.name)
jsonObject.addNonNull("desc", project.description)
jsonObject.addNonNull("vcs_url", project.scm?.url)
jsonObject.addNonNull("website_url", project.url)
val licenses = JsonArray()
project.licenses.forEach {
licenses.add(it.name)
}
jsonObject.add("licenses", licenses)
return jsonObject
} }
fun uploadMaven(project: Project, files: List<File>, config: BintrayConfig?): TaskResult { fun uploadMaven(project: Project, files: List<File>, config: BintrayConfig?): TaskResult {
if (! packageExists(project)) { validatePackage(project)
throw KobaltException("Couldn't find a package called ${project.name} on bintray, please create one first" + return upload(project, files, config, generateMd5 = true)
" as explained at https://bintray.com/docs/usermanual/uploads/uploads_creatinganewpackage.html")
} }
val fileToPath: (File) -> String = { f: File -> fun uploadFile(project: Project, file: File, config: BintrayConfig?, generateMd5: Boolean = false) =
arrayListOf( upload(project, arrayListOf(file), config, generateMd5)
UnauthenticatedBintrayApi.BINTRAY_URL_API_CONTENT,
org ?: username!!,
"maven",
project.name,
project.version!!,
project.group!!.replace(".", "/"),
project.artifactId!!,
project.version!!,
f.name)
.joinToString("/")
}
return upload(files, config, fileToPath, generateMd5 = true) private fun upload(project: Project, files: List<File>, config: BintrayConfig?, generateMd5: Boolean = false): TaskResult {
}
fun uploadFile(file: File, url: String, config: BintrayConfig?, generateMd5: Boolean = false) =
upload(arrayListOf(file), config, {
f: File -> "${UnauthenticatedBintrayApi.BINTRAY_URL_API_CONTENT}/${org ?: username}/generic/$url"},
generateMd5)
private fun upload(files: List<File>, config: BintrayConfig?, fileToPath: (File) -> String,
generateMd5: Boolean = false) : TaskResult {
val filesToUpload = arrayListOf<File>() val filesToUpload = arrayListOf<File>()
if (config != null && config.sign) { if (config != null && config.sign) {
@ -185,9 +153,9 @@ class BintrayApi @Inject constructor (
filesToUpload.add(it) filesToUpload.add(it)
if (generateMd5) { if (generateMd5) {
// Create and upload the md5 for this file // Create and upload the md5 for this file
with(File(it.absolutePath)) { with(it) {
val md5: String = Md5.toMd5(this) val md5: String = Md5.toMd5(this)
val md5File = File(absolutePath + ".md5") val md5File = File(path + ".md5")
md5File.writeText(md5) md5File.writeText(md5)
filesToUpload.add(md5File) filesToUpload.add(md5File)
} }
@ -205,36 +173,43 @@ class BintrayApi @Inject constructor (
optionPath.append("?" + options.joinToString("&")) optionPath.append("?" + options.joinToString("&"))
} }
//
// Uploads can'be done in parallel or Bintray rejects them
//
val fileCount = filesToUpload.size val fileCount = filesToUpload.size
if (fileCount > 0) { if (fileCount > 0) {
log(1, " Found $fileCount artifacts to upload: " + filesToUpload[0] log(1, " Found $fileCount artifacts to upload: " + filesToUpload[0]
+ if (fileCount > 1) "..." else "") + if (fileCount > 1) "..." else "")
var i = 1
val errorMessages = arrayListOf<String>() val errorMessages = arrayListOf<String>()
fun dots(total: Int, list: List<Boolean>, file: File?): String {
fun dots(total: Int, list: List<Boolean>) : String {
val spaces: String = Array(total - list.size, { " " }).joinToString("") val spaces: String = Array(total - list.size, { " " }).joinToString("")
return "|" + list.map { if (it) "." else "X" }.joinToString("") + spaces + "|" return "|" + list.map { if (it) "." else "X" }.joinToString("") + spaces + (if(file != null) "| [ ${file} ]" else "|")
} }
val results = arrayListOf<Boolean>() val results = arrayListOf<Boolean>()
filesToUpload.forEach { file -> filesToUpload.forEachIndexed { i, file ->
http.uploadFile(username, password, fileToPath(file) + optionPath, val type = MediaType.parse("multipart/form-data")
Http.TypedFile(MediaType.ANY_APPLICATION_TYPE.toString(), file),
post = false, // Bintray requires PUT val body = MultipartBody.Part.createFormData("artifact", file.name, RequestBody.create(type, file));
success = { r: Response -> results.add(true) },
error = { r: Response -> var upload = if(file.extension != "pom" ) {
results.add(false) service.uploadArtifact(org ?: username!!, project.name,
val jcResponse = parseResponse(r) project.group!!.replace('.', '/'), project.artifactId!!, project.version!!, file.name, body)
errorMessages.add(jcResponse.errorMessage!!) } else {
}) service.uploadPom(org ?: username!!, project.name,
val end = if (i >= fileCount) "\n" else "" project.group!!.replace('.', '/'), project.artifactId!!, project.version!!, file.name, body)
log(1, " Uploading " + (i++) + " / $fileCount " + dots(fileCount, results) + end, false)
} }
val result = upload.execute()
val error = result.errorBody()?.string()
if (result.errorBody() != null) {
errorMessages.add(error!!)
results.add(false)
} else {
results.add(true)
}
log(1, " Uploading ${i + 1} / $fileCount " + dots(fileCount, results, file), false)
}
log(1, " Uploading ${fileCount} / $fileCount " + dots(fileCount, results, null), false)
log(1, "", true)
if (errorMessages.isEmpty()) { if (errorMessages.isEmpty()) {
return TaskResult() return TaskResult()
} else { } else {
@ -246,4 +221,11 @@ class BintrayApi @Inject constructor (
return TaskResult() return TaskResult()
} }
} }
fun JsonObject.addNonNull(name: String, value: String?) {
if (value != null) {
addProperty(name, value);
}
}
} }

View file

@ -85,8 +85,7 @@ public class PublishPlugin @Inject constructor(val files: KFiles, val factory: P
// Upload individual files, if applicable // Upload individual files, if applicable
// //
configuration.files.forEach { configuration.files.forEach {
val taskResult = jcenter.uploadFile(File(project.directory, it.first), it.second /* url */, val taskResult = jcenter.uploadFile(project, File(project.directory, it.first), configuration)
configuration)
success = success and taskResult.success success = success and taskResult.success
if (!taskResult.success) { if (!taskResult.success) {
messages.add(taskResult.errorMessage!!) messages.add(taskResult.errorMessage!!)