Fix: use comments
This commit is contained in:
parent
4710d20b7d
commit
4bc7ba11bf
|
@ -1,5 +1,5 @@
|
||||||
plugins {
|
plugins {
|
||||||
java
|
`java-library`
|
||||||
application
|
application
|
||||||
id("com.github.johnrengelman.shadow") version "7.1.2"
|
id("com.github.johnrengelman.shadow") version "7.1.2"
|
||||||
}
|
}
|
||||||
|
@ -13,16 +13,23 @@ application {
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven("https://gitlab.com/api/v4/projects/35745143/packages/maven")
|
maven("https://maven.frohnmeyer-wds.de/artifacts")
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("net.freeutils:jlhttp:2.6")
|
implementation("net.freeutils:jlhttp:2.6")
|
||||||
implementation("com.amihaiemil.web:eo-yaml:6.1.0")
|
implementation("io.gitlab.jfronny:commons:2022.11.2+21-36-56")
|
||||||
implementation("io.gitlab.jfronny:commons:2022.9.26+17-56-16")
|
implementation("io.gitlab.jfronny:commons-gson:2022.11.2+21-36-56")
|
||||||
implementation("io.gitlab.jfronny:commons-gson:2022.9.26+17-56-16")
|
|
||||||
|
api("io.gitlab.jfronny.gson:gson-compile-core:1.0-SNAPSHOT")
|
||||||
|
compileOnly("io.gitlab.jfronny.gson:gson-compile-annotations:1.0-SNAPSHOT")
|
||||||
|
annotationProcessor("io.gitlab.jfronny.gson:gson-compile-processor:1.0-SNAPSHOT")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.runShadow {
|
tasks.runShadow {
|
||||||
args("8002")
|
args("8002")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.withType<JavaCompile> {
|
||||||
|
options.compilerArgs.add("-AgsonCompileNoReflect")
|
||||||
|
}
|
|
@ -1,12 +1,8 @@
|
||||||
package io.gitlab.jfronny.woodpecker.include;
|
package io.gitlab.jfronny.woodpecker.include;
|
||||||
|
|
||||||
import com.amihaiemil.eoyaml.*;
|
|
||||||
import io.gitlab.jfronny.commons.HttpUtils;
|
import io.gitlab.jfronny.commons.HttpUtils;
|
||||||
import io.gitlab.jfronny.commons.log.Logger;
|
import io.gitlab.jfronny.commons.log.Logger;
|
||||||
import io.gitlab.jfronny.commons.serialize.Serializer;
|
|
||||||
import io.gitlab.jfronny.commons.serialize.gson.api.v1.GsonHolders;
|
|
||||||
import io.gitlab.jfronny.woodpecker.include.model.*;
|
import io.gitlab.jfronny.woodpecker.include.model.*;
|
||||||
import io.gitlab.jfronny.woodpecker.include.util.YamlTypeAdapter;
|
|
||||||
import net.freeutils.httpserver.HTTPServer;
|
import net.freeutils.httpserver.HTTPServer;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
@ -22,8 +18,6 @@ public class Main {
|
||||||
}
|
}
|
||||||
HTTPServer server = new HTTPServer(Integer.parseInt(args[0]));
|
HTTPServer server = new HTTPServer(Integer.parseInt(args[0]));
|
||||||
HTTPServer.VirtualHost host = server.getVirtualHost(null);
|
HTTPServer.VirtualHost host = server.getVirtualHost(null);
|
||||||
GsonHolders.registerSerializer();
|
|
||||||
GsonHolders.registerTypeAdapter(YamlMapping.class, new YamlTypeAdapter());
|
|
||||||
HttpUtils.setUserAgent("Woodpecker-Include/1.0");
|
HttpUtils.setUserAgent("Woodpecker-Include/1.0");
|
||||||
host.addContext("/ciconfig", (req, resp) -> {
|
host.addContext("/ciconfig", (req, resp) -> {
|
||||||
Ref ref = new Ref();
|
Ref ref = new Ref();
|
||||||
|
@ -45,9 +39,8 @@ public class Main {
|
||||||
|
|
||||||
private static int processRequest(HTTPServer.Request req, HTTPServer.Response resp, Ref ref) throws IOException {
|
private static int processRequest(HTTPServer.Request req, HTTPServer.Response resp, Ref ref) throws IOException {
|
||||||
RequestModel request;
|
RequestModel request;
|
||||||
try (var is = req.getBody()) {
|
try (var isr = new InputStreamReader(req.getBody())) {
|
||||||
String body = new String(is.readAllBytes());
|
request = GC_RequestModel.read(isr);
|
||||||
request = Serializer.getInstance().deserialize(body, RequestModel.class);
|
|
||||||
}
|
}
|
||||||
ref.name = request.repo.full_name;
|
ref.name = request.repo.full_name;
|
||||||
AtomicBoolean changed = new AtomicBoolean(false);
|
AtomicBoolean changed = new AtomicBoolean(false);
|
||||||
|
@ -55,7 +48,7 @@ public class Main {
|
||||||
if (changed.get()) {
|
if (changed.get()) {
|
||||||
resp.sendHeaders(200);
|
resp.sendHeaders(200);
|
||||||
try (OutputStreamWriter writer = new OutputStreamWriter(resp.getBody())) {
|
try (OutputStreamWriter writer = new OutputStreamWriter(resp.getBody())) {
|
||||||
Serializer.getInstance().serialize(response, writer);
|
GC_ResponseModel.write(writer, response);
|
||||||
}
|
}
|
||||||
LOG.info("Processed includes for pipeline for " + ref.name);
|
LOG.info("Processed includes for pipeline for " + ref.name);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
package io.gitlab.jfronny.woodpecker.include;
|
package io.gitlab.jfronny.woodpecker.include;
|
||||||
|
|
||||||
import com.amihaiemil.eoyaml.*;
|
|
||||||
import io.gitlab.jfronny.commons.HttpUtils;
|
import io.gitlab.jfronny.commons.HttpUtils;
|
||||||
|
import io.gitlab.jfronny.commons.StreamIterable;
|
||||||
import io.gitlab.jfronny.woodpecker.include.model.Pipeline;
|
import io.gitlab.jfronny.woodpecker.include.model.Pipeline;
|
||||||
import io.gitlab.jfronny.woodpecker.include.util.FilteringYamlMapping;
|
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
@ -11,12 +10,17 @@ import java.net.URISyntaxException;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.*;
|
||||||
import java.util.function.Consumer;
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
final class PipelineUnpacker implements BiConsumer<Pipeline, Consumer<Pipeline>> {
|
final class PipelineUnpacker implements BiConsumer<Pipeline, Consumer<Pipeline>> {
|
||||||
|
private static final String URL = "https?://(?:www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b[-a-zA-Z0-9()@:%_+.~#?&/=]*";
|
||||||
|
private static final Pattern INCLUDE = Pattern.compile("^#include (" + URL + ")$");
|
||||||
|
private static final Pattern LINK = Pattern.compile("^#link (" + URL + ")$");
|
||||||
|
|
||||||
private final AtomicBoolean changed;
|
private final AtomicBoolean changed;
|
||||||
private final Set<String> included = new HashSet<>();
|
private final Set<String> linked = new HashSet<>();
|
||||||
|
|
||||||
public PipelineUnpacker(AtomicBoolean changed) {
|
public PipelineUnpacker(AtomicBoolean changed) {
|
||||||
this.changed = changed;
|
this.changed = changed;
|
||||||
|
@ -25,7 +29,7 @@ final class PipelineUnpacker implements BiConsumer<Pipeline, Consumer<Pipeline>>
|
||||||
@Override
|
@Override
|
||||||
public void accept(Pipeline pipeline, Consumer<Pipeline> pipelineConsumer) {
|
public void accept(Pipeline pipeline, Consumer<Pipeline> pipelineConsumer) {
|
||||||
try {
|
try {
|
||||||
processPipeline(pipeline, pipelineConsumer);
|
processPipeline(pipeline, pipelineConsumer, 0);
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException e) {
|
||||||
throw new UncheckedIOException(new IOException("Could not find URL", e));
|
throw new UncheckedIOException(new IOException("Could not find URL", e));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -33,47 +37,59 @@ final class PipelineUnpacker implements BiConsumer<Pipeline, Consumer<Pipeline>>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processPipeline(Pipeline pipeline, Consumer<Pipeline> pipelineConsumer) throws URISyntaxException, IOException {
|
private void processPipeline(Pipeline pipeline, Consumer<Pipeline> pipelineConsumer, int depth) throws URISyntaxException, IOException {
|
||||||
YamlNode include = pipeline.data.value("include");
|
if (depth > 5) throw new IOException("Too many nested includes, a maximum of 5 is supported");
|
||||||
if (include == null) {
|
List<String> toLink = pipeline.data().lines()
|
||||||
|
.map(LINK::matcher)
|
||||||
|
.filter(Matcher::matches)
|
||||||
|
.map(s -> s.group(1))
|
||||||
|
.filter(s -> !linked.contains(s))
|
||||||
|
.toList();
|
||||||
|
boolean hasIncludes = pipeline.data().lines().anyMatch(INCLUDE.asPredicate());
|
||||||
|
if (toLink.isEmpty() && !hasIncludes) {
|
||||||
// Has no includes
|
// Has no includes
|
||||||
pipelineConsumer.accept(pipeline);
|
pipelineConsumer.accept(pipeline);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
changed.set(true);
|
changed.set(true);
|
||||||
// Send included
|
|
||||||
//TODO switch back to switch pattern matching once that is available
|
// Fill in includes and reprocess
|
||||||
if (include instanceof Scalar str) download(str.value(), null, pipelineConsumer);
|
if (hasIncludes) {
|
||||||
else if (include instanceof YamlMapping map) {
|
StringBuilder newData = new StringBuilder();
|
||||||
for (YamlNode key : map.keys()) {
|
for (String line : new StreamIterable<>(pipeline.data().lines())) {
|
||||||
download(map.string(key), key.asScalar().value(), pipelineConsumer);
|
Matcher matcher = INCLUDE.matcher(line);
|
||||||
|
if (!matcher.matches()) newData.append(line);
|
||||||
|
else {
|
||||||
|
newData.append(download(matcher.group(1)).data());
|
||||||
|
}
|
||||||
|
newData.append('\n');
|
||||||
}
|
}
|
||||||
} else if (include instanceof YamlSequence seq) {
|
processPipeline(new Pipeline(pipeline.name(), newData.toString()), pipelineConsumer, depth + 1);
|
||||||
for (YamlNode node : seq) {
|
return;
|
||||||
download(node.asScalar().value(), null, pipelineConsumer);
|
}
|
||||||
}
|
|
||||||
} else throw new IllegalStateException("Unexpected value: " + include);
|
// Link additional pipelines
|
||||||
if (pipeline.data.keys().size() > 1) {
|
for (String url : toLink) {
|
||||||
|
if (linked.contains(url)) continue;
|
||||||
|
linked.add(url);
|
||||||
|
processPipeline(download(url), pipelineConsumer, depth + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pipeline.data().lines()
|
||||||
|
.anyMatch(INCLUDE.asPredicate().negate()
|
||||||
|
.and(LINK.asPredicate().negate())
|
||||||
|
.and(Predicate.not(String::isBlank)))) {
|
||||||
// More than just includes: generate override without include node
|
// More than just includes: generate override without include node
|
||||||
Pipeline filtered = new Pipeline();
|
pipelineConsumer.accept(pipeline);
|
||||||
filtered.name = pipeline.name;
|
|
||||||
pipeline.data = new FilteringYamlMapping(pipeline.data, s -> !s.asScalar().value().equals("include"));
|
|
||||||
pipelineConsumer.accept(filtered);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void download(String url, String fileName, Consumer<Pipeline> pipelineConsumer) throws URISyntaxException, IOException {
|
private Pipeline download(String url) throws URISyntaxException, IOException {
|
||||||
if (included.contains(url)) return;
|
|
||||||
included.add(url);
|
|
||||||
URI uri = new URI(url.replace(" ", "%20"));
|
URI uri = new URI(url.replace(" ", "%20"));
|
||||||
if (!"http".equalsIgnoreCase(uri.getScheme()) && !"https".equalsIgnoreCase(uri.getScheme())) {
|
if (!"http".equalsIgnoreCase(uri.getScheme()) && !"https".equalsIgnoreCase(uri.getScheme())) {
|
||||||
throw new URISyntaxException(url, "Could not find scheme");
|
throw new URISyntaxException(url, "Could not find scheme");
|
||||||
}
|
}
|
||||||
try (InputStream is = HttpUtils.get(url).sendInputStream()) {
|
String fileName = Paths.get(new URI(url.replace(" ", "%20")).getPath()).getFileName().toString();
|
||||||
Pipeline pipeline = new Pipeline();
|
return new Pipeline(fileName, HttpUtils.get(url).sendString());
|
||||||
pipeline.name = fileName != null ? fileName : Paths.get(new URI(url.replace(" ", "%20")).getPath()).getFileName().toString();
|
|
||||||
pipeline.data = Yaml.createYamlInput(is).readYamlMapping();
|
|
||||||
processPipeline(pipeline, pipelineConsumer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package io.gitlab.jfronny.woodpecker.include.model;
|
package io.gitlab.jfronny.woodpecker.include.model;
|
||||||
|
|
||||||
|
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@GSerializable
|
||||||
public class Build {
|
public class Build {
|
||||||
public Long id;
|
public Long id;
|
||||||
public Long number;
|
public Long number;
|
||||||
|
|
|
@ -1,21 +1,7 @@
|
||||||
package io.gitlab.jfronny.woodpecker.include.model;
|
package io.gitlab.jfronny.woodpecker.include.model;
|
||||||
|
|
||||||
import com.amihaiemil.eoyaml.YamlMapping;
|
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
|
||||||
|
|
||||||
public class Pipeline {
|
@GSerializable
|
||||||
public String name;
|
public record Pipeline(String name, String data) {
|
||||||
public YamlMapping data;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "{\"name\":\"" + escape(name) + ",\"data\":\"" + escape(data.toString()) + '}';
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String escape(String text) {
|
|
||||||
return text
|
|
||||||
.replace("\\", "\\\\")
|
|
||||||
.replace("\"", "\\\"")
|
|
||||||
.replace("\r", "\\r")
|
|
||||||
.replace("\n", "\\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package io.gitlab.jfronny.woodpecker.include.model;
|
package io.gitlab.jfronny.woodpecker.include.model;
|
||||||
|
|
||||||
import io.gitlab.jfronny.gson.annotations.SerializedName;
|
import io.gitlab.jfronny.gson.annotations.SerializedName;
|
||||||
|
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@GSerializable
|
||||||
public class Repo {
|
public class Repo {
|
||||||
public Long id;
|
public Long id;
|
||||||
public String owner;
|
public String owner;
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package io.gitlab.jfronny.woodpecker.include.model;
|
package io.gitlab.jfronny.woodpecker.include.model;
|
||||||
|
|
||||||
|
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@GSerializable
|
||||||
public class RequestModel {
|
public class RequestModel {
|
||||||
public Repo repo;
|
public Repo repo;
|
||||||
public Build pipeline;
|
public Build pipeline;
|
||||||
|
|
|
@ -1,27 +1,9 @@
|
||||||
package io.gitlab.jfronny.woodpecker.include.model;
|
package io.gitlab.jfronny.woodpecker.include.model;
|
||||||
|
|
||||||
|
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ResponseModel {
|
@GSerializable
|
||||||
public List<Pipeline> configs;
|
public record ResponseModel(List<Pipeline> configs) {
|
||||||
|
|
||||||
public ResponseModel() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResponseModel(List<Pipeline> configs) {
|
|
||||||
this.configs = List.copyOf(configs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
StringBuilder sb = new StringBuilder("{\"configs\":[");
|
|
||||||
boolean first = false;
|
|
||||||
for (Pipeline config : configs) {
|
|
||||||
if (!first) sb.append(',');
|
|
||||||
first = true;
|
|
||||||
sb.append(config.toString());
|
|
||||||
}
|
|
||||||
sb.append("]}");
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
package io.gitlab.jfronny.woodpecker.include.util;
|
|
||||||
|
|
||||||
import com.amihaiemil.eoyaml.*;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class FilteringYamlMapping extends BaseYamlMapping {
|
|
||||||
private final YamlMapping base;
|
|
||||||
private final Predicate<YamlNode> filter;
|
|
||||||
|
|
||||||
public FilteringYamlMapping(YamlMapping base, Predicate<YamlNode> filter) {
|
|
||||||
this.base = base;
|
|
||||||
this.filter = filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<YamlNode> keys() {
|
|
||||||
return base.keys().stream().filter(filter).collect(Collectors.toSet());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public YamlNode value(YamlNode key) {
|
|
||||||
return filter.test(key) ? base.value(key) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Comment comment() {
|
|
||||||
return base.comment();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
package io.gitlab.jfronny.woodpecker.include.util;
|
|
||||||
|
|
||||||
import com.amihaiemil.eoyaml.Yaml;
|
|
||||||
import com.amihaiemil.eoyaml.YamlMapping;
|
|
||||||
import io.gitlab.jfronny.gson.TypeAdapter;
|
|
||||||
import io.gitlab.jfronny.gson.stream.JsonReader;
|
|
||||||
import io.gitlab.jfronny.gson.stream.JsonWriter;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class YamlTypeAdapter extends TypeAdapter<YamlMapping> {
|
|
||||||
@Override
|
|
||||||
public void write(JsonWriter jsonWriter, YamlMapping yamlMapping) throws IOException {
|
|
||||||
jsonWriter.value(yamlMapping.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public YamlMapping read(JsonReader jsonReader) throws IOException {
|
|
||||||
return Yaml.createYamlInput(jsonReader.nextString()).readYamlMapping();
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue