View Javadoc

1   /**
2    * Copyright 2009-2012 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.codehaus.mojo.properties;
17  
18  import java.io.File;
19  import java.io.IOException;
20  import java.text.SimpleDateFormat;
21  import java.util.ArrayList;
22  import java.util.Arrays;
23  import java.util.Collections;
24  import java.util.Date;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Properties;
28  import java.util.Set;
29  
30  import org.apache.commons.io.FileUtils;
31  import org.apache.maven.plugin.MojoExecutionException;
32  import org.apache.maven.plugin.MojoFailureException;
33  import org.codehaus.plexus.util.StringUtils;
34  
35  /**
36   * Write project properties to a file.
37   * 
38   * @author Jeff Caddel
39   * 
40   * @goal write-project-properties
41   */
42  public class WriteProjectProperties extends AbstractWritePropertiesMojo {
43      private static final String CR = "\r";
44      private static final String LF = "\n";
45      private static final String TAB = "\t";
46      private static final String[] ANT_ESCAPE_CHARS = { CR, LF, TAB, ":", "#", "=" };
47  
48      /**
49       * Comma separated list of characters to escape when writing property values. cr=carriage return, lf=linefeed,
50       * tab=tab. Any other values are taken literally.
51       * 
52       * @parameter default-value="cr,lf,tab" expression="${properties.escapeChars}"
53       */
54      private String escapeChars;
55  
56      /**
57       * If true, the plugin will create the properties file formatted the same way Ant formats properties files using the
58       * <code>echoproperties</code> task. This mode adds 3 custom properties at the top of the file, DSTAMP, TODAY, and
59       * TSTAMP. In this mode <code>escapeChars</code> is ignored and the 6 characters Ant escapes are used instead
60       * <code>CR</code>,<code>LF</code>,<code>TAB</code>,<code>:</code>,<code>#</code>,<code>=</code>
61       * 
62       * @parameter default-value="false" expression="${properties.antEchoPropertiesMode}"
63       */
64      private boolean antEchoPropertiesMode;
65  
66      /**
67       * If true, the plugin will include system properties when writing the properties file. System properties override
68       * both environment variables and project properties.
69       * 
70       * @parameter default-value="false" expression="${properties.includeSystemProperties}"
71       */
72      private boolean includeSystemProperties;
73  
74      /**
75       * If true, the plugin will include environment variables when writing the properties file. Environment variables
76       * are prefixed with "env". Environment variables override project properties.
77       * 
78       * @parameter default-value="false" expression="${properties.includeEnvironmentVariables}"
79       */
80      private boolean includeEnvironmentVariables;
81  
82      /**
83       * Comma separated set of properties to exclude when writing the properties file
84       * 
85       * @parameter expression="${properties.exclude}"
86       */
87      private String exclude;
88  
89      /**
90       * Comma separated set of properties to write to the properties file. If provided, only the properties matching
91       * those supplied here will be written to the properties file.
92       * 
93       * @parameter expression="${properties.include}"
94       */
95      private String include;
96  
97      @Override
98      public void execute() throws MojoExecutionException, MojoFailureException {
99          Properties properties = new Properties();
100         // Add project properties
101         properties.putAll(project.getProperties());
102         if (includeEnvironmentVariables) {
103             // Add environment variables, overriding any existing properties with the same key
104             properties.putAll(getEnvironmentVariables());
105         }
106         if (includeSystemProperties) {
107             // Add system properties, overriding any existing properties with the same key
108             properties.putAll(System.getProperties());
109         }
110 
111         // Remove properties as appropriate
112         trim(properties, exclude, include);
113 
114         String comment = "# " + new Date() + "\n";
115         List<String> escapeTokens = getEscapeChars(escapeChars);
116         if (antEchoPropertiesMode) {
117             escapeTokens = Arrays.asList(ANT_ESCAPE_CHARS);
118             comment = getAntHeader();
119             properties.remove("DSTAMP");
120             properties.remove("TODAY");
121             properties.remove("TSTAMP");
122         }
123 
124         getLog().info("Creating " + outputFile);
125         writeProperties(outputFile, comment, properties, escapeTokens);
126     }
127 
128     protected static Properties getEnvironmentVariables() {
129         String prefix = "env";
130         Map<String, String> map = System.getenv();
131         Properties props = new Properties();
132         for (String key : map.keySet()) {
133             String newKey = prefix + "." + key;
134             String value = map.get(key);
135             props.setProperty(newKey, value);
136         }
137         return props;
138     }
139 
140     protected void trim(Properties properties, String omitCSV, String includeCSV) {
141         List<String> omitKeys = ReadPropertiesMojo.getListFromCSV(omitCSV);
142         for (String key : omitKeys) {
143             properties.remove(key);
144         }
145         if (StringUtils.isBlank(includeCSV)) {
146             return;
147         }
148         List<String> includeKeys = ReadPropertiesMojo.getListFromCSV(includeCSV);
149         Set<String> keys = properties.stringPropertyNames();
150         for (String key : keys) {
151             if (!includeKeys.contains(key)) {
152                 properties.remove(key);
153             }
154         }
155     }
156 
157     protected String getAntHeader() {
158         SimpleDateFormat dstamp = new SimpleDateFormat("yyyyMMdd");
159         SimpleDateFormat today = new SimpleDateFormat("MMMM d yyyy");
160         SimpleDateFormat tstamp = new SimpleDateFormat("HHmm");
161         Date now = new Date();
162         StringBuilder sb = new StringBuilder();
163         sb.append("# Ant properties\n");
164         sb.append("# " + now + "\n");
165         sb.append("DSTAMP=" + dstamp.format(now) + "\n");
166         sb.append("TODAY=" + today.format(now) + "\n");
167         sb.append("TSTAMP=" + tstamp.format(now) + "\n");
168         return sb.toString();
169     }
170 
171     protected List<String> getEscapeChars(String escapeChars) {
172         List<String> tokens = ReadPropertiesMojo.getListFromCSV(escapeChars);
173         List<String> realTokens = new ArrayList<String>();
174         for (String token : tokens) {
175             String realToken = getRealToken(token);
176             realTokens.add(realToken);
177         }
178         return realTokens;
179     }
180 
181     protected String getRealToken(String token) {
182         if (token.equalsIgnoreCase("CR")) {
183             return CR;
184         } else if (token.equalsIgnoreCase("LF")) {
185             return LF;
186         } else if (token.equalsIgnoreCase("TAB")) {
187             return TAB;
188         } else {
189             return token;
190         }
191     }
192 
193     protected String getContent(String comment, Properties properties, List<String> escapeTokens) {
194         List<String> names = new ArrayList<String>(properties.stringPropertyNames());
195         Collections.sort(names);
196         StringBuilder sb = new StringBuilder();
197         if (!StringUtils.isBlank(comment)) {
198             sb.append(comment);
199         }
200         for (String name : names) {
201             String value = properties.getProperty(name);
202             String escapedValue = escape(value, escapeTokens);
203             sb.append(name + "=" + escapedValue + "\n");
204         }
205         return sb.toString();
206     }
207 
208     protected void writeProperties(File file, String comment, Properties properties, List<String> escapeTokens)
209             throws MojoExecutionException {
210         try {
211             String content = getContent(comment, properties, escapeTokens);
212             FileUtils.writeStringToFile(file, content);
213         } catch (IOException e) {
214             throw new MojoExecutionException("Error creating properties file", e);
215         }
216     }
217 
218     protected String escape(String s, List<String> escapeChars) {
219         for (String escapeChar : escapeChars) {
220             s = s.replace(escapeChar, getReplacementToken(escapeChar));
221         }
222         return s;
223     }
224 
225     protected String getReplacementToken(String escapeChar) {
226         if (escapeChar.equals(CR)) {
227             return "\\r";
228         } else if (escapeChar.equals(LF)) {
229             return "\\n";
230         } else if (escapeChar.equals(TAB)) {
231             return "\\t";
232         } else
233             return "\\" + escapeChar;
234     }
235 
236     public boolean isAntEchoPropertiesMode() {
237         return antEchoPropertiesMode;
238     }
239 
240     public void setAntEchoPropertiesMode(boolean antEchoPropertiesMode) {
241         this.antEchoPropertiesMode = antEchoPropertiesMode;
242     }
243 
244     public boolean isIncludeSystemProperties() {
245         return includeSystemProperties;
246     }
247 
248     public void setIncludeSystemProperties(boolean includeSystemProperties) {
249         this.includeSystemProperties = includeSystemProperties;
250     }
251 
252     public String getEscapeChars() {
253         return escapeChars;
254     }
255 
256     public void setEscapeChars(String escapeChars) {
257         this.escapeChars = escapeChars;
258     }
259 
260     public boolean isIncludeEnvironmentVariables() {
261         return includeEnvironmentVariables;
262     }
263 
264     public void setIncludeEnvironmentVariables(boolean includeEnvironmentVariables) {
265         this.includeEnvironmentVariables = includeEnvironmentVariables;
266     }
267 
268     public String getExclude() {
269         return exclude;
270     }
271 
272     public void setExclude(String exclude) {
273         this.exclude = exclude;
274     }
275 
276     public String getInclude() {
277         return include;
278     }
279 
280     public void setInclude(String include) {
281         this.include = include;
282     }
283 }