From 124375d341ef75404da41ea9d995a1944cb9a8aa Mon Sep 17 00:00:00 2001 From: evanchooly Date: Sat, 16 Apr 2016 16:42:23 -0400 Subject: [PATCH] Revert "retrofit the rest of the bintry calls" This reverts commit a84a721412b10815b90208f84793b2d5dacf8f55. --- .../beust/kobalt/plugin/publish/BintrayApi.kt | 224 ++++++++++-------- .../kobalt/plugin/publish/PublishPlugin.kt | 3 +- 2 files changed, 123 insertions(+), 104 deletions(-) diff --git a/src/main/kotlin/com/beust/kobalt/plugin/publish/BintrayApi.kt b/src/main/kotlin/com/beust/kobalt/plugin/publish/BintrayApi.kt index 8d5ee4da..7c1c42d1 100644 --- a/src/main/kotlin/com/beust/kobalt/plugin/publish/BintrayApi.kt +++ b/src/main/kotlin/com/beust/kobalt/plugin/publish/BintrayApi.kt @@ -10,79 +10,90 @@ import com.beust.kobalt.misc.KobaltExecutors import com.beust.kobalt.misc.error import com.beust.kobalt.misc.log import com.beust.kobalt.misc.warn -import com.google.gson.JsonArray +import com.google.common.net.MediaType import com.google.gson.JsonObject +import com.google.gson.JsonParser +import com.google.gson.annotations.SerializedName import com.google.inject.assistedinject.Assisted import okhttp3.Credentials import okhttp3.Interceptor -import okhttp3.MediaType -import okhttp3.MultipartBody import okhttp3.OkHttpClient -import okhttp3.RequestBody +import okhttp3.Response import retrofit2.Call import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import retrofit2.http.Body import retrofit2.http.GET -import retrofit2.http.Headers -import retrofit2.http.Multipart +import retrofit2.http.PATCH import retrofit2.http.POST -import retrofit2.http.PUT -import retrofit2.http.Part import retrofit2.http.Path import java.io.File import javax.annotation.Nullable import javax.inject.Inject -class BintrayResponse() - -class BintrayApi @Inject constructor(val http: Http, - @Nullable @Assisted("username") val username: String?, - @Nullable @Assisted("password") val password: String?, - @Nullable @Assisted("org") val org: String?, - val gpg: Gpg, val executors: KobaltExecutors) { +data class BintrayPackage(val jo: JsonObject) { +// @Suppress("UNCHECKED_CAST") +// val latestPublishedVersion = (jo.get("versions") as JsonArray).get(0) as JsonObject). +} +open public class UnauthenticatedBintrayApi @Inject constructor(open 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("password") val password: String?, + @Nullable @Assisted("org") val org: String?, + override val http: Http, val gpg: Gpg, val executors: KobaltExecutors) : UnauthenticatedBintrayApi(http) { + interface IFactory { fun create(@Nullable @Assisted("username") username: String?, @Nullable @Assisted("password") password: String?, - @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 { @GET("/packages/{owner}/maven/{package}") fun getPackage(@Path("owner") owner: String, @Path("package") name: String): Call - @POST("/packages/{owner}/maven") + @POST("/packages/{owner}/maven/{package}") fun createPackage(@Path("owner") owner: String, - @Body content: JsonObject): Call - - @Multipart - @Headers("Content-Type: application/xml") - @PUT("/content/{owner}/maven/{repo}/{version}/{group}/{artifact}/{version}/{name}") - fun uploadPom(@Path("owner") owner: String, - @Path("repo") repo: String, - @Path("version") version: String, - @Path("group", encoded = true) group: String, - @Path("artifact") artifact: String, - @Path("name") name: String, - @Part file: MultipartBody.Part): Call - - @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 + @Path("package") name: String, + @Body content: String): Call +/* + @GET("/repos/{owner}/{repo}/releases") + fun getReleases(@Path("owner") owner: String, + @Path("repo") repo: String, + @Query("access_token") accessToken: String): Call> + @GET("/repos/{owner}/{repo}/releases") + fun getReleasesNoAuth(@Path("owner") owner: String, + @Path("repo") repo: String): Call> +*/ } private val service: Api @@ -92,57 +103,78 @@ class BintrayApi @Inject constructor(val http: Http, builder.interceptors().add(Interceptor { chain -> var original = chain.request(); - chain.proceed(original.newBuilder() + var requestBuilder = original.newBuilder() .header("Authorization", Credentials.basic(username, password)) - .method(original.method(), original.body()) - .build()); + .header("Accept", "application/json") + .method(original.method(), original.body()); + + chain.proceed(requestBuilder.build()); }) val okHttpClient = builder.build() service = Retrofit.Builder() .client(okHttpClient) - .baseUrl(BintrayApi.BINTRAY_URL_API) + .baseUrl(UnauthenticatedBintrayApi.BINTRAY_URL_API) .addConverterFactory(GsonConverterFactory.create()) .build() .create(Api::class.java) } - fun validatePackage(project: Project) { + fun packageExists(project: Project) : Boolean { + 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() - if (execute.errorBody()?.string()?.contains("'${project.name}' was not found") ?: false) { + if (execute.errorBody()?.string()?.contains("was not found") ?: false) { warn("Package does not exist on bintray. Creating now.") - val result = service.createPackage(org ?: username!!, buildPackageInfo(project)) - .execute() + val content = mapOf( + "desc" to project.description, + "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) { - throw KobaltException("Error while creating package:\n" + result.errorBody().string()) + error(" Errors 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) + fun uploadMaven(project: Project, files: List, config: BintrayConfig?) : TaskResult { + if (! packageExists(project)) { + throw KobaltException("Couldn't find a package called ${project.name} on bintray, please create one first" + + " as explained at https://bintray.com/docs/usermanual/uploads/uploads_creatinganewpackage.html") } - jsonObject.add("licenses", licenses) - return jsonObject + + val fileToPath: (File) -> String = { f: File -> + arrayListOf( + 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) } - fun uploadMaven(project: Project, files: List, config: BintrayConfig?): TaskResult { - validatePackage(project) - return upload(project, files, config, generateMd5 = true) - } + 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) - fun uploadFile(project: Project, file: File, config: BintrayConfig?, generateMd5: Boolean = false) = - upload(project, arrayListOf(file), config, generateMd5) - - private fun upload(project: Project, files: List, config: BintrayConfig?, generateMd5: Boolean = false): TaskResult { + private fun upload(files: List, config: BintrayConfig?, fileToPath: (File) -> String, + generateMd5: Boolean = false) : TaskResult { val filesToUpload = arrayListOf() if (config != null && config.sign) { @@ -153,9 +185,9 @@ class BintrayApi @Inject constructor(val http: Http, filesToUpload.add(it) if (generateMd5) { // Create and upload the md5 for this file - with(it) { + with(File(it.absolutePath)) { val md5: String = Md5.toMd5(this) - val md5File = File(path + ".md5") + val md5File = File(absolutePath + ".md5") md5File.writeText(md5) filesToUpload.add(md5File) } @@ -173,43 +205,36 @@ class BintrayApi @Inject constructor(val http: Http, optionPath.append("?" + options.joinToString("&")) } + // + // Uploads can'be done in parallel or Bintray rejects them + // val fileCount = filesToUpload.size if (fileCount > 0) { log(1, " Found $fileCount artifacts to upload: " + filesToUpload[0] + if (fileCount > 1) "..." else "") + var i = 1 val errorMessages = arrayListOf() - fun dots(total: Int, list: List, file: File?): String { - val spaces: String = Array(total - list.size, { " " }).joinToString("") - return "|" + list.map { if (it) "." else "X" }.joinToString("") + spaces + (if(file != null) "| [ ${file} ]" else "|") + + fun dots(total: Int, list: List) : String { + val spaces : String = Array(total - list.size, { " " }).joinToString("") + return "|" + list.map { if (it) "." else "X" }.joinToString("") + spaces + "|" } val results = arrayListOf() - filesToUpload.forEachIndexed { i, file -> - val type = MediaType.parse("multipart/form-data") - - val body = MultipartBody.Part.createFormData("artifact", file.name, RequestBody.create(type, file)); - - var upload = if(file.extension != "pom" ) { - service.uploadArtifact(org ?: username!!, project.name, - project.group!!.replace('.', '/'), project.artifactId!!, project.version!!, file.name, body) - } else { - service.uploadPom(org ?: username!!, project.name, - project.group!!.replace('.', '/'), project.artifactId!!, project.version!!, file.name, body) - } - - 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) + filesToUpload.forEach { file -> + http.uploadFile(username, password, fileToPath(file) + optionPath, + Http.TypedFile(MediaType.ANY_APPLICATION_TYPE.toString(), file), + post = false, // Bintray requires PUT + success = { r: Response -> results.add(true) }, + error = { r: Response -> + results.add(false) + val jcResponse = parseResponse(r) + errorMessages.add(jcResponse.errorMessage!!) + }) + val end = if (i >= fileCount) "\n" else "" + log(1, " Uploading " + (i++) + " / $fileCount " + dots(fileCount, results) + end, false) } - log(1, " Uploading ${fileCount} / $fileCount " + dots(fileCount, results, null), false) - log(1, "", true) if (errorMessages.isEmpty()) { return TaskResult() } else { @@ -221,11 +246,4 @@ class BintrayApi @Inject constructor(val http: Http, return TaskResult() } } - - fun JsonObject.addNonNull(name: String, value: String?) { - if (value != null) { - addProperty(name, value); - } - } - } diff --git a/src/main/kotlin/com/beust/kobalt/plugin/publish/PublishPlugin.kt b/src/main/kotlin/com/beust/kobalt/plugin/publish/PublishPlugin.kt index c94768cd..db7c9e45 100644 --- a/src/main/kotlin/com/beust/kobalt/plugin/publish/PublishPlugin.kt +++ b/src/main/kotlin/com/beust/kobalt/plugin/publish/PublishPlugin.kt @@ -85,7 +85,8 @@ public class PublishPlugin @Inject constructor(val files: KFiles, val factory: P // Upload individual files, if applicable // configuration.files.forEach { - val taskResult = jcenter.uploadFile(project, File(project.directory, it.first), configuration) + val taskResult = jcenter.uploadFile(File(project.directory, it.first), it.second /* url */, + configuration) success = success and taskResult.success if (!taskResult.success) { messages.add(taskResult.errorMessage!!)