1 /*
2  * Copyright 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.build.importMaven
18 
19 import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
20 import okhttp3.OkHttpClient
21 import okhttp3.Request
22 import org.apache.logging.log4j.kotlin.logger
23 import org.jetbrains.kotlin.com.google.common.annotations.VisibleForTesting
24 
25 /**
26  * Downloads the license for a given Github project URL.
27  */
28 class GithubLicenseApiClient {
29     private val logger = logger("GithubLicenseApiClient")
30     private val client = OkHttpClient()
31 
32     /**
33      * Returns the license for the given [githubUrl] if it is a Github url and the project has a
34      * license file.
35      */
getProjectLicensenull36     fun getProjectLicense(githubUrl: String): String? {
37         val (owner, repo) = githubUrl.extractGithubOwnerAndRepo() ?: return null
38         logger.trace {
39             "Getting license for $githubUrl"
40         }
41         val request = Request.Builder().url(
42             "https://api.github.com/repos/$owner/$repo/license"
43         ).addHeader(
44             "Accept", "application/vnd.github.v3.raw"
45         ).build()
46         val response = client.newCall(request).execute()
47         if (response.code == 404) {
48             logger.warn {
49                 """
50                 Failed to get license from github for $githubUrl
51                 API response: ${response.body?.string()}
52                 """.trimIndent()
53             }
54             return null
55         }
56         return response.body?.use {
57             it.string()
58         }
59     }
60 
61     @VisibleForTesting
extractGithubOwnerAndReponull62     internal fun String.extractGithubOwnerAndRepo(): Pair<String, String>? {
63         val httpUrl = this.toHttpUrlOrNull() ?: return null
64         httpUrl.host.split('.').let {
65             if (it.size < 2) return null
66             if (it.last() != "com") return null
67             if (it[it.size - 2] != "github") return null
68         }
69         val pathSegments = httpUrl.pathSegments.filter { it.isNotBlank() }
70         if (pathSegments.size != 2) {
71             return null
72         }
73         return pathSegments[0] to pathSegments[1]
74     }
75 }