diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 400f73ee..4321ab2f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,14 +37,15 @@ jobs: id: properties shell: bash run: | + cat changelog.md PROPERTIES="$(./gradlew properties --console=plain -q)" VERSION="$(echo "$PROPERTIES" | grep "^version:" | cut -f2- -d ' ')" CHANGELOG="$(./gradlew getChangelog --unreleased --no-header --console=plain -q)" - CHANGELOG="${CHANGELOG//'%'/'%25'}" - CHANGELOG="${CHANGELOG//$'\n'/'%0A'}" - CHANGELOG="${CHANGELOG//$'\r'/'%0D'}" - echo "::set-output name=version::$VERSION" - echo "::set-output name=changelog::$CHANGELOG" + + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "changelog<> $GITHUB_OUTPUT + echo "$CHANGELOG" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT - name: build run: ./gradlew build diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 809fbc57..5a240b17 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -23,6 +23,7 @@ jobs: uses: actions/setup-java@v4 with: java-version: 21 + distribution: zulu - name: Setup Gradle uses: gradle/actions/setup-gradle@v3 @@ -42,11 +43,27 @@ jobs: SONATYPE_PROFILE_ID: ${{ secrets.SONATYPE_PROFILE_ID }} run: ./gradlew -Psigning.keyId=${{ secrets.SIGNING_KEY_ID}} -Psigning.password=${{ secrets.SIGNING_KEY_PASSWORD }} -Psigning.secretKeyRingFile=${{ secrets.SIGNING_KEY_FILE_PATH }} --no-configuration-cache publishAndReleaseToMavenCentral - - name: Patch Changelog + # Set environment variables + - name: Export Properties + id: properties + shell: bash run: | - ./gradlew patchChangelog --release-note="`cat << EOM + CHANGELOG="$(cat << 'EOM' | sed -e 's/^[[:space:]]*$//g' -e '/./,$!d' ${{ github.event.release.body }} - EOM`" + EOM + )" + + echo "changelog<> $GITHUB_OUTPUT + echo "$CHANGELOG" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + # Update Unreleased section with the current release note + - name: Patch Changelog + if: ${{ steps.properties.outputs.changelog != '' }} + env: + CHANGELOG: ${{ steps.properties.outputs.changelog }} + run: | + ./gradlew patchChangelog --release-note="$CHANGELOG" - name: Open PR for Changelog Update env: diff --git a/build.gradle.kts b/build.gradle.kts index 6acc266b..b7931224 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,4 @@ import org.gradle.api.tasks.testing.logging.TestExceptionFormat -import org.jetbrains.changelog.date import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension import org.jlleitschuh.gradle.ktlint.KtlintExtension @@ -14,6 +13,8 @@ plugins { version = property("VERSION_NAME").toString() +changelog.path.set("changelog.md") + subprojects { apply() configure { @@ -84,8 +85,3 @@ subprojects { ) } } - -changelog { - header.set(provider { "${version.get()}\n_${date()}_\n" }) - groups.set(listOf("New", "Improvement", "Fix", "Upgrade")) -} diff --git a/changelog.md b/changelog.md index 515b91d6..6583f428 100644 --- a/changelog.md +++ b/changelog.md @@ -2,18 +2,11 @@ ## Unreleased -### New -- Use Android Studio conversion tools are used for SVG → vector drawable conversions +### Added -### Improvement +- More robust SVG → vector conversions by Android Studio tools -### Fix - -### Upgrade - -## 2.1.0 - -_09-14-2021_ +## 2.1.0 - 09-14-2021 - New: Simplified optimization machinery with `ElementVisitor` - Improvement: `MergePaths` no longer requires its own tree traversal @@ -21,21 +14,15 @@ _09-14-2021_ - Fix: theme referenced colors like `?attrs/dark` no longer cause crashes - Upgrade: Build tools -## 2.0.2 - -_06.02.2021_ +## 2.0.2 - 06.02.2021 - Fixed: Vector Drawable shorthand hex colors (like #FFF) are properly handled -## 2.0.1 - -_06.01.2021_ +## 2.0.1 - 06.01.2021 - Fixed: Groups that wrap clip paths are no longer removed -## 2.0.0 - -_05.29.2021_ +## 2.0.0 - 05.29.2021 - New, breaking(vgo-core): Structured graphic element attributes. * This greatly simplifies the conversions between formats @@ -48,59 +35,43 @@ _05.29.2021_ - Fixed: Test failures on Windows due to path handling - Upgrade: Build with Kotlin 1.5.10 -## 1.4.1 - -_02.16.2021_ +## 1.4.1 - 02.16.2021 - Added: A new type for the `shrinkVectorArtwork` task -## 1.4.0 - -_02.15.2021_ +## 1.4.0 - 02.15.2021 - Added: Gradle plugin - Improved: Reworked the gradle modules to better be published as a library (vgo-core) and thin application wrapper (vgo). - Added: Sonatype publishing -## 1.3.0 - -_01.18.2021_ +## 1.3.0 - 01.18.2021 - Added: Collapse multiple Bézier curves into elliptical arcs when possible - Improvement: Target JVM 11 -## 1.2.2 - -_10.20.2020_ +## 1.2.2 - 10.20.2020 - Improvement: Show filenames with statistics with multiple file inputs and `--stats` - Improvement: Remove Kotlin metadata from the output jar - Fixed: Temporarily removed an optimization that distorted some images -## 1.2.1 - -_10.01.2020_ +## 1.2.1 - 10.01.2020 - Fixed: Some images with curves that lie on a circle omit any representation of that circle in the output - Fixed: Modifying files in-place sometimes results in destroying non-vector files. -## 1.2.0 - -_09.28.2020_ +## 1.2.0 - 09.28.2020 - Improvement: Resort to distribution via a fat jar. Requires managing fewer files and results in a smaller installation since R8 can operate on classes from dependencies as well. - Improvement: Use R8 for optimization. R8 produces a slightly smaller jar and in some cases faster code as well. -## 1.1.1 - -_07.13.2020_ +## 1.1.1 - 07.13.2020 - Fixed: A crash when running on a file in the current directory - Improvement: Report an error when an input file doesn't exist -## 1.1.0 - -_06.20.2020_ +## 1.1.0 - 06.20.2020 - New: Remove redundant close path commands - Improvement: Use the Gradle Application Plugin to build application distrobutions, simplifying installation and making running the tool a little simpler. diff --git a/vgo/build.gradle.kts b/vgo/build.gradle.kts index 5c0afa79..f5d5de40 100644 --- a/vgo/build.gradle.kts +++ b/vgo/build.gradle.kts @@ -9,16 +9,13 @@ plugins { id("com.vanniktech.maven.publish") } -sourceSets { - main { - java.srcDirs("src/generated/kotlin") - } -} +kotlin.sourceSets.getByName("main").kotlin.srcDir("src/generated/kotlin") val r8: Configuration by configurations.creating dependencies { implementation(project(":vgo-core")) + implementation("com.android.tools:sdk-common:31.5.1") testImplementation("com.willowtreeapps.assertk:assertk-jvm:0.28.1") testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.3") @@ -55,6 +52,17 @@ tasks { "**/module-info.class", "META-INF/maven/**", "META-INF/*.version", + "META-INF/LICENSE*", + "META-INF/LGPL2.1", + "META-INF/DEPENDENCIES", + "META-INF/AL2.0", + "META-INF/BCKEY.DSA", + "META-INF/BC2048KE.DSA", + "META-INF/BCKEY.SF", + "META-INF/BC2048KE.SF", + "**/NOTICE*", + "javax/activation/**", + "xsd/catalog.xml", ) } } diff --git a/vgo/src/main/kotlin/com/jzbrooks/vgo/Application.kt b/vgo/src/main/kotlin/com/jzbrooks/vgo/Application.kt index 4f4d3c1a..842be7db 100644 --- a/vgo/src/main/kotlin/com/jzbrooks/vgo/Application.kt +++ b/vgo/src/main/kotlin/com/jzbrooks/vgo/Application.kt @@ -1,18 +1,20 @@ package com.jzbrooks.vgo +import com.android.ide.common.vectordrawable.Svg2Vector import com.jzbrooks.BuildConstants import com.jzbrooks.vgo.core.Writer import com.jzbrooks.vgo.svg.ScalableVectorGraphic import com.jzbrooks.vgo.svg.ScalableVectorGraphicWriter import com.jzbrooks.vgo.svg.SvgOptimizationRegistry import com.jzbrooks.vgo.svg.parse -import com.jzbrooks.vgo.svg.toVectorDrawable import com.jzbrooks.vgo.util.xml.asSequence import com.jzbrooks.vgo.vd.VectorDrawable import com.jzbrooks.vgo.vd.VectorDrawableOptimizationRegistry import com.jzbrooks.vgo.vd.VectorDrawableWriter import com.jzbrooks.vgo.vd.toSvg import org.w3c.dom.Document +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream import java.io.File import javax.xml.parsers.DocumentBuilderFactory import kotlin.math.absoluteValue @@ -63,11 +65,11 @@ class Application { if (inputs.isEmpty()) { require(outputs.isEmpty()) - var path = readLine() + var path = readlnOrNull() val standardInPaths = mutableListOf() while (path != null) { standardInPaths.add(path) - path = readLine() + path = readlnOrNull() } inputs = standardInPaths @@ -139,19 +141,47 @@ class Application { input.inputStream().use { inputStream -> val sizeBefore = inputStream.channel.size() - val document = - DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(input).apply { - documentElement.normalize() - } + val document = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder().parse(input) + document.documentElement.normalize() val rootNodes = document.childNodes.asSequence().filter { it.nodeType == Document.ELEMENT_NODE }.toList() + var graphic = when { - rootNodes.any { it.nodeName == "svg" || input.extension == "svg" } -> parse(rootNodes.first()) - rootNodes.any { it.nodeName == "vector" && input.extension == "xml" } -> - com.jzbrooks.vgo.vd.parse( - rootNodes.first(), - ) + rootNodes.any { it.nodeName == "svg" || input.extension == "svg" } -> { + if (outputFormat == "vd") { + ByteArrayOutputStream().use { pipeOrigin -> + val errors = Svg2Vector.parseSvgToXml(input.toPath(), pipeOrigin) + if (errors != "") { + System.err.println( + """ + Skipping ${input.path} + + $errors + """.trimIndent(), + ) + null + } else { + val pipeTerminal = ByteArrayInputStream(pipeOrigin.toByteArray()) + val convertedDocument = + DOCUMENT_BUILDER_FACTORY.newDocumentBuilder().parse(pipeTerminal) + convertedDocument.documentElement.normalize() + + val documentRoot = + convertedDocument.childNodes.asSequence().first { + it.nodeType == Document.ELEMENT_NODE + } + + com.jzbrooks.vgo.vd.parse(documentRoot) + } + } + } else { + parse(rootNodes.first()) + } + } + rootNodes.any { it.nodeName == "vector" && input.extension == "xml" } -> { + com.jzbrooks.vgo.vd.parse(rootNodes.first()) + } else -> if (input == output) return else null } @@ -159,10 +189,6 @@ class Application { graphic = graphic.toSvg() } - if (graphic is ScalableVectorGraphic && outputFormat == "vd") { - graphic = graphic.toVectorDrawable() - } - val optimizationRegistry = when (graphic) { is VectorDrawable -> VectorDrawableOptimizationRegistry() @@ -217,9 +243,10 @@ class Application { assert(input.isDirectory) assert(output.isDirectory || !output.exists()) - input.listFiles { file -> !file.isHidden }?.forEach { file -> + for (file in input.walkTopDown().filter { file -> !file.isHidden && !file.isDirectory }) { handleFile(file, File(output, file.name), options) } + if (printStats) { val message = "| Total bytes saved: ${(totalBytesBefore - totalBytesAfter).roundToInt()} |" val border = "-".repeat(message.length) @@ -262,6 +289,7 @@ class Application { get() = key.isDirectory && (value.isDirectory || !value.exists()) companion object { + private val DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance() private const val HELP_MESSAGE = """ > vgo [options] [file/directory]