Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Okcurl multiplatform build #7416

Merged
merged 7 commits into from
Aug 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 1 addition & 3 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ org-conscrypt = "2.5.2"
org-jetbrains-coroutines = "1.6.4"
org-jetbrains-kotlin = "1.6.21"
org-junit-jupiter = "5.9.0"
picocli = "4.6.3"

[libraries]
amazonCorretto = "software.amazon.cryptools:AmazonCorrettoCryptoProvider:1.6.1"
Expand All @@ -27,6 +26,7 @@ bouncycastle-bcprov = { module = "org.bouncycastle:bcprov-jdk15to18", version.re
bouncycastle-bctls = { module = "org.bouncycastle:bctls-jdk15to18", version.ref = "org-bouncycastle" }
brotli-dec = "org.brotli:dec:0.1.2"
checkStyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkStyle" }
clikt = "com.github.ajalt.clikt:clikt:3.5.0"
codehaus-signature-java18 = "org.codehaus.mojo.signature:java18:1.0"
conscrypt-android = { module = "org.conscrypt:conscrypt-android", version.ref = "org-conscrypt" }
conscrypt-openjdk = { module = "org.conscrypt:conscrypt-openjdk-uber", version.ref = "org-conscrypt" }
Expand Down Expand Up @@ -70,8 +70,6 @@ kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-c
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "org-jetbrains-coroutines" }
nativeImageSvm = { module = "org.graalvm.nativeimage:svm", version.ref = "graalvm" }
openjsse = "org.openjsse:openjsse:1.1.10"
picocli = { module = "info.picocli:picocli", version.ref = "picocli" }
picocli-compiler = { module = "info.picocli:picocli-codegen", version.ref = "picocli" }
playservices-safetynet = "com.google.android.gms:play-services-safetynet:18.0.1"
robolectric-android = "org.robolectric:android-all:12.1-robolectric-8229987"
signature-android-apilevel21 = "net.sf.androidscents.signature:android-api-level-21:5.0.1_r2"
Expand Down
99 changes: 76 additions & 23 deletions okcurl/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,47 +4,87 @@ import com.vanniktech.maven.publish.KotlinJvm
import org.apache.tools.ant.taskdefs.condition.Os

plugins {
kotlin("jvm")
kotlin("multiplatform")
kotlin("kapt")
id("org.jetbrains.dokka")
id("com.vanniktech.maven.publish.base")
id("com.palantir.graal")
id("com.github.johnrengelman.shadow")
}

