Skip to content

Commit c1a20ec

Browse files
committed
Merge branch 'jb-main' into integration
# Conflicts: # collection/collection/build.gradle # window/window-core/build.gradle
2 parents 07e1ed4 + 554fb7e commit c1a20ec

File tree

41 files changed

+789
-163
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+789
-163
lines changed

buildSrc/private/src/main/kotlin/androidx/build/MavenUploadHelper.kt

Lines changed: 36 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import com.android.build.gradle.AppPlugin
2020
import com.android.build.gradle.LibraryPlugin
2121
import com.android.utils.childrenIterator
2222
import com.android.utils.forEach
23-
import com.android.utils.mapValuesNotNull
2423
import com.google.gson.GsonBuilder
2524
import com.google.gson.JsonObject
2625
import com.google.gson.stream.JsonWriter
@@ -59,8 +58,10 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
5958
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper
6059
import org.xml.sax.InputSource
6160
import org.xml.sax.XMLReader
62-
import androidx.build.jetbrains.ArtifactRedirecting
63-
import androidx.build.jetbrains.artifactRedirecting
61+
import androidx.build.jetbrains.originalToRedirectedDependency
62+
import org.gradle.api.artifacts.ModuleIdentifier
63+
import org.gradle.api.artifacts.ModuleVersionIdentifier
64+
import org.gradle.api.internal.artifacts.DefaultModuleIdentifier
6465
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
6566

