core/src/commonMain/kotlin/licensee/LicenseeLicenseInfoRepository.kt
changeset 28 19cf2e8a0627
child 29 b6b62004b1e7
equal deleted inserted replaced
27:6469637350c6 28:19cf2e8a0627
       
     1 /*
       
     2  * AboutOss is an utility library to retrieve and display
       
     3  * opensource licenses in Android applications.
       
     4  *
       
     5  * Copyright (C) 2023 by Frederic-Charles Barthelery.
       
     6  *
       
     7  * This file is part of AboutOss.
       
     8  *
       
     9  * AboutOss is free software: you can redistribute it and/or modify
       
    10  * it under the terms of the GNU General Public License as published by
       
    11  * the Free Software Foundation, either version 3 of the License, or
       
    12  * (at your option) any later version.
       
    13  *
       
    14  * AboutOss is distributed in the hope that it will be useful,
       
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    17  * GNU General Public License for more details.
       
    18  *
       
    19  * You should have received a copy of the GNU General Public License
       
    20  * along with AboutOss.  If not, see <http://www.gnu.org/licenses/>.
       
    21  */
       
    22 package com.geekorum.aboutoss.core.licensee
       
    23 
       
    24 import kotlinx.coroutines.CoroutineDispatcher
       
    25 import kotlinx.coroutines.withContext
       
    26 import kotlinx.serialization.ExperimentalSerializationApi
       
    27 import kotlinx.serialization.Serializable
       
    28 import kotlinx.serialization.json.Json
       
    29 import okio.Source
       
    30 import okio.buffer
       
    31 
       
    32 class LicenseeLicenseInfoRepository(
       
    33     private val produceInput: suspend () -> Source,
       
    34     private val mainCoroutineDispatcher: CoroutineDispatcher,
       
    35     private val ioCoroutineDispatcher: CoroutineDispatcher,
       
    36 ) {
       
    37 
       
    38     private var licensesInfo: Map<String, String>? = null
       
    39 
       
    40     suspend fun getLicensesInfo(): Map<String, String> = withContext(mainCoroutineDispatcher) {
       
    41         parseLicenses()
       
    42         checkNotNull(licensesInfo)
       
    43     }
       
    44 
       
    45     suspend fun getLicenseFor(dependency: String): String = withContext(mainCoroutineDispatcher) {
       
    46         parseLicenses()
       
    47         checkNotNull(licensesInfo).let {
       
    48             return@withContext it[dependency] ?: error("Dependency not found")
       
    49         }
       
    50     }
       
    51 
       
    52     @OptIn(ExperimentalSerializationApi::class)
       
    53     private suspend fun parseLicenses() = withContext(mainCoroutineDispatcher) {
       
    54         if (licensesInfo == null) {
       
    55             val licenses = withContext(ioCoroutineDispatcher) {
       
    56                 LicenseeParser(produceInput()).use {
       
    57                     it.readLicensee()
       
    58                 }
       
    59             }
       
    60             licensesInfo = licenses
       
    61         }
       
    62     }
       
    63 }
       
    64 
       
    65 
       
    66 private class LicenseeParser(
       
    67     input: Source
       
    68 ): AutoCloseable {
       
    69     private val buffered = input.buffer()
       
    70 
       
    71     fun readLicensee(): Map<String, String> {
       
    72         val json = Json {
       
    73             ignoreUnknownKeys = true
       
    74         }
       
    75         val items: List<LicenseItem> = json.decodeFromString(buffered.readUtf8())
       
    76 
       
    77         return items.associate {
       
    78             val name = it.name ?: "${it.groupId}:${it.artifactId}"
       
    79             val license = it.spdxLicenses.firstNotNullOfOrNull {
       
    80                 "${it.name}\n\n${it.url}"
       
    81             } ?: it.unknownLicenses.firstNotNullOf {
       
    82                 "${it.name}\n\n${it.url}"
       
    83             }
       
    84             name to license
       
    85         }
       
    86     }
       
    87 
       
    88     override fun close() {
       
    89         buffered.close()
       
    90     }
       
    91 }
       
    92 
       
    93 
       
    94 @Serializable
       
    95 private data class LicenseItem(
       
    96     val groupId: String,
       
    97     val artifactId: String,
       
    98     val version: String,
       
    99     val spdxLicenses: List<SpdxLicense> = emptyList(),
       
   100     val unknownLicenses: List<UnknownLicense> = emptyList(),
       
   101     val name: String? = null,
       
   102     val scm: Scm? = null,
       
   103 )
       
   104 
       
   105 @Serializable
       
   106 private data class SpdxLicense(
       
   107     val identifier: String,
       
   108     val name: String,
       
   109     val url: String,
       
   110 )
       
   111 
       
   112 @Serializable
       
   113 private data class UnknownLicense(
       
   114     val name: String,
       
   115     val url: String
       
   116 )
       
   117 
       
   118 @Serializable
       
   119 private data class Scm(
       
   120     val url: String,
       
   121 )