tasks.jar {
manifest {
attributes("Automatic-Module-Name" to "okhttp3.curl")
attributes("Main-Class" to "okhttp3.curl.Main")
}
}
kotlin {
jvm()

// resources-templates.
sourceSets {
main {
resources.srcDirs("$buildDir/generated/resources-templates")
}
}
sourceSets {
all {
languageSettings.optIn("kotlin.RequiresOptIn")
}

commonMain {
dependencies {
api(libs.kotlin.stdlib)
}
}

commonTest {
dependencies {
api(libs.kotlin.stdlib)
implementation(kotlin("test"))
}
}

val jvmMain by getting {
kotlin.srcDir("$buildDir/generated/resources-templates")

dependencies {
api(projects.okhttp)
api(projects.loggingInterceptor)
implementation(libs.picocli)
implementation(libs.guava.jre)
dependencies {
api(libs.kotlin.stdlib)
api(projects.okhttp)
api(projects.loggingInterceptor)
api(libs.squareup.okio)
implementation(libs.clikt)
api(libs.guava.jre)
}
}

kapt(libs.picocli.compiler)
val jvmTest by getting {
dependencies {
api(libs.kotlin.stdlib)
implementation(projects.okhttpTestingSupport)
api(libs.squareup.okio)
api(libs.assertk)
implementation(kotlin("test"))
}
}

testImplementation(projects.okhttpTestingSupport)
testImplementation(libs.junit.jupiter.api)
testImplementation(libs.assertj.core)
// Workaround for https://github.com/palantir/gradle-graal/issues/129
// Add a second configuration to populate
// runtimeClasspath vs jvmRuntimeClasspath
val main by register("main") {
dependencies {
implementation(libs.kotlin.stdlib)
implementation(projects.okhttp)
implementation(projects.loggingInterceptor)
implementation(libs.squareup.okio)
implementation(libs.clikt)
implementation(libs.guava.jre)
}
}
}
}

tasks.jar {
manifest {
attributes("Automatic-Module-Name" to "okhttp3.curl")
attributes("Main-Class" to "okhttp3.curl.MainCommandLineKt")
}
}

tasks.shadowJar {
mergeServiceFiles()
}

graal {
mainClass("okhttp3.curl.Main")
mainClass("okhttp3.curl.MainCommandLineKt")
outputName("okcurl")
graalVersion(libs.versions.graalvm.get())
javaVersion("11")
Expand All @@ -59,6 +99,18 @@ graal {
}
}

// Workaround for https://github.com/palantir/gradle-graal/issues/129
// Copy the jvmJar output into the normal jar location
val copyJvmJar = tasks.register<Copy>("copyJvmJar") {
val sourceFile = project.tasks.getByName("jvmJar").outputs.files.singleFile
val destinationFile = project.tasks.getByName("jar").outputs.files.singleFile
from(sourceFile)
into(destinationFile.parentFile)
rename (sourceFile.name, destinationFile.name)
}
tasks.getByName("copyJvmJar").dependsOn(tasks.getByName("jvmJar"))
tasks.getByName("nativeImage").dependsOn(copyJvmJar)

mavenPublishing {
configure(KotlinJvm(javadocJar = JavadocJar.Dokka("dokkaGfm")))
}
Expand All @@ -70,5 +122,6 @@ tasks.register<Copy>("copyResourcesTemplates") {
filteringCharset = Charsets.UTF_8.toString()
}.let {
tasks.processResources.dependsOn(it)
tasks.compileJava.dependsOn(it)
tasks["javaSourcesJar"].dependsOn(it)
}
46 changes: 46 additions & 0 deletions okcurl/src/commonMain/kotlin/okhttp3/curl/Main.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (C) 2014 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package okhttp3.curl

import com.github.ajalt.clikt.core.CliktCommand
import okhttp3.Call
import okhttp3.Request

expect class Main() : CliktCommand {
val method: String?

val data: String?

val url: String?

val referer: String?

val headers: List<String>?

val showHeaders: Boolean

val userAgent: String

var client: Call.Factory?

override fun run()

fun createClient(): Call.Factory

fun createRequest(): Request

internal fun close()
}
101 changes: 101 additions & 0 deletions okcurl/src/commonMain/kotlin/okhttp3/curl/internal/-MainCommon.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright (C) 2021 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package okhttp3.curl.internal

import java.io.IOException
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.curl.Main
import okhttp3.internal.http.StatusLine
import okio.sink

internal fun Main.commonCreateRequest(): Request {
val request = Request.Builder()

val requestMethod = method ?: if (data != null) "POST" else "GET"

val url = url ?: throw IOException("No url provided")

request.url(url)

data?.let {
request.method(requestMethod, it.toRequestBody(mediaType()))
}

for (header in headers.orEmpty()) {
val parts = header.split(':', limit = 2)
if (!isSpecialHeader(parts[0])) {
request.header(parts[0], parts[1])
}
}
referer?.let {
request.header("Referer", it)
}
request.header("User-Agent", userAgent)

return request.build()
}

private fun Main.mediaType(): MediaType? {
val mimeType = headers?.let {
for (header in it) {
val parts = header.split(':', limit = 2)
if ("Content-Type".equals(parts[0], ignoreCase = true)) {
return@let parts[1].trim()
}
}
return@let null
} ?: "application/x-www-form-urlencoded"

return mimeType.toMediaTypeOrNull()
}

private fun isSpecialHeader(s: String): Boolean {
return s.equals("Content-Type", ignoreCase = true)
}

fun Main.commonRun() {
client = createClient()
val request = createRequest()

try {
val response = client!!.newCall(request).execute()
if (showHeaders) {
println(StatusLine.get(response))
val headers = response.headers
for ((name, value) in headers) {
println("$name: $value")
}
println()
}

// Stream the response to the System.out as it is returned from the server.
val out = System.out.sink()
val source = response.body.source()
while (!source.exhausted()) {
out.write(source.buffer, source.buffer.size)
out.flush()
}

response.body.close()
} catch (e: IOException) {
e.printStackTrace()
} finally {
close()
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020 Square, Inc.
* Copyright (C) 2014 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -15,6 +15,11 @@
*/
package okhttp3.curl

fun main() {
Main.main(arrayOf("https://www.google.com/robots.txt"))
}
import kotlin.test.Test

class OkcurlTest {
@Test
fun simple() {
Main().main(listOf("--help"))
}
}