/* * Copyright 2012-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.cli; import com.facebook.buck.event.ConsoleEvent; import com.facebook.buck.util.DirtyPrintStreamDecorator; import com.facebook.buck.util.MoreCollectors; import com.facebook.buck.util.ObjectMappers; import com.facebook.buck.util.immutables.BuckStyleImmutable; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSortedSet; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Stream; import org.immutables.value.Value; import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Option; public class AuditConfigCommand extends AbstractCommand { @Option(name = "--json", usage = "Output in JSON format") private boolean generateJsonOutput; public boolean shouldGenerateJsonOutput() { return generateJsonOutput; } @Option(name = "--tab", usage = "Output in a tab-delmiited format key/value format") private boolean generateTabbedOutput; public boolean shouldGenerateTabbedOutput() { return generateTabbedOutput; } @Argument private List<String> arguments = new ArrayList<>(); public List<String> getArguments() { return arguments; } @BuckStyleImmutable @Value.Immutable abstract static class AbstractConfigValue { @Value.Parameter public abstract String getKey(); @Value.Parameter public abstract String getSection(); @Value.Parameter public abstract String getProperty(); @Value.Parameter public abstract Optional<String> getValue(); } @Override public int runWithoutHelp(final CommandRunnerParams params) throws IOException, InterruptedException { if (shouldGenerateTabbedOutput() && shouldGenerateJsonOutput()) { params .getBuckEventBus() .post(ConsoleEvent.severe("--json and --tab cannot both be specified")); return 1; } final BuckConfig buckConfig = params.getBuckConfig(); final ImmutableSortedSet<ConfigValue> configs = getArguments() .stream() .flatMap( input -> { String[] parts = input.split("\\.", 2); DirtyPrintStreamDecorator stdErr = params.getConsole().getStdErr(); if (parts.length == 1) { Optional<ImmutableMap<String, String>> section = buckConfig.getSection(parts[0]); if (!section.isPresent()) { stdErr.println(String.format("%s is not a valid section string", input)); return Stream.of(ConfigValue.of(input, "", input, Optional.empty())); } return section .get() .entrySet() .stream() .map( entry -> ConfigValue.of( parts[0] + "." + entry.getKey(), parts[0], entry.getKey(), Optional.of(entry.getValue()))); } else if (parts.length != 2) { stdErr.println( String.format("%s is not a valid section/property string", input)); return Stream.of(ConfigValue.of(input, "", input, Optional.empty())); } return Stream.of( ConfigValue.of( input, parts[0], parts[1], buckConfig.getValue(parts[0], parts[1]))); }) .collect( MoreCollectors.toImmutableSortedSet( Comparator.comparing(ConfigValue::getSection) .thenComparing(ConfigValue::getKey))); if (shouldGenerateJsonOutput()) { printJsonOutput(params, configs); } else if (shouldGenerateTabbedOutput()) { printTabbedOutput(params, configs); } else { printBuckconfigOutput(params, configs); } return 0; } private void printTabbedOutput( final CommandRunnerParams params, ImmutableSortedSet<ConfigValue> configs) { for (ConfigValue config : configs) { params .getConsole() .getStdOut() .println(String.format("%s\t%s", config.getKey(), config.getValue().orElse(""))); } } private void printJsonOutput( final CommandRunnerParams params, ImmutableSortedSet<ConfigValue> configs) throws IOException { ImmutableMap.Builder<String, Optional<String>> jsBuilder; jsBuilder = ImmutableMap.builder(); for (ConfigValue config : configs) { jsBuilder.put(config.getKey(), config.getValue()); } ObjectMappers.WRITER.writeValue(params.getConsole().getStdOut(), jsBuilder.build()); } private void printBuckconfigOutput( final CommandRunnerParams params, ImmutableSortedSet<ConfigValue> configs) { ImmutableListMultimap<String, ConfigValue> iniData = FluentIterable.from(configs) .filter(config -> config.getSection() != "" && config.getValue().isPresent()) .index(ConfigValue::getSection); for (Map.Entry<String, Collection<ConfigValue>> entry : iniData.asMap().entrySet()) { params.getConsole().getStdOut().println(String.format("[%s]", entry.getKey())); for (ConfigValue config : entry.getValue()) { params .getConsole() .getStdOut() .println(String.format(" %s = %s", config.getProperty(), config.getValue().get())); } params.getConsole().getStdOut().println(""); } } @Override public boolean isReadOnly() { return true; } @Override public String getShortDescription() { return "provides facilities to audit configuration values"; } }