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

Extract APK Creator in common module #145

Merged
merged 3 commits into from
Dec 18, 2023
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion ruler-cli/src/main/java/com/spotify/ruler/cli/RulerCli.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import com.github.ajalt.clikt.parameters.options.required
import com.github.ajalt.clikt.parameters.types.file
import com.spotify.ruler.common.BaseRulerTask
import com.spotify.ruler.common.FEATURE_NAME
import com.spotify.ruler.common.apk.ApkCreator
import com.spotify.ruler.common.apk.InjectedToolApkCreator
import com.spotify.ruler.common.dependency.ArtifactResult
import com.spotify.ruler.common.dependency.DependencyComponent
import com.spotify.ruler.common.dependency.DependencyEntry
Expand All @@ -38,15 +40,20 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import java.io.File
import java.util.logging.Level
import java.util.logging.Logger

class RulerCli : CliktCommand(), BaseRulerTask {
private val logger = Logger.getLogger("Ruler")
private val dependencyMap by option().file().required()
private val rulerConfigJson by option().file().required()
private val apkFile by option().file().required()
private val reportDir by option().file(canBeDir = true).required()
private val mappingFile: File? by option().file()
private val resourceMappingFile: File? by option().file()
private val unstrippedNativeFiles: List<File> by option().file().multiple()
private val aapt2Tool: File? by option().file()

override fun print(content: String) = echo(content)

override fun provideMappingFile() = mappingFile
Expand All @@ -60,7 +67,7 @@ class RulerCli : CliktCommand(), BaseRulerTask {
val json = Json.decodeFromStream<JsonRulerConfig>(rulerConfigJson.inputStream())
RulerConfig(
projectPath = json.projectPath,
apkFilesMap = mapOf(FEATURE_NAME to listOf(apkFile)),
apkFilesMap = createApkFile(json.projectPath, json.deviceSpec!!),
reportDir = reportDir,
ownershipFile = json.ownershipFile?.let { File(it) },
staticDependenciesFile = json.staticComponentsPath?.let { File(it) },
Expand Down Expand Up @@ -100,8 +107,40 @@ class RulerCli : CliktCommand(), BaseRulerTask {
override fun provideDependencies(): Map<String, List<DependencyComponent>> = dependencies

override fun run() {
logger.log(Level.INFO, """
~~~~~ Starting Ruler ~~~~~
Using Dependency Map: ${dependencyMap.path}
Using Ruler Config: ${rulerConfigJson.path}
Using App File: ${apkFile.path}
Using Proguard Mapping File: ${mappingFile?.path}
Using Resource Mapping File: ${resourceMappingFile?.path}
Using AAPT2: ${aapt2Tool?.path}
Writing reports to: ${reportDir.path}
""".trimIndent())
super.run()
}

private fun createApkFile(projectPath: String, deviceSpec: DeviceSpec): Map<String, List<File>> {

val apkCreator = if (aapt2Tool != null) {
InjectedToolApkCreator(aapt2Tool!!.toPath())
} else {
ApkCreator(File(projectPath))
}

return if (apkFile.extension == "apk") {
mapOf(FEATURE_NAME to listOf(apkFile))
} else {
apkCreator.createSplitApks(
apkFile,
deviceSpec,
File(projectPath).resolve(File("tmp")).apply {
mkdir()
}
)
}
}

}

@Serializable
Expand Down
6 changes: 6 additions & 0 deletions ruler-cli/src/test/resources/rulerConfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
"variantName": "release",
"versionName": "1.0.0"
},
"deviceSpec": {
"supportedAbis": ["arm64-v8a"],
"supportedLocales": ["en"],
"screenDensity": 480,
"sdkVersion": 27
},
"defaultOwner": "main_activity",
"omitFileBreakdown": false,
"ownershipFile": "src/test/resources/test_ownership.yaml",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.spotify.ruler.plugin.apk
package com.spotify.ruler.common.apk

import com.android.SdkConstants
import com.android.build.gradle.internal.SdkLocator
Expand Down Expand Up @@ -47,7 +47,7 @@ import java.util.concurrent.TimeUnit
*
* @param rootDir Root directory of the Gradle project, needed to look up the path of certain binaries.
*/
class ApkCreator(private val rootDir: File) {
open class ApkCreator(private val rootDir: File) {

private val rulerDebugKey = "rulerDebug.keystore"
private val rulerKeystorePassword = "rulerpassword"
Expand Down Expand Up @@ -91,7 +91,7 @@ class ApkCreator(private val rootDir: File) {
}

/** Finds and returns the location of the aapt2 executable. */
private fun getAapt2Location(): Path {
open fun getAapt2Location(): Path {
val sdkLocation = getAndroidSdkLocation()
val sdkHandler = AndroidSdkHandler.getInstance(AndroidLocationsSingleton, sdkLocation)
val progressIndicator = object : ProgressIndicatorAdapter() { /* No progress reporting */ }
Expand Down Expand Up @@ -133,3 +133,7 @@ class ApkCreator(private val rootDir: File) {
const val BASE_FEATURE_NAME = "base"
}
}

class InjectedToolApkCreator(private val aapt2Tool: Path): ApkCreator(File("")) {
override fun getAapt2Location(): Path = aapt2Tool
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,14 @@ class DependencySanitizer(private val classNameSanitizer: ClassNameSanitizer) {
}
}

/** Determines the correct component type for a given [entry]. */
private val versionRegex = Regex("^\\d+\\.\\d+\\.\\d.*")

/**
* Determines the correct component type for a given [entry].
* Assuming that all external dependencies do have a version number in the format XX.XX.XX
* */
private fun getComponentType(entry: DependencyEntry): ComponentType = when {
entry.component.startsWith(':') -> ComponentType.INTERNAL
else -> ComponentType.EXTERNAL
versionRegex.containsMatchIn(entry.component.substringAfterLast(":","")) -> ComponentType.EXTERNAL
else -> ComponentType.INTERNAL
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@
* limitations under the License.
*/

package com.spotify.ruler.plugin
package com.spotify.ruler.common.apk

import com.google.common.truth.Truth.assertThat
import com.spotify.ruler.common.models.DeviceSpec
import com.spotify.ruler.plugin.apk.ApkCreator
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir
import java.io.File
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

package com.spotify.ruler.plugin

import com.spotify.ruler.plugin.apk.ApkCreator
import com.spotify.ruler.common.apk.ApkCreator
import com.spotify.ruler.plugin.dependency.EntryParser
import com.spotify.ruler.common.BaseRulerTask
import com.spotify.ruler.common.dependency.DependencyComponent
Expand Down
Loading