// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "tools/gn/json_project_writer.h"

#include <iostream>

#include "base/command_line.h"
#include "base/json/json_writer.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "tools/gn/builder.h"
#include "tools/gn/commands.h"
#include "tools/gn/deps_iterator.h"
#include "tools/gn/desc_builder.h"
#include "tools/gn/exec_process.h"
#include "tools/gn/filesystem_utils.h"
#include "tools/gn/settings.h"

// Structure of JSON output file
// {
//   "build_settings" = {
//     "root_path" : "absolute path of project root",
//     "build_dir" : "build directory (project relative)",
//     "default_toolchain" : "name of default toolchain"
//   }
//   "targets" = {
//      "target x name" : { target x properties },
//      "target y name" : { target y properties },
//      ...
//    }
// }
// See desc_builder.cc for overview of target properties

namespace {

void AddTargetDependencies(const Target* target,
                           std::set<const Target*>* deps) {
  for (const auto& pair : target->GetDeps(Target::DEPS_LINKED)) {
    if (deps->find(pair.ptr) == deps->end()) {
      deps->insert(pair.ptr);
      AddTargetDependencies(pair.ptr, deps);
    }
  }
}

// Filters targets according to filter string; Will also recursively
// add dependent targets.
bool FilterTargets(const BuildSettings* build_settings,
                   std::vector<const Target*>& all_targets,
                   std::vector<const Target*>* targets,
                   const std::string& dir_filter_string,
                   Err* err) {
  if (dir_filter_string.empty()) {
    *targets = all_targets;
  } else {
    targets->reserve(all_targets.size());
    std::vector<LabelPattern> filters;
    if (!commands::FilterPatternsFromString(build_settings, dir_filter_string,
                                            &filters, err)) {
      return false;
    }
    commands::FilterTargetsByPatterns(all_targets, filters, targets);

    std::set<const Target*> target_set(targets->begin(), targets->end());
    for (const auto* target : *targets)
      AddTargetDependencies(target, &target_set);

    targets->clear();
    targets->insert(targets->end(), target_set.begin(), target_set.end());
  }

  // Sort the list of targets per-label to get a consistent ordering of them
  // in the generated project (and thus stability of the file generated).
  std::sort(targets->begin(), targets->end(),
            [](const Target* a, const Target* b) {
              return a->label().name() < b->label().name();
            });

  return true;
}

std::string RenderJSON(const BuildSettings* build_settings,
                       const Builder& builder,
                       std::vector<const Target*>& all_targets) {
  Label default_toolchain_label;

  auto targets = base::MakeUnique<base::DictionaryValue>();
  for (const auto* target : all_targets) {
    if (default_toolchain_label.is_null())
      default_toolchain_label = target->settings()->default_toolchain_label();
    auto description =
        DescBuilder::DescriptionForTarget(target, "", false, false, false);
    // Outputs need to be asked for separately.
    auto outputs = DescBuilder::DescriptionForTarget(target, "source_outputs",
                                                     false, false, false);
    base::DictionaryValue* outputs_value = nullptr;
    if (outputs->GetDictionary("source_outputs", &outputs_value) &&
        !outputs_value->empty()) {
      description->MergeDictionary(outputs.get());
    }
    targets->SetWithoutPathExpansion(
        target->label().GetUserVisibleName(default_toolchain_label),
        std::move(description));
  }

  auto settings = base::MakeUnique<base::DictionaryValue>();
  settings->SetStringWithoutPathExpansion("root_path",
                                          build_settings->root_path_utf8());
  settings->SetStringWithoutPathExpansion("build_dir",
                                          build_settings->build_dir().value());
  settings->SetStringWithoutPathExpansion(
      "default_toolchain",
      default_toolchain_label.GetUserVisibleName(false));

  auto output = base::MakeUnique<base::DictionaryValue>();
  output->SetWithoutPathExpansion("targets", std::move(targets));
  output->SetWithoutPathExpansion("build_settings", std::move(settings));

  std::string s;
  base::JSONWriter::WriteWithOptions(
      *output.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &s);
  return s;
}

bool InvokePython(const BuildSettings* build_settings,
                  const base::FilePath& python_script_path,
                  const std::string& python_script_extra_args,
                  const base::FilePath& output_path,
                  bool quiet,
                  Err* err) {
  const base::FilePath& python_path = build_settings->python_path();
  base::CommandLine cmdline(python_path);
  cmdline.AppendArg("--");
  cmdline.AppendArgPath(python_script_path);
  cmdline.AppendArgPath(output_path);
  if (!python_script_extra_args.empty()) {
    cmdline.AppendArg(python_script_extra_args);
  }
  base::FilePath startup_dir =
      build_settings->GetFullPath(build_settings->build_dir());

  std::string output;
  std::string stderr_output;

  int exit_code = 0;
  if (!internal::ExecProcess(cmdline, startup_dir, &output, &stderr_output,
                             &exit_code)) {
    *err =
        Err(Location(), "Could not execute python.",
            "I was trying to execute \"" + FilePathToUTF8(python_path) + "\".");
    return false;
  }

  if (!quiet) {
    std::cout << output;
    std::cerr << stderr_output;
  }

  if (exit_code != 0) {
    *err = Err(Location(), "Python has quit with exit code " +
                               base::IntToString(exit_code) + ".");
    return false;
  }

  return true;
}

}  // namespace

bool JSONProjectWriter::RunAndWriteFiles(
    const BuildSettings* build_settings,
    const Builder& builder,
    const std::string& file_name,
    const std::string& exec_script,
    const std::string& exec_script_extra_args,
    const std::string& dir_filter_string,
    bool quiet,
    Err* err) {
  SourceFile output_file = build_settings->build_dir().ResolveRelativeFile(
      Value(nullptr, file_name), err);
  if (output_file.is_null()) {
    return false;
  }

  base::FilePath output_path = build_settings->GetFullPath(output_file);

  std::vector<const Target*> all_targets = builder.GetAllResolvedTargets();
  std::vector<const Target*> targets;
  if (!FilterTargets(build_settings, all_targets, &targets, dir_filter_string,
                     err)) {
    return false;
  }

  std::string json = RenderJSON(build_settings, builder, targets);
  if (!ContentsEqual(output_path, json)) {
    if (!WriteFileIfChanged(output_path, json, err)) {
      return false;
    }

    if (!exec_script.empty()) {
      SourceFile script_file;
      if (exec_script[0] != '/') {
        // Relative path, assume the base is in build_dir.
        script_file = build_settings->build_dir().ResolveRelativeFile(
            Value(nullptr, exec_script), err);
        if (script_file.is_null()) {
          return false;
        }
      } else {
        script_file = SourceFile(exec_script);
      }
      base::FilePath script_path = build_settings->GetFullPath(script_file);
      return InvokePython(build_settings, script_path, exec_script_extra_args,
                          output_path, quiet, err);
    }
  }

  return true;
}
