Skip to content

Commit 3c52f3a

Browse files
Add files copy to core (#1548)
* Adds GuideProjectGenerator to core. * Adds GuideProjectGenerator to core. * Adds FileCopyUtility to core. * Adds test file. * Adds tests. * Fixes tests. * Format code, optimize imports. * Changes order of arguments in transferFiles method.
1 parent 48d136f commit 3c52f3a

File tree

54 files changed

+808
-208
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+808
-208
lines changed

buildSrc/src/main/java/io/micronaut/guides/core/App.java

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,30 @@
66
import io.micronaut.core.util.StringUtils;
77
import io.micronaut.jsonschema.JsonSchema;
88
import io.micronaut.serde.annotation.Serdeable;
9-
import io.micronaut.starter.application.ApplicationType;
109
import io.micronaut.starter.api.TestFramework;
10+
import io.micronaut.starter.application.ApplicationType;
1111
import jakarta.validation.constraints.NotBlank;
12+
1213
import java.util.List;
1314

1415
/**
15-
*
16-
* @param name The app's name. For single application guides, the application needs to be named default
17-
* @param packageName The app's package name. If you don't specify, the package name example.micronaut is used
18-
* @param applicationType The app type. If you don't specify, default is used
19-
* @param framework The app's framework. Default is Micronaut but Spring Boot is also supported
20-
* @param features The Micronaut Starter features' name that the app requires
16+
* @param name The app's name. For single application guides, the application needs to be named default
17+
* @param packageName The app's package name. If you don't specify, the package name example.micronaut is used
18+
* @param applicationType The app type. If you don't specify, default is used
19+
* @param framework The app's framework. Default is Micronaut but Spring Boot is also supported
20+
* @param features The Micronaut Starter features' name that the app requires
2121
* @param invisibleFeatures The app's invisible features
22-
* @param kotlinFeatures The app's Kotlin features
23-
* @param javaFeatures The app's Java features
24-
* @param groovyFeatures The app's Groovy features
25-
* @param testFramework The app's test framework
26-
* @param excludeTest The tests that should not be run
27-
* @param excludeSource The source files that should not be included
28-
* @param validateLicense To enable Spotless code check
22+
* @param kotlinFeatures The app's Kotlin features
23+
* @param javaFeatures The app's Java features
24+
* @param groovyFeatures The app's Groovy features
25+
* @param testFramework The app's test framework
26+
* @param excludeTest The tests that should not be run
27+
* @param excludeSource The source files that should not be included
28+
* @param validateLicense To enable Spotless code check
2929
*/
3030
@JsonSchema
3131
@Serdeable
32-
public record App (
32+
public record App(
3333
@NonNull
3434
@NotBlank
3535
String name,

buildSrc/src/main/java/io/micronaut/guides/core/BuildDiffLinkSubstitution.java

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,17 @@
55
import io.micronaut.http.uri.UriBuilder;
66
import io.micronaut.starter.application.ApplicationType;
77
import jakarta.inject.Singleton;
8+
89
import java.net.URI;
9-
import java.util.*;
10-
import static io.micronaut.guides.core.MacroUtils.*;
10+
import java.util.HashSet;
11+
import java.util.Optional;
12+
import java.util.Set;
13+
14+
import static io.micronaut.guides.core.MacroUtils.findMacroLines;
1115

1216
@Singleton
1317
public class BuildDiffLinkSubstitution implements MacroSubstitution {
18+
public static final String MACRO_DIFF_LINK = "diffLink";
1419
private static final String QUERY_PARAMLANG = "lang";
1520
private static final String QUERY_PARAM_BUILD = "build";
1621
private static final String QUERY_PARAM_TEST = "test";
@@ -19,7 +24,6 @@ public class BuildDiffLinkSubstitution implements MacroSubstitution {
1924
private static final String QUERY_PARAM_PACKAGE = "package";
2025
private static final String QUERY_PARAM_ACTIVITY = "activity";
2126
private static final String QUERY_PARAM_FEATURES = "features";
22-
public static final String MACRO_DIFF_LINK = "diffLink";
2327
private static final String ATTRIBUTE_FEATURES = "features";
2428
private static final String ATTRIBUTE_EXCLUDE_FEATURES = "featureExcludes";
2529
private final GuidesConfiguration guidesConfiguration;
@@ -28,16 +32,32 @@ public BuildDiffLinkSubstitution(GuidesConfiguration config) {
2832
this.guidesConfiguration = config;
2933
}
3034

35+
private static Set<String> features(App app, AsciidocMacro asciidocMacro, GuidesOption option) {
36+
Set<String> features = new HashSet<>();
37+
if (app != null) {
38+
features.addAll(GuideUtils.getAppVisibleFeatures(app, option.getLanguage()));
39+
}
40+
asciidocMacro.attributes().stream()
41+
.filter(attribute -> attribute.key().equals(ATTRIBUTE_FEATURES))
42+
.map(Attribute::values)
43+
.forEach(features::addAll);
44+
asciidocMacro.attributes().stream()
45+
.filter(attribute -> attribute.key().equals(ATTRIBUTE_EXCLUDE_FEATURES))
46+
.map(Attribute::values)
47+
.forEach(features::removeAll);
48+
return features;
49+
}
50+
3151
@Override
3252
public String substitute(String str, Guide guide, GuidesOption option) {
33-
for(String line : findMacroLines(str, MACRO_DIFF_LINK)) {
53+
for (String line : findMacroLines(str, MACRO_DIFF_LINK)) {
3454
Optional<AsciidocMacro> asciidocMacroOptional = AsciidocMacro.of(MACRO_DIFF_LINK, line);
3555
if (asciidocMacroOptional.isEmpty()) {
3656
continue;
3757
}
3858
AsciidocMacro asciidocMacro = asciidocMacroOptional.get();
3959
String res = buildDiffLink(asciidocMacro, guide, option).toString() + "[Diff]";
40-
str = str.replace(line,res);
60+
str = str.replace(line, res);
4161
}
4262
return str;
4363
}
@@ -57,20 +77,4 @@ private URI buildDiffLink(AsciidocMacro asciidocMacro, Guide guide, GuidesOption
5777
features.forEach(f -> uriBuilder.queryParam(QUERY_PARAM_FEATURES, f));
5878
return uriBuilder.build();
5979
}
60-
61-
private static Set<String> features(App app, AsciidocMacro asciidocMacro, GuidesOption option) {
62-
Set<String> features = new HashSet<>();
63-
if (app != null) {
64-
features.addAll(GuideUtils.getAppVisibleFeatures(app, option.getLanguage()));
65-
}
66-
asciidocMacro.attributes().stream()
67-
.filter(attribute -> attribute.key().equals(ATTRIBUTE_FEATURES))
68-
.map(Attribute::values)
69-
.forEach(features::addAll);
70-
asciidocMacro.attributes().stream()
71-
.filter(attribute -> attribute.key().equals(ATTRIBUTE_EXCLUDE_FEATURES))
72-
.map(Attribute::values)
73-
.forEach(features::removeAll);
74-
return features;
75-
}
7680
}

buildSrc/src/main/java/io/micronaut/guides/core/CliMacroSubstitution.java

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import jakarta.inject.Singleton;
44
import org.gradle.api.GradleException;
5+
56
import java.util.stream.Collectors;
67

78
@Singleton
@@ -12,6 +13,17 @@ public class CliMacroSubstitution extends PlaceholderWithTargetMacroSubstitution
1213
private static final String CLI_FUNCTION = "create-function-app";
1314
private static final String CLI_CLI = "create-cli-app";
1415

16+
private static String cliCommandForApp(App app) {
17+
return switch (app.applicationType()) {
18+
case CLI -> CLI_CLI;
19+
case FUNCTION -> CLI_FUNCTION;
20+
case GRPC -> CLI_GRPC;
21+
case MESSAGING -> CLI_MESSAGING;
22+
case DEFAULT -> CLI_DEFAULT;
23+
default -> throw new IllegalArgumentException("Unknown application type: " + app.applicationType());
24+
};
25+
}
26+
1527
@Override
1628
protected String getMacroName() {
1729
return "cli-command";
@@ -25,19 +37,8 @@ protected String getSubstitution(Guide guide, GuidesOption option, String appNam
2537
.orElse(null);
2638
if (app != null) {
2739
return cliCommandForApp(app);
28-
} else{
40+
} else {
2941
throw new GradleException("No CLI command found for app: " + app + " -- should be one of " + guide.apps().stream().map(el -> "@" + el + ":cli-command@").collect(Collectors.joining(", ")));
3042
}
3143
}
32-
33-
private static String cliCommandForApp(App app) {
34-
return switch (app.applicationType()) {
35-
case CLI -> CLI_CLI;
36-
case FUNCTION -> CLI_FUNCTION;
37-
case GRPC -> CLI_GRPC;
38-
case MESSAGING -> CLI_MESSAGING;
39-
case DEFAULT -> CLI_DEFAULT;
40-
default -> throw new IllegalArgumentException("Unknown application type: " + app.applicationType());
41-
};
42-
}
4344
}

buildSrc/src/main/java/io/micronaut/guides/core/Cloud.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
public enum Cloud implements Ordered {
66
OCI("Oracle Cloud", "OCI", 1),
7-
AWS("Amazon Web Services", "AWS", 2),
7+
AWS("Amazon Web Services", "AWS", 2),
88
AZURE("Microsoft Azure", "Azure", 3),
99
GCP("Google Cloud Platform", "GCP", 4);
1010

buildSrc/src/main/java/io/micronaut/guides/core/DefaultCoordinatesProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import java.util.Map;
99

1010
@Singleton
11-
public class DefaultCoordinatesProvider implements CoordinatesProvider{
11+
public class DefaultCoordinatesProvider implements CoordinatesProvider {
1212
@Override
1313
public Map<String, Coordinate> getCoordinates() {
1414
try (ApplicationContext context = ApplicationContext.run()) {
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
package io.micronaut.guides.core;
2+
3+
import io.micronaut.core.annotation.NonNull;
4+
import jakarta.inject.Singleton;
5+
import jakarta.validation.constraints.NotNull;
6+
import org.gradle.api.GradleException;
7+
import org.slf4j.Logger;
8+
import org.slf4j.LoggerFactory;
9+
10+
import java.io.File;
11+
import java.io.IOException;
12+
import java.nio.file.Files;
13+
import java.nio.file.Path;
14+
import java.nio.file.Paths;
15+
import java.nio.file.StandardCopyOption;
16+
import java.util.Arrays;
17+
import java.util.List;
18+
19+
import static io.micronaut.core.util.StringUtils.EMPTY_STRING;
20+
21+
@Singleton
22+
public class DefaultFilesTransferUtility implements FilesTransferUtility {
23+
private static final Logger LOG = LoggerFactory.getLogger(DefaultFilesTransferUtility.class);
24+
private static final String EXTENSION_JAVA = ".java";
25+
private static final String EXTENSION_GROOVY = ".groovy";
26+
private static final String EXTENSION_KT = ".kt";
27+
28+
private final LicenseLoader licenseLoader;
29+
private final GuidesConfiguration guidesConfiguration;
30+
31+
DefaultFilesTransferUtility(LicenseLoader licenseLoader,
32+
GuidesConfiguration guidesConfiguration) {
33+
this.licenseLoader = licenseLoader;
34+
this.guidesConfiguration = guidesConfiguration;
35+
}
36+
37+
private static boolean fileContainsText(File file, String text) {
38+
try {
39+
return new String(Files.readAllBytes(file.toPath())).contains(text);
40+
} catch (IOException e) {
41+
e.printStackTrace();
42+
return false;
43+
}
44+
}
45+
46+
private static void copyGuideSourceFiles(File inputDir, Path destinationPath,
47+
String appName, String language,
48+
boolean ignoreMissingDirectories) throws IOException {
49+
50+
// look for a common 'src' directory shared by multiple languages and copy those files first
51+
final String srcFolder = "src";
52+
Path srcPath = Paths.get(inputDir.getAbsolutePath(), appName, srcFolder);
53+
if (Files.exists(srcPath)) {
54+
Files.walkFileTree(srcPath, new CopyFileVisitor(Paths.get(destinationPath.toString(), srcFolder)));
55+
}
56+
57+
Path sourcePath = Paths.get(inputDir.getAbsolutePath(), appName, language);
58+
if (!Files.exists(sourcePath)) {
59+
sourcePath.toFile().mkdir();
60+
}
61+
if (Files.exists(sourcePath)) {
62+
// copy source/resource files for the current language
63+
Files.walkFileTree(sourcePath, new CopyFileVisitor(destinationPath));
64+
} else if (!ignoreMissingDirectories) {
65+
throw new GradleException("source directory " + sourcePath.toFile().getAbsolutePath() + " does not exist");
66+
}
67+
}
68+
69+
private static File fileToDelete(File destination, String path) {
70+
return Paths.get(destination.getAbsolutePath(), path).toFile();
71+
}
72+
73+
private static void copyFile(File inputDir, File destinationRoot, String filePath) throws IOException {
74+
File sourceFile = new File(inputDir, filePath);
75+
File destinationFile = new File(destinationRoot, filePath);
76+
77+
File destinationFileDir = destinationFile.getParentFile();
78+
if (!destinationFileDir.exists()) {
79+
Files.createDirectories(destinationFileDir.toPath());
80+
}
81+
82+
Files.copy(sourceFile.toPath(), destinationFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
83+
}
84+
85+
@Override
86+
public void transferFiles(@NotNull @NonNull File inputDirectory, @NotNull @NonNull File outputDirectory, @NotNull @NonNull Guide guide) throws IOException {
87+
List<GuidesOption> guidesOptionList = GuideGenerationUtils.guidesOptions(guide, LOG);
88+
for (GuidesOption guidesOption : guidesOptionList) {
89+
for (App app : guide.apps()) {
90+
String appName = app.name().equals(guidesConfiguration.getDefaultAppName()) ? EMPTY_STRING : app.name();
91+
String folder = MacroUtils.getSourceDir(guide.slug(), guidesOption);
92+
Path destinationPath = Paths.get(outputDirectory.getAbsolutePath(), folder, appName);
93+
File destination = destinationPath.toFile();
94+
95+
if (guide.base() != null) {
96+
File baseDir = new File(inputDirectory.getParentFile(), guide.base());
97+
copyGuideSourceFiles(baseDir, destinationPath, appName, guidesOption.getLanguage().toString(), true);
98+
}
99+
100+
copyGuideSourceFiles(inputDirectory, destinationPath, appName, guidesOption.getLanguage().toString(), false);
101+
102+
if (app.excludeSource() != null) {
103+
for (String mainSource : app.excludeSource()) {
104+
File f = fileToDelete(destination, GuideGenerationUtils.mainPath(appName, mainSource, guidesOption, guidesConfiguration));
105+
if (f.exists()) {
106+
f.delete();
107+
}
108+
f = fileToDelete(destination, GuideGenerationUtils.mainPath(appName, mainSource, guidesOption, guidesConfiguration));
109+
if (f.exists()) {
110+
f.delete();
111+
}
112+
}
113+
}
114+
115+
if (app.excludeTest() != null) {
116+
for (String testSource : app.excludeTest()) {
117+
File f = fileToDelete(destination, GuideGenerationUtils.testPath(appName, testSource, guidesOption, guidesConfiguration));
118+
if (f.exists()) {
119+
f.delete();
120+
}
121+
f = fileToDelete(destination, GuideGenerationUtils.testPath(appName, testSource, guidesOption, guidesConfiguration));
122+
if (f.exists()) {
123+
f.delete();
124+
}
125+
}
126+
}
127+
128+
if (guide.zipIncludes() != null) {
129+
File destinationRoot = new File(outputDirectory.getAbsolutePath(), folder);
130+
for (String zipInclude : guide.zipIncludes()) {
131+
copyFile(inputDirectory, destinationRoot, zipInclude);
132+
}
133+
}
134+
addLicenses(new File(outputDirectory.getAbsolutePath(), folder));
135+
}
136+
}
137+
}
138+
139+
void addLicenses(File folder) {
140+
String licenseHeader = licenseLoader.getLicenseHeaderText();
141+
Arrays.stream(folder.listFiles()).forEach(file -> {
142+
if ((file.getPath().endsWith(EXTENSION_JAVA) || file.getPath().endsWith(EXTENSION_GROOVY) || file.getPath().endsWith(EXTENSION_KT))
143+
&& !fileContainsText(file, "Licensed under")) {
144+
try {
145+
String content = new String(Files.readAllBytes(file.toPath()));
146+
Files.write(file.toPath(), (licenseHeader + content).getBytes());
147+
} catch (IOException e) {
148+
e.printStackTrace();
149+
}
150+
}
151+
});
152+
}
153+
}

buildSrc/src/main/java/io/micronaut/guides/core/DefaultGuideParser.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ public DefaultGuideParser(JsonSchemaProvider jsonSchemaProvider, JsonMapper json
3939
public List<Guide> parseGuidesMetadata(@NonNull @NotNull File guidesDir, @NonNull @NotNull String metadataConfigName) {
4040
List<Guide> metadatas = new ArrayList<>();
4141

42-
File dirs[] = guidesDir.listFiles(File::isDirectory);
43-
if(dirs == null) {
42+
File[] dirs = guidesDir.listFiles(File::isDirectory);
43+
if (dirs == null) {
4444
return metadatas;
4545
}
4646
for (File dir : dirs) {
@@ -69,10 +69,10 @@ public Optional<Guide> parseGuideMetadata(@NonNull @NotNull File guidesDir, @Non
6969
return Optional.empty();
7070
}
7171

72-
Map<String, Object> config = (Map<String,Object>) new JsonSlurper().parse(configFile);
72+
Map<String, Object> config = (Map<String, Object>) new JsonSlurper().parse(configFile);
7373
boolean publish = config.get("publish") == null || (Boolean) config.get("publish");
7474

75-
if(publish) {
75+
if (publish) {
7676
Set<ValidationMessage> assertions = jsonSchemaProvider.getSchema().validate(content, InputFormat.JSON);
7777

7878
if (!assertions.isEmpty()) {

0 commit comments

Comments
 (0)