001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * Copyright 2015 ForgeRock AS 024 */ 025package org.forgerock.maven; 026 027import java.io.File; 028import java.util.LinkedList; 029import java.util.List; 030 031import org.apache.maven.plugin.AbstractMojo; 032import org.apache.maven.plugin.MojoExecutionException; 033import org.apache.maven.plugin.MojoFailureException; 034import org.apache.maven.plugins.annotations.LifecyclePhase; 035import org.apache.maven.plugins.annotations.Mojo; 036import org.apache.maven.plugins.annotations.Parameter; 037import org.apache.maven.project.MavenProject; 038import org.tmatesoft.svn.core.SVNDepth; 039import org.tmatesoft.svn.core.SVNException; 040import org.tmatesoft.svn.core.wc.ISVNStatusHandler; 041import org.tmatesoft.svn.core.wc.SVNClientManager; 042import org.tmatesoft.svn.core.wc.SVNPropertyData; 043import org.tmatesoft.svn.core.wc.SVNRevision; 044 045/** 046 * This be used to make sure that the file has the correct "svn:eol-style" 047 * property value. 048 */ 049@Mojo(name = "check-svn-property", defaultPhase = LifecyclePhase.VALIDATE) 050public class CheckSVNPropertyMojo extends AbstractMojo implements ISVNStatusHandler { 051 052 /** The Maven Project. */ 053 @Parameter(property = "project", required = true, readonly = true) 054 private MavenProject project; 055 056 /** The path to the root of the Subversion workspace to check. */ 057 @Parameter(required = true, defaultValue = "${basedir}") 058 private String svnWorkspaceRoot; 059 060 @Parameter(required = true) 061 private String svnPropertyName; 062 063 @Parameter(required = true) 064 private String svnPropertyExpectedValue; 065 066 @Parameter(property = "skipSvnPropCheck", required = true, defaultValue = "false") 067 private boolean checkDisabled; 068 069 /** 070 * The name of the system property that may be used to prevent eol-style 071 * problems from failing the build. 072 */ 073 @Parameter(property = "ignoreSvnPropertyCheckErrors", required = true, defaultValue = "false") 074 private boolean ignoreErrors; 075 076 /** The overall SVN Client Manager. */ 077 private final SVNClientManager svnClientManager = SVNClientManager.newInstance(); 078 079 private final List<String> errorFilePaths = new LinkedList<>(); 080 081 /** {@inheritDoc} **/ 082 public void execute() throws MojoExecutionException, MojoFailureException { 083 if (checkDisabled) { 084 getLog().info("Check svn property " + svnPropertyName + " is disabled"); 085 return; 086 } 087 088 try { 089 svnClientManager.getStatusClient().doStatus(new File(svnWorkspaceRoot), SVNRevision.WORKING, 090 SVNDepth.INFINITY, false, false, false, false, this, null); 091 } catch (Exception e) { 092 throw new MojoExecutionException("Encountered an error while examining subversion status: " 093 + e.getMessage() + "No further checks will be performed.", e); 094 } 095 096 if (!errorFilePaths.isEmpty()) { 097 logWithAppropriateLevel(" Potential " + svnPropertyName + " updates needed " + "for the following files:"); 098 for (String fileName : errorFilePaths) { 099 logWithAppropriateLevel(" " + fileName); 100 } 101 102 if (!ignoreErrors) { 103 throw new MojoExecutionException("Fix " + svnPropertyName + " problems before proceeding, or " 104 + "use '-DignoreSvnPropertyCheckErrors=true' to ignore these warnings warnings."); 105 } 106 } 107 } 108 109 private void logWithAppropriateLevel(final String message) { 110 if (!ignoreErrors) { 111 getLog().error(message); 112 } else { 113 getLog().warn(message); 114 } 115 } 116 117 /** 118 * Examines the provided status item to determine whether the associated 119 * file is acceptable. 120 * 121 * @param status 122 * The SVN status information for the file of interest. 123 */ 124 public void handleStatus(org.tmatesoft.svn.core.wc.SVNStatus status) { 125 File changedFile = status.getFile(); 126 if (!changedFile.exists() || !changedFile.isFile()) { 127 return; 128 } 129 130 try { 131 SVNPropertyData propertyData = SVNClientManager.newInstance().getWCClient() 132 .doGetProperty(changedFile, svnPropertyName, SVNRevision.BASE, SVNRevision.WORKING); 133 if (propertyData == null || !svnPropertyExpectedValue.equals(propertyData.getValue().getString())) { 134 errorFilePaths.add(changedFile.getPath()); 135 } 136 } catch (SVNException se) { 137 // This could happen if the file isn't under version control. 138 getLog().warn("Impossible to check svn:eol-style for the file " + changedFile.getAbsolutePath() 139 + " you might need to add it to svn."); 140 } 141 } 142}