6667
fun Project.configureMavenArtifactUpload(
@@ -120,19 +121,6 @@ private fun Project.configureComponentPublishing(
120121
)
121122
group = androidxGroup.group
122123

123-
val mavenCoordsToRedirecting: Provider<Map<String, ArtifactRedirecting>> = provider {
124-
project
125-
.getProjectsMap()
126-
.values
127-
.mapNotNull { project.findProject(it) }
128-
.associateBy {
129-
val group = it.group
130-
val name = it.name
131-
"$group:$name"
132-
}
133-
.mapValuesNotNull { it.value.artifactRedirecting() }
134-
}
135-
136124
/*
137125
* Provides a set of maven coordinates (groupId:artifactId) of artifacts in AndroidX
138126
* that are Android Libraries.
@@ -206,10 +194,21 @@ private fun Project.configureComponentPublishing(
206194
}
207195
project.tasks.withType(GenerateMavenPom::class.java).configureEach { task ->
208196
task.doLast {
197+
fun hasTargetWithComponent(componentName: String) =
198+
multiplatformExtension?.targets?.find { target ->
199+
target.components.any { it.name == componentName }
200+
} != null
201+
202+
// extract heuristically from:
203+
// "build/publications/kotlinMultiplatformDecorated/pom-default.xml"
204+
// "build/publications/desktop/pom-default.xml"
205+
// ...
206+
// and take only if it is a target's component (we redirect only targets)
207+
val componentName = task.destination.parentFile.name.takeIf(::hasTargetWithComponent)
208+
209209
val pomFile = task.destination
210210
val pom = pomFile.readText()
211-
val modifiedPom = modifyPomDependencies(pom, mavenCoordsToRedirecting.get())
212-
211+
val modifiedPom = modifyPomDependencies(pom, componentName)
213212
if (pom != modifiedPom) {
214213
pomFile.writeText(modifiedPom)
215214
}
@@ -234,10 +233,7 @@ private fun Project.configureComponentPublishing(
234233
/**
235234
* Looks for a dependencies XML element within [pom], sorts its contents and modify it by redirecting coordinates
236235
*/
237-
internal fun modifyPomDependencies(
238-
pom: String,
239-
mavenCoordsToRedirecting: Map<String, ArtifactRedirecting>
240-
): String {
236+
internal fun Project.modifyPomDependencies(pom: String, componentName: String?): String {
241237
// Workaround for using the default namespace in dom4j.
242238
val namespaceUris = mapOf("ns" to "http://maven.apache.org/POM/4.0.0")
243239
val docFactory = DocumentFactory()
@@ -246,14 +242,20 @@ internal fun modifyPomDependencies(
246242
val xmlReader = JAXPSAXParser()
247243
val document = parseText(docFactory, xmlReader, pom)
248244

245+
val originalToRedirected = if (componentName != null) {
246+
originalToRedirectedDependency(componentName)
247+
} else {
248+
emptyMap()
249+
}
250+
249251
// For each <dependencies> element, sort the contained elements in-place.
250252
document.rootElement
251253
.selectNodes("ns:dependencies")
252254
.filterIsInstance<Element>()
253255
.forEach { element ->
254256
val deps = element.elements()
255257
val modifiedDeps = deps
256-
.map { modifyPomDependency(it, mavenCoordsToRedirecting) }
258+
.onEach { modifyPomDependency(it, originalToRedirected) }
257259
.sortedBy { it.stringValue }
258260

259261
// Content contains formatting nodes, so to avoid modifying those we replace
@@ -284,22 +286,18 @@ internal fun modifyPomDependencies(
284286

285287
internal fun modifyPomDependency(
286288
dependency: Element,
287-
mavenCoordsToRedirecting: Map<String, ArtifactRedirecting>
288-
): Element {
289-
val groupId = dependency.selectSingleNode("ns:groupId")
290-
val artifactId = dependency.selectSingleNode("ns:artifactId")
291-
val version = dependency.selectSingleNode("ns:version")
292-
val name = artifactId.stringValue.substringBeforeLast("-")
293-
val target = artifactId.stringValue.substringAfterLast("-")
294-
295-
val coords = "${groupId.stringValue}:$name"
296-
val redirecting = mavenCoordsToRedirecting[coords] ?: return dependency
297-
val shouldReplace = redirecting.targetNames.contains(target)
298-
if (shouldReplace) {
299-
groupId.text = redirecting.groupId
300-
version.text = redirecting.versionForTargetOrDefault(target)
289+
originalToRedirected: Map<ModuleIdentifier, ModuleVersionIdentifier>
290+
) {
291+
val groupIdNode = dependency.selectSingleNode("ns:groupId")
292+
val artifactIdNode = dependency.selectSingleNode("ns:artifactId")
293+
val versionNode = dependency.selectSingleNode("ns:version")
294+
val id = DefaultModuleIdentifier.newId(groupIdNode.stringValue, artifactIdNode.stringValue)
295+
val redirected = originalToRedirected[id]
296+
if (redirected != null) {
297+
groupIdNode.text = redirected.group
298+
artifactIdNode.text = redirected.name
299+
versionNode.text = redirected.version
301300
}
302-
return dependency
303301
}
304302

305303
// Coped from org.dom4j.DocumentHelper with modifications to allow SAXReader configuration.

buildSrc/private/src/main/kotlin/androidx/build/jetbrains/JetbrainsAndroidXRedirectingPublicationHelpers.kt

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,27 @@
1616

1717
package androidx.build.jetbrains
1818

19+
import androidx.build.getProjectsMap
20+
import com.android.utils.mapValuesNotNull
1921
import org.gradle.api.Project
2022
import org.jetbrains.kotlin.gradle.plugin.mpp.*
2123
import org.gradle.api.publish.PublishingExtension
2224
import org.gradle.api.publish.maven.internal.publication.DefaultMavenPublication
23-
import org.gradle.api.attributes.Usage
2425
import org.gradle.api.artifacts.Configuration
2526
import org.gradle.api.artifacts.DependencyConstraint
2627
import org.gradle.api.artifacts.ExcludeRule
2728
import org.gradle.api.artifacts.ModuleDependency
29+
import org.gradle.api.artifacts.ModuleIdentifier
2830
import org.gradle.api.artifacts.ModuleVersionIdentifier
2931
import org.gradle.api.artifacts.PublishArtifact
32+
import org.gradle.api.artifacts.ResolvedDependency
3033
import org.gradle.api.attributes.AttributeContainer
3134
import org.gradle.api.capabilities.Capability
3235
import org.gradle.api.component.ComponentWithCoordinates
3336
import org.gradle.api.component.ComponentWithVariants
3437
import org.gradle.api.component.SoftwareComponent
38+
import org.gradle.api.internal.artifacts.DefaultModuleIdentifier
39+
import org.gradle.api.internal.artifacts.DefaultModuleVersionIdentifier
3540
import org.gradle.api.internal.component.SoftwareComponentInternal
3641
import org.gradle.api.internal.component.UsageContext
3742
import org.gradle.api.publish.maven.MavenPublication
@@ -150,4 +155,85 @@ internal class CustomRootComponent(
150155
)
151156
)
152157
}
153-
}
158+
}
159+
160+
internal fun Project.originalToRedirectedDependency(
161+
componentName: String
162+
): Map<ModuleIdentifier, ModuleVersionIdentifier> {
163+
/**
164+
* Find a redirect to another group and version.
165+
*
166+
* Use heuristic method that compares modules names. Example:
167+
* [first-level-dependency] org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.8.4 ->
168+
* [artifact-with-the-same-name] androidx.lifecycle:lifecycle-runtime:2.8.5 ->
169+
* [artifact-with-the-same-name-plus-suffix] androidx.lifecycle:lifecycle-runtime-desktop:2.8.5
170+
*
171+
* The first dependency redirects to the last one.
172+
*/
173+
fun ResolvedDependency.findRedirectedDependencyHeuristically() =
174+
children
175+
.find { it.moduleName == moduleName }
176+
?.children
177+
// don't check `it.moduleName == "moduleName-$target"` here,
178+
// as it can be resolved to any other suitable target
179+
// (for example, to jvm, or any other custom)
180+
?.find { it.moduleName.startsWith(moduleName) }
181+
182+
/**
183+
* Extract redirections from project configuration
184+
*
185+
* Example for compose:ui
186+
* org.jetbrains.androidx.performance:performance-annotation-iosarm64=androidx.performance:performance-annotation-iosarm64:1.0.0-alpha01
187+
* org.jetbrains.androidx.performance:performance-annotation-jvm=androidx.performance:performance-annotation-jvm:1.0.0-alpha01
188+
* org.jetbrains.compose.annotation-internal:annotation-jvm=androidx.annotation:annotation-jvm:1.9.1
189+
* org.jetbrains.compose.collection-internal:collection-jvm=androidx.collection:collection-jvm:1.5.0-beta01
190+
* ...
191+
*/
192+
val projectDefined =
193+
getProjectsMap()
194+
.values
195+
.mapNotNull { project.findProject(it) }
196+
.flatMap { project ->
197+
val redirecting = project.artifactRedirecting()
198+
redirecting.targetNames.filter { it.isNotEmpty() }.map {
199+
val group = project.group.toString()
200+
val name = project.name.toString()
201+
val target = it
202+
val original = DefaultModuleIdentifier.newId(group, "$name-$target")
203+
val redirected = DefaultModuleVersionIdentifier.newId(
204+
redirecting.groupId,
205+
"$name-$target",
206+
redirecting.versionForTargetOrDefault(target)
207+
)
208+
original to redirected
209+
}
210+
}
211+
.associate { it }
212+
213+
fun mainConfiguration() =
214+
configurations.find { it.name == "${componentName}RuntimeClasspath" } ?:
215+
configurations.find { it.name == "${componentName}CompileKlibraries" }!!
216+
217+
/**
218+
* Extract redirections for dependencies using heuristic method (for both project, and external)
219+
*
220+
* Example for compose:ui
221+
* org.jetbrains.compose.annotation-internal:annotation=androidx.annotation:annotation-jvm:1.9.1
222+
* org.jetbrains.compose.collection-internal:collection=androidx.collection:collection-jvm:1.5.0-beta02
223+
* org.jetbrains.androidx.lifecycle:lifecycle-common=androidx.lifecycle:lifecycle-common-jvm:2.8.5
224+
* org.jetbrains.androidx.lifecycle:lifecycle-runtime=androidx.lifecycle:lifecycle-runtime-desktop:2.8.5
225+
* org.jetbrains.androidx.lifecycle:lifecycle-viewmodel=androidx.lifecycle:lifecycle-viewmodel-desktop:2.8.5
226+
*
227+
* It is workaround for
228+
* https://youtrack.jetbrains.com/issue/CMP-7764/Redirection-of-artifacts-breaks-poms-for-multiplatform-libraries-that-use-them
229+
* After it is resolved, externalWithHeuristic shouldn't be needed.
230+
*/
231+
val externalWithHeuristic = mainConfiguration()
232+
.resolvedConfiguration
233+
.firstLevelModuleDependencies
234+
.orEmpty()
235+
.associateBy { DefaultModuleIdentifier.newId(it.moduleGroup, it.moduleName) }
236+
.mapValuesNotNull { it.value.findRedirectedDependencyHeuristically()?.module?.id }
237+
238+
return projectDefined + externalWithHeuristic
239+
}

buildSrc/public/src/main/kotlin/androidx/build/jetbrains/ArtifactRedirecting.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ data class ArtifactRedirecting(
2222
val groupId: String,
2323
val defaultVersion: String,
2424
val targetNames: Set<String>,
25-
val targetVersions: Map<String, String>
25+
26+
/**
27+
* Versions for specific targets. If not specified, [defaultVersion] is used.
28+
*/
29+
val targetVersions: Map<String, String> = emptyMap()
2630
) {
2731
fun versionForTargetOrDefault(target: String): String {
2832
return targetVersions[target.lowercase()] ?: defaultVersion

collection/collection-compatibility-stub/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ kotlin {
6666
commonMain {
6767
dependencies {
6868
api(libs.kotlinStdlib)
69-
api("androidx.collection:collection:1.5.0-beta02")
69+
api("androidx.collection:collection:1.5.0")
7070
}
7171
}
7272

compose/foundation/foundation/build.gradle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@ if (AndroidXComposePlugin.isMultiplatformEnabled(project)) {
108108
implementation(libs.kotlinStdlib)
109109
implementation(project(":annotation:annotation"))
110110
implementation(project(":collection:collection"))
111-
implementation(project(":performance:performance-annotation"))
112111
api(project(':compose:animation:animation'))
113112
api(project(':compose:runtime:runtime'))
114113
api(project(':compose:ui:ui'))

compose/foundation/foundation/src/skikoMain/kotlin/androidx/compose/foundation/text/input/internal/TextInputSession.skiko.kt

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,20 +57,22 @@ internal actual suspend fun PlatformTextInputSession.platformSpecificTextInputSe
5757
value = state.untransformedText.toTextFieldValue(),
5858
textInputSession = null
5959
)
60-
6160
val newValue = editProcessor.apply(commands)
6261

63-
state.replaceAll(newValue.text)
6462
state.editUntransformedTextAsUser {
65-
val untransformedSelection = state.mapFromTransformed(newValue.selection)
66-
setSelectionCoerced(untransformedSelection.start, untransformedSelection.end)
63+
// Update text
64+
replace(0, length, newValue.text)
65+
66+
// Update selection
67+
val selection = newValue.selection
68+
setSelectionCoerced(selection.start, selection.end)
6769

70+
// Update composition
6871
val composition = newValue.composition
6972
if (composition == null) {
7073
commitComposition()
7174
} else {
72-
val untransformedComposition = state.mapFromTransformed(composition)
73-
setComposition(untransformedComposition.start, untransformedComposition.end)
75+
setComposition(composition.start, composition.end)
7476
}
7577
}
7678
}

0 commit comments

Comments
 (0)