/*
 * 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.cxx;

import com.facebook.buck.event.ConsoleEvent;
import com.facebook.buck.io.ProjectFilesystem;
import com.facebook.buck.step.ExecutionContext;
import com.facebook.buck.step.Step;
import com.facebook.buck.step.StepExecutionResult;
import com.facebook.buck.util.CommandSplitter;
import com.facebook.buck.util.ProcessExecutor;
import com.facebook.buck.util.ProcessExecutorParams;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;

import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;

/**
 * Create an object archive with ar.
 */
public class ArchiveStep implements Step {

  private final ProjectFilesystem filesystem;
  private final ImmutableMap<String, String> environment;
  private final ImmutableList<String> archiverCommand;
  private final ImmutableList<String> archiverFlags;
  private final ImmutableList<String> archiverExtraFlags;
  private final Path output;
  private final ImmutableList<Path> inputs;
  private final Archiver archiver;

  public ArchiveStep(
      ProjectFilesystem filesystem,
      ImmutableMap<String, String> environment,
      ImmutableList<String> archiverCommand,
      ImmutableList<String> archiverFlags,
      ImmutableList<String> archiverExtraFlags,
      Path output,
      ImmutableList<Path> inputs,
      Archiver archiver) {
    Preconditions.checkArgument(!output.isAbsolute());
    // Our current support for thin archives requires that all the inputs are relative paths from
    // the same cell as the output.
    for (Path input : inputs) {
      Preconditions.checkArgument(!input.isAbsolute());
    }
    this.filesystem = filesystem;
    this.environment = environment;
    this.archiverCommand = archiverCommand;
    this.archiverFlags = archiverFlags;
    this.archiverExtraFlags = archiverExtraFlags;
    this.output = output;
    this.inputs = inputs;
    this.archiver = archiver;
  }

  private ImmutableList<String> getAllInputs() throws IOException {
    ImmutableList.Builder<String> allInputs = ImmutableList.builder();

    // Inputs can either be files or directories.  In the case of the latter, we add all files
    // found from a recursive search.
    for (Path input : inputs) {
      if (filesystem.isDirectory(input)) {
        // We make sure to sort the files we find under the directories so that we get
        // deterministic output.
        final Set<String> dirFiles = new TreeSet<>();
        filesystem.walkFileTree(
            filesystem.resolve(input),
            new SimpleFileVisitor<Path>() {
              @Override
              public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                dirFiles.add(file.toString());
                return FileVisitResult.CONTINUE;
              }
            });
        allInputs.addAll(dirFiles);
      } else {
        allInputs.add(input.toString());
      }
    }

    return allInputs.build();
  }

  private ProcessExecutor.Result runArchiver(
      ExecutionContext context,
      final ImmutableList<String> command)
      throws IOException, InterruptedException {
    Map<String, String> env = new HashMap<>(System.getenv());
    env.putAll(environment);
    ProcessExecutorParams params = ProcessExecutorParams.builder()
        .setDirectory(filesystem.getRootPath())
        .setEnvironment(env)
        .setCommand(command)
        .build();
    ProcessExecutor.Result result = context.getProcessExecutor().launchAndExecute(params);
    if (result.getExitCode() != 0 && result.getStderr().isPresent()) {
      context.getBuckEventBus().post(ConsoleEvent.create(Level.SEVERE, result.getStderr().get()));
    }
    return result;
  }

  @Override
  public StepExecutionResult execute(ExecutionContext context)
      throws IOException, InterruptedException {
    ImmutableList<String> allInputs = getAllInputs();
    if (allInputs.isEmpty()) {
      filesystem.writeContentsToPath("!<arch>\n", output);
      return StepExecutionResult.SUCCESS;
    } else {
      ImmutableList<String> archiveCommandPrefix =
          ImmutableList.<String>builder()
              .addAll(archiverCommand)
              .addAll(archiverFlags)
              .addAll(archiverExtraFlags)
              .addAll(archiver.outputArgs(output.toString()))
              .build();
      CommandSplitter commandSplitter = new CommandSplitter(archiveCommandPrefix);
      for (ImmutableList<String> command : commandSplitter.getCommandsForArguments(allInputs)) {
        ProcessExecutor.Result result = runArchiver(context, command);
        if (result.getExitCode() != 0) {
          return StepExecutionResult.of(result);
        }
      }
      return StepExecutionResult.SUCCESS;
    }
  }

  @Override
  public String getDescription(ExecutionContext context) {
    ImmutableList.Builder<String> command = ImmutableList.<String>builder()
        .add("ar")
        .addAll(archiverFlags)
        .addAll(archiverExtraFlags)
        .addAll(archiver.outputArgs(output.toString()))
        .addAll(Iterables.transform(inputs, Object::toString));
    return Joiner.on(' ').join(command.build());
  }

  @Override
  public String getShortName() {
    return "archive";
  }

}

@@ -4144,21 +4144,30 @@
 p%3C%3E(
-System.getenv
+context.getEnvironment
 ());

Use ExecutionContext.getEnvironment instead fo System.getEnv