/* * Copyright 2015-present Facebook, Inc. * * Licensed 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 com.facebook.buck.config; import com.facebook.buck.log.Logger; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSortedSet; import java.io.IOException; import java.io.Reader; import java.nio.charset.StandardCharsets; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; /** Utility functions for working with {@link Config}s. */ public final class Configs { private static final Logger LOG = Logger.get(Configs.class); private static final String DEFAULT_BUCK_CONFIG_FILE_NAME = ".buckconfig"; private static final String DEFAULT_BUCK_CONFIG_OVERRIDE_FILE_NAME = ".buckconfig.local"; private static final String DEFAULT_BUCK_CONFIG_DIRECTORY_NAME = ".buckconfig.d"; private static final Path GLOBAL_BUCK_CONFIG_FILE_PATH = Paths.get("/etc/buckconfig"); private static final Path GLOBAL_BUCK_CONFIG_DIRECTORY_PATH = Paths.get("/etc/buckconfig.d"); private Configs() {} /** Convienence constructor */ public static Config createDefaultConfig(Path root) throws IOException { return createDefaultConfig(root, RawConfig.of(ImmutableMap.of())); } /** * Generates a Buck config by merging configs from specified locations on disk. * * <p>In order: * * <ol> * <li>{@code /etc/buckconfig} * <li>Files (in lexicographical order) in {@code /etc/buckconfig.d} * <li>{@code <HOME>/.buckconfig} * <li>Files (in lexicographical order) in {@code <HOME>/buckconfig.d} * <li>{@code <PROJECT ROOT>/.buckconfig} * <li>{@code <PROJECT ROOT>/.buckconfig.local} * <li>Any overrides (usually from the command line) * </ol> * * @param root Project root. * @param configOverrides Config overrides to merge in after the other sources. * @return the resulting {@code Config}. * @throws IOException on any exceptions during the underlying filesystem operations. */ public static Config createDefaultConfig(Path root, RawConfig configOverrides) throws IOException { LOG.debug("Loading configuration for %s", root); ImmutableList.Builder<Path> configFileBuilder = ImmutableList.builder(); configFileBuilder.addAll(listFiles(GLOBAL_BUCK_CONFIG_DIRECTORY_PATH)); if (Files.isRegularFile(GLOBAL_BUCK_CONFIG_FILE_PATH)) { configFileBuilder.add(GLOBAL_BUCK_CONFIG_FILE_PATH); } Path homeDirectory = Paths.get(System.getProperty("user.home")); Path userConfigDir = homeDirectory.resolve(DEFAULT_BUCK_CONFIG_DIRECTORY_NAME); configFileBuilder.addAll(listFiles(userConfigDir)); Path userConfigFile = homeDirectory.resolve(DEFAULT_BUCK_CONFIG_FILE_NAME); if (Files.isRegularFile(userConfigFile)) { configFileBuilder.add(userConfigFile); } Path configFile = root.resolve(DEFAULT_BUCK_CONFIG_FILE_NAME); if (Files.isRegularFile(configFile)) { configFileBuilder.add(configFile); } Path overrideConfigFile = root.resolve(DEFAULT_BUCK_CONFIG_OVERRIDE_FILE_NAME); if (Files.isRegularFile(overrideConfigFile)) { configFileBuilder.add(overrideConfigFile); } ImmutableList<Path> configFiles = configFileBuilder.build(); RawConfig.Builder builder = RawConfig.builder(); for (Path file : configFiles) { try (Reader reader = Files.newBufferedReader(file, StandardCharsets.UTF_8)) { ImmutableMap<String, ImmutableMap<String, String>> parsedConfiguration = Inis.read(reader); LOG.debug("Loaded a configuration file %s: %s", file, parsedConfiguration); builder.putAll(parsedConfiguration); } } LOG.debug("Adding configuration overrides %s", configOverrides); builder.putAll(configOverrides); return new Config(builder.build()); } private static ImmutableSortedSet<Path> listFiles(Path root) throws IOException { if (!Files.isDirectory(root)) { return ImmutableSortedSet.of(); } try (DirectoryStream<Path> directory = Files.newDirectoryStream(root)) { return ImmutableSortedSet.<Path>naturalOrder().addAll(directory.iterator()).build(); } } }