rmannibucau commented on code in PR #746:
URL: https://github.com/apache/creadur-rat/pull/746#discussion_r4381509975


##########
apache-rat-core/src/main/java/org/apache/rat/config/exclusion/fileprocessors/GitConfig.java:
##########
@@ -0,0 +1,462 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.rat.config.exclusion.fileprocessors;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+import java.util.Set;
+
+import org.apache.rat.api.EnvVar;
+
+/**
+ * Reads the global git configuration files to resolve the file configured
+ * for {@code core.excludesFile}.
+ * <p>
+ * The configuration files are read in git order: {@code 
$XDG_CONFIG_HOME/git/config}
+ * first and {@code ~/.gitconfig} second. The last value found for
+ * {@code core.excludesFile} wins.
+ * </p>
+ * <p>
+ * {@code [include] path} directives are supported and the included files are 
expanded
+ * in place, recursively. The relative paths of included files are resolved 
against the
+ * directory of the including file, {@code ~/} is expanded to the home 
directory and a
+ * depth limit of {@value #MAX_INCLUDE_DEPTH} is enforced like git does.
+ * </p>
+ * <p>
+ * {@code includeIf} directives, the system configuration ({@code 
/etc/gitconfig}), the
+ * {@code GIT_CONFIG_SYSTEM} variable and the repository configuration ({@code 
.git/config}) are
+ * not supported. The {@code GIT_CONFIG_GLOBAL} variable, when set, replaces 
the
+ * {@code $HOME/.gitconfig} and {@code $XDG_CONFIG_HOME/git/config} files.
+ * </p>
+ * <p>
+ * The home directory used for {@code ~} expansion is resolved from {@code 
HOME}, falling back to
+ * {@link org.apache.rat.api.EnvVar#USER_PROFILE} (Windows, backed by the 
{@code USERPROFILE}
+ * environment variable) and then the {@code user.home} system property.
+ * </p>
+ * <p>
+ * When {@code core.excludesFile} is not configured the default location next 
to the XDG
+ * configuration ({@code $XDG_CONFIG_HOME/git/ignore} or {@code 
$HOME/.config/git/ignore})
+ * is used.
+ * </p>
+ */
+public class GitConfig {
+    /** The name of the 'core' section. */
+    private static final String CORE_SECTION = "core";
+    /** The name of the 'include' section. */
+    private static final String INCLUDE_SECTION = "include";
+    /** The key of the core section holding the global ignore file. */
+    private static final String EXCLUDES_FILE_KEY = "excludesfile";
+    /** The key of the include section holding the file to include. */
+    private static final String INCLUDE_PATH_KEY = "path";
+    /** The maximum depth of nested includes, matching the git limit. */
+    private static final int MAX_INCLUDE_DEPTH = 10;
+    /** The home directory prefix of a path. */
+    private static final String HOME_PREFIX = "~/";
+    /** The Windows style home directory prefix of a path. */
+    private static final String HOME_BACKSLASH_PREFIX = "~\\";
+    /** The comment marker for a full line comment. */
+    private static final String COMMENT_PREFIX = "#";
+    /** The alternate comment marker for a full line comment. */
+    private static final String SEMICOLON_COMMENT_PREFIX = ";";
+    /** The opening quote of a quoted value. */
+    private static final String QUOTE = "\"";
+    /** The escape character of a quoted value. */
+    private static final String ESCAPE = "\\";
+
+    /** The XDG configuration file. */
+    private final File xdgConfig;
+    /** The user configuration file. */
+    private final File userConfig;
+    /** The home directory or {@code null} when not defined. */
+    private final String home;
+    /** The directory against which relative paths are resolved. */
+    private final File cwd;
+    /** The default global ignore file, next to the XDG configuration or 
{@code null}. */
+    private final File defaultIgnore;
+    /** The file configured by the {@code GIT_CONFIG_GLOBAL} environment 
variable or {@code null}. */
+    private final File globalConfig;
+
+    /**
+     * Creates a GitConfig reading the configuration files from the 
environment.
+     */
+    public GitConfig() {
+        this(gitConfigGlobalFile(), xdgConfigFile(), userConfigFile(), 
homeDir(),
+                new File(System.getProperty("user.dir")));
+    }
+
+    /**
+     * Creates a GitConfig reading the given configuration files.
+     * @param xdgConfig the XDG configuration file or {@code null} if there is 
none.
+     * @param userConfig the user configuration file or {@code null} if there 
is none.
+     * @param home the home directory used for {@code ~/} expansion.
+     */
+    GitConfig(final File xdgConfig, final File userConfig, final String home) {
+        this(null, xdgConfig, userConfig, home, new 
File(System.getProperty("user.dir")));
+    }
+
+    /**
+     * Creates a GitConfig reading the given configuration files.
+     * @param xdgConfig the XDG configuration file or {@code null} if there is 
none.
+     * @param userConfig the user configuration file or {@code null} if there 
is none.
+     * @param home the home directory used for {@code ~/} expansion.
+     * @param cwd the directory against which relative paths are resolved.
+     */
+    GitConfig(final File xdgConfig, final File userConfig, final String home, 
final File cwd) {
+        this(null, xdgConfig, userConfig, home, cwd);
+    }
+
+    /**
+     * Creates a GitConfig reading the given configuration files.
+     * @param globalConfig the effective global config file (from {@code 
GIT_CONFIG_GLOBAL})
+     *        or {@code null} to use the XDG and user configuration files.
+     * @param xdgConfig the XDG configuration file or {@code null} if there is 
none.
+     * @param userConfig the user configuration file or {@code null} if there 
is none.
+     * @param home the home directory used for {@code ~} expansion.
+     * @param cwd the directory against which relative paths are resolved.
+     */
+    GitConfig(final File globalConfig, final File xdgConfig, final File 
userConfig, final String home, final File cwd) {
+        this.globalConfig = globalConfig;
+        this.xdgConfig = xdgConfig;
+        this.userConfig = userConfig;
+        this.home = home;
+        this.cwd = cwd;
+        File parent = xdgConfig == null ? null : 
xdgConfig.getAbsoluteFile().getParentFile();
+        this.defaultIgnore = parent == null ? null : new File(parent, 
"ignore");
+    }
+
+    /**
+     * Resolves the global git ignore file.
+     * <p>
+     * If {@code core.excludesFile} is configured in one of the git 
configuration files the configured
+     * file is returned - even if it does not exist, matching git behavior 
where a configured file
+     * disables the default location. Otherwise the default location is 
returned if it exists.
+     * </p>
+     * @return the configured or default global git ignore file or an empty 
Optional if neither exists.
+     */
+    public Optional<File> coreExcludesFile() {
+        List<String> configured = new ArrayList<>();
+        Set<File> includeChain = new HashSet<>();
+        if (globalConfig != null) {
+            // when GIT_CONFIG_GLOBAL is set, neither ~/.gitconfig nor 
$XDG_CONFIG_HOME/git/config are read
+            parseFile(globalConfig, configured, includeChain, 0);
+        } else {
+            parseFile(xdgConfig, configured, includeChain, 0);
+            parseFile(userConfig, configured, includeChain, 0);
+        }
+        if (!configured.isEmpty()) {
+            String value = configured.get(configured.size() - 1);
+            return resolveExcludesFile(value);
+        }
+        return defaultIgnore != null && defaultIgnore.isFile() ? 
Optional.of(defaultIgnore) : Optional.empty();
+    }
+
+    /**
+     * Parses a configuration file, expanding {@code [include] path} 
directives in place.
+     * @param file the file to parse or {@code null} if there is none.
+     * @param excludesFileValues the collected raw {@code core.excludesFile} 
values in order.
+     * @param includeChain the canonical files of the current include chain to 
detect cycles.
+     * @param depth the current include depth.
+     */
+    private void parseFile(final File file, final List<String> 
excludesFileValues, final Set<File> includeChain, final int depth) {

Review Comment:
   FTR git config files are not init files (subsections for ex are diff)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to