//===- Reproducer.cpp -----------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "Reproducer.h"
#include "llvm/Support/Path.h"

using namespace llvm;
using namespace llvm::dsymutil;

static std::string createReproducerDir(std::error_code &EC) {
  SmallString<128> Root;
  if (const char *Path = getenv("DSYMUTIL_REPRODUCER_PATH")) {
    Root.assign(Path);
    EC = sys::fs::create_directory(Root);
  } else {
    EC = sys::fs::createUniqueDirectory("dsymutil", Root);
  }
  return EC ? "" : std::string(Root);
}

Reproducer::Reproducer() : VFS(vfs::getRealFileSystem()) {}
Reproducer::~Reproducer() = default;

ReproducerGenerate::ReproducerGenerate(std::error_code &EC)
    : Root(createReproducerDir(EC)) {
  if (!Root.empty())
    FC = std::make_shared<FileCollector>(Root, Root);
  VFS = FileCollector::createCollectorVFS(vfs::getRealFileSystem(), FC);
}

ReproducerGenerate::~ReproducerGenerate() {
  if (!FC)
    return;
  FC->copyFiles(false);
  SmallString<128> Mapping(Root);
  sys::path::append(Mapping, "mapping.yaml");
  FC->writeMapping(Mapping.str());
  outs() << "reproducer written to " << Root << '\n';
}

ReproducerUse::~ReproducerUse() = default;

ReproducerUse::ReproducerUse(StringRef Root, std::error_code &EC) {
  SmallString<128> Mapping(Root);
  sys::path::append(Mapping, "mapping.yaml");
  ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
      vfs::getRealFileSystem()->getBufferForFile(Mapping.str());

  if (!Buffer) {
    EC = Buffer.getError();
    return;
  }

  VFS = llvm::vfs::getVFSFromYAML(std::move(Buffer.get()), nullptr, Mapping);
}

llvm::Expected<std::unique_ptr<Reproducer>>
Reproducer::createReproducer(ReproducerMode Mode, StringRef Root) {
  switch (Mode) {
  case ReproducerMode::Generate: {
    std::error_code EC;
    std::unique_ptr<Reproducer> Repro =
        std::make_unique<ReproducerGenerate>(EC);
    if (EC)
      return errorCodeToError(EC);
    return std::move(Repro);
  }
  case ReproducerMode::Use: {
    std::error_code EC;
    std::unique_ptr<Reproducer> Repro =
        std::make_unique<ReproducerUse>(Root, EC);
    if (EC)
      return errorCodeToError(EC);
    return std::move(Repro);
  }
  case ReproducerMode::Off:
    return std::make_unique<Reproducer>();
  }
  llvm_unreachable("All cases handled above.");
}
