Skip to content

Commit 7640b4d

Browse files
committed
Migrate Utils to Extensions
1 parent 35ffb85 commit 7640b4d

File tree

3 files changed

+130
-39
lines changed

3 files changed

+130
-39
lines changed

plugins/src/main/java/com/google/firebase/gradle/plugins/GradleUtils.kt renamed to plugins/src/main/java/com/google/firebase/gradle/plugins/GradleExtensions.kt

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,19 @@
1616

1717
package com.google.firebase.gradle.plugins
1818

19+
import com.android.build.api.variant.LibraryAndroidComponentsExtension
20+
import com.android.build.api.variant.LibraryVariant
21+
import java.io.BufferedOutputStream
1922
import java.io.File
23+
import java.util.zip.ZipEntry
24+
import java.util.zip.ZipOutputStream
2025
import org.gradle.api.DefaultTask
2126
import org.gradle.api.Project
27+
import org.gradle.api.Task
2228
import org.gradle.api.artifacts.Dependency
2329
import org.gradle.api.attributes.Attribute
2430
import org.gradle.api.attributes.AttributeContainer
31+
import org.gradle.api.plugins.PluginManager
2532
import org.gradle.api.provider.Provider
2633
import org.gradle.kotlin.dsl.apply
2734
import org.gradle.workers.WorkAction
@@ -165,7 +172,7 @@ inline fun <reified T> attributeFrom(name: String) = Attribute.of(name, T::class
165172
* attribute(Attribute.of(name, T::class.java), value)
166173
* ```
167174
*/
168-
inline fun <reified T> AttributeContainer.attribute(name: String, value: T) =
175+
inline fun <reified T : Any> AttributeContainer.attribute(name: String, value: T) =
169176
attribute(attributeFrom(name), value)
170177

171178
/**
@@ -174,8 +181,7 @@ inline fun <reified T> AttributeContainer.attribute(name: String, value: T) =
174181
* pluginManager.apply(T::class)
175182
* ```
176183
*/
177-
inline fun <reified T : Any> org.gradle.api.plugins.PluginManager.`apply`(): Unit =
178-
`apply`(T::class)
184+
inline fun <reified T : Any> PluginManager.apply(): Unit = apply(T::class)
179185

180186
/**
181187
* The name provided to this artifact when published.
@@ -186,4 +192,53 @@ inline fun <reified T : Any> org.gradle.api.plugins.PluginManager.`apply`(): Uni
186192
* ```
187193
*/
188194
val Dependency.artifactName: String
189-
get() = listOf(group, name, version).filterNotNull().joinToString(":")
195+
get() = listOfNotNull(group, name, version).joinToString(":")
196+
197+
/**
198+
* Creates an archive of this directory at the [dest] file.
199+
*
200+
* Can only be ran within the context of a [Task], as outside of a [Task] so you should likely be
201+
* using the `copy` or `sync` tasks instead.
202+
*/
203+
context(Task)
204+
fun File.zipFilesTo(dest: File): File {
205+
logger.info("Zipping '$absolutePath' to '${dest.absolutePath}'")
206+
207+
logger.debug("Ensuring parent directories are present for zip file")
208+
dest.parentFile?.mkdirs()
209+
210+
logger.debug("Creating empty zip file to write to")
211+
dest.createNewFile()
212+
213+
logger.debug("Packing file contents into zip")
214+
ZipOutputStream(BufferedOutputStream(dest.outputStream())).use { zipFile ->
215+
for (file in walk().filter { it.isFile }) {
216+
val relativePath = file.relativeTo(this).unixPath
217+
logger.debug("Adding file to zip: $relativePath")
218+
219+
zipFile.putNextEntry(ZipEntry(relativePath))
220+
file.inputStream().use { it.copyTo(zipFile) }
221+
zipFile.closeEntry()
222+
}
223+
}
224+
225+
return dest
226+
}
227+
228+
/**
229+
* Bind a callback to run whenever there are release variants for this android build.
230+
*
231+
* Syntax sugar for:
232+
* ```
233+
* components.onVariants(components.selector().withBuildType("release")) {
234+
* // ...
235+
* }
236+
* ```
237+
*
238+
* @see LibraryAndroidComponentsExtension.onVariants
239+
*/
240+
fun LibraryAndroidComponentsExtension.onReleaseVariants(
241+
callback: (variant: LibraryVariant) -> Unit
242+
) {
243+
onVariants(selector().withBuildType("release"), callback)
244+
}

plugins/src/main/java/com/google/firebase/gradle/plugins/KotlinUtils.kt renamed to plugins/src/main/java/com/google/firebase/gradle/plugins/KotlinExtensions.kt

Lines changed: 71 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.google.firebase.gradle.plugins
1818

19+
import java.io.File
1920
import org.w3c.dom.Element
2021
import org.w3c.dom.NodeList
2122

@@ -26,16 +27,14 @@ fun String.remove(regex: Regex) = replace(regex, "")
2627
fun String.remove(str: String) = replace(str, "")
2728

2829
/**
29-
* Returns a sequence containing all elements.
30-
*
31-
* The operation is _terminal_.
30+
* Joins a variable amount of [strings][Any.toString] to a single [String] split by newlines (`\n`).
3231
*
33-
* Syntax sugar for:
34-
* ```
35-
* take(count())
32+
* For example:
33+
* ```kotlin
34+
* println(multiLine("Hello", "World", "!")) // "Hello\nWorld\n!"
3635
* ```
3736
*/
38-
public fun <T> Sequence<T>.takeAll(): Sequence<T> = take(count())
37+
fun multiLine(vararg strings: Any?) = strings.joinToString("\n")
3938

4039
/**
4140
* Converts an [Element] to an Artifact string.
@@ -77,19 +76,30 @@ fun Element.toArtifactString() =
7776
* ```
7877
*
7978
* @throws NoSuchElementException if the [Element] does not have descendant [Element]s with tags
80-
* that match the components of an Artifact string; groupId, artifactId, version.
79+
* that match the components of an Artifact string; groupId and artifactId.
8180
*/
8281
fun Element.toMavenName() = "${textByTag("groupId")}:${textByTag("artifactId")}"
8382

8483
/**
85-
* Finds a descendant [Element] by a given [tag], and returns the [textContent]
86-
* [Element.getTextContent] of it.
84+
* Finds a descendant [Element] by a [tag], and returns the [textContent][Element.getTextContent] of
85+
* it.
8786
*
8887
* @param tag the XML tag to filter for (the special value "*" matches all tags)
8988
* @throws NoSuchElementException if an [Element] with the given [tag] does not exist
9089
* @see findElementsByTag
90+
* @see textByTagOrNull
91+
*/
92+
fun Element.textByTag(tag: String) =
93+
textByTagOrNull(tag) ?: throw RuntimeException("Element tag was missing: $tag")
94+
95+
/**
96+
* Finds a descendant [Element] by a [tag], and returns the [textContent][Element.getTextContent] of
97+
* it, or null if it couldn't be found.
98+
*
99+
* @param tag the XML tag to filter for (the special value "*" matches all tags)
100+
* @see textByTag
91101
*/
92-
fun Element.textByTag(tag: String) = findElementsByTag(tag).first().textContent
102+
fun Element.textByTagOrNull(tag: String) = findElementsByTag(tag).firstOrNull()?.textContent
93103

94104
/**
95105
* Finds a descendant [Element] by a given [tag], or creates a new one.
@@ -99,7 +109,7 @@ fun Element.textByTag(tag: String) = findElementsByTag(tag).first().textContent
99109
* @param tag the XML tag to filter for (the special value "*" matches all tags)
100110
* @see findElementsByTag
101111
*/
102-
fun Element.findOrCreate(tag: String) =
112+
fun Element.findOrCreate(tag: String): Element =
103113
findElementsByTag(tag).firstOrNull() ?: ownerDocument.createElement(tag).also { appendChild(it) }
104114

105115
/**
@@ -118,27 +128,21 @@ fun Element.findElementsByTag(tag: String) =
118128
* Yields the items of this [NodeList] as a [Sequence].
119129
*
120130
* [NodeList] does not typically offer an iterator. This extension method offers a means to loop
121-
* through a NodeList's [item][NodeList.item] method, while also taking into account its [length]
122-
* [NodeList.getLength] property to avoid an [IndexOutOfBoundsException].
131+
* through a NodeList's [item][NodeList.item] method, while also taking into account the element's
132+
* [length][NodeList.getLength] property to avoid an [IndexOutOfBoundsException].
123133
*
124134
* Additionally, this operation is _intermediate_ and _stateless_.
125135
*/
126-
fun NodeList.children() = sequence {
127-
for (index in 0..length) {
128-
yield(item(index))
136+
fun NodeList.children(removeDOMSections: Boolean = true) = sequence {
137+
for (index in 0 until length) {
138+
val child = item(index)
139+
140+
if (!removeDOMSections || !child.nodeName.startsWith("#")) {
141+
yield(child)
142+
}
129143
}
130144
}
131145

132-
/**
133-
* Joins a variable amount of [strings][Any.toString] to a single [String] split by newlines (`\n`).
134-
*
135-
* For example:
136-
* ```kotlin
137-
* println(multiLine("Hello", "World", "!")) // "Hello\nWorld\n!"
138-
* ```
139-
*/
140-
fun multiLine(vararg strings: Any?) = strings.joinToString("\n")
141-
142146
/**
143147
* Returns the first match of a regular expression in the [input], beginning at the specified
144148
* [startIndex].
@@ -152,6 +156,26 @@ fun Regex.findOrThrow(input: CharSequence, startIndex: Int = 0) =
152156
find(input, startIndex)
153157
?: throw RuntimeException(multiLine("No match found for the given input:", input.toString()))
154158

159+
/**
160+
* Returns the value of the first capture group.
161+
*
162+
* Intended to be used in [MatchResult] that are only supposed to capture a single entry.
163+
*/
164+
val MatchResult.firstCapturedValue: String
165+
get() = groupValues[1]
166+
167+
/**
168+
* Returns a sequence containing all elements.
169+
*
170+
* The operation is _terminal_.
171+
*
172+
* Syntax sugar for:
173+
* ```
174+
* take(count())
175+
* ```
176+
*/
177+
fun <T> Sequence<T>.takeAll(): Sequence<T> = take(count())
178+
155179
/**
156180
* Creates a [Pair] out of an [Iterable] with only two elements.
157181
*
@@ -212,14 +236,6 @@ fun List<String>.replaceMatches(regex: Regex, transform: (MatchResult) -> String
212236
}
213237
}
214238

215-
/**
216-
* Returns the value of the first capture group.
217-
*
218-
* Intended to be used in [MatchResult] that are only supposed to capture a single entry.
219-
*/
220-
val MatchResult.firstCapturedValue: String
221-
get() = groupValues[1]
222-
223239
/**
224240
* Creates a diff between two lists.
225241
*
@@ -250,3 +266,23 @@ infix fun <T> List<T>.diff(other: List<T>): List<Pair<T?, T?>> {
250266
* ```
251267
*/
252268
fun <T> List<T>.coerceToSize(targetSize: Int) = List(targetSize) { getOrNull(it) }
269+
270+
/**
271+
* The [path][File.path] represented as a qualified unix path.
272+
*
273+
* Useful when a system expects a unix path, but you need to be able to run it on non unix systems.
274+
*
275+
* @see absoluteUnixPath
276+
*/
277+
val File.unixPath: String
278+
get() = path.replace("\\", "/")
279+
280+
/**
281+
* The [absolutePath][File.getAbsolutePath] represented as a qualified unix path.
282+
*
283+
* Useful when a system expects a unix path, but you need to be able to run it on non unix systems.
284+
*
285+
* @see unixPath
286+
*/
287+
val File.absoluteUnixPath: String
288+
get() = absolutePath.replace("\\", "/")

0 commit comments

Comments
 (0)