Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add subcmd add #914

Merged
merged 2 commits into from
Feb 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/Cli.cc
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,12 @@ Subcmd::noSuchArg(StringRef arg) const {
return EXIT_FAILURE;
}

[[nodiscard]] int
Subcmd::missingArgumentForOpt(const StringRef arg) {
logger::error("Missing argument for `", arg, "`");
return EXIT_FAILURE;
}

usize
Subcmd::calcMaxShortSize() const noexcept {
usize maxShortSize = 0;
Expand Down
1 change: 1 addition & 0 deletions src/Cli.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ class Subcmd : public CliBase<Subcmd>, public ShortAndHidden<Subcmd> {
Subcmd& addOpt(Opt opt) noexcept;
Subcmd& setMainFn(Fn<int(std::span<const StringRef>)> mainFn) noexcept;
[[nodiscard]] int noSuchArg(StringRef arg) const;
[[nodiscard]] static int missingArgumentForOpt(StringRef arg);

private:
constexpr bool hasShort() const noexcept {
Expand Down
1 change: 1 addition & 0 deletions src/Cmd.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "Cmd/Add.hpp"
#include "Cmd/Build.hpp"
#include "Cmd/Clean.hpp"
#include "Cmd/Fmt.hpp"
Expand Down
205 changes: 205 additions & 0 deletions src/Cmd/Add.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
#include "Add.hpp"

#include "../Logger.hpp"
#include "../Manifest.hpp"
#include "../Rustify.hpp"
#include "Common.hpp"

#include <cstdlib>
#include <fstream>
#include <toml.hpp>

static int addMain(std::span<const StringRef> args);

const Subcmd ADD_CMD =
Subcmd{ "add" }
.setDesc("Add dependencies to poac.toml")
.setArg(Arg{ "args" }
.setDesc("Dependencies to add")
.setRequired(true)
.setVariadic(true))
.addOpt(Opt{ "--sys" }.setDesc("Use system dependency"))
.addOpt(Opt{ "--version" }.setDesc(
"Dependency version (Only used with system-dependencies)"
))
.addOpt(
Opt{ "--tag" }.setDesc("Specify a git tag").setPlaceholder("<TAG>")
)
.addOpt(Opt{ "--rev" }
.setDesc("Specify a git revision")
.setPlaceholder("<REVISION>"))
.addOpt(Opt{ "--branch" }
.setDesc("Specify a branch of the git repository")
.setPlaceholder("<BRANCH_NAME>"))
.setMainFn(addMain);

static Option<int>
handleNextArg(
std::span<const StringRef>::iterator& itr,
const std::span<const StringRef>::iterator& end, String& arg
) {
++itr;
if (itr == end) {
return Subcmd::missingArgumentForOpt(*--itr);
}
arg = String(*itr);
return None;
}

static void
handleDependency(HashSet<StringRef>& newDeps, const StringRef dep) {
if (!newDeps.contains(dep)) {
logger::warn("The dependency `", dep, "` is already in the poac.toml");
return;
}
newDeps.insert(dep);
}

static String
getDependencyGitUrl(const StringRef dep) {
if (dep.find("://") == String::npos) {
// check if atleast in "user/repo" format
if (dep.find('/') == String::npos) {
logger::error("Invalid dependency: " + String(dep));
return "";
}

return "https://github.com/" + String(dep) + ".git";
}
return String(dep);
}

static String
getDependencyName(const StringRef dep) {
String name;
if (dep.find("://") == String::npos) {
name = dep.substr(dep.find_last_of('/') + 1);
} else {
name = dep.substr(
dep.find_last_of('/') + 1, dep.find(".git") - dep.find_last_of('/') - 1
);
}

// Remove trailing '.git' if it exists
if (name.ends_with(".git")) {
name = name.substr(0, name.size() - 4);
}

return name;
}

static int
addDependencyToManifest(
const HashSet<StringRef>& newDeps, bool isSystemDependency, String& version,
String& tag, String& rev, String& branch
) {
toml::value depData = toml::table{};

if (isSystemDependency) {
if (version.empty()) {
logger::error("The `--version` option is required for system dependencies"
);
return EXIT_FAILURE;
}
depData["version"] = version;
depData["system"] = true;
} else {
if (!tag.empty()) {
depData["tag"] = tag;
}
if (!rev.empty()) {
depData["rev"] = rev;
}
if (!branch.empty()) {
depData["branch"] = branch;
}
}

auto data = toml::parse(getManifestPath());
auto& deps = toml::find<toml::table>(data, "dependencies");

for (const auto& dep : newDeps) {

if (!isSystemDependency) {
const String gitUrl = getDependencyGitUrl(dep);
const String depName = getDependencyName(dep);

if (gitUrl.empty() || depName.empty()) {
return EXIT_FAILURE;
}

deps[depName] = depData;
deps[depName]["git"] = gitUrl;
} else {
deps[String(dep)] = depData;
}
}

std::ofstream ofs(getManifestPath());
ofs << toml::format(data);

logger::info("Added", "to the poac.toml");

return EXIT_SUCCESS;
}

static int
addMain(const std::span<const StringRef> args) {
if (args.empty()) {
logger::error("No dependencies to add");
return EXIT_FAILURE;
}

HashSet<StringRef> newDeps = {};

bool isSystemDependency = false;
String version; // Only used with system-dependencies

String tag;
String rev;
String branch;

HashMap<
StringRef,
Fn<Option<int>(decltype(args)::iterator&, decltype(args)::iterator)>>
handlers = {
{ "--sys",
[&](auto&, auto) {
isSystemDependency = true;
return None;
} },
{ "--version", [&](auto& itr, const auto end
) { return handleNextArg(itr, end, version); } },
{ "-v", [&](auto& itr, const auto end
) { return handleNextArg(itr, end, version); } },
{ "--tag", [&](auto& itr, const auto end
) { return handleNextArg(itr, end, tag); } },
{ "--rev", [&](auto& itr, const auto end
) { return handleNextArg(itr, end, rev); } },
{ "--branch", [&](auto& itr, const auto end
) { return handleNextArg(itr, end, branch); } },
};

for (auto itr = args.begin(); itr != args.end(); ++itr) {
if (const auto res = Cli::handleGlobalOpts(itr, args.end(), "add")) {
if (res.value() == Cli::CONTINUE) {
continue;
} else {
return res.value();
}
} else {
auto handler = handlers.find(*itr);
if (handler != handlers.end()) {
if (auto res = handler->second(itr, args.end()); res.has_value()) {
return res.value();
}
} else {
handleDependency(newDeps, *itr);
}
}
}

return addDependencyToManifest(
newDeps, isSystemDependency, version, tag, rev, branch
);
}
5 changes: 5 additions & 0 deletions src/Cmd/Add.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma once

#include "../Cli.hpp"

extern const Subcmd ADD_CMD;
3 changes: 1 addition & 2 deletions src/Cmd/Build.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ buildMain(const std::span<const StringRef> args) {
buildCompdb = true;
} else if (*itr == "-j" || *itr == "--jobs") {
if (itr + 1 == args.end()) {
logger::error("Missing argument for ", *itr);
return EXIT_FAILURE;
return Subcmd::missingArgumentForOpt(*itr);
}
setParallelism(std::stoul((++itr)->data()));
} else {
Expand Down
3 changes: 1 addition & 2 deletions src/Cmd/Clean.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ cleanMain(const std::span<const StringRef> args) noexcept {
}
} else if (*itr == "-p" || *itr == "--profile") {
if (itr + 1 == args.end()) {
logger::error("Missing argument for ", *itr);
return EXIT_FAILURE;
return Subcmd::missingArgumentForOpt(*itr);
}

++itr;
Expand Down
3 changes: 1 addition & 2 deletions src/Cmd/Lint.cc
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,7 @@ lintMain(const std::span<const StringRef> args) {
}
} else if (*itr == "--exclude") {
if (itr + 1 == args.end()) {
logger::error("Missing argument for ", *itr);
return EXIT_FAILURE;
return Subcmd::missingArgumentForOpt(*itr);
}

lintArgs.excludes += " --exclude=";
Expand Down
3 changes: 1 addition & 2 deletions src/Cmd/Run.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ runMain(const std::span<const StringRef> args) {
isDebug = false;
} else if (*itr == "-j" || *itr == "--jobs") {
if (itr + 1 == args.end()) {
logger::error("Missing argument for ", *itr);
return EXIT_FAILURE;
return Subcmd::missingArgumentForOpt(*itr);
}
setParallelism(std::stoul((++itr)->data()));
} else {
Expand Down
3 changes: 1 addition & 2 deletions src/Cmd/Test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ testMain(const std::span<const StringRef> args) {
isDebug = false;
} else if (*itr == "-j" || *itr == "--jobs") {
if (itr + 1 == args.end()) {
logger::error("Missing argument for ", *itr);
return EXIT_FAILURE;
return Subcmd::missingArgumentForOpt(*itr);
}
setParallelism(std::stoul((++itr)->data()));
} else {
Expand Down
3 changes: 1 addition & 2 deletions src/Cmd/Tidy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ tidyMain(const std::span<const StringRef> args) {
fix = true;
} else if (*itr == "-j" || *itr == "--jobs") {
if (itr + 1 == args.end()) {
logger::error("Missing argument for ", *itr);
return EXIT_FAILURE;
return Subcmd::missingArgumentForOpt(*itr);
}
setParallelism(std::stoul((++itr)->data()));
} else {
Expand Down
1 change: 1 addition & 0 deletions src/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ getCli() noexcept {
.setDesc("List all subcommands")
.setGlobal(false)
.setHidden(true))
.addSubcmd(ADD_CMD)
.addSubcmd(BUILD_CMD)
.addSubcmd(CLEAN_CMD)
.addSubcmd(FMT_CMD)
Expand Down