Skip to content

Commit

Permalink
Add all the code from our internal tooling for NodeJS and serving a s…
Browse files Browse the repository at this point in the history
…tatic web page.
  • Loading branch information
nedtwigg committed Jul 5, 2024
1 parent 246be85 commit 2952bd3
Show file tree
Hide file tree
Showing 7 changed files with 354 additions and 31 deletions.
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ apply from: 干.file('base/maven.gradle')
apply from: 干.file('base/sonatype.gradle')

dependencies {
// node.js
api 'com.github.eirslett:frontend-maven-plugin:1.15.0' // JitPack HEAD as of 04/23/2020
// static file server
String VER_JETTY = '11.0.20'
api "org.eclipse.jetty:jetty-server:$VER_JETTY"
Expand Down
19 changes: 6 additions & 13 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,13 @@ org=diffplug
license=apache
git_url=github.com/diffplug/webtools
plugin_tags=node
plugin_list=\
node \
servestatic
plugin_list=node

ver_java=17
ver_java=11

javadoc_links=

plugin_node_id=com.diffplug.eclipse.apt
plugin_node_impl=com.diffplug.gradle.eclipse.apt.AptEclipsePlugin
plugin_node_name=Copy of net.ltgt.apt-eclipse which is still maintained
plugin_node_desc=Fixes eclipse projects to work with gradle annotation processing

plugin_servestatic_id=com.diffplug.eclipse.buildproperties
plugin_servestatic_impl=com.diffplug.gradle.eclipse.BuildPropertiesPlugin
plugin_servestatic_name=Goomph servestatic
plugin_servestatic_desc=Uses Eclipse''s build.properties to control a gradle build, and fixes the eclipse project classpath to include binary assets specified in build.properties.
plugin_node_id=com.diffplug.webtools.node
plugin_node_impl=com.diffplug.webtools.node.NodePlugin
plugin_node_name=DiffPlug NodeJS
plugin_node_desc=Runs `npm install` and `npm run xx` in an efficient way
18 changes: 0 additions & 18 deletions src/main/java/com/diffplug/gradle/CmdLine.java

This file was deleted.

98 changes: 98 additions & 0 deletions src/main/java/com/diffplug/webtools/node/NodePlugin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright (C) 2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.diffplug.webtools.node;

import com.github.eirslett.maven.plugins.frontend.lib.ProxyConfig;
import java.util.Collections;
import java.util.Objects;
import org.gradle.api.Action;
import org.gradle.api.DefaultTask;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.CacheableTask;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.TaskProvider;

/**
* Installs a specific version of node.js and npm,
* Runs 'npm ci' to install the packages, and then `gulp blah`
* to run whatever gulp tasks you want.
*/
public class NodePlugin implements Plugin<Project> {
private static final String EXTENSION_NAME = "node";

public static class Extension {
private final Project project;

public Extension(Project project) {
this.project = Objects.requireNonNull(project);
}

public final SetupCleanupNode setup = new SetupCleanupNode();

public TaskProvider<?> npm_run(String name, Action<Task> taskConfig) {
return project.getTasks().register("npm_run_" + name, NpmRunTask.class, task -> {
task.taskName = name;
task.getSetup().set(setup);
task.getProjectDir().set(project.getProjectDir());
task.getInputs().file("package-lock.json").withPathSensitivity(PathSensitivity.RELATIVE);

task.getInputs().property("nodeVersion", setup.nodeVersion);
task.getInputs().property("npmVersion", setup.npmVersion);
taskConfig.execute(task);
});
}
}

@CacheableTask
public abstract static class NpmRunTask extends DefaultTask {
public String taskName;

@Input
public String getTaskName() {
return taskName;
}

@Internal
public abstract Property<SetupCleanupNode> getSetup();

@Internal
public abstract DirectoryProperty getProjectDir();

@TaskAction
public void npmCiRunTask() throws Exception {
SetupCleanupNode setup = getSetup().get();
// install node, npm, and package-lock.json
setup.start(getProjectDir().get().getAsFile());
// run the gulp task
ProxyConfig proxyConfig = new ProxyConfig(Collections.emptyList());
setup.factory().getNpmRunner(proxyConfig, null).execute("run " + taskName, null);
}
}

@Override
public void apply(Project project) {
extension = project.getExtensions().create(EXTENSION_NAME, Extension.class, project);
}

private Extension extension;
}
70 changes: 70 additions & 0 deletions src/main/java/com/diffplug/webtools/node/SetupCleanup.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright (C) 2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.diffplug.webtools.node;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.nio.file.Files;
import java.util.Arrays;

abstract class SetupCleanup<K> {
public void start(File keyFile, K key) throws Exception {
byte[] required = toBytes(key);
if (keyFile.exists()) {
byte[] actual = Files.readAllBytes(keyFile.toPath());
if (Arrays.equals(actual, required)) {
// short-circuit if our state is already setup
return;
} else {
Files.delete(keyFile.toPath());
@SuppressWarnings("unchecked")
K lastKey = (K) fromBytes(required);
doStop(lastKey);
}
}
// write out the key
doStart(key);
Files.createDirectories(keyFile.toPath().getParent());
Files.write(keyFile.toPath(), required);
}

protected abstract void doStart(K key) throws Exception;

protected abstract void doStop(K key) throws Exception;

private static byte[] toBytes(Object key) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try (ObjectOutputStream objectOutput = new ObjectOutputStream(bytes)) {
objectOutput.writeObject(key);
} catch (IOException e) {
throw new RuntimeException(e);
}
return bytes.toByteArray();
}

private static Object fromBytes(byte[] raw) throws ClassNotFoundException {
ByteArrayInputStream bytes = new ByteArrayInputStream(raw);
try (ObjectInputStream objectOutput = new ObjectInputStream(bytes)) {
return objectOutput.readObject();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
67 changes: 67 additions & 0 deletions src/main/java/com/diffplug/webtools/node/SetupCleanupNode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright (C) 2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.diffplug.webtools.node;

import com.github.eirslett.maven.plugins.frontend.lib.FrontendPluginFactory;
import com.github.eirslett.maven.plugins.frontend.lib.InstallationException;
import com.github.eirslett.maven.plugins.frontend.lib.ProxyConfig;
import com.github.eirslett.maven.plugins.frontend.lib.TaskRunnerException;
import java.io.File;
import java.io.Serializable;
import java.nio.file.Files;
import java.util.Collections;

class SetupCleanupNode implements Serializable {
public String nodeVersion;
public String npmVersion;
private File workingDir, installDir;
@SuppressWarnings("unused") // used for serialized equality
private byte[] packageLockJson;

public void start(File projectDir) throws Exception {
workingDir = projectDir;
installDir = new File(projectDir, "build/node-install");
packageLockJson = Files.readAllBytes(workingDir.toPath().resolve("package-lock.json"));
new Impl().start(keyFile(projectDir), this);
}

FrontendPluginFactory factory() {
return new FrontendPluginFactory(workingDir, installDir);
}

private static File keyFile(File projectDir) {
return new File(projectDir, "build/node_modules/.gradle-state");
}

private static class Impl extends SetupCleanup<SetupCleanupNode> {
@Override
protected void doStart(SetupCleanupNode key) throws TaskRunnerException, InstallationException {
ProxyConfig proxyConfig = new ProxyConfig(Collections.emptyList());
FrontendPluginFactory factory = key.factory();
factory.getNodeInstaller(proxyConfig)
.setNodeVersion(key.nodeVersion)
.setNpmVersion(key.npmVersion)
.install();
factory.getNpmRunner(proxyConfig, null)
.execute("ci", null);
}

@Override
protected void doStop(SetupCleanupNode key) throws Exception {

}
}
}
Loading

0 comments on commit 2952bd3

Please sign in to comment.