mirror of
https://github.com/jlengrand/jreleaser.git
synced 2026-03-10 08:31:24 +00:00
[brew] support Linux formulae. Fixes #215
This commit is contained in:
@@ -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<String, Object> 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ import static org.jreleaser.util.StringUtils.isNotBlank;
|
||||
public class Cask implements Domain {
|
||||
private final List<CaskItem> uninstall = new ArrayList<>();
|
||||
private final List<CaskItem> 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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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<Brew> {
|
||||
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<Brew> {
|
||||
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<String, Object> 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<String> 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<String, Object> 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<Brew> {
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private String resolveArtifactUrl(Map<String, Object> props, Artifact artifact) {
|
||||
String artifactFileName = artifact.getEffectivePath(context).getFileName().toString();
|
||||
Map<String, Object> 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<Brew> {
|
||||
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);
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -32,6 +32,8 @@ import org.gradle.api.provider.Property
|
||||
interface Brew extends RepositoryTool {
|
||||
Property<String> getFormulaName()
|
||||
|
||||
Property<Boolean> getMultiPlatform()
|
||||
|
||||
ListProperty<String> getLivecheck()
|
||||
|
||||
MapProperty<String, String> getDependencies()
|
||||
|
||||
@@ -43,6 +43,7 @@ import static org.jreleaser.util.StringUtils.isNotBlank
|
||||
@CompileStatic
|
||||
class BrewImpl extends AbstractRepositoryTool implements Brew {
|
||||
final Property<String> formulaName
|
||||
final Property<Boolean> 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()
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user