diff --git a/build.gradle b/build.gradle index e4a36abc9..70f40a9f7 100644 --- a/build.gradle +++ b/build.gradle @@ -33,7 +33,6 @@ allprojects { repositories { mavenCentral() { metadataSources { mavenPom(); ignoreGradleMetadataRedirection() } } - mavenLocal() } } diff --git a/gradle-sls-packaging/src/main/java/com/palantir/gradle/dist/tasks/CreateManifest.java b/gradle-sls-packaging/src/main/java/com/palantir/gradle/dist/tasks/CreateManifest.java index 8c7a8cfb4..56d46faec 100644 --- a/gradle-sls-packaging/src/main/java/com/palantir/gradle/dist/tasks/CreateManifest.java +++ b/gradle-sls-packaging/src/main/java/com/palantir/gradle/dist/tasks/CreateManifest.java @@ -18,19 +18,15 @@ import com.google.common.base.Preconditions; import com.google.common.base.Splitter; -import com.google.common.collect.ImmutableList; import com.google.common.collect.Streams; -import com.palantir.gradle.dist.BaseDistributionExtension; +import com.palantir.gradle.autoparallelizable.AutoParallelizable; import com.palantir.gradle.dist.ObjectMappers; import com.palantir.gradle.dist.ProductDependency; -import com.palantir.gradle.dist.ProductDependencyIntrospectionPlugin; import com.palantir.gradle.dist.ProductDependencyLockFile; import com.palantir.gradle.dist.ProductId; import com.palantir.gradle.dist.ProductType; import com.palantir.gradle.dist.SlsManifest; -import com.palantir.gradle.dist.pdeps.ProductDependencies; import com.palantir.gradle.dist.pdeps.ProductDependencyManifest; -import com.palantir.gradle.dist.pdeps.ResolveProductDependenciesTask; import com.palantir.sls.versions.OrderableSlsVersion; import com.palantir.sls.versions.SlsVersion; import java.io.ByteArrayOutputStream; @@ -42,26 +38,22 @@ import java.util.List; import java.util.Optional; import java.util.stream.Collectors; -import org.gradle.StartParameter; import org.gradle.api.GradleException; -import org.gradle.api.Project; -import org.gradle.api.Task; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.file.RegularFile; import org.gradle.api.file.RegularFileProperty; -import org.gradle.api.invocation.Gradle; import org.gradle.api.logging.Logger; import org.gradle.api.logging.Logging; import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.api.provider.SetProperty; -import org.gradle.api.specs.Spec; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.InputFile; import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.OutputFile; -import org.gradle.api.tasks.TaskProvider; -import org.gradle.language.base.plugins.LifecycleBasePlugin; +@AutoParallelizable final class CreateManifest { private static final Logger logger = Logging.getLogger(CreateManifest.class); @@ -90,19 +82,25 @@ interface Params { @Input Property getProjectVersion(); - /** - * Intentionally checking whether file exists as gradle's {@link org.gradle.api.tasks.Optional} only operates on - * whether the method returns null or not. Otherwise, it will fail when the file doesn't exist. - */ - @InputFile - @org.gradle.api.tasks.Optional - RegularFileProperty getLockfileIfExists(); + default Provider getLockfile() { + return getProjectDir().map(projectDir -> projectDir.file(ProductDependencyLockFile.LOCK_FILE)); + } + + default boolean lockfileExists() { + return getLockfile().get().getAsFile().exists(); + } @Input Property getShouldWriteLocks(); @Internal Property getTaskName(); + + @Internal + DirectoryProperty getRootDir(); + + @Internal + DirectoryProperty getProjectDir(); } static void action(Params params) { @@ -119,29 +117,33 @@ static void action(Params params) { if (productDependencies.isEmpty()) { requireAbsentLockfile(params); } else { - ensureLockfileIsUpToDate(productDependencies); + ensureLockfileIsUpToDate(params, productDependencies); } - ObjectMappers.jsonMapper.writeValue( - getManifestFile().getAsFile().get(), - SlsManifest.builder() - .manifestVersion("1.0") - .productType(getProductType().get()) - .productGroup(getServiceGroup().get()) - .productName(getServiceName().get()) - .productVersion(getProjectVersion()) - .putAllExtensions(getManifestExtensions().get()) - .putExtensions("product-dependencies", productDependencies) - .build()); + try { + ObjectMappers.jsonMapper.writeValue( + params.getManifestFile().getAsFile().get(), + SlsManifest.builder() + .manifestVersion("1.0") + .productType(params.getProductType().get()) + .productGroup(params.getServiceGroup().get()) + .productName(params.getServiceName().get()) + .productVersion(params.getProjectVersion().get()) + .putAllExtensions(params.getManifestExtensions().get()) + .putExtensions("product-dependencies", productDependencies) + .build()); + } catch (IOException e) { + throw new RuntimeException("Failed to write json for manifest", e); + } } private static void requireAbsentLockfile(Params params) { - File lockfile = getLockfile(); - - if (!lockfile.exists()) { + if (!params.lockfileExists()) { return; } + File lockfile = params.getLockfile().get().getAsFile(); + if (params.getShouldWriteLocks().get()) { lockfile.delete(); logger.lifecycle("Deleted {}", lockfile); @@ -152,64 +154,62 @@ private static void requireAbsentLockfile(Params params) { } } - private File getLockfile() { - return getProject().file(ProductDependencyLockFile.LOCK_FILE); - } - - public static boolean shouldWriteLocks(Project project) { - String taskName = project.getPath().equals(":") - ? ":writeProductDependenciesLocks" - : project.getPath() + ":writeProductDependenciesLocks"; - Gradle gradle = project.getGradle(); - return gradle.getStartParameter().isWriteDependencyLocks() - || gradle.getTaskGraph().hasTask(taskName); - } + private static void ensureLockfileIsUpToDate(Params params, List productDeps) { + File lockfile = params.getLockfile().get().getAsFile(); + Path relativePath = params.getRootDir().getAsFile().get().toPath().relativize(lockfile.toPath()); - private static void ensureLockfileIsUpToDate(Params params, List productDeps) - throws IOException { - File lockfile = getLockfile(); - Path relativePath = getProject().getRootDir().toPath().relativize(lockfile.toPath()); String upToDateContents = ProductDependencyLockFile.asString( productDeps, params.getInRepoProductIds().get()); - boolean lockfileExists = lockfile.exists(); if (params.getShouldWriteLocks().get()) { - Files.writeString(lockfile.toPath(), upToDateContents); + try { + Files.writeString(lockfile.toPath(), upToDateContents); + } catch (IOException e) { + throw new RuntimeException("Failed to write lockfile " + relativePath, e); + } - if (!lockfileExists) { + if (!params.lockfileExists()) { logger.lifecycle("Created {}\n\t{}", relativePath, upToDateContents.replaceAll("\n", "\n\t")); } else { logger.lifecycle("Updated {}", relativePath); } } else { - if (!lockfileExists) { + if (!params.lockfileExists()) { throw new GradleException(String.format( "%s does not exist, please run `./gradlew %s --write-locks` and commit the resultant file", relativePath, params.getTaskName().get())); } else { - String fromDisk = Files.readString(lockfile.toPath()); - Preconditions.checkState( - fromDisk.equals(upToDateContents), - "%s is out of date, please run `./gradlew %s --write-locks` to update it%s", - relativePath, - getName(), - diff(lockfile, upToDateContents).map(s -> ":\n" + s).orElse("")); + try { + String fromDisk = Files.readString(lockfile.toPath()); + + Preconditions.checkState( + fromDisk.equals(upToDateContents), + "%s is out of date, please run `./gradlew %s --write-locks` to update it%s", + relativePath, + params.getTaskName(), + diff(params, lockfile, upToDateContents) + .map(s -> ":\n" + s) + .orElse("")); + } catch (IOException e) { + throw new RuntimeException("Failed to read lockfile " + relativePath, e); + } } } } /** Provide a rich diff so the user understands what change will be made before they run --write-locks. */ - private Optional diff(File existing, String upToDateContents) { + private static Optional diff(Params params, File existing, String upToDateContents) { try { File tempFile = Files.createTempFile("product-dependencies", "lock").toFile(); Files.writeString(tempFile.toPath(), upToDateContents); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - getProject().exec(spec -> { - spec.commandLine("diff", "-u", existing.getAbsolutePath(), tempFile.getAbsolutePath()); - spec.setStandardOutput(baos); - spec.setIgnoreExitValue(true); - }); + + // params.getExecOperations().exec(spec -> { + // spec.commandLine("diff", "-u", existing.getAbsolutePath(), tempFile.getAbsolutePath()); + // spec.setStandardOutput(baos); + // spec.setIgnoreExitValue(true); + // }); return Optional.of( Streams.stream(Splitter.on("\n").split(new String(baos.toByteArray(), StandardCharsets.UTF_8))) .skip(2) @@ -229,58 +229,5 @@ private static void validateProjectVersion(Provider projectVersion) { } } - public static TaskProvider createManifestTask(Project project, BaseDistributionExtension ext) { - TaskProvider resolveProductDependenciesTask = - ProductDependencies.registerProductDependencyTasks(project, ext); - - TaskProvider createManifest = project.getTasks() - .register("createManifest", CreateManifest.class, task -> { - task.getServiceName().set(ext.getDistributionServiceName()); - task.getServiceGroup().set(ext.getDistributionServiceGroup()); - task.getProductType().set(ext.getProductType()); - task.getManifestFile().set(new File(project.getBuildDir(), "/deployment/manifest.yml")); - task.getProductDependenciesFile() - .set(resolveProductDependenciesTask.flatMap( - ResolveProductDependenciesTask::getManifestFile)); - task.getManifestExtensions().set(ext.getManifestExtensions()); - task.getInRepoProductIds() - .set(project.provider(() -> ProductDependencyIntrospectionPlugin.getInRepoProductIds( - project.getRootProject()) - .keySet())); - - // Ensure we re-run task to write locks - task.getOutputs().upToDateWhen(new Spec() { - @Override - public boolean isSatisfiedBy(Task _task) { - return !shouldWriteLocks(project); - } - }); - - task.dependsOn(resolveProductDependenciesTask); - }); - - project.getPluginManager().withPlugin("lifecycle-base", _p -> { - project.getTasks() - .named(LifecycleBasePlugin.CHECK_TASK_NAME) - .configure(task -> task.dependsOn(createManifest)); - }); - - project.getTasks() - .register("writeProductDependenciesLocks", WriteProductDependenciesLocksMarkerTask.class, task -> { - task.dependsOn(createManifest); - }); - - // We want `./gradlew --write-locks` to magically fix up the product-dependencies.lock file - // We can't do this at configuration time because it would mess up gradle-consistent-versions. - StartParameter startParam = project.getGradle().getStartParameter(); - if (startParam.isWriteDependencyLocks() && !startParam.getTaskNames().contains("createManifest")) { - List taskNames = ImmutableList.builder() - .addAll(startParam.getTaskNames()) - .add("createManifest") - .build(); - startParam.setTaskNames(taskNames); - } - - return createManifest; - } + private CreateManifest() {} } diff --git a/gradle-sls-packaging/src/main/java/com/palantir/gradle/dist/tasks/CreateManifestTask.java b/gradle-sls-packaging/src/main/java/com/palantir/gradle/dist/tasks/CreateManifestTask.java index 064a367be..0257734f8 100644 --- a/gradle-sls-packaging/src/main/java/com/palantir/gradle/dist/tasks/CreateManifestTask.java +++ b/gradle-sls-packaging/src/main/java/com/palantir/gradle/dist/tasks/CreateManifestTask.java @@ -16,75 +16,21 @@ package com.palantir.gradle.dist.tasks; -import com.google.common.base.Preconditions; -import com.google.common.base.Splitter; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Streams; -import com.palantir.gradle.dist.BaseDistributionExtension; -import com.palantir.gradle.dist.ObjectMappers; -import com.palantir.gradle.dist.ProductDependency; -import com.palantir.gradle.dist.ProductDependencyIntrospectionPlugin; -import com.palantir.gradle.dist.ProductDependencyLockFile; -import com.palantir.gradle.dist.ProductId; -import com.palantir.gradle.dist.ProductType; -import com.palantir.gradle.dist.SlsManifest; -import com.palantir.gradle.dist.pdeps.ProductDependencies; -import com.palantir.gradle.dist.pdeps.ProductDependencyManifest; -import com.palantir.gradle.dist.pdeps.ResolveProductDependenciesTask; -import com.palantir.sls.versions.OrderableSlsVersion; -import com.palantir.sls.versions.SlsVersion; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; -import org.gradle.StartParameter; -import org.gradle.api.DefaultTask; -import org.gradle.api.GradleException; -import org.gradle.api.Project; -import org.gradle.api.Task; -import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.file.RegularFile; import org.gradle.api.invocation.Gradle; -import org.gradle.api.provider.MapProperty; -import org.gradle.api.provider.Property; -import org.gradle.api.provider.SetProperty; -import org.gradle.api.specs.Spec; -import org.gradle.api.tasks.Input; +import org.gradle.api.provider.Provider; import org.gradle.api.tasks.InputFile; -import org.gradle.api.tasks.OutputFile; -import org.gradle.api.tasks.TaskAction; -import org.gradle.api.tasks.TaskProvider; -import org.gradle.language.base.plugins.LifecycleBasePlugin; -public abstract class CreateManifestTask extends DefaultTask { - @Input - abstract SetProperty getInRepoProductIds(); - - @Input - abstract Property getServiceName(); - - @Input - abstract Property getServiceGroup(); - - @Input - abstract Property getProductType(); - - @Input - abstract MapProperty getManifestExtensions(); - - @InputFile - abstract RegularFileProperty getProductDependenciesFile(); - - @OutputFile - abstract RegularFileProperty getManifestFile(); - - @Input - final String getProjectVersion() { - return getProject().getVersion().toString(); +public abstract class CreateManifestTask extends CreateManifestTaskImpl { + public CreateManifestTask() { + getShouldWriteLocks().set(getProject().provider(() -> { + String taskName = project.getPath().equals(":") + ? ":writeProductDependenciesLocks" + : project.getPath() + ":writeProductDependenciesLocks"; + Gradle gradle = project.getGradle(); + return gradle.getStartParameter().isWriteDependencyLocks() + || gradle.getTaskGraph().hasTask(taskName); + })); } /** @@ -93,196 +39,11 @@ final String getProjectVersion() { */ @InputFile @org.gradle.api.tasks.Optional - final File getLockfileIfExists() { - File file = getLockfile(); - if (file.exists()) { - return file; - } - return null; - } - - @TaskAction - final void createManifest() throws IOException { - validateProjectVersion(); - Preconditions.checkArgument( - !getManifestExtensions().get().containsKey("product-dependencies"), - "Use productDependencies configuration option instead of setting " - + "'product-dependencies' key in manifestExtensions"); - - ProductDependencyManifest productDependencyManifest = ObjectMappers.readProductDependencyManifest( - getProductDependenciesFile().getAsFile().get()); - - List productDependencies = productDependencyManifest.productDependencies(); - if (productDependencies.isEmpty()) { - requireAbsentLockfile(); - } else { - ensureLockfileIsUpToDate(productDependencies); - } - - ObjectMappers.jsonMapper.writeValue( - getManifestFile().getAsFile().get(), - SlsManifest.builder() - .manifestVersion("1.0") - .productType(getProductType().get()) - .productGroup(getServiceGroup().get()) - .productName(getServiceName().get()) - .productVersion(getProjectVersion()) - .putAllExtensions(getManifestExtensions().get()) - .putExtensions("product-dependencies", productDependencies) - .build()); - } - - private void requireAbsentLockfile() { - File lockfile = getLockfile(); - Path relativePath = getProject().getRootDir().toPath().relativize(lockfile.toPath()); - - if (!lockfile.exists()) { - return; - } - - if (shouldWriteLocks(getProject())) { - lockfile.delete(); - getLogger().lifecycle("Deleted {}", relativePath); - } else { - throw new GradleException(String.format( - "%s must not exist, please run `./gradlew %s --write-locks` to delete it", - relativePath, getName())); - } - } - - private File getLockfile() { - return getProject().file(ProductDependencyLockFile.LOCK_FILE); - } - - public static boolean shouldWriteLocks(Project project) { - String taskName = project.getPath().equals(":") - ? ":writeProductDependenciesLocks" - : project.getPath() + ":writeProductDependenciesLocks"; - Gradle gradle = project.getGradle(); - return gradle.getStartParameter().isWriteDependencyLocks() - || gradle.getTaskGraph().hasTask(taskName); - } - - private void ensureLockfileIsUpToDate(List productDeps) throws IOException { - File lockfile = getLockfile(); - Path relativePath = getProject().getRootDir().toPath().relativize(lockfile.toPath()); - String upToDateContents = ProductDependencyLockFile.asString( - productDeps, getInRepoProductIds().get()); - boolean lockfileExists = lockfile.exists(); - - if (shouldWriteLocks(getProject())) { - Files.writeString(lockfile.toPath(), upToDateContents); - - if (!lockfileExists) { - getLogger().lifecycle("Created {}\n\t{}", relativePath, upToDateContents.replaceAll("\n", "\n\t")); - } else { - getLogger().lifecycle("Updated {}", relativePath); - } - } else { - if (!lockfileExists) { - throw new GradleException(String.format( - "%s does not exist, please run `./gradlew %s --write-locks` and commit the resultant file", - relativePath, getName())); - } else { - String fromDisk = Files.readString(lockfile.toPath()); - Preconditions.checkState( - fromDisk.equals(upToDateContents), - "%s is out of date, please run `./gradlew %s --write-locks` to update it%s", - relativePath, - getName(), - diff(lockfile, upToDateContents).map(s -> ":\n" + s).orElse("")); - } - } - } - - /** Provide a rich diff so the user understands what change will be made before they run --write-locks. */ - private Optional diff(File existing, String upToDateContents) { - try { - File tempFile = Files.createTempFile("product-dependencies", "lock").toFile(); - Files.writeString(tempFile.toPath(), upToDateContents); - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - getProject().exec(spec -> { - spec.commandLine("diff", "-u", existing.getAbsolutePath(), tempFile.getAbsolutePath()); - spec.setStandardOutput(baos); - spec.setIgnoreExitValue(true); - }); - return Optional.of( - Streams.stream(Splitter.on("\n").split(new String(baos.toByteArray(), StandardCharsets.UTF_8))) - .skip(2) - .collect(Collectors.joining("\n"))); - } catch (IOException e) { - getLogger().debug("Unable to provide diff", e); - return Optional.empty(); - } - } - - private void validateProjectVersion() { - String stringVersion = getProjectVersion(); - Preconditions.checkArgument( - SlsVersion.check(stringVersion), "Project version must be a valid SLS version: %s", stringVersion); - if (!OrderableSlsVersion.check(stringVersion)) { - getProject() - .getLogger() - .info( - "Version string in project {} is not orderable as per SLS specification: {}", - getProject().getName(), - stringVersion); - } - } - - public static TaskProvider createManifestTask(Project project, BaseDistributionExtension ext) { - TaskProvider resolveProductDependenciesTask = - ProductDependencies.registerProductDependencyTasks(project, ext); - - TaskProvider createManifest = project.getTasks() - .register("createManifest", CreateManifestTask.class, task -> { - task.getServiceName().set(ext.getDistributionServiceName()); - task.getServiceGroup().set(ext.getDistributionServiceGroup()); - task.getProductType().set(ext.getProductType()); - task.getManifestFile().set(new File(project.getBuildDir(), "/deployment/manifest.yml")); - task.getProductDependenciesFile() - .set(resolveProductDependenciesTask.flatMap( - ResolveProductDependenciesTask::getManifestFile)); - task.getManifestExtensions().set(ext.getManifestExtensions()); - task.getInRepoProductIds() - .set(project.provider(() -> ProductDependencyIntrospectionPlugin.getInRepoProductIds( - project.getRootProject()) - .keySet())); - - // Ensure we re-run task to write locks - task.getOutputs().upToDateWhen(new Spec() { - @Override - public boolean isSatisfiedBy(Task _task) { - return !shouldWriteLocks(project); - } - }); - - task.dependsOn(resolveProductDependenciesTask); - }); - - project.getPluginManager().withPlugin("lifecycle-base", _p -> { - project.getTasks() - .named(LifecycleBasePlugin.CHECK_TASK_NAME) - .configure(task -> task.dependsOn(createManifest)); - }); - - project.getTasks() - .register("writeProductDependenciesLocks", WriteProductDependenciesLocksMarkerTask.class, task -> { - task.dependsOn(createManifest); - }); - - // We want `./gradlew --write-locks` to magically fix up the product-dependencies.lock file - // We can't do this at configuration time because it would mess up gradle-consistent-versions. - StartParameter startParam = project.getGradle().getStartParameter(); - if (startParam.isWriteDependencyLocks() && !startParam.getTaskNames().contains("createManifest")) { - List taskNames = ImmutableList.builder() - .addAll(startParam.getTaskNames()) - .add("createManifest") - .build(); - startParam.setTaskNames(taskNames); + final Provider getLockfileIfExists() { + if (lockfileExists()) { + return getLockfile(); } - return createManifest; + return getLockfile().map(_ignored -> null); } } diff --git a/versions.lock b/versions.lock index 43b7e1243..c82669924 100644 --- a/versions.lock +++ b/versions.lock @@ -13,7 +13,7 @@ com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava (1 c com.google.j2objc:j2objc-annotations:1.3 (1 constraints: b809eda0) com.netflix.nebula:nebula-dependency-recommender:9.1.1 (1 constraints: bf1b4246) com.netflix.nebula:nebula-gradle-interop:1.0.11 (1 constraints: 9214098d) -com.palantir.gradle.auto-parallelizable:auto-parallelizable-annotations:999 (1 constraints: c104512c) +com.palantir.gradle.auto-parallelizable:auto-parallelizable-annotations:1.1.0 (1 constraints: 0405f335) com.palantir.gradle.consistentversions:gradle-consistent-versions:1.27.0 (1 constraints: 3c05423b) com.palantir.safe-logging:logger:3.2.0 (1 constraints: f31075c3) com.palantir.safe-logging:logger-slf4j:3.2.0 (1 constraints: 000e5942) diff --git a/versions.props b/versions.props index 345b38c32..03f0475e5 100644 --- a/versions.props +++ b/versions.props @@ -1,6 +1,6 @@ com.fasterxml.jackson.*:* = 2.11.1 com.google.guava:guava = 31.1-jre -com.palantir.gradle.auto-parallelizable:* = 999 +com.palantir.gradle.auto-parallelizable:* = 1.1.0 com.palantir.gradle.consistentversions:gradle-consistent-versions = 1.27.0 com.palantir.safe-logging:* = 3.2.0 com.palantir.sls.versions:sls-versions = 1.4.0