ExecutionLogger interface.
25 | * 26 | * @author Olivier Lamy 27 | */ 28 | public interface ExecutionLogger { 29 | /** 30 | * The stream which will catch the output of the {@link org.apache.maven.shared.scriptinterpreter.ScriptRunner}. 31 | * 32 | * @return the output stream 33 | */ 34 | PrintStream getPrintStream(); 35 | 36 | /** 37 | * Consume logging from this component. 38 | * 39 | * @param line the line to consume 40 | */ 41 | void consumeLine(String line); 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/apache/maven/shared/scriptinterpreter/FileLogger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | package org.apache.maven.shared.scriptinterpreter; 20 | 21 | import java.io.File; 22 | import java.io.IOException; 23 | import java.io.OutputStream; 24 | import java.io.PrintStream; 25 | import java.nio.file.Files; 26 | 27 | /** 28 | *FileLogger class.
29 | */ 30 | public class FileLogger implements ExecutionLogger, AutoCloseable { 31 | 32 | /** 33 | * The path to the log file. 34 | */ 35 | private File file; 36 | 37 | /** 38 | * The underlying file stream this logger writes to. 39 | */ 40 | private PrintStream stream; 41 | 42 | /** 43 | * Creates a new logger that writes to the specified file. 44 | * 45 | * @param outputFile The path to the output file, if null all message will be discarded. 46 | * @throws java.io.IOException If the output file could not be created. 47 | */ 48 | public FileLogger(File outputFile) throws IOException { 49 | this(outputFile, null); 50 | } 51 | 52 | /** 53 | * Creates a new logger that writes to the specified file and optionally mirrors messages. 54 | * 55 | * @param outputFile The path to the output file, if null all message will be discarded. 56 | * @param mirrorHandler The class which handle mirrored message, can benull
.
57 | * @throws java.io.IOException If the output file could not be created.
58 | */
59 | public FileLogger(File outputFile, FileLoggerMirrorHandler mirrorHandler) throws IOException {
60 | this.file = outputFile;
61 |
62 | OutputStream outputStream;
63 |
64 | if (outputFile != null) {
65 | outputFile.getParentFile().mkdirs();
66 | outputStream = Files.newOutputStream(outputFile.toPath());
67 | } else {
68 | outputStream = new NullOutputStream();
69 | }
70 |
71 | if (mirrorHandler != null) {
72 | stream = new PrintStream(new MirrorStreamWrapper(outputStream, mirrorHandler));
73 | } else {
74 | stream = new PrintStream(outputStream);
75 | }
76 | }
77 |
78 | /**
79 | * Gets the path to the output file.
80 | *
81 | * @return The path to the output file, never null
.
82 | */
83 | public File getOutputFile() {
84 | return file;
85 | }
86 |
87 | /**
88 | * Gets the underlying stream used to write message to the log file.
89 | *
90 | * @return The underlying stream used to write message to the log file, never null
.
91 | */
92 | @Override
93 | public PrintStream getPrintStream() {
94 | return stream;
95 | }
96 |
97 | /**
98 | * Writes the specified line to the log file
99 | * and invoke {@link FileLoggerMirrorHandler#consumeOutput(String)} if is given.
100 | *
101 | * @param line The message to log.
102 | */
103 | @Override
104 | public void consumeLine(String line) {
105 | stream.println(line);
106 | stream.flush();
107 | }
108 |
109 | /**
110 | * Closes the underlying file stream.
111 | */
112 | public void close() {
113 | if (stream != null) {
114 | stream.flush();
115 | stream.close();
116 | stream = null;
117 | }
118 | }
119 |
120 | private static class MirrorStreamWrapper extends OutputStream {
121 | private OutputStream out;
122 |
123 | private final FileLoggerMirrorHandler mirrorHandler;
124 |
125 | private StringBuilder lineBuffer;
126 |
127 | MirrorStreamWrapper(OutputStream outputStream, FileLoggerMirrorHandler mirrorHandler) {
128 | this.out = outputStream;
129 | this.mirrorHandler = mirrorHandler;
130 | this.lineBuffer = new StringBuilder();
131 | }
132 |
133 | @Override
134 | public void write(int b) throws IOException {
135 | out.write(b);
136 | lineBuffer.append((char) (b));
137 | }
138 |
139 | @Override
140 | public void write(byte[] b, int off, int len) throws IOException {
141 | out.write(b, off, len);
142 | lineBuffer.append(new String(b, off, len));
143 | }
144 |
145 | @Override
146 | public void flush() throws IOException {
147 | out.flush();
148 |
149 | int len = lineBuffer.length();
150 | if (len == 0) {
151 | // nothing to log
152 | return;
153 | }
154 |
155 | // remove line end for log
156 | while (len > 0 && (lineBuffer.charAt(len - 1) == '\n' || lineBuffer.charAt(len - 1) == '\r')) {
157 | len--;
158 | }
159 | lineBuffer.setLength(len);
160 |
161 | mirrorHandler.consumeOutput(lineBuffer.toString());
162 |
163 | // clear buffer
164 | lineBuffer = new StringBuilder();
165 | }
166 |
167 | @Override
168 | public void close() throws IOException {
169 | flush();
170 | if (out != null) {
171 | out.close();
172 | out = null;
173 | }
174 | }
175 | }
176 |
177 | private static class NullOutputStream extends OutputStream {
178 | @Override
179 | public void write(int b) {
180 | // do nothing
181 | }
182 |
183 | @Override
184 | public void write(byte[] b, int off, int len) {
185 | // do nothing
186 | }
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/maven/shared/scriptinterpreter/FileLoggerMirrorHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 | package org.apache.maven.shared.scriptinterpreter;
20 |
21 | /**
22 | * Handle output form interpreter.
23 | *
24 | * @since 1.3
25 | */
26 | public interface FileLoggerMirrorHandler {
27 | /**
28 | * Handle output message generated by script interpreter.
29 | * This method is invoked when flush occurs on the underlying stream.
30 | *
31 | * @param message last message
32 | */
33 | void consumeOutput(String message);
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/maven/shared/scriptinterpreter/GroovyScriptInterpreter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 | package org.apache.maven.shared.scriptinterpreter;
20 |
21 | import java.io.File;
22 | import java.io.IOException;
23 | import java.io.PrintStream;
24 | import java.io.UncheckedIOException;
25 | import java.net.MalformedURLException;
26 | import java.net.URL;
27 | import java.util.List;
28 | import java.util.Map;
29 |
30 | import groovy.lang.Binding;
31 | import groovy.lang.GroovyShell;
32 | import org.codehaus.groovy.control.CompilerConfiguration;
33 | import org.codehaus.groovy.tools.RootLoader;
34 |
35 | /**
36 | * Provides a facade to evaluate Groovy scripts.
37 | *
38 | * @author Benjamin Bentmann
39 | */
40 | class GroovyScriptInterpreter implements ScriptInterpreter {
41 |
42 | private final RootLoader childFirstLoader =
43 | new RootLoader(new URL[] {}, Thread.currentThread().getContextClassLoader());
44 |
45 | @Override
46 | public void setClassPath(Listnull
.
38 | */
39 | ScriptEvaluationException(Throwable cause) {
40 | super(cause);
41 | }
42 |
43 | /**
44 | * Creates a new exception with the specified message and cause.
45 | *
46 | * @param message The message, may be null
.
47 | * @param cause The cause, may be null
.
48 | * @since 1.3
49 | */
50 | public ScriptEvaluationException(String message, Throwable cause) {
51 | super(message, cause);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/maven/shared/scriptinterpreter/ScriptException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 | package org.apache.maven.shared.scriptinterpreter;
20 |
21 | /**
22 | * Common errors during script running.
23 | *
24 | * @author Slawomir Jaranowski
25 | * @since 1.3
26 | */
27 | public class ScriptException extends Exception {
28 | private static final long serialVersionUID = 4553276474852776472L;
29 |
30 | /**
31 | * Creates a new exception with the specified message and cause.
32 | *
33 | * @param message The message, may be null
.
34 | * @param cause The cause, may be null
.
35 | */
36 | public ScriptException(String message, Throwable cause) {
37 | super(message, cause);
38 | }
39 |
40 | ScriptException(String message) {
41 | super(message);
42 | }
43 |
44 | ScriptException(Throwable cause) {
45 | super(cause);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/maven/shared/scriptinterpreter/ScriptInterpreter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 | package org.apache.maven.shared.scriptinterpreter;
20 |
21 | import java.io.Closeable;
22 | import java.io.PrintStream;
23 | import java.util.List;
24 | import java.util.Map;
25 |
26 | /**
27 | * Defines a simple abstraction used to plug-in several script interpreters for the pre-/post-build-hooks. Each
28 | * interpreter implementation should be stateless and support reuse.
29 | *
30 | * @author Benjamin Bentmann
31 | */
32 | public interface ScriptInterpreter extends Closeable {
33 |
34 | /**
35 | * Set class path used by interpreted.
36 | *
37 | * @param classPath The additional class path for the script interpreter, may be null
or empty if only
38 | * the plugin realm should be used for the script evaluation. If specified, this class path will
39 | * precede
40 | * the artifacts from the plugin class path.
41 | */
42 | void setClassPath(Listnull
.
48 | * @param globalVariables The global variables (as a mapping from variable name to value) to define for the script,
49 | * may be null
if not used.
50 | * @param scriptOutput A print stream to redirect any output from the script to, may be null
to use
51 | * stdout/stderr.
52 | * @return The return value from the script, can be null
53 | * @throws ScriptEvaluationException If the script evaluation produced an error.
54 | */
55 | Object evaluateScript(String script, Mapnull
.
39 | * @param result The cause, may be null
.
40 | */
41 | ScriptReturnException(String message, Object result) {
42 | super(message);
43 | this.result = result;
44 | }
45 |
46 | /**
47 | * Retrieve result returned by script.
48 | *
49 | * @return script result.
50 | */
51 | public Object getResult() {
52 | return result;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/maven/shared/scriptinterpreter/ScriptRunner.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 | package org.apache.maven.shared.scriptinterpreter;
20 |
21 | import java.io.Closeable;
22 | import java.io.File;
23 | import java.io.IOException;
24 | import java.io.PrintStream;
25 | import java.nio.file.Files;
26 | import java.util.HashMap;
27 | import java.util.LinkedHashMap;
28 | import java.util.List;
29 | import java.util.Locale;
30 | import java.util.Map;
31 |
32 | import org.apache.commons.io.FilenameUtils;
33 | import org.slf4j.Logger;
34 | import org.slf4j.LoggerFactory;
35 |
36 | /**
37 | * Runs pre-/post-build hook scripts.
38 | *
39 | * @author Benjamin Bentmann
40 | */
41 | public class ScriptRunner implements Closeable {
42 |
43 | private static final Object LOCK = new Object();
44 |
45 | private static final Logger LOG = LoggerFactory.getLogger(ScriptRunner.class);
46 |
47 | /**
48 | * The supported script interpreters, indexed by the lower-case file extension of their associated script files,
49 | * never null
.
50 | */
51 | private Mapnull
.
55 | */
56 | private Mapnull
to use platform encoding.
60 | */
61 | private String encoding;
62 |
63 | /**
64 | * Creates a new script runner with BSH and Groovy interpreters.
65 | */
66 | public ScriptRunner() {
67 | scriptInterpreters = new LinkedHashMap<>();
68 | scriptInterpreters.put("bsh", new BeanShellScriptInterpreter());
69 | scriptInterpreters.put("groovy", new GroovyScriptInterpreter());
70 | globalVariables = new HashMap<>();
71 | }
72 |
73 | /**
74 | * Add new script Interpreter
75 | *
76 | * @param id The Id of interpreter
77 | * @param scriptInterpreter the Script Interpreter implementation
78 | */
79 | public void addScriptInterpreter(String id, ScriptInterpreter scriptInterpreter) {
80 | scriptInterpreters.put(id, scriptInterpreter);
81 | }
82 |
83 | /**
84 | * Sets a global variable for the script interpreter.
85 | *
86 | * @param name The name of the variable, must not be null
.
87 | * @param value The value of the variable, may be null
.
88 | */
89 | public void setGlobalVariable(String name, Object value) {
90 | this.globalVariables.put(name, value);
91 | }
92 |
93 | /**
94 | * Sets the additional class path for the hook scripts. Note that the provided list is copied, so any later changes
95 | * will not affect the scripts.
96 | *
97 | * @param classPath The additional class path for the script interpreter, may be null
or empty if only
98 | * the plugin realm should be used for the script evaluation. If specified, this class path will precede the
99 | * artifacts from the plugin class path.
100 | */
101 | public void setClassPath(Listnull
or empty to use the platform's
111 | * default encoding.
112 | */
113 | public void setScriptEncoding(String encoding) {
114 | this.encoding = encoding != null && !encoding.isEmpty() ? encoding : null;
115 | }
116 |
117 | /**
118 | * Runs the specified hook script (after resolution).
119 | *
120 | * @param scriptDescription The description of the script to use for logging, must not be null
.
121 | * @param basedir The base directory of the project, must not be null
.
122 | * @param relativeScriptPath The path to the script relative to the project base directory, may be null
123 | * to skip the script execution and may not have extensions (resolution will search).
124 | * @param context The key-value storage used to share information between hook scripts, may be null
.
125 | * @param logger The logger to redirect the script output to, may be null
to use stdout/stderr.
126 | * @throws IOException If an I/O error occurred while reading the script file.
127 | * @throws ScriptException If the script did not return true
of threw an exception.
128 | */
129 | public void run(
130 | final String scriptDescription,
131 | final File basedir,
132 | final String relativeScriptPath,
133 | final Mapnull
.
165 | * @param scriptFile The path to the script, may be null
to skip the script execution.
166 | * @param context The key-value storage used to share information between hook scripts, may be null
.
167 | * @param logger The logger to redirect the script output to, may be null
to use stdout/stderr.
168 | * @throws IOException If an I/O error occurred while reading the script file.
169 | * @throws ScriptException If the script did not return true
of threw an exception.
170 | */
171 | public void run(
172 | final String scriptDescription, File scriptFile, final Mapnull
.
245 | * @return The effective path to the script file or null
if the input was null
.
246 | */
247 | private File resolveScript(File scriptFile) {
248 | if (scriptFile != null && !scriptFile.exists()) {
249 | for (String ext : this.scriptInterpreters.keySet()) {
250 | File candidateFile = new File(scriptFile.getPath() + '.' + ext);
251 | if (candidateFile.exists()) {
252 | scriptFile = candidateFile;
253 | break;
254 | }
255 | }
256 | }
257 | return scriptFile;
258 | }
259 |
260 | /**
261 | * Determines the script interpreter for the specified script file by looking at its file extension. In this
262 | * context, file extensions are considered case-insensitive. For backward compatibility with plugin versions 1.2-,
263 | * the BeanShell interpreter will be used for any unrecognized extension.
264 | *
265 | * @param scriptFile The script file for which to determine an interpreter, must not be null
.
266 | * @return The script interpreter for the file, never null
.
267 | */
268 | private ScriptInterpreter getInterpreter(File scriptFile) {
269 | String ext = FilenameUtils.getExtension(scriptFile.getName()).toLowerCase(Locale.ENGLISH);
270 | ScriptInterpreter interpreter = scriptInterpreters.get(ext);
271 | if (interpreter == null) {
272 | interpreter = scriptInterpreters.get("bsh");
273 | }
274 | return interpreter;
275 | }
276 |
277 | /**
278 | * Closes this script interpreter and releases any system resources associated with it.
279 | *
280 | * @throws IOException if an I/O error occurs.
281 | */
282 | @Override
283 | public void close() throws IOException {
284 | for (ScriptInterpreter scriptInterpreter : scriptInterpreters.values()) {
285 | scriptInterpreter.close();
286 | }
287 | scriptInterpreters.clear();
288 | }
289 | }
290 |
--------------------------------------------------------------------------------
/src/site/apt/index.apt.vm:
--------------------------------------------------------------------------------
1 | ------
2 | Introduction
3 | ------
4 | Olivier Lamy
5 | ------
6 | 2013-07-24
7 | ------
8 |
9 | ~~ Licensed to the Apache Software Foundation (ASF) under one
10 | ~~ or more contributor license agreements. See the NOTICE file
11 | ~~ distributed with this work for additional information
12 | ~~ regarding copyright ownership. The ASF licenses this file
13 | ~~ to you under the Apache License, Version 2.0 (the
14 | ~~ "License"); you may not use this file except in compliance
15 | ~~ with the License. You may obtain a copy of the License at
16 | ~~
17 | ~~ http://www.apache.org/licenses/LICENSE-2.0
18 | ~~
19 | ~~ Unless required by applicable law or agreed to in writing,
20 | ~~ software distributed under the License is distributed on an
21 | ~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
22 | ~~ KIND, either express or implied. See the License for the
23 | ~~ specific language governing permissions and limitations
24 | ~~ under the License.
25 |
26 | ~~ NOTE: For help with the syntax of this file, see:
27 | ~~ http://maven.apache.org/doxia/references/apt-format.html
28 |
29 | ${project.name}
30 |
31 | This component provides some utilities to interpret/execute some scripts for various implementations: groovy or beanshell.
32 |
33 | * Dependency declaration
34 |
35 | +---------
36 |