001    /**
002     * Copyright 2009-2012 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.codehaus.mojo.properties;
017    
018    import java.io.File;
019    import java.io.IOException;
020    import java.text.SimpleDateFormat;
021    import java.util.ArrayList;
022    import java.util.Collections;
023    import java.util.Date;
024    import java.util.List;
025    import java.util.Map;
026    import java.util.Properties;
027    import java.util.Set;
028    
029    import org.apache.commons.io.FileUtils;
030    import org.apache.maven.plugin.MojoExecutionException;
031    import org.apache.maven.plugin.MojoFailureException;
032    import org.codehaus.plexus.util.StringUtils;
033    
034    /**
035     * Writes project properties to a file.
036     * 
037     * @author <a href="mailto:zarars@gmail.com">Zarar Siddiqi</a>
038     * @version $Id: WriteProjectProperties.java 9747 2009-05-20 13:27:44Z mark $
039     * @goal write-project-properties
040     */
041    public class WriteProjectProperties extends AbstractWritePropertiesMojo {
042        private static final String[] ESCAPE_CHARS = { "\n", "\r", "\t", ":", "#", "=" };
043    
044        /**
045         * If true, the plugin will create the properties file formatted the same way Ant formats properties files using the
046         * <code>echoproperties</code> task. This mode adds 3 custom properties at the top of the file, DSTAMP, TODAY, and
047         * TSTAMP
048         * 
049         * @parameter default-value="false" expression="${properties.antEchoPropertiesMode}"
050         */
051        private boolean antEchoPropertiesMode;
052    
053        /**
054         * If true, the plugin will include system properties when writing the properties file. System properties override
055         * both environment variables and project properties.
056         * 
057         * @parameter default-value="false" expression="${properties.includeSystemProperties}"
058         */
059        private boolean includeSystemProperties;
060    
061        /**
062         * If true, the plugin will include environment variables when writing the properties file. Environment variables
063         * are prefixed with "env". Environment variables override project properties.
064         * 
065         * @parameter default-value="false" expression="${properties.includeEnvironmentVariables}"
066         */
067        private boolean includeEnvironmentVariables;
068    
069        /**
070         * Comma separated set of properties to exclude when writing the properties file
071         * 
072         * @parameter expression="${properties.exclude}"
073         */
074        private String exclude;
075    
076        /**
077         * Comma separated set of properties to write to the properties file. If provided, only the properties matching
078         * those supplied here will be written to the properties file.
079         * 
080         * @parameter expression="${properties.include}"
081         */
082        private String include;
083    
084        @Override
085        public void execute() throws MojoExecutionException, MojoFailureException {
086            Properties properties = new Properties();
087            // Add project properties
088            properties.putAll(project.getProperties());
089            if (includeEnvironmentVariables) {
090                // Add environment variables, overriding any properties with the same key
091                properties.putAll(getEnvironmentVariables());
092            }
093            if (includeSystemProperties) {
094                // Add system properties, overriding any properties with the same key
095                properties.putAll(System.getProperties());
096            }
097    
098            // Remove properties as appropriate
099            trim(properties, exclude, include);
100    
101            String comment = "# " + new Date() + "\n";
102            if (antEchoPropertiesMode) {
103                comment = getAntHeader();
104                properties.remove("DSTAMP");
105                properties.remove("TODAY");
106                properties.remove("TSTAMP");
107            }
108    
109            getLog().info("Creating " + outputFile);
110            writeProperties(outputFile, comment, properties);
111        }
112    
113        protected Properties getEnvironmentVariables() {
114            String prefix = "env";
115            Map<String, String> map = System.getenv();
116            Properties props = new Properties();
117            for (String key : map.keySet()) {
118                String newKey = prefix + "." + key;
119                String value = map.get(key);
120                props.setProperty(newKey, value);
121            }
122            return props;
123        }
124    
125        protected void trim(Properties properties, String omitCSV, String includeCSV) {
126            List<String> omitKeys = ReadPropertiesMojo.getListFromCSV(omitCSV);
127            for (String key : omitKeys) {
128                properties.remove(key);
129            }
130            if (StringUtils.isBlank(includeCSV)) {
131                return;
132            }
133            List<String> includeKeys = ReadPropertiesMojo.getListFromCSV(includeCSV);
134            Set<String> keys = properties.stringPropertyNames();
135            for (String key : keys) {
136                if (!includeKeys.contains(key)) {
137                    properties.remove(key);
138                }
139            }
140        }
141    
142        protected String getAntHeader() throws MojoExecutionException {
143            SimpleDateFormat dstamp = new SimpleDateFormat("yyyyMMdd");
144            SimpleDateFormat today = new SimpleDateFormat("MMMM d yyyy");
145            SimpleDateFormat tstamp = new SimpleDateFormat("HHmm");
146            Date now = new Date();
147            StringBuilder sb = new StringBuilder();
148            sb.append("# Ant properties\n");
149            sb.append("# " + now + "\n");
150            sb.append("DSTAMP=" + dstamp.format(now) + "\n");
151            sb.append("TODAY=" + today.format(now) + "\n");
152            sb.append("TSTAMP=" + tstamp.format(now) + "\n");
153            return sb.toString();
154        }
155    
156        protected void writeProperties(File file, String comment, Properties properties) throws MojoExecutionException {
157            List<String> names = new ArrayList<String>(properties.stringPropertyNames());
158            Collections.sort(names);
159            StringBuilder sb = new StringBuilder();
160            if (!StringUtils.isBlank(comment)) {
161                sb.append(comment);
162            }
163            for (String name : names) {
164                String value = properties.getProperty(name);
165                String escapedValue = escape(value, ESCAPE_CHARS);
166                sb.append(name + "=" + escapedValue + "\n");
167            }
168            try {
169                FileUtils.writeStringToFile(file, sb.toString());
170            } catch (IOException e) {
171                throw new MojoExecutionException("Error creating properties file", e);
172            }
173        }
174    
175        protected String escape(String s, String[] escapeChars) {
176            for (String escapeChar : escapeChars) {
177                s = s.replace(escapeChar, "\\" + escapeChar);
178            }
179            return s;
180    
181        }
182    
183        public boolean isAntEchoPropertiesMode() {
184            return antEchoPropertiesMode;
185        }
186    
187        public void setAntEchoPropertiesMode(boolean antEchoPropertiesMode) {
188            this.antEchoPropertiesMode = antEchoPropertiesMode;
189        }
190    
191        public boolean isIncludeSystemProperties() {
192            return includeSystemProperties;
193        }
194    
195        public void setIncludeSystemProperties(boolean includeSystemProperties) {
196            this.includeSystemProperties = includeSystemProperties;
197        }
198    }