/* * Copyright 2020 ETSI * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package fr.mines_stetienne.ci.saref.checkers; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.file.Files; import java.util.Arrays; import java.util.Calendar; import java.util.HashSet; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import fr.mines_stetienne.ci.saref.SAREFPipelineException; import fr.mines_stetienne.ci.saref.managers.RepositoryManager; /** * Checks TS 103 673 Clause 9.2: Structure of the SAREF project version directory * */ public class Clause_9_2_Checker extends AbstractClauseChecker { private static enum MESSAGE { requirements, ontology, tests, examples, documentation, readme_missing, gitignore_missing, gitignore_incomplete, gitignore_ioexception, license_missing, license_firstline, license_year, license_line, license_overcomplete, license_incomplete, license_ioexception, securityexception; } private static final Set gitignoreLines = new HashSet<>( Arrays.asList("target", "*~", ".DS_Store", "catalog-v001.xml", "saref-pipeline.jar")); public Clause_9_2_Checker(RepositoryManager repositoryManager) { super(repositoryManager, Clause_9_2_Checker.class); } @Override public void checkClause() throws SAREFPipelineException { checkReadme(); checkGitignore(); checkLICENSE(); checkDirectory("requirements", MESSAGE.requirements); checkDirectory("ontology", MESSAGE.ontology); checkDirectory("tests", MESSAGE.tests); checkDirectory("examples", MESSAGE.examples); checkDirectory("documentation", MESSAGE.documentation); } private void checkReadme() { final File file = new File(repository.getDirectory(), "README.md"); if (file.isFile()) { return; } logError(getMessage(MESSAGE.readme_missing)); } private void checkGitignore() throws SAREFPipelineException { final File file = new File(repository.getDirectory(), ".gitignore"); if (!file.isFile()) { logError(getMessage(MESSAGE.gitignore_missing)); return; } try (BufferedReader br = Files.newBufferedReader(file.toPath())) { for (String line = br.readLine(); line != null; line = br.readLine()) { gitignoreLines.remove(line); } if (!gitignoreLines.isEmpty()) { logError(getMessage(MESSAGE.gitignore_incomplete, gitignoreLines.toString())); } } catch (IOException ex) { logError(getMessage(MESSAGE.gitignore_ioexception, ex)); } } private void checkLICENSE() throws SAREFPipelineException { final File licenseFile = new File(repository.getDirectory(), "LICENSE"); if (!licenseFile.exists()) { logError(getMessage(MESSAGE.license_missing)); return; } InputStream licenseModelFile = Clause_9_2_Checker.class.getClassLoader() .getResourceAsStream("LICENSE_MODEL"); try (BufferedReader licenseModelFileReader = new BufferedReader(new InputStreamReader(licenseModelFile)); BufferedReader licenseFileReader = new BufferedReader(new FileReader(licenseFile));) { // first line String modelLine = licenseModelFileReader.readLine(); String licenseLine = licenseFileReader.readLine(); String regex = modelLine.replaceFirst("YYYY", "(?\\\\d{4})"); Pattern pattern = Pattern.compile(String.format("^%s$", regex)); Matcher regexMatcher = pattern.matcher(licenseLine); if (!regexMatcher.find()) { logError(getMessage(MESSAGE.license_firstline, licenseLine, modelLine)); return; } int year = Integer.parseInt(regexMatcher.group("year")); int currentYear = Calendar.getInstance().get(Calendar.YEAR); if (year < 2015 || year > currentYear) { logWarning(getMessage(MESSAGE.license_year, 2015, currentYear)); return; } int i = 1; modelLine = licenseModelFileReader.readLine(); licenseLine = licenseFileReader.readLine(); while (modelLine != null && licenseLine != null) { i++; if (!modelLine.equals(licenseLine)) { logError(getMessage(MESSAGE.license_line, i, modelLine)); return; } modelLine = licenseModelFileReader.readLine(); licenseLine = licenseFileReader.readLine(); } if (modelLine == null && licenseLine != null) { logError(getMessage(MESSAGE.license_overcomplete, i, modelLine)); return; } if (modelLine != null && licenseLine == null) { logError(getMessage(MESSAGE.license_incomplete, i)); return; } } catch (Exception ex) { logError(getMessage(MESSAGE.license_ioexception, ex)); } } private void checkDirectory(String dirName, MESSAGE message) throws SAREFPipelineException { final File dir = new File(repository.getDirectory(), dirName); try { if (!dir.isDirectory()) { String msg = getMessage(message, dirName); logError(msg); } } catch (SecurityException ex) { logError(getMessage(MESSAGE.securityexception, ex)); } } }