about summary refs log tree commit diff
path: root/third_party/nix/src/nix/command.cc
#include "nix/command.hh"

#include <utility>

#include "libstore/derivations.hh"
#include "libstore/store-api.hh"

namespace nix {

Commands* RegisterCommand::commands = nullptr;

void Command::printHelp(const std::string& programName, std::ostream& out) {
  Args::printHelp(programName, out);

  auto exs = examples();
  if (!exs.empty()) {
    out << "\n";
    out << "Examples:\n";
    for (auto& ex : exs) {
      out << "\n"
          << "  " << ex.description << "\n"  // FIXME: wrap
          << "  $ " << ex.command << "\n";
    }
  }
}

MultiCommand::MultiCommand(Commands _commands)
    : commands(std::move(_commands)) {
  expectedArgs.push_back(ExpectedArg{
      "command", 1, true, [=](std::vector<std::string> ss) {
        assert(!command);
        auto i = commands.find(ss[0]);
        if (i == commands.end()) {
          throw UsageError("'%s' is not a recognised command", ss[0]);
        }
        command = i->second;
      }});
}

void MultiCommand::printHelp(const std::string& programName,
                             std::ostream& out) {
  if (command) {
    command->printHelp(programName + " " + command->name(), out);
    return;
  }

  out << "Usage: " << programName << " <COMMAND> <FLAGS>... <ARGS>...\n";

  out << "\n";
  out << "Common flags:\n";
  printFlags(out);

  out << "\n";
  out << "Available commands:\n";

  Table2 table;
  for (auto& command : commands) {
    auto descr = command.second->description();
    if (!descr.empty()) {
      table.push_back(std::make_pair(command.second->name(), descr));
    }
  }
  printTable(out, table);

#if 0
    out << "\n";
    out << "For full documentation, run 'man " << programName << "' or 'man " << programName << "-<COMMAND>'.\n";
#endif
}

bool MultiCommand::processFlag(Strings::iterator& pos, Strings::iterator end) {
  if (Args::processFlag(pos, end)) {
    return true;
  }
  if (command && command->processFlag(pos, end)) {
    return true;
  }
  return false;
}

bool MultiCommand::processArgs(const Strings& args, bool finish) {
  if (command) {
    return command->processArgs(args, finish);
  }
  return Args::processArgs(args, finish);
}

StoreCommand::StoreCommand() = default;

ref<Store> StoreCommand::getStore() {
  if (!_store) {
    _store = createStore();
  }
  return ref<Store>(_store);
}

ref<Store> StoreCommand::createStore() { return openStore(); }

void StoreCommand::run() { run(getStore()); }

StorePathsCommand::StorePathsCommand(bool recursive) : recursive(recursive) {
  if (recursive) {
    mkFlag()
        .longName("no-recursive")
        .description("apply operation to specified paths only")
        .set(&this->recursive, false);
  } else {
    mkFlag()
        .longName("recursive")
        .shortName('r')
        .description("apply operation to closure of the specified paths")
        .set(&this->recursive, true);
  }

  mkFlag(0, "all", "apply operation to the entire store", &all);
}

void StorePathsCommand::run(ref<Store> store) {
  Paths storePaths;

  if (all) {
    if (!installables.empty() != 0u) {
      throw UsageError("'--all' does not expect arguments");
    }
    for (auto& p : store->queryAllValidPaths()) {
      storePaths.push_back(p);
    }
  }

  else {
    for (auto& p : toStorePaths(store, NoBuild, installables)) {
      storePaths.push_back(p);
    }

    if (recursive) {
      PathSet closure;
      store->computeFSClosure(PathSet(storePaths.begin(), storePaths.end()),
                              closure, false, false);
      storePaths = Paths(closure.begin(), closure.end());
    }
  }

  run(store, storePaths);
}

void StorePathCommand::run(ref<Store> store) {
  auto storePaths = toStorePaths(store, NoBuild, installables);

  if (storePaths.size() != 1) {
    throw UsageError("this command requires exactly one store path");
  }

  run(store, *storePaths.begin());
}

}  // namespace nix