package fr.emse.gitlab.saref.jobs; 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.FileSystems; import java.nio.file.Files; import java.nio.file.PathMatcher; 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.emse.gitlab.saref.Constants; import fr.emse.gitlab.saref.SAREFPipelineException; import fr.emse.gitlab.saref.entities.git.Version; public class CheckRepositoryStructure extends JobRunner { public static final PathMatcher ttlMatcher = FileSystems.getDefault().getPathMatcher("glob:**/*.ttl"); private final Set gitignoreLines = new HashSet<>( Arrays.asList("target", "*~", ".DS_Store", "catalog-v001.xml", "saref-pipeline.jar")); private Version version; private File directory; public CheckRepositoryStructure(String testSuiteName) { super(testSuiteName); } public void check(Version version) throws SAREFPipelineException { this.version = version; this.directory = version.getRepository().getDirectory(); checkThereExistsDirectory("diagrams"); checkThereExistsDirectory("ontology"); String repoName = checkRepoName(); if (repoName == null) { return; } String ontologyFile = repoName.equals("saref-core") ? "saref.ttl" : repoName + ".ttl"; checkOntoloyFolder(ontologyFile); checkGitIgnoreFolder(); checkLICENSE(); checkExamplesFolder(); } private void checkThereExistsDirectory(String dirName) throws SAREFPipelineException { final File dir = new File(directory, dirName); try { if (!dir.isDirectory()) { logger.warn(String.format("There should exist a folder named `%s`", dirName)); } } catch (SecurityException ex) { logger.error(String.format("Error while checking if there exists a folder named `%s`", dirName), ex); throw new SAREFPipelineException(String.format("Error while checking if there exists a folder named `%s`", dirName), ex); } } private String checkRepoName() throws SAREFPipelineException { String REGEX = "(?saref-core|saref4[a-z][a-z][a-z][a-z])"; String name = version.getRepositoryName(); Pattern pattern = Pattern.compile(REGEX); Matcher matcher = pattern.matcher(name); if (!matcher.find()) { logger.error(String.format( "The repository directory should contain `saref-core`, or `saref4abcd` (where abcd can be any sequence of four letters). Got: %s", name)); throw new SAREFPipelineException(String.format( "The repository directory should contain `saref-core`, or `saref4abcd` (where abcd can be any sequence of four letters). Got: %s", name)); } return matcher.group("ext"); } private void checkOntoloyFolder(String ontoName) throws SAREFPipelineException { final File ontoDir = new File(directory, "ontology"); final File ontoFile = new File(ontoDir, ontoName); if (!ontoFile.isFile()) { logger.error(String.format("The ontology folder must contain an ontology file named `%s`", ontoName)); throw new SAREFPipelineException(String.format("The ontology folder must contain an ontology file named `%s`", ontoName)); } } private void checkGitIgnoreFolder() throws SAREFPipelineException { final File gitignore = new File(directory, ".gitignore"); if (!gitignore.exists()) { logger.warn("The directory must contain a file named `.gitignore`"); return; } try (BufferedReader br = Files.newBufferedReader(gitignore.toPath())) { for (String line = br.readLine(); line != null; line = br.readLine()) { gitignoreLines.remove(line); } if (!gitignoreLines.isEmpty()) { logger.warn(String.format("The file `.gitignore` lacks one line for each of the following strings: %s", gitignoreLines.toString())); } } catch (IOException ex) { logger.error("Error while checking if the file `.gitignore` contains the appropriate lines: " + gitignoreLines, ex); throw new SAREFPipelineException("Error while checking if the file `.gitignore` contains the appropriate lines: " + gitignoreLines, ex); } } private void checkLICENSE() throws SAREFPipelineException { final File licenseFile = new File(directory, "LICENSE"); if (!licenseFile.exists()) { logger.warn("The directory must contain a file named `LICENSE`"); return; } InputStream licenseModelFile = CheckRepositoryStructure.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()) { logger.warn("First line of the `LICENSE` file must match the following string (see details below)", "First line of the `LICENSE` file must match the following string, where YYYY is a year. Got: " + licenseLine, modelLine); return; } int year = Integer.parseInt(regexMatcher.group("year")); int currentYear = Calendar.getInstance().get(Calendar.YEAR); if (year < 2015 || year > currentYear) { logger.warn(String.format("The year in the `LICENSE` should be between %s and %s", 2015, currentYear)); return; } int i = 1; modelLine = licenseModelFileReader.readLine(); licenseLine = licenseFileReader.readLine(); while (modelLine != null && licenseLine != null) { i++; if (!modelLine.equals(licenseLine)) { logger.warn(String.format("Line %s in the `LICENSE` should be `%s`", i, modelLine)); return; } modelLine = licenseModelFileReader.readLine(); licenseLine = licenseFileReader.readLine(); } if (modelLine == null && licenseLine != null) { logger.warn(String.format("The license contains too many lines. Need %s", i)); return; } if (modelLine != null && licenseLine == null) { logger.warn(String.format("The license is incomplete.", i)); return; } } catch (Exception ex) { logger.error("Exception while creating the path for the LICENSE model", ex); throw new SAREFPipelineException("Exception while creating the path for the LICENSE model", ex); } } private void checkExamplesFolder() throws SAREFPipelineException { final File dir = new File(directory, "examples"); try { if (!dir.isDirectory()) { logger.warn("There should exist a folder named `examples`"); return; } } catch (SecurityException ex) { logger.error("Error while checking if there exists a folder named `examples`", ex); throw new SAREFPipelineException("Error while checking if there exists a folder named `examples`", ex); } try { boolean containsExample = Files.walk(dir.toPath()) .anyMatch(p -> { return ttlMatcher.matches(p); }); if (!containsExample) { logger.warn("The `examples` folder should contain at least one example file (some `.ttl` document)"); } } catch (IOException ex) { logger.error("Exception while browsing the `examples` folder", ex); throw new SAREFPipelineException("Exception while browsing the `examples` folder", ex); } } }