Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for offline and local builds #237

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
42 changes: 39 additions & 3 deletions README.md
Expand Up @@ -39,14 +39,14 @@ external Git source code hosting providers are available:
## Building

[JDK 12](http://jdk.java.net/12/) or later and [Gradle](https://gradle.org/)
5.2.1 or later is required for building. To build the project on macOS or
GNU/Linux, just run the following command from the source tree root:
5.6.2 or later is required for building. To build the project on macOS or
GNU/Linux x64, just run the following command from the source tree root:

```bash
$ sh gradlew
```

To build the project on Windows, run the following command from the source tree root:
To build the project on Windows x64, run the following command from the source tree root:

```bat
> gradlew
Expand All @@ -55,6 +55,42 @@ To build the project on Windows, run the following command from the source tree
The extracted jlinked image will end up in the `build` directory in the source
tree root.

### Other operating systems and CPU architectures

If you want to build on an operating system other than GNU/Linux, macOS or
Windows _or_ if you want to build on a CPU architecture other than x64, then
ensure that you have JDK 12 or later installed locally. You can then run the
following command from the source tree root:

```bash
$ sh gradlew
```

The extracted jlinked image will end up in the `build` directory in the source
tree root.

### Offline builds

If you don't want the build to automatically download any depenendcies, then
edvbld marked this conversation as resolved.
Show resolved Hide resolved
you must ensure that you have installed the following software locally:

- JDK 12 or later
- Gradle 5.6.2 or later

To create a build then run the command
edvbld marked this conversation as resolved.
Show resolved Hide resolved

```bash
$ gradle offline
```

_Please note_ that the above command does _not_ make use of `gradlew` to avoid
downloading Gradle.

The extracted jlinked image will end up in the `build` directory in the source
tree root.

### Cross-linking

It is also supported to cross-jlink jimages to GNU/Linux, macOS and/or Windows from
any of the aforementioned operating systems. To build all applicable jimages
(including the server-side tooling), run the following command from the
Expand Down
2 changes: 1 addition & 1 deletion bots/cli/build.gradle
Expand Up @@ -64,7 +64,7 @@ dependencies {
}

images {
linux {
linux_x64 {
modules = ['jdk.crypto.ec',
'org.openjdk.skara.bots.pr',
'org.openjdk.skara.bots.hgbridge',
Expand Down
70 changes: 65 additions & 5 deletions build.gradle
Expand Up @@ -104,19 +104,79 @@ reproduce {
dockerfile = 'test.dockerfile'
}

def getOS() {
def os = System.getProperty('os.name').toLowerCase()
if (os.startsWith('linux')) {
return 'linux'
}
if (os.startsWith('mac')) {
return 'macos'
}
if (os.startsWith('win')) {
return 'windows'
}
if (os.startsWith('sunos')) {
return 'solaris'
}
throw new GradleException("Unexpected operating system: " + os)
}

def getCPU() {
def cpu = System.getProperty('os.arch').toLowerCase()
edvbld marked this conversation as resolved.
Show resolved Hide resolved
if (cpu.startsWith('amd64')) {
return 'x64'
}
if (cpu.startsWith('x86') || cpu.startsWith('i386')) {
return 'x86'
}
if (cpu.startsWith('sparc')) {
return 'sparc'
}
if (cpu.startsWith('ppc')) {
return 'ppc'
}
if (cpu.startsWith('arm')) {
return 'arm'
}
edvbld marked this conversation as resolved.
Show resolved Hide resolved
throw new GradleException("Unexpected operating system: " + cpu)
edvbld marked this conversation as resolved.
Show resolved Hide resolved
}

task local(type: Copy) {
doFirst {
delete project.buildDir
}
def os = System.getProperty('os.name').toLowerCase()
def osName = os.startsWith('win') ? 'Windows' :
os.startsWith('mac') ? 'Macos' : 'Linux'

dependsOn ':cli:image' + osName
def os = getOS()
def cpu = getCPU()

if (os in ['linux', 'macos', 'windows'] && cpu == 'x64') {
def target = os.substring(0, 1).toUpperCase() + os.substring(1) +
cpu.substring(0, 1).toUpperCase() + cpu.substring(1)
dependsOn ':cli:image' + target
} else {
dependsOn ':cli:imageLocal'
}

from zipTree(file(project.rootDir.toString() +
'/cli/build/distributions/cli' +
'-' + project.version + '-' +
os + '-' + cpu + '.zip'))
into project.buildDir
}

task offline(type: Copy) {
doFirst {
delete project.buildDir
}

def os = getOS()
def cpu = getCPU()

dependsOn ':cli:imageLocal'
from zipTree(file(project.rootDir.toString() +
'/cli/build/distributions/cli' +
'-' + project.version + '-' +
osName.toLowerCase() + '.zip'))
os + '-' + cpu + '.zip'))
into project.buildDir
}

Expand Down
Expand Up @@ -29,9 +29,49 @@
import org.gradle.api.artifacts.UnknownConfigurationException;

import java.util.ArrayList;
import java.util.HashSet;
import java.io.File;

public class ImagesPlugin implements Plugin<Project> {
private static String getOS() {
var p = System.getProperty("os.name").toLowerCase();
if (p.startsWith("win")) {
return "windows";
}
if (p.startsWith("mac")) {
return "macos";
}
if (p.startsWith("linux")) {
return "linux";
}
if (p.startsWith("sunos")) {
return "solaris";
}

throw new RuntimeException("Unknown operating system: " + System.getProperty("os.name"));
}

private static String getCPU() {
var p = System.getProperty("os.arch").toLowerCase();
if (p.startsWith("amd64")) {
edvbld marked this conversation as resolved.
Show resolved Hide resolved
return "x64";
}
if (p.startsWith("x86") || p.startsWith("i386")) {
return "x86";
}
if (p.startsWith("sparc")) {
return "sparc";
}
if (p.startsWith("ppc")) {
return "ppc";
}
if (p.startsWith("arm")) {
return "arm";
}
edvbld marked this conversation as resolved.
Show resolved Hide resolved

throw new RuntimeException("Unknown CPU: " + System.getProperty("os.arch"));
}

@Override
public void apply(Project project) {
NamedDomainObjectContainer<ImageEnvironment> imageEnvironmentContainer =
Expand All @@ -49,15 +89,23 @@ public ImageEnvironment create(String name) {

imageEnvironmentContainer.all(new Action<ImageEnvironment>() {
public void execute(ImageEnvironment env) {
var name = env.getName();
var subName = name.substring(0, 1).toUpperCase() + name.substring(1);
var parts = env.getName().split("_");;
var isLocal = parts.length == 1 && parts[0].equals("local");
var os = isLocal ? getOS() : parts[0];
var cpu = isLocal ? getCPU() : parts[1];
var osAndCpuPascalCased =
os.substring(0, 1).toUpperCase() + os.substring(1) +
cpu.substring(0, 1).toUpperCase() + cpu.substring(1);
var subName = isLocal ? "Local" : osAndCpuPascalCased;

var downloadTaskName = "download" + subName + "JDK";
project.getTasks().register(downloadTaskName, DownloadJDKTask.class, (task) -> {
task.getUrl().set(env.getUrl());
task.getSha256().set(env.getSha256());
task.getToDir().set(rootDir.resolve(".jdk"));
});
if (!isLocal) {
project.getTasks().register(downloadTaskName, DownloadJDKTask.class, (task) -> {
task.getUrl().set(env.getUrl());
task.getSha256().set(env.getSha256());
task.getToDir().set(rootDir.resolve(".jdk"));
});
}

var linkTaskName = "link" + subName;
project.getTasks().register(linkTaskName, LinkTask.class, (task) -> {
Expand All @@ -75,10 +123,15 @@ public void execute(ImageEnvironment env) {
// ignored
}

task.dependsOn(projectPath + ":" + downloadTaskName);
if (!isLocal) {
task.dependsOn(projectPath + ":" + downloadTaskName);
task.getUrl().set(env.getUrl());
} else {
task.getUrl().set("local");
}
task.getToDir().set(buildDir.resolve("images"));
task.getUrl().set(env.getUrl());
task.getOS().set(name);
task.getOS().set(os);
task.getCPU().set(cpu);
task.getLaunchers().set(env.getLaunchers());
task.getModules().set(env.getModules());
});
Expand All @@ -88,7 +141,8 @@ public void execute(ImageEnvironment env) {
task.getLaunchers().set(env.getLaunchers());
task.getOptions().set(env.getOptions());
task.getToDir().set(buildDir.resolve("launchers"));
task.getOS().set(name);
task.getOS().set(os);
task.getCPU().set(cpu);
});

var zipTaskName = "bundleZip" + subName;
Expand All @@ -99,7 +153,7 @@ public void execute(ImageEnvironment env) {
task.setPreserveFileTimestamps(false);
task.setReproducibleFileOrder(true);
task.getArchiveBaseName().set(project.getName());
task.getArchiveClassifier().set(name);
task.getArchiveClassifier().set(os + "-" + cpu);
task.getArchiveExtension().set("zip");

if (env.getMan().isPresent()) {
Expand All @@ -109,10 +163,11 @@ public void execute(ImageEnvironment env) {
});
}

task.from(buildDir.resolve("images").resolve(name), (s) -> {
var subdir = os + "-" + cpu;
task.from(buildDir.resolve("images").resolve(subdir), (s) -> {
s.into("image");
});
task.from(buildDir.resolve("launchers").resolve(name), (s) -> {
task.from(buildDir.resolve("launchers").resolve(subdir), (s) -> {
s.into("bin");
});
});
Expand All @@ -125,7 +180,7 @@ public void execute(ImageEnvironment env) {
task.setPreserveFileTimestamps(false);
task.setReproducibleFileOrder(true);
task.getArchiveBaseName().set(project.getName());
task.getArchiveClassifier().set(name);
task.getArchiveClassifier().set(os + "-" + cpu);
task.getArchiveExtension().set("tar.gz");
task.setCompression(Compression.GZIP);

Expand All @@ -136,10 +191,11 @@ public void execute(ImageEnvironment env) {
});
}

task.from(buildDir.resolve("images").resolve(name), (s) -> {
var subdir = os + "-" + cpu;
task.from(buildDir.resolve("images").resolve(subdir), (s) -> {
s.into("image");
});
task.from(buildDir.resolve("launchers").resolve(name), (s) -> {
task.from(buildDir.resolve("launchers").resolve(subdir), (s) -> {
s.into("bin");
});
});
Expand Down
Expand Up @@ -37,13 +37,15 @@
public class LaunchersTask extends DefaultTask {
private Property<Path> toDir;
private Property<String> os;
private Property<String> cpu;
private MapProperty<String, String> launchers;
private ListProperty<String> options;

@Inject
public LaunchersTask(ObjectFactory factory) {
toDir = factory.property(Path.class);
os = factory.property(String.class);
cpu = factory.property(String.class);
launchers = factory.mapProperty(String.class, String.class);
options = factory.listProperty(String.class);
}
Expand All @@ -63,6 +65,11 @@ Property<String> getOS() {
return os;
}

@Input
Property<String> getCPU() {
return cpu;
}

@Input
MapProperty<String, String> getLaunchers() {
return launchers;
Expand All @@ -77,7 +84,7 @@ private static void clearDirectory(Path directory) throws IOException {

@TaskAction
void generate() throws IOException {
var dest = toDir.get().resolve(os.get());
var dest = toDir.get().resolve(os.get() + "-" + cpu.get());
if (Files.isDirectory(dest)) {
clearDirectory(dest);
}
Expand Down