001    /**
002     * Copyright 2004-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.kuali.maven.common;
017    
018    import java.util.Properties;
019    
020    import org.apache.commons.lang.StringUtils;
021    import org.apache.maven.model.Scm;
022    import org.apache.maven.plugin.AbstractMojo;
023    import org.apache.maven.plugin.MojoExecutionException;
024    import org.apache.maven.project.MavenProject;
025    
026    /**
027     * Extracts information contained in a pom and exposes it as project properties
028     * 
029     * eg major version, scm type, scm url
030     * 
031     */
032    public class Extractor {
033        PropertiesUtils utils = new PropertiesUtils();
034    
035        public void handleSVNBranch(AbstractMojo mojo, MavenProject project, String property) {
036            String scmType = getScmType(project.getScm());
037            if (!"svn".equalsIgnoreCase(scmType)) {
038                mojo.getLog().warn("This should only be used with Subversion");
039            }
040            String scmUrl = getScmUrl(project.getScm());
041            String branch = getBranch(scmUrl);
042    
043            if (!StringUtils.isEmpty(branch)) {
044                project.getProperties().setProperty(property, branch);
045                mojo.getLog().info(property + "=" + branch);
046            } else {
047                mojo.getLog().debug("SVN branch could not be determined");
048            }
049        }
050    
051        public void handleSVNTagBase(AbstractMojo mojo, MavenProject project, String property) {
052            String scmType = getScmType(project.getScm());
053            if (!"svn".equalsIgnoreCase(scmType)) {
054                mojo.getLog().warn("This should only be used with Subversion");
055            }
056            String scmUrl = getScmUrl(project.getScm());
057            String tagBase = getTagBase(scmUrl);
058    
059            if (!StringUtils.isEmpty(tagBase)) {
060                project.getProperties().setProperty(property, tagBase);
061                mojo.getLog().info(property + "=" + tagBase);
062            } else {
063                mojo.getLog().debug("SVN tag base could not be determined");
064            }
065        }
066    
067        public void handleMajorVersion(AbstractMojo mojo, MavenProject project, String property) {
068            String majorVersion = getMajorVersion(project.getVersion());
069            if (!StringUtils.isEmpty(majorVersion)) {
070                project.getProperties().setProperty(property, majorVersion);
071                mojo.getLog().info(property + "=" + majorVersion);
072            } else {
073                mojo.getLog().info("Major version could not be determined");
074            }
075        }
076    
077        public void handleScmUrl(AbstractMojo mojo, MavenProject project, String property) {
078            String scmUrl = getScmUrl(project.getScm());
079            if (!StringUtils.isEmpty(scmUrl)) {
080                project.getProperties().setProperty(property, scmUrl);
081                mojo.getLog().info(property + "=" + scmUrl);
082            } else {
083                mojo.getLog().info("scm url could not be determined");
084            }
085        }
086    
087        public void handleScmType(AbstractMojo mojo, MavenProject project, String property) {
088            String scmType = getScmType(project.getScm());
089            if (!StringUtils.isEmpty(scmType)) {
090                project.getProperties().setProperty(property, scmType);
091                mojo.getLog().info(property + "=" + scmType);
092            } else {
093                mojo.getLog().info("scm type could not be determined");
094            }
095        }
096    
097        public String getActualUrl(MavenProject project, String property) throws MojoExecutionException {
098            Properties props = utils.getMavenProperties(project);
099            String rawUrl = props.getProperty(property);
100            if (StringUtils.isBlank(rawUrl)) {
101                throw new MojoExecutionException("The project property '" + property + "' is blank");
102            }
103            String resolvedValue = utils.getResolvedValue(rawUrl, props);
104            if (StringUtils.isBlank(resolvedValue)) {
105                throw new MojoExecutionException("Resolved value for '" + property + "' is blank");
106            }
107            return resolvedValue;
108        }
109    
110        public Scm getTrimmedScm(Scm scm) {
111            String trimmedDeveloperConnection = getTrimmedScmUrl(scm.getDeveloperConnection());
112            String trimmedConnection = getTrimmedScmUrl(scm.getConnection());
113            String trimmedUrl = scm.getUrl().trim();
114            Scm trimmedScm = new Scm();
115            trimmedScm.setDeveloperConnection(trimmedDeveloperConnection);
116            trimmedScm.setConnection(trimmedConnection);
117            trimmedScm.setUrl(trimmedUrl);
118            return trimmedScm;
119        }
120    
121        public String getScmUrl(Scm scm) {
122            String devCon = scm.getDeveloperConnection();
123            String con = scm.getConnection();
124            String scmUrl = StringUtils.isEmpty(devCon) ? con : devCon;
125            if (StringUtils.isEmpty(scmUrl)) {
126                return null;
127            }
128            return getTrimmedScmUrl(scmUrl);
129        }
130    
131        protected String getTrimmedScmUrl(String url) {
132            String[] tokens = StringUtils.splitByWholeSeparatorPreserveAllTokens(url.trim(), ":");
133            if (tokens == null || tokens.length < 3) {
134                throw new IllegalArgumentException("Unable to trim url " + url);
135            }
136            StringBuilder sb = new StringBuilder();
137            for (int i = 2; i < tokens.length; i++) {
138                if (i != 2) {
139                    sb.append(":");
140                }
141                sb.append(tokens[i]);
142            }
143            return sb.toString();
144        }
145    
146        public String getScmType(Scm scm) {
147            String scmType1 = getScmType(scm.getDeveloperConnection());
148            String scmType2 = getScmType(scm.getConnection());
149            if (!StringUtils.isEmpty(scmType1)) {
150                return scmType1;
151            } else if (!StringUtils.isEmpty(scmType2)) {
152                return scmType2;
153            } else {
154                return null;
155            }
156        }
157    
158        public String getScmType(String url) {
159            if (StringUtils.isEmpty(url)) {
160                return null;
161            }
162            String[] tokens = StringUtils.splitByWholeSeparatorPreserveAllTokens(url, ":");
163            if (tokens == null || tokens.length < 2) {
164                return null;
165            } else {
166                return tokens[1];
167            }
168        }
169    
170        public String getBranch(String url) {
171            int pos = url.lastIndexOf("/trunk");
172            if (pos != -1) {
173                return "trunk";
174            }
175            String token = "/branches/";
176            pos = url.lastIndexOf(token);
177            if (pos == -1) {
178                return null;
179            }
180            String s = url.substring(pos + token.length());
181            pos = s.indexOf("/");
182            if (pos == -1) {
183                return s;
184            } else {
185                return s.substring(0, pos);
186            }
187        }
188    
189        public void validateTrimmedScm(Scm scm, String actualUrl) {
190            validateUrls(scm.getDeveloperConnection(), actualUrl);
191            validateUrls(scm.getConnection(), actualUrl);
192            validateUrls(scm.getUrl(), actualUrl);
193        }
194    
195        public void validateUrls(String url, String actualUrl) {
196            if (StringUtils.isBlank(url)) {
197                throw new IllegalArgumentException("url cannot be blank");
198            }
199            if (StringUtils.isBlank(actualUrl)) {
200                throw new IllegalArgumentException("actualUrl cannot be blank");
201            }
202            if (!url.equals(actualUrl)) {
203                throw new IllegalArgumentException("URL's don't match. url=[" + url + "] actual=[" + actualUrl);
204            }
205        }
206    
207        public String getTagBase(String url) {
208            int pos1 = url.lastIndexOf("/branches");
209            int pos2 = url.lastIndexOf("/trunk");
210            int pos = Math.max(pos1, pos2);
211            if (pos == -1) {
212                return null;
213            } else {
214                return url.substring(0, pos) + "/tags";
215            }
216        }
217    
218        public String getMajorVersion(String version) {
219            if (StringUtils.isEmpty(version)) {
220                return null;
221            }
222            int pos = getPos(version);
223            if (pos == -1) {
224                return version;
225            } else {
226                int peekAhead = peekAhead(pos, version);
227                return version.substring(0, peekAhead);
228            }
229        }
230    
231        protected int peekAhead(int pos, String version) {
232            // Attempt to peek ahead one character after the dot/dash
233            int index = pos + 1;
234    
235            // If we go past the end of the string, forget it
236            if (index >= version.length()) {
237                return pos;
238            }
239    
240            // Is that character an integer?
241            char c = version.charAt(index);
242    
243            if (isInteger(c)) {
244                // If so, include it
245                return index + 1;
246            } else {
247                // If not return the original
248                return pos;
249            }
250        }
251    
252        protected int getPos(String version) {
253            int pos1 = version.indexOf(".");
254            int pos2 = version.indexOf("-");
255            // No dot or dash
256            if (pos1 == pos2 && pos2 == -1) {
257                return -1;
258            }
259            // Dash but no dot
260            if (pos1 == -1 && pos2 != -1) {
261                return pos2;
262            }
263            // Dot but no dash
264            if (pos1 != -1 && pos2 == -1) {
265                return pos1;
266            }
267    
268            // Both a dot and a dash, use the first one
269            return Math.min(pos1, pos2);
270    
271        }
272    
273        protected boolean isInteger(char c) {
274            switch (c) {
275            case '0':
276            case '1':
277            case '2':
278            case '3':
279            case '4':
280            case '5':
281            case '6':
282            case '7':
283            case '8':
284            case '9':
285                return true;
286            default:
287                return false;
288            }
289        }
290    }