RemainderValidator.java

/*
 * Copyright (C) 2017-2025 Gerd Neugebauer
 *
 * This file is distributed under the 3-clause BSD license.
 * See file LICENSE for details.
 */
package org.ctan.site.services.upload.util;

import static java.util.Map.entry;

import java.util.ArrayList;
import java.util.Map;

/**
 * The class <code>RemainderValidator</code> contains the classifier for files
 * according to the file name.
 *
 * @author <a href="mailto:gene@ctan.org">Gerd Neugebauer</a>
 */
public class RemainderValidator extends ArrayList<String> {

    /**
     * The field <code>serialVersionUID</code> contains the version number.
     */
    private static final long serialVersionUID = 1L;

    /**
     * The field <code>REMAINDER</code> contains the mapping from extensions to
     * the source of the evil.
     */
    private static final Map<String, String> REMAINDER =
        Map.ofEntries(
            entry(".gitignore", "version control"),
            entry(".svnignore", "version control"),
            entry(".hgignore", "version control"),
            entry(".hgtags", "version control"),
            entry(".bak", "editor"),
            entry(".swp", "editor"),
            entry(".aux", "TeX"),
            entry(".dvi", "TeX"),
            entry(".log", "TeX"),
            entry(".blg", "BibTeX"),
            entry(".bbl", "BibTeX"),
            entry(".ilg", "makeindex"),
            entry(".ind", "makeindex"),
            entry(".idx", "makeindex"),
            entry(".brf", "LaTeX"),
            entry(".glg", "LaTeX"),
            entry(".glo", "LaTeX"),
            entry(".gls", "LaTeX"),
            entry(".loa", "LaTeX"),
            entry(".lof", "LaTeX"),
            entry(".lot", "LaTeX"),
            entry(".nav", "LaTeX"),
            entry(".out", "LaTeX"),
            entry(".tmp", "LaTeX"),
            entry(".toc", "LaTeX"),
            entry(".snm", "LaTeX"),
            entry(".vrb", "LaTeX"),
            entry(".tuc", "ConTeXt"),
            entry(".synctex", "TeX"),
            entry(".o", "compiler"),
            entry(".obj", "compiler"),
            entry(".so", "compiler"),
            entry(".DS_Store", "OS"));

    /**
     * The method <code>checkRemainderFiles</code> provides means to check a
     * file to be a remainder which should be avoided in CTAN packages.
     *
     * @param messages the messages
     * @param files the files
     */
    public void checkRemainderFiles(Messages messages,
        Map<String, Boolean> files) {

        for (var f : files.keySet()) {
            int i = f.lastIndexOf(".");
            if (i > 0) {
                var ext = f.substring(i);
                var lo = REMAINDER.get(ext);
                if (lo != null) {
                    messages.errorOrWarning("Remainder found", lo, f);
                }
            }
            if (f.endsWith("~") || f.contains("#")) {
                messages.errorOrWarning("Remainder found", "editor", f);
            } else if (f.endsWith(".synctex.gz")) {
                messages.errorOrWarning("Remainder found", "TeX", f);
            } else if (f.contains("/.git/")
                || f.startsWith(".git/")
                || f.contains("/.svn/")
                || f.startsWith(".svn/")
                || f.contains("/.hg/")
                || f.startsWith(".hg/")
                || f.contains("/CVS/")
                || f.startsWith("CVS/")
                || f.contains("/RCS/")
                || f.startsWith("RCS/")) {
                messages.errorOrWarning("Remainder found", "version control",
                    f);
            } else if (f.contains("__MACOSX/")) {
                messages.errorOrWarning("Remainder found", "OS", f);
            }
        }

        for (var it : this) {
            if (files.get(it) != null) {
                messages.error("Remainder found", "LaTeX ins", it);
            }
        }
    }
}