From b036ddfe2332d7e0ab5daa227b338cadbccf062e Mon Sep 17 00:00:00 2001 From: Andres Almiray Date: Thu, 22 Jul 2021 21:07:02 +0200 Subject: [PATCH] [brew] support Linux formulae. Fixes #215 --- .../main/java/org/jreleaser/model/Brew.java | 18 +++++ .../main/java/org/jreleaser/model/Cask.java | 8 +- .../model/validation/BrewValidator.java | 21 ++++- .../binary/brew/formula-multi.rb.tpl | 30 ++++++++ .../templates/jlink/brew/formula-multi.rb.tpl | 30 ++++++++ .../native-image/brew/formula-multi.rb.tpl | 30 ++++++++ .../jreleaser/tools/BrewToolProcessor.java | 77 +++++++++++++++++-- .../java/org/jreleaser/util/Constants.java | 1 + .../jreleaser/gradle/plugin/dsl/Brew.groovy | 2 + .../plugin/internal/dsl/BrewImpl.groovy | 4 + .../java/org/jreleaser/maven/plugin/Brew.java | 15 ++++ .../java/org/jreleaser/maven/plugin/Cask.java | 8 +- .../internal/JReleaserModelConverter.java | 3 +- 13 files changed, 233 insertions(+), 14 deletions(-) create mode 100644 core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/brew/formula-multi.rb.tpl create mode 100644 core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/jlink/brew/formula-multi.rb.tpl create mode 100644 core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/native-image/brew/formula-multi.rb.tpl diff --git a/core/jreleaser-model/src/main/java/org/jreleaser/model/Brew.java b/core/jreleaser-model/src/main/java/org/jreleaser/model/Brew.java index 72b521ba..2756f68f 100644 --- a/core/jreleaser-model/src/main/java/org/jreleaser/model/Brew.java +++ b/core/jreleaser-model/src/main/java/org/jreleaser/model/Brew.java @@ -43,6 +43,7 @@ public class Brew extends AbstractRepositoryTool { private String formulaName; private String cachedFormulaName; + private Boolean multiPlatform; public Brew() { super(NAME); @@ -51,6 +52,7 @@ public class Brew extends AbstractRepositoryTool { void setAll(Brew brew) { super.setAll(brew); this.formulaName = brew.formulaName; + this.multiPlatform = brew.multiPlatform; setTap(brew.tap); setDependenciesAsList(brew.dependencies); setLivecheck(brew.livecheck); @@ -92,6 +94,18 @@ public class Brew extends AbstractRepositoryTool { this.formulaName = formulaName; } + public boolean isMultiPlatform() { + return multiPlatform != null && multiPlatform; + } + + public void setMultiPlatform(Boolean multiPlatform) { + this.multiPlatform = multiPlatform; + } + + public boolean isMultiPlatformSet() { + return multiPlatform != null; + } + public HomebrewTap getTap() { return tap; } @@ -160,6 +174,7 @@ public class Brew extends AbstractRepositoryTool { protected void asMap(boolean full, Map props) { super.asMap(full, props); props.put("formulaName", formulaName); + props.put("multiPlatform", isMultiPlatform()); props.put("tap", tap.asMap(full)); props.put("dependencies", dependencies); props.put("livecheck", livecheck); @@ -173,6 +188,9 @@ public class Brew extends AbstractRepositoryTool { @Override public boolean supportsPlatform(String platform) { + if (isMultiPlatform()) { + return isBlank(platform) || PlatformUtils.isMac(platform) || PlatformUtils.isLinux(platform); + } return isBlank(platform) || PlatformUtils.isMac(platform); } diff --git a/core/jreleaser-model/src/main/java/org/jreleaser/model/Cask.java b/core/jreleaser-model/src/main/java/org/jreleaser/model/Cask.java index d651b0b8..48007975 100644 --- a/core/jreleaser-model/src/main/java/org/jreleaser/model/Cask.java +++ b/core/jreleaser-model/src/main/java/org/jreleaser/model/Cask.java @@ -37,7 +37,7 @@ import static org.jreleaser.util.StringUtils.isNotBlank; public class Cask implements Domain { private final List uninstall = new ArrayList<>(); private final List zap = new ArrayList<>(); - protected boolean enabled; + protected Boolean enabled; private String name; private String displayName; private String pkgName; @@ -69,7 +69,11 @@ public class Cask implements Domain { } public boolean isEnabled() { - return enabled; + return enabled != null && enabled; + } + + public boolean isEnabledSet() { + return enabled != null; } public void setEnabled(boolean enabled) { diff --git a/core/jreleaser-model/src/main/java/org/jreleaser/model/validation/BrewValidator.java b/core/jreleaser-model/src/main/java/org/jreleaser/model/validation/BrewValidator.java index 54274544..d5e4ea78 100644 --- a/core/jreleaser-model/src/main/java/org/jreleaser/model/validation/BrewValidator.java +++ b/core/jreleaser-model/src/main/java/org/jreleaser/model/validation/BrewValidator.java @@ -102,7 +102,21 @@ public abstract class BrewValidator extends Validator { tap.getToken(), service.getResolvedToken())); + if (!tool.isMultiPlatformSet() && parentTool.isMultiPlatformSet()) { + tool.setMultiPlatform(parentTool.isMultiPlatform()); + } + if (tool.isMultiPlatform() && + (distribution.getType() == Distribution.DistributionType.SINGLE_JAR || + distribution.getType() == Distribution.DistributionType.JAVA_BINARY || + distribution.getType() == Distribution.DistributionType.NATIVE_PACKAGE)) { + tool.setMultiPlatform(false); + } + if (tool.isMultiPlatform()) { + tool.getCask().disable(); + } + validateCask(context, distribution, tool, errors); + if (!tool.getCask().isEnabled()) { validateArtifactPlatforms(context, distribution, tool, errors); } @@ -114,6 +128,12 @@ public abstract class BrewValidator extends Validator { return; } + Cask cask = tool.getCask(); + + if (cask.isEnabledSet() && !cask.isEnabled()) { + return; + } + context.getLogger().debug("distribution.{}.brew.cask", distribution.getName()); // look for a .dmg, .pkg. or .zip @@ -133,7 +153,6 @@ public abstract class BrewValidator extends Validator { } } - Cask cask = tool.getCask(); if (dmgFound == 0 && pkgFound == 0 && zipFound == 0) { // no artifacts found, disable cask diff --git a/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/brew/formula-multi.rb.tpl b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/brew/formula-multi.rb.tpl new file mode 100644 index 00000000..dc768093 --- /dev/null +++ b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/binary/brew/formula-multi.rb.tpl @@ -0,0 +1,30 @@ +class {{brewFormulaName}} < Formula + desc "{{projectDescription}}" + homepage "{{projectWebsite}}" + version "{{projectVersion}}" + license "{{projectLicense}}" + bottle :unneeded + + {{brewMultiPlatform}} + + {{#brewHasLivecheck}} + livecheck do + {{#brewLivecheck}} + {{.}} + {{/brewLivecheck}} + end + {{/brewHasLivecheck}} + {{#brewDependencies}} + depends_on {{.}} + {{/brewDependencies}} + + def install + libexec.install Dir["*"] + bin.install_symlink "#{libexec}/bin/{{distributionExecutable}}" + end + + test do + output = shell_output("#{bin}/{{distributionExecutable}} --version") + assert_match "{{projectVersion}}", output + end +end diff --git a/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/jlink/brew/formula-multi.rb.tpl b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/jlink/brew/formula-multi.rb.tpl new file mode 100644 index 00000000..dc768093 --- /dev/null +++ b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/jlink/brew/formula-multi.rb.tpl @@ -0,0 +1,30 @@ +class {{brewFormulaName}} < Formula + desc "{{projectDescription}}" + homepage "{{projectWebsite}}" + version "{{projectVersion}}" + license "{{projectLicense}}" + bottle :unneeded + + {{brewMultiPlatform}} + + {{#brewHasLivecheck}} + livecheck do + {{#brewLivecheck}} + {{.}} + {{/brewLivecheck}} + end + {{/brewHasLivecheck}} + {{#brewDependencies}} + depends_on {{.}} + {{/brewDependencies}} + + def install + libexec.install Dir["*"] + bin.install_symlink "#{libexec}/bin/{{distributionExecutable}}" + end + + test do + output = shell_output("#{bin}/{{distributionExecutable}} --version") + assert_match "{{projectVersion}}", output + end +end diff --git a/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/native-image/brew/formula-multi.rb.tpl b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/native-image/brew/formula-multi.rb.tpl new file mode 100644 index 00000000..dc768093 --- /dev/null +++ b/core/jreleaser-templates/src/main/resources/META-INF/jreleaser/templates/native-image/brew/formula-multi.rb.tpl @@ -0,0 +1,30 @@ +class {{brewFormulaName}} < Formula + desc "{{projectDescription}}" + homepage "{{projectWebsite}}" + version "{{projectVersion}}" + license "{{projectLicense}}" + bottle :unneeded + + {{brewMultiPlatform}} + + {{#brewHasLivecheck}} + livecheck do + {{#brewLivecheck}} + {{.}} + {{/brewLivecheck}} + end + {{/brewHasLivecheck}} + {{#brewDependencies}} + depends_on {{.}} + {{/brewDependencies}} + + def install + libexec.install Dir["*"] + bin.install_symlink "#{libexec}/bin/{{distributionExecutable}}" + end + + test do + output = shell_output("#{bin}/{{distributionExecutable}} --version") + assert_match "{{projectVersion}}", output + end +end diff --git a/core/jreleaser-tools/src/main/java/org/jreleaser/tools/BrewToolProcessor.java b/core/jreleaser-tools/src/main/java/org/jreleaser/tools/BrewToolProcessor.java index 21065f20..c44d3ac5 100644 --- a/core/jreleaser-tools/src/main/java/org/jreleaser/tools/BrewToolProcessor.java +++ b/core/jreleaser-tools/src/main/java/org/jreleaser/tools/BrewToolProcessor.java @@ -25,11 +25,15 @@ import org.jreleaser.model.GitService; import org.jreleaser.model.JReleaserContext; import org.jreleaser.model.Project; import org.jreleaser.model.tool.spi.ToolProcessingException; +import org.jreleaser.util.Algorithm; import org.jreleaser.util.Constants; import org.jreleaser.util.MustacheUtils; +import org.jreleaser.util.PlatformUtils; import java.nio.file.Path; +import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -37,6 +41,7 @@ import static org.jreleaser.templates.TemplateUtils.trimTplExtension; import static org.jreleaser.util.MustacheUtils.applyTemplate; import static org.jreleaser.util.MustacheUtils.passThrough; import static org.jreleaser.util.StringUtils.getFilename; +import static org.jreleaser.util.StringUtils.isBlank; import static org.jreleaser.util.StringUtils.isNotBlank; import static org.jreleaser.util.StringUtils.isTrue; @@ -45,6 +50,21 @@ import static org.jreleaser.util.StringUtils.isTrue; * @since 0.1.0 */ public class BrewToolProcessor extends AbstractRepositoryToolProcessor { + private static final String KEY_DISTRIBUTION_CHECKSUM_SHA_256 = "distributionChecksumSha256"; + + private static final String TPL_MAC_INTEL = " if OS.mac?\n" + + " url \"{{distributionUrl}}\"\n" + + " sha256 \"{{distributionChecksumSha256}}\"\n" + + " end\n"; + private static final String TPL_LINUX_INTEL = " if OS.linux? && Hardware::CPU.intel?\n" + + " url \"{{distributionUrl}}\"\n" + + " sha256 \"{{distributionChecksumSha256}}\"\n" + + " end\n"; + private static final String TPL_LINUX_ARM = " if OS.linux? && Hardware::CPU.arm?\n" + + " url \"{{distributionUrl}}\"\n" + + " sha256 \"{{distributionChecksumSha256}}\"\n" + + " end"; + public BrewToolProcessor(JReleaserContext context) { super(context); } @@ -98,16 +118,43 @@ public class BrewToolProcessor extends AbstractRepositoryToolProcessor { for (Artifact artifact : distribution.getArtifacts()) { if (!artifact.isActive()) continue; if (artifact.getPath().endsWith(".zip") && !isTrue(artifact.getExtraProperties().get("skipBrew"))) { - String artifactFileName = artifact.getEffectivePath(context).getFileName().toString(); - Map newProps = new LinkedHashMap<>(props); - newProps.put(Constants.KEY_ARTIFACT_FILE_NAME, artifactFileName); - props.put(Constants.KEY_DISTRIBUTION_ARTIFACT_NAME, getFilename(artifactFileName)); - String artifactUrl = applyTemplate(context.getModel().getRelease().getGitService().getDownloadUrl(), newProps); - props.put(Constants.KEY_DISTRIBUTION_URL, artifactUrl); + props.put(Constants.KEY_DISTRIBUTION_URL, resolveArtifactUrl(props, artifact)); props.put(Constants.KEY_BREW_CASK_HAS_BINARY, true); break; } } + } else if (tool.isMultiPlatform()) { + List multiPlatforms = new ArrayList<>(); + for (Artifact artifact : distribution.getArtifacts()) { + if (!artifact.isActive() || + !artifact.getPath().endsWith(".zip") || + isBlank(artifact.getPlatform()) || + isTrue(artifact.getExtraProperties().get("skipBrew"))) continue; + + String template = null; + String artifactUrl = resolveArtifactUrl(props, artifact); + if (PlatformUtils.isMac(artifact.getPlatform())) { + template = TPL_MAC_INTEL; + } else if (PlatformUtils.isLinux(artifact.getPlatform())) { + if (artifact.getPlatform().contains("arm")) { + template = TPL_LINUX_ARM; + } else { + template = TPL_LINUX_INTEL; + } + } + + if (isNotBlank(template)) { + Map newProps = new LinkedHashMap<>(props); + newProps.put(Constants.KEY_DISTRIBUTION_URL, artifactUrl); + newProps.put(KEY_DISTRIBUTION_CHECKSUM_SHA_256, artifact.getHash(Algorithm.SHA_256)); + multiPlatforms.add(applyTemplate(template, newProps)); + } + } + + if (multiPlatforms.isEmpty()) { + throw new ToolProcessingException("There are no matching multi-platform binaries."); + } + props.put(Constants.KEY_BREW_MULTIPLATFORM, passThrough(String.join(System.lineSeparator()+" ", multiPlatforms))); } else if ((distribution.getType() == Distribution.DistributionType.JAVA_BINARY || distribution.getType() == Distribution.DistributionType.SINGLE_JAR) && !isTrue(tool.getExtraProperties().get("javaSkip")) && @@ -122,6 +169,14 @@ public class BrewToolProcessor extends AbstractRepositoryToolProcessor { .collect(Collectors.toList())); } + private String resolveArtifactUrl(Map props, Artifact artifact) { + String artifactFileName = artifact.getEffectivePath(context).getFileName().toString(); + Map newProps = new LinkedHashMap<>(props); + newProps.put(Constants.KEY_ARTIFACT_FILE_NAME, artifactFileName); + newProps.put(Constants.KEY_DISTRIBUTION_ARTIFACT_NAME, getFilename(artifactFileName)); + return applyTemplate(context.getModel().getRelease().getGitService().getDownloadUrl(), newProps); + } + @Override protected void writeFile(Project project, Distribution distribution, @@ -133,13 +188,19 @@ public class BrewToolProcessor extends AbstractRepositoryToolProcessor { fileName = trimTplExtension(fileName); if (tool.getCask().isEnabled()) { - if ("formula.rb".equals(fileName)) return; + if ("formula.rb".equals(fileName) || "formula-multi.rb".equals(fileName)) return; Path outputFile = "cask.rb".equals(fileName) ? outputDirectory.resolve("Casks").resolve(tool.getCask().getResolvedCaskName(props).concat(".rb")) : outputDirectory.resolve(fileName); writeFile(content, outputFile); + } else if (tool.isMultiPlatform()) { + if ("cask.rb".equals(fileName) || "formula.rb".equals(fileName)) return; + Path outputFile = "formula-multi.rb".equals(fileName) ? + outputDirectory.resolve("Formula").resolve(distribution.getExecutable().concat(".rb")) : + outputDirectory.resolve(fileName); + writeFile(content, outputFile); } else { - if ("cask.rb".equals(fileName)) return; + if ("cask.rb".equals(fileName) || "formula-multi.rb".equals(fileName)) return; Path outputFile = "formula.rb".equals(fileName) ? outputDirectory.resolve("Formula").resolve(distribution.getExecutable().concat(".rb")) : outputDirectory.resolve(fileName); diff --git a/core/jreleaser-utils/src/main/java/org/jreleaser/util/Constants.java b/core/jreleaser-utils/src/main/java/org/jreleaser/util/Constants.java index 3ad4a974..ef64a645 100644 --- a/core/jreleaser-utils/src/main/java/org/jreleaser/util/Constants.java +++ b/core/jreleaser-utils/src/main/java/org/jreleaser/util/Constants.java @@ -137,6 +137,7 @@ public interface Constants { String KEY_BREW_CASK_HAS_APPCAST = "brewCaskHasAppcast"; String KEY_BREW_CASK_APPCAST = "brewCaskAppcast"; String KEY_BREW_CASK_HAS_BINARY = "brewCaskHasBinary"; + String KEY_BREW_MULTIPLATFORM = "brewMultiPlatform"; // Docker String KEY_DOCKER_SPEC_NAME = "dockerSpecName"; diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/jreleaser/gradle/plugin/dsl/Brew.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/jreleaser/gradle/plugin/dsl/Brew.groovy index 7c78b397..047d88e0 100644 --- a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/jreleaser/gradle/plugin/dsl/Brew.groovy +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/jreleaser/gradle/plugin/dsl/Brew.groovy @@ -32,6 +32,8 @@ import org.gradle.api.provider.Property interface Brew extends RepositoryTool { Property getFormulaName() + Property getMultiPlatform() + ListProperty getLivecheck() MapProperty getDependencies() diff --git a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/jreleaser/gradle/plugin/internal/dsl/BrewImpl.groovy b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/jreleaser/gradle/plugin/internal/dsl/BrewImpl.groovy index 7b680801..c9717869 100644 --- a/plugins/jreleaser-gradle-plugin/src/main/groovy/org/jreleaser/gradle/plugin/internal/dsl/BrewImpl.groovy +++ b/plugins/jreleaser-gradle-plugin/src/main/groovy/org/jreleaser/gradle/plugin/internal/dsl/BrewImpl.groovy @@ -43,6 +43,7 @@ import static org.jreleaser.util.StringUtils.isNotBlank @CompileStatic class BrewImpl extends AbstractRepositoryTool implements Brew { final Property formulaName + final Property multiPlatform final CommitAuthorImpl commitAuthor final TapImpl tap final CaskImpl cask @@ -53,6 +54,7 @@ class BrewImpl extends AbstractRepositoryTool implements Brew { BrewImpl(ObjectFactory objects) { super(objects) formulaName = objects.property(String).convention(Providers.notDefined()) + multiPlatform = objects.property(Boolean).convention(Providers.notDefined()) tap = objects.newInstance(TapImpl, objects) cask = objects.newInstance(CaskImpl, objects) commitAuthor = objects.newInstance(CommitAuthorImpl, objects) @@ -79,6 +81,7 @@ class BrewImpl extends AbstractRepositoryTool implements Brew { boolean isSet() { super.isSet() || formulaName.present || + multiPlatform.present || dependencies.present || tap.isSet() || commitAuthor.isSet() || @@ -120,6 +123,7 @@ class BrewImpl extends AbstractRepositoryTool implements Brew { org.jreleaser.model.Brew tool = new org.jreleaser.model.Brew() fillToolProperties(tool) if (formulaName.present) tool.formulaName = formulaName.get() + if (multiPlatform.present) tool.multiPlatform = multiPlatform.get() if (tap.isSet()) tool.tap = tap.toHomebrewTap() if (commitAuthor.isSet()) tool.commitAuthor = commitAuthor.toModel() if (dependencies.present) tool.dependencies = dependencies.get() diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/jreleaser/maven/plugin/Brew.java b/plugins/jreleaser-maven-plugin/src/main/java/org/jreleaser/maven/plugin/Brew.java index b9492854..5ce4384a 100644 --- a/plugins/jreleaser-maven-plugin/src/main/java/org/jreleaser/maven/plugin/Brew.java +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/jreleaser/maven/plugin/Brew.java @@ -34,10 +34,12 @@ public class Brew extends AbstractRepositoryTool { private final Cask cask = new Cask(); private String formulaName; + private Boolean multiPlatform; void setAll(Brew brew) { super.setAll(brew); this.formulaName = brew.formulaName; + this.multiPlatform = brew.multiPlatform; setTap(brew.tap); setDependencies(brew.dependencies); setLivecheck(brew.livecheck); @@ -52,6 +54,18 @@ public class Brew extends AbstractRepositoryTool { this.formulaName = formulaName; } + public boolean isMultiPlatform() { + return multiPlatform != null && multiPlatform; + } + + public void setMultiPlatform(Boolean multiPlatform) { + this.multiPlatform = multiPlatform; + } + + public boolean isMultiPlatformSet() { + return multiPlatform != null; + } + public Tap getTap() { return tap; } @@ -92,6 +106,7 @@ public class Brew extends AbstractRepositoryTool { !dependencies.isEmpty() || tap.isSet() || !livecheck.isEmpty() || + multiPlatform != null || cask.isSet(); } } diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/jreleaser/maven/plugin/Cask.java b/plugins/jreleaser-maven-plugin/src/main/java/org/jreleaser/maven/plugin/Cask.java index e5477387..50cec52e 100644 --- a/plugins/jreleaser-maven-plugin/src/main/java/org/jreleaser/maven/plugin/Cask.java +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/jreleaser/maven/plugin/Cask.java @@ -36,7 +36,7 @@ public class Cask { private String pkgName; private String appName; private String appcast; - private boolean enabled; + private Boolean enabled; void setAll(Cask cask) { this.name = cask.name; @@ -90,7 +90,11 @@ public class Cask { } public boolean isEnabled() { - return enabled; + return enabled != null && enabled; + } + + public boolean isEnabledSet() { + return enabled != null; } public void setEnabled(boolean enabled) { diff --git a/plugins/jreleaser-maven-plugin/src/main/java/org/jreleaser/maven/plugin/internal/JReleaserModelConverter.java b/plugins/jreleaser-maven-plugin/src/main/java/org/jreleaser/maven/plugin/internal/JReleaserModelConverter.java index f0ca02f8..11be319e 100644 --- a/plugins/jreleaser-maven-plugin/src/main/java/org/jreleaser/maven/plugin/internal/JReleaserModelConverter.java +++ b/plugins/jreleaser-maven-plugin/src/main/java/org/jreleaser/maven/plugin/internal/JReleaserModelConverter.java @@ -771,6 +771,7 @@ public final class JReleaserModelConverter { t.setExtraProperties(tool.getExtraProperties()); t.setTap(convertHomebrewTap(tool.getTap())); t.setFormulaName(tool.getFormulaName()); + if (tool.isMultiPlatformSet()) t.setMultiPlatform(tool.isMultiPlatform()); t.setCommitAuthor(convertCommitAuthor(tool.getCommitAuthor())); tool.getDependencies().forEach(dependency -> { if (isNotBlank(dependency.getValue())) { @@ -793,7 +794,7 @@ public final class JReleaserModelConverter { c.setPkgName(cask.getPkgName()); c.setAppName(cask.getAppName()); c.setAppcast(cask.getAppcast()); - c.setEnabled(cask.isEnabled()); + if (cask.isEnabledSet()) c.setEnabled(cask.isEnabled()); c.setUninstall(cask.getUninstall()); c.setZap(cask.getZap()); return c;