svnserver.repository.git.prop.GitAttributes.java Source code

Java tutorial

Introduction

Here is the source code for svnserver.repository.git.prop.GitAttributes.java

Source

/**
 * This file is part of git-as-svn. It is subject to the license terms
 * in the LICENSE file found in the top-level directory of this distribution
 * and at http://www.gnu.org/licenses/gpl-2.0.html. No part of git-as-svn,
 * including this file, may be copied, modified, propagated, or distributed
 * except according to the terms contained in the LICENSE file.
 */
package svnserver.repository.git.prop;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOCase;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.tmatesoft.svn.core.SVNProperty;
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;

import java.io.IOException;
import java.util.*;

/**
 * Parse and processing .gitattributes.
 *
 * @author Artem V. Navrotskiy <bozaro@users.noreply.github.com>
 */
final class GitAttributes implements GitProperty {
    @SuppressWarnings("UnusedDeclaration")
    public static final class Factory implements GitPropertyFactory {
        @NotNull
        @Override
        public String getFileName() {
            return ".gitattributes";
        }

        @NotNull
        @Override
        public GitProperty create(@NotNull String content) throws IOException {
            return new GitAttributes(content);
        }
    }

    @NotNull
    private static final String EOL_PREFIX = "eol=";
    @NotNull
    private static final Rule[] emptyRules = {};
    @NotNull
    private final GitRuleDir eolDir;

    private static final class Rule {
        @NotNull
        private final String mask;
        @NotNull
        private final String prop;
        @NotNull
        private final String value;

        protected Rule(@NotNull String mask, @NotNull String prop, @NotNull String value) {
            this.mask = mask;
            this.prop = prop;
            this.value = value;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (o == null || getClass() != o.getClass())
                return false;

            final Rule rule = (Rule) o;
            return mask.equals(rule.mask) && prop.equals(rule.prop) && value.equals(rule.value);
        }

        @Override
        public int hashCode() {
            int result = mask.hashCode();
            result = 31 * result + prop.hashCode();
            result = 31 * result + value.hashCode();
            return result;
        }
    }

    /**
     * Parse and store .gitattribues data.
     *
     * @param content Original file content.
     */
    public GitAttributes(@NotNull String content) {
        this.eolDir = new GitRuleDir(parseRules(content));
    }

    @NotNull
    private Rule[] parseRules(@NotNull String content) {
        final List<Rule> parsedRules = new ArrayList<>();
        for (String line : content.split("(?:#[^\n]*)?\n")) {
            final String[] tokens = line.trim().split("\\s+");
            final String mimeType = getMimeType(tokens);
            if (mimeType != null) {
                parsedRules.add(new Rule(tokens[0], SVNProperty.MIME_TYPE, mimeType));
            }
            final String eol = getEol(tokens);
            if (eol != null) {
                parsedRules.add(new Rule(tokens[0], SVNProperty.EOL_STYLE, eol));
            }
        }
        if (parsedRules.isEmpty())
            return emptyRules;
        return parsedRules.toArray(new Rule[parsedRules.size()]);
    }

    @Nullable
    private String getMimeType(String[] tokens) {
        for (int i = 1; i < tokens.length; ++i) {
            String token = tokens[i];
            if (token.startsWith("binary")) {
                return SVNFileUtil.BINARY_MIME_TYPE;
            }
        }
        return null;
    }

    @Nullable
    private String getEol(String[] tokens) {
        for (int i = 1; i < tokens.length; ++i) {
            final String token = tokens[i];
            if (token.startsWith(EOL_PREFIX)) {
                switch (token.substring(EOL_PREFIX.length())) {
                case "lf":
                    return SVNProperty.EOL_STYLE_LF;
                case "native":
                    return SVNProperty.EOL_STYLE_NATIVE;
                case "cr":
                    return SVNProperty.EOL_STYLE_CR;
                case "crlf":
                    return SVNProperty.EOL_STYLE_CRLF;
                }
            }
        }
        return null;
    }

    @Override
    public void apply(@NotNull Map<String, String> props) {
        if (eolDir.rules.length > 0) {
            final Map<String, String> autoprops = new LinkedHashMap<>();
            for (Rule rule : eolDir.rules) {
                autoprops.compute(rule.mask,
                        (key, value) -> (value == null ? "" : value + "; ") + rule.prop + "=" + rule.value);
            }
            final StringBuilder sb = new StringBuilder();
            for (Map.Entry<String, String> entry : autoprops.entrySet()) {
                sb.append(entry.getKey()).append(" = ").append(entry.getValue()).append('\n');
            }
            props.put(SVNProperty.INHERITABLE_AUTO_PROPS, sb.toString());
        }
    }

    @Nullable
    @Override
    public GitProperty createForChild(@NotNull String name, @NotNull FileMode fileMode) {
        return eolDir.createForChild(name, fileMode);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;

        GitAttributes that = (GitAttributes) o;
        return eolDir.equals(that.eolDir);
    }

    @Override
    public int hashCode() {
        return eolDir.hashCode();
    }

    private static final class GitRuleDir implements GitProperty {
        @NotNull
        private final Rule[] rules;

        public GitRuleDir(@NotNull Rule[] rules) {
            this.rules = rules;
        }

        @Override
        public void apply(@NotNull Map<String, String> props) {
        }

        @Nullable
        @Override
        public GitProperty createForChild(@NotNull String name, @NotNull FileMode mode) {
            if (mode.getObjectType() == Constants.OBJ_BLOB) {
                for (Rule rule : rules) {
                    if (FilenameUtils.wildcardMatch(name, rule.mask, IOCase.SENSITIVE)) {
                        return new GitRuleFile(rule);
                    }
                }
                return null;
            } else {
                return this;
            }
        }

        @Override
        public boolean equals(@Nullable Object o) {
            if (this == o)
                return true;
            if (o == null || getClass() != o.getClass())
                return false;

            GitRuleDir that = (GitRuleDir) o;
            return Arrays.equals(rules, that.rules);
        }

        @Override
        public int hashCode() {
            return Arrays.hashCode(rules);
        }
    }

    private static final class GitRuleFile implements GitProperty {
        @NotNull
        private final Rule rule;

        private GitRuleFile(@NotNull Rule rule) {
            this.rule = rule;
        }

        @Override
        public void apply(@NotNull Map<String, String> props) {
            props.put(rule.prop, rule.value);
        }

        @Nullable
        @Override
        public GitProperty createForChild(@NotNull String name, @NotNull FileMode fileMode) {
            return null;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (o == null || getClass() != o.getClass())
                return false;

            final GitRuleFile that = (GitRuleFile) o;
            return rule.equals(that.rule);
        }

        @Override
        public int hashCode() {
            return rule.hashCode();
        }
    }
}