# HG changeset patch # User Da Risk # Date 1681416567 14400 # Node ID 137a5da55ed9de0732922e6b6cfbf394a4ec2ef8 # Parent 0a13dcabf7d3955e2ec18681e703c8282743449f core: add LicenseInfoRepository and OssLicenseParser diff -r 0a13dcabf7d3 -r 137a5da55ed9 core/build.gradle.kts --- a/core/build.gradle.kts Fri Apr 14 14:29:05 2023 -0400 +++ b/core/build.gradle.kts Thu Apr 13 16:09:27 2023 -0400 @@ -36,10 +36,9 @@ } dependencies { + implementation(libs.okio) + implementation(libs.kotlinx.coroutines) - implementation(libs.core.ktx) - implementation(libs.appcompat) - implementation(libs.material) testImplementation(libs.junit) androidTestImplementation(libs.androidx.test.ext.junit) androidTestImplementation(libs.espresso.core) diff -r 0a13dcabf7d3 -r 137a5da55ed9 core/src/main/java/com/geekorum/aboutoss/core/LicenseInfoRepository.kt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/main/java/com/geekorum/aboutoss/core/LicenseInfoRepository.kt Thu Apr 13 16:09:27 2023 -0400 @@ -0,0 +1,65 @@ +/* + * AboutOss is a utility library to retrieve and display + * opensource licenses in Android applications. + * + * Copyright (C) 2023 by Frederic-Charles Barthelery. + * + * This file is part of AboutOss. + * + * AboutOss is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AboutOss is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AboutOss. If not, see . + */ +package com.geekorum.aboutoss.core + +import android.content.Context +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.withContext + +class LicenseInfoRepository( + private val appContext: Context, + private val mainCoroutineDispatcher: CoroutineDispatcher, + private val ioCoroutineDispatcher: CoroutineDispatcher, +) { + + private var licensesInfo: Map? = null + + suspend fun getLicensesInfo(): Map = withContext(mainCoroutineDispatcher) { + parseLicenses() + checkNotNull(licensesInfo) + } + + suspend fun getLicenseFor(dependency: String): String = withContext(mainCoroutineDispatcher) { + parseLicenses() + checkNotNull(licensesInfo).let { + return@withContext it[dependency] ?: error("Dependency not found") + } + } + + private suspend fun parseLicenses() = withContext(mainCoroutineDispatcher) { + if (licensesInfo == null) { + val licenses = withContext(ioCoroutineDispatcher) { + OssLicenseParser.openDefaultThirdPartyLicenses(appContext).use { licensesInput -> + OssLicenseParser.openDefaultThirdPartyLicensesMetadata(appContext) + .use { licensesMetadataInput -> + val parser = OssLicenseParser( + thirdPartyLicensesInput = licensesInput, + thirdPartyLicensesMetadataInput = licensesMetadataInput + ) + parser.parseLicenses() + } + } + } + licensesInfo = licenses + } + } +} \ No newline at end of file diff -r 0a13dcabf7d3 -r 137a5da55ed9 core/src/main/java/com/geekorum/aboutoss/core/OssLicenseParser.kt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/main/java/com/geekorum/aboutoss/core/OssLicenseParser.kt Thu Apr 13 16:09:27 2023 -0400 @@ -0,0 +1,122 @@ +/* + * AboutOss is a utility library to retrieve and display + * opensource licenses in Android applications. + * + * Copyright (C) 2023 by Frederic-Charles Barthelery. + * + * This file is part of AboutOss. + * + * AboutOss is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AboutOss is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AboutOss. If not, see . + */ +package com.geekorum.aboutoss.core + +import android.annotation.SuppressLint +import android.content.Context +import okio.ByteString +import okio.buffer +import okio.source +import java.io.InputStream + +/** + * Parse licences data generated by the "com.google.android.gms.oss-licenses-plugin" gradle plugin. + * [thirdPartyLicensesInput] is usually res/raw/third_party_licenses file + * [thirdPartyLicensesMetadataInput] is usually res/raw/third_party_license_metadata file + */ +class OssLicenseParser( + private val thirdPartyLicensesInput: InputStream, + private val thirdPartyLicensesMetadataInput: InputStream +) { + fun parseLicenses(): Map { + val licenses = readLicensesFile() + return buildLicenseInfo(licenses) + } + + private fun readLicensesFile(): ByteString { + return thirdPartyLicensesInput.source().use { source -> + source.buffer().use { + it.readByteString() + } + } + } + + private fun buildLicenseInfo(license: ByteString): Map { + return thirdPartyLicensesMetadataInput.source().use { source -> + source.buffer().use { + buildMap { + while (true) { + val line = it.readUtf8Line() ?: break + if (line.isNotBlank()) { + with(line.toLineParser()) { + val start = readStartIdx() + val length = readLength() + val dependency = readName() + val licenseTxt = license.substring( + beginIndex = start, + endIndex = start + length + 1 + ).string(Charsets.UTF_8) + put(dependency, licenseTxt) + } + } + } + } + } + } + } + + companion object { + @SuppressLint("DiscouragedApi") + fun openDefaultThirdPartyLicenses(context: Context): InputStream { + val thirdPartyLicensesId = context.resources.getIdentifier("third_party_licenses", "raw", context.packageName) + check(thirdPartyLicensesId != 0) { "third_party_licenses was not found in resources raw of ${context.packageName}"} + return context.resources.openRawResource(thirdPartyLicensesId) + } + + @SuppressLint("DiscouragedApi") + fun openDefaultThirdPartyLicensesMetadata(context: Context): InputStream { + val thirdPartyLicensesMetadataId = context.resources.getIdentifier("third_party_license_metadata", "raw", context.packageName) + check(thirdPartyLicensesMetadataId != 0) { "third_party_license_metadata was not found in resources raw of ${context.packageName}"} + return context.resources.openRawResource(thirdPartyLicensesMetadataId) + } + } +} + +private class LicenseMetadataLineParser( + private val line: String +) { + + private var idx = 0 + + fun readStartIdx(): Int { + val end = line.indexOf(':', startIndex = idx) + val result = line.substring(idx, end).toInt() + idx = end + 1 + return result + } + + fun readLength(): Int { + val end = line.indexOf(' ', startIndex = idx) + val result = line.substring(idx, end).toInt() + idx = end + 1 + return result + } + + fun readName(): String { + val result = line.substring(idx) + idx = line.length + 1 + return result + } + +} + +private fun String.toLineParser() = LicenseMetadataLineParser(this) \ No newline at end of file diff -r 0a13dcabf7d3 -r 137a5da55ed9 core/src/test/java/com/geekorum/aboutoss/ExampleUnitTest.kt --- a/core/src/test/java/com/geekorum/aboutoss/ExampleUnitTest.kt Fri Apr 14 14:29:05 2023 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * AboutOss is a utility library to retrieve and display - * opensource licenses in Android applications. - * - * Copyright (C) 2023 by Frederic-Charles Barthelery. - * - * This file is part of AboutOss. - * - * AboutOss is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AboutOss is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AboutOss. If not, see . - */ -package com.geekorum.aboutoss - -import org.junit.Test - -import org.junit.Assert.* - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } -} \ No newline at end of file diff -r 0a13dcabf7d3 -r 137a5da55ed9 core/src/test/java/com/geekorum/aboutoss/core/ExampleUnitTest.kt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/test/java/com/geekorum/aboutoss/core/ExampleUnitTest.kt Thu Apr 13 16:09:27 2023 -0400 @@ -0,0 +1,37 @@ +/* + * AboutOss is a utility library to retrieve and display + * opensource licenses in Android applications. + * + * Copyright (C) 2023 by Frederic-Charles Barthelery. + * + * This file is part of AboutOss. + * + * AboutOss is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AboutOss is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AboutOss. If not, see . + */ +package com.geekorum.aboutoss.core + +import org.junit.Assert +import org.junit.Test + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + Assert.assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff -r 0a13dcabf7d3 -r 137a5da55ed9 gradle/libs.versions.toml --- a/gradle/libs.versions.toml Fri Apr 14 14:29:05 2023 -0400 +++ b/gradle/libs.versions.toml Thu Apr 13 16:09:27 2023 -0400 @@ -8,6 +8,8 @@ espresso-core = "3.5.1" appcompat = "1.6.1" material = "1.8.0" +okio = "3.3.0" +kotlinx-coroutines = "1.6.4" [libraries] core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" } @@ -16,6 +18,9 @@ espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso-core" } appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } material = { group = "com.google.android.material", name = "material", version.ref = "material" } +okio = { module = "com.squareup.okio:okio", version.ref = "okio"} +kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines"} + [plugins] com-android-application = { id = "com.android.application", version.ref = "com-android-application" }