package fr.emse.gitlab.saref.jobs.library; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.nio.file.Files; import java.util.Arrays; import java.util.Calendar; import java.util.HashSet; import java.util.Set; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import fr.emse.gitlab.saref.jobs.AbstractJobRunner; public class RepositoryStructureChecker extends AbstractJobRunner { static Logger logger = Logger.getLogger("MaintenanceReport"); private final Set gitignoreLines = new HashSet<>( Arrays.asList("target", "*~", ".DS_Store", "catalog-v001.xml")); private final String NAME = "Check the structure of the repository"; public RepositoryStructureChecker(File dir) { super(dir); } public void doJob0() { try { if (!directory.isDirectory()) { error("The SAREF pipeline must be run inside a directory"); } } catch (SecurityException ex) { error("Security error while running the SAREF pipeline", ex); } 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) { final File dir = new File(directory, dirName); try { if (dir.isDirectory()) { success(String.format("There exists a folder named `%s`", dirName)); } else { failure(String.format("There should exist a folder named `%s`", dirName)); } } catch (SecurityException ex) { error(String.format("Error while checking if there exists a folder named `%s`", dirName), ex); } } private String checkRepoName() { String REGEX = "^(?saref-core|saref4[a-z][a-z][a-z][a-z])"; String name = directory.getName(); Pattern pattern = Pattern.compile(REGEX); Matcher matcher = pattern.matcher(name); if (!matcher.find()) { error(String.format( "The SAREF pipeline must be run inside a directory whose name begins with `saref-core`, or `saref4abcd` (where abcd can be any sequence of four letters). Got: %s", name)); return null; } return matcher.group("ext"); } private void checkOntoloyFolder(String ontoName) { final File ontoDir = new File(directory, "ontology"); final File ontoFile = new File(ontoDir, ontoName); if (!ontoFile.isFile()) { error(String.format("The ontology folder must contain an ontology file named `%s`", ontoName)); return; } } private void checkGitIgnoreFolder() { final File gitignore = new File(directory, ".gitignore"); if (!gitignore.exists()) { failure("The directory must contain a file named `.gitignore`"); } try (BufferedReader br = Files.newBufferedReader(gitignore.toPath())) { for (String line = br.readLine(); line != null; line = br.readLine()) { gitignoreLines.remove(line); } if (!gitignoreLines.isEmpty()) { failure(String.format("The file `.gitignore` lacks one line for each of the following strings: %s", gitignoreLines.toString())); } } catch (IOException ex) { error("Error while checking if the file `.gitignore` has the appropriate lines", ex); } } private void checkLICENSE() { final File licenseFile = new File(directory, "LICENSE"); if (!licenseFile.exists()) { failure("The directory must contain a file named `LICENSE`"); return; } File licenseModelFile = new File( RepositoryStructureChecker.class.getClassLoader().getResource("LICENSE_MODEL").getFile()); try (BufferedReader licenseModelFileReader = new BufferedReader(new FileReader(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()) { failure("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) { failure(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)) { failure(String.format("Line %s in the `LICENSE` should be `%s`", i, modelLine)); return; } modelLine = licenseModelFileReader.readLine(); licenseLine = licenseFileReader.readLine(); } if(modelLine == null && licenseLine != null) { failure(String.format("The license contains too many lines. Need %s", i)); return; } if(modelLine != null && licenseLine == null) { failure(String.format("The license is incomplete.", i)); return; } } catch (Exception ex) { error("Exception while creating the path for the LICENSE model", ex); return; } } private void checkExamplesFolder() { final File dir = new File(directory, "examples"); try { if (!dir.isDirectory()) { failure("There should exist a folder named `examples`"); return; } } catch (SecurityException ex) { error("Error while checking if there exists a folder named `examples`", ex); return; } try { boolean containsExample = Files.walk(dir.toPath()).anyMatch(p -> { return p.endsWith(".ttl"); }); if (!containsExample) { failure("The `examples` folder should contain at least one example file (some `.ttl` document"); } } catch (IOException ex) { error("Exception while browsing the `examples` folder", ex); } } }