-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild.gradle.kts
More file actions
120 lines (117 loc) · 4.9 KB
/
Copy pathbuild.gradle.kts
File metadata and controls
120 lines (117 loc) · 4.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.android.library) apply false
alias(libs.plugins.androidx.room3) apply false
alias(libs.plugins.ksp) apply false
alias(libs.plugins.kotlin.compose) apply false
}
val hookSourceFiles = fileTree(rootDir) {
include("**/*.kt", "**/*.java")
exclude("**/build/**", "**/.gradle/**")
}
val hookModuleBuildFiles = fileTree(rootDir) {
include("**/build.gradle.kts")
exclude("build.gradle.kts", "**/build/**", "**/.gradle/**")
}
val featureHookFiles = fileTree(rootDir) {
include("feature/*-hook/src/**/*.kt", "feature/*-hook/build.gradle.kts")
exclude("**/build/**", "**/.gradle/**")
}
val featureHookMainSourceFiles = fileTree(rootDir) {
include("feature/*-hook/src/main/**/*.kt")
exclude("**/build/**", "**/.gradle/**")
}
val verifyHookArchitecture = tasks.register("verifyHookArchitecture") {
group = "verification"
description = "Checks Hook module dependency boundaries and legacy API removal."
inputs.files(
hookSourceFiles,
hookModuleBuildFiles,
featureHookFiles,
featureHookMainSourceFiles,
)
doLast {
val architectureFiles = inputs.files.files
val libxposedApiViolations = architectureFiles.filter { architectureFile ->
val normalizedPath = architectureFile.invariantSeparatorsPath
val allowedModule = normalizedPath.contains("/core/hook-runtime/") ||
normalizedPath.contains("/xposed/entry/")
val sourceReference = architectureFile.extension != "kts" &&
architectureFile.readText().contains("io.github.libxposed.api")
val dependencyReference = architectureFile.extension == "kts" &&
architectureFile.readText().contains("libs.libxposed.api")
!allowedModule && (sourceReference || dependencyReference)
}
check(libxposedApiViolations.isEmpty()) {
"Only Hook runtime and entry may reference libxposed API: " +
libxposedApiViolations.joinToString()
}
val legacyApiViolations = architectureFiles.filter { sourceFile ->
sourceFile.readText().contains("de.robv.android.xposed")
}
check(legacyApiViolations.isEmpty()) {
"Legacy Xposed API references remain: ${legacyApiViolations.joinToString()}"
}
val forbiddenFeatureReferences = listOf(
"androidx.activity.",
"androidx.compose.",
"androidx.room",
"top.yukonga.miuix",
"project(\":app\")",
"project(\":core:logging-app\")",
"project(\":feature:logviewer\")",
)
val featureHookArchitectureFiles = architectureFiles.filter { architectureFile ->
val path = architectureFile.invariantSeparatorsPath
path.contains("/feature/") && path.contains("-hook/")
}
val featureBoundaryViolations = featureHookArchitectureFiles.filter { featureFile ->
val content = featureFile.readText()
forbiddenFeatureReferences.any(content::contains)
}
check(featureBoundaryViolations.isEmpty()) {
"Feature Hook modules depend on UI or app-only infrastructure: " +
featureBoundaryViolations.joinToString()
}
val requiredDiagnosticEvents = setOf(
"target.resolve.started",
"target.resolve.succeeded",
"target.resolve.failed",
"hook.callback.entered",
"hook.callback.transformed",
"hook.callback.bypassed",
"hook.callback.failed",
)
val featureModuleNames = listOf(
"googlephotos-hook",
"ime-hook",
"keepalive-hook",
)
val missingDiagnosticEvents = featureModuleNames.flatMap { moduleName ->
val moduleContent = featureHookArchitectureFiles
.filter { sourceFile ->
val path = sourceFile.invariantSeparatorsPath
path.contains("/feature/$moduleName/src/main/") &&
sourceFile.extension == "kt"
}
.joinToString(separator = "\n") { sourceFile -> sourceFile.readText() }
requiredDiagnosticEvents
.filterNot(moduleContent::contains)
.map { eventName -> "$moduleName:$eventName" }
}
check(missingDiagnosticEvents.isEmpty()) {
"Feature Hook modules are missing required diagnostic events: " +
missingDiagnosticEvents.joinToString()
}
}
}
tasks.register("verifyXposedMigration") {
group = "verification"
description = "Runs Hook architecture, catalog, and packaged metadata verification."
dependsOn(
verifyHookArchitecture,
":feature:googlephotos-hook:testReleaseUnitTest",
":xposed:entry:testDebugUnitTest",
":app:verifyXposedMetadata",
)
}