RepositoryStructureChecker.java 6.35 KB
Newer Older
Maxime Lefrançois's avatar
Maxime Lefrançois committed
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<String> 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 = "^(?<ext>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", "(?<year>\\\\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);
		}
	}

}