View Javadoc
1   /*
2    * SPDX-FileCopyrightText: Copyright (c) 2011-2025 Yegor Bugayenko
3    * SPDX-License-Identifier: MIT
4    */
5   package com.qulice.maven;
6   
7   import com.jcabi.log.Logger;
8   import com.qulice.spi.ValidationException;
9   import java.io.File;
10  import java.util.Collection;
11  import org.apache.commons.io.FileUtils;
12  import org.apache.maven.project.MavenProject;
13  import org.cactoos.text.TextOf;
14  import org.cactoos.text.Trimmed;
15  import org.cactoos.text.UncheckedText;
16  
17  /**
18   * Check for required svn properties in all text files.
19   *
20   * <p>Every text file should have two SVN properties:
21   *
22   * <pre>
23   * svn:keywords=Id
24   * svn:eol-style=native
25   * </pre>
26   *
27   * <p>Read SVN documentation about how you can set them.
28   *
29   * @see <a href="http://svnbook.red-bean.com/en/1.5/svn.ref.properties.html">Properties in Subversion</a>
30   * @since 0.3
31   */
32  public final class SvnPropertiesValidator implements MavenValidator {
33  
34      @Override
35      public void validate(final MavenEnvironment env)
36          throws ValidationException {
37          if (SvnPropertiesValidator.isSvn(env.project())) {
38              final File dir = new File(env.project().getBasedir(), "src");
39              if (dir.exists()) {
40                  this.validate(dir);
41              } else {
42                  Logger.info(
43                      this,
44                      "%s directory is absent, no need to check SVN properties",
45                      dir
46                  );
47              }
48          } else {
49              Logger.info(this, "This is not an SVN project");
50          }
51      }
52  
53      /**
54       * Validate directory.
55       * @param dir The directory
56       * @throws ValidationException If fails
57       */
58      private void validate(final File dir) throws ValidationException {
59          final Collection<File> files = FileUtils.listFiles(
60              dir,
61              new String[] {
62                  "java", "txt", "xsl", "xml", "html", "js", "css", "vm",
63                  "php", "py", "groovy", "ini", "properties", "bsh", "xsd", "sql",
64              },
65              true
66          );
67          int errors = 0;
68          for (final File file : files) {
69              if (!this.valid(file)) {
70                  ++errors;
71              }
72          }
73          if (errors == 0) {
74              Logger.info(
75                  this,
76                  "%d text files have all required SVN properties",
77                  files.size()
78              );
79          } else {
80              Logger.info(
81                  this,
82                  "%d of %d files don't have required SVN properties",
83                  errors,
84                  files.size()
85              );
86              throw new ValidationException(
87                  "%d files with invalid SVN properties",
88                  errors
89              );
90          }
91      }
92  
93      /**
94       * Check whether this project uses SVN.
95       * @param project The Maven project
96       * @return TRUE if yes
97       */
98      private static boolean isSvn(final MavenProject project) {
99          return project.getScm() != null
100             && project.getScm().getConnection() != null
101             && project.getScm().getConnection().startsWith("scm:svn");
102     }
103 
104     /**
105      * Check one file.
106      * @param file The file to check
107      * @return TRUE if valid
108      */
109     private boolean valid(final File file) {
110         boolean valid = true;
111         final String style = SvnPropertiesValidator.propget(
112             file, "svn:eol-style"
113         );
114         if (!"native".equals(style)) {
115             Logger.error(
116                 this,
117                 "File %s doesn't have 'svn:eol-style' set to 'native': '%s'",
118                 file,
119                 style
120             );
121             valid = false;
122         }
123         final String keywords = SvnPropertiesValidator.propget(
124             file, "svn:keywords"
125         );
126         if (!keywords.contains("Id")) {
127             Logger.error(
128                 this,
129                 "File %s doesn't have 'svn:keywords' with 'Id': '%s'",
130                 file,
131                 keywords
132             );
133             valid = false;
134         }
135         return valid;
136     }
137 
138     /**
139      * Get SVN property from the file.
140      * @param file The file to check
141      * @param name Property name
142      * @return Property value
143      */
144     private static String propget(final File file, final String name) {
145         final ProcessBuilder builder = new ProcessBuilder(
146             "svn",
147             "propget",
148             name,
149             file.getAbsolutePath()
150         );
151         builder.redirectErrorStream(true);
152         try {
153             final Process process = builder.start();
154             process.waitFor();
155             return new UncheckedText(
156                 new Trimmed(
157                     new TextOf(
158                         process.getInputStream()
159                     )
160                 )
161             ).asString();
162         } catch (final java.io.IOException ex) {
163             throw new IllegalArgumentException(ex);
164         } catch (final InterruptedException ex) {
165             Thread.currentThread().interrupt();
166             throw new IllegalStateException(ex);
167         }
168     }
169 
170 }