1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.cli.props;
20
21 import java.io.IOException;
22 import java.nio.file.Files;
23 import java.nio.file.Path;
24 import java.util.Enumeration;
25 import java.util.StringTokenizer;
26 import java.util.function.Function;
27
28 import static org.apache.maven.cli.props.InterpolationHelper.substVars;
29
30 public class MavenPropertiesLoader {
31
32 public static final String INCLUDES_PROPERTY = "${includes}";
33
34 public static final String OVERRIDE_PREFIX =
35 "maven.override.";
36
37 public static void loadProperties(
38 java.util.Properties properties, Path path, Function<String, String> callback, boolean escape)
39 throws IOException {
40 MavenProperties sp = new MavenProperties(false);
41 if (Files.exists(path)) {
42 sp.load(path);
43 }
44 properties.forEach(
45 (k, v) -> sp.put(k.toString(), escape ? InterpolationHelper.escape(v.toString()) : v.toString()));
46 loadIncludes(path, sp, callback);
47 substitute(sp, callback);
48 sp.forEach(properties::setProperty);
49 }
50
51 public static void substitute(MavenProperties props, Function<String, String> callback) {
52 for (Enumeration<?> e = props.propertyNames(); e.hasMoreElements(); ) {
53 String name = (String) e.nextElement();
54 String value = props.getProperty(name);
55 if (value == null) {
56 value = callback.apply(name);
57 }
58 if (name.startsWith(OVERRIDE_PREFIX)) {
59 String overrideName = name.substring(OVERRIDE_PREFIX.length());
60 props.put(overrideName, substVars(value, name, null, props, callback));
61 } else {
62 props.put(name, substVars(value, name, null, props, callback));
63 }
64 }
65 props.keySet().removeIf(k -> k.startsWith(OVERRIDE_PREFIX));
66 }
67
68 private static MavenProperties loadPropertiesFile(
69 Path path, boolean failIfNotFound, Function<String, String> callback) throws IOException {
70 MavenProperties configProps = new MavenProperties(null, false);
71 if (Files.exists(path) || failIfNotFound) {
72 configProps.load(path);
73 loadIncludes(path, configProps, callback);
74 trimValues(configProps);
75 }
76 return configProps;
77 }
78
79 private static void loadIncludes(Path configProp, MavenProperties configProps, Function<String, String> callback)
80 throws IOException {
81 String includes = configProps.get(INCLUDES_PROPERTY);
82 if (includes != null) {
83 includes = substVars(includes, INCLUDES_PROPERTY, null, configProps, callback);
84 StringTokenizer st = new StringTokenizer(includes, "?\",", true);
85 if (st.countTokens() > 0) {
86 String location;
87 do {
88 location = nextLocation(st);
89 if (location != null) {
90 boolean mandatory = true;
91 if (location.startsWith("?")) {
92 mandatory = false;
93 location = location.substring(1);
94 }
95 Path path = configProp.resolveSibling(location);
96 MavenProperties props = loadPropertiesFile(path, mandatory, s -> {
97 var v = callback.apply(s);
98 return v != null ? v : configProps.getProperty(s);
99 });
100 configProps.putAll(props);
101 }
102 } while (location != null);
103 }
104 }
105 configProps.remove(INCLUDES_PROPERTY);
106 }
107
108 private static void trimValues(MavenProperties configProps) {
109 configProps.replaceAll((k, v) -> v.trim());
110 }
111
112 private static String nextLocation(StringTokenizer st) {
113 boolean optional = false;
114 String retVal = null;
115
116 if (st.countTokens() > 0) {
117 String tokenList = "?\",";
118 StringBuilder tokBuf = new StringBuilder(10);
119 String tok;
120 boolean inQuote = false;
121 boolean tokStarted = false;
122 boolean exit = false;
123 while ((st.hasMoreTokens()) && (!exit)) {
124 tok = st.nextToken(tokenList);
125 switch (tok) {
126 case "\"":
127 inQuote = !inQuote;
128 if (inQuote) {
129 tokenList = "\"";
130 } else {
131 tokenList = "\" ";
132 }
133 break;
134 case ",":
135 if (tokStarted) {
136 retVal = tokBuf.toString();
137 tokStarted = false;
138 tokBuf = new StringBuilder(10);
139 exit = true;
140 }
141 break;
142 case "?":
143 optional = true;
144 break;
145 default:
146 tokStarted = true;
147 tokBuf.append(tok.trim());
148 break;
149 }
150 }
151
152
153
154 if ((!exit) && (tokStarted)) {
155 retVal = tokBuf.toString();
156 }
157 }
158
159 return optional ? "?" + retVal : retVal;
160 }
161 }