Skip to content

Commit

Permalink
Dependency: extract dependency download logic from Manifest
Browse files Browse the repository at this point in the history
  • Loading branch information
ken-matsui committed Feb 1, 2025
1 parent 9fc0647 commit 20fd646
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 142 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ $(O)/tests/test_BuildConfig: $(O)/tests/test_BuildConfig.o $(O)/Algos.o \
$(O)/TermColor.o $(O)/Manifest.o $(O)/Parallelism.o $(O)/Semver.o \
$(O)/VersionReq.o $(O)/Git2/Repository.o $(O)/Git2/Object.o $(O)/Git2/Oid.o \
$(O)/Git2/Global.o $(O)/Git2/Config.o $(O)/Git2/Exception.o $(O)/Git2/Time.o \
$(O)/Git2/Commit.o $(O)/Command.o
$(O)/Git2/Commit.o $(O)/Command.o $(O)/Dependency.o
$(CXX) $(CXXFLAGS) $^ $(LIBS) $(LDFLAGS) -o $@

$(O)/tests/test_Algos: $(O)/tests/test_Algos.o $(O)/TermColor.o $(O)/Command.o
Expand All @@ -116,7 +116,7 @@ $(O)/tests/test_VersionReq: $(O)/tests/test_VersionReq.o $(O)/TermColor.o \
$(O)/tests/test_Manifest: $(O)/tests/test_Manifest.o $(O)/TermColor.o \
$(O)/Semver.o $(O)/VersionReq.o $(O)/Algos.o $(O)/Git2/Repository.o \
$(O)/Git2/Global.o $(O)/Git2/Oid.o $(O)/Git2/Config.o $(O)/Git2/Exception.o \
$(O)/Git2/Object.o $(O)/Command.o
$(O)/Git2/Object.o $(O)/Command.o $(O)/Dependency.o
$(CXX) $(CXXFLAGS) $^ $(LIBS) $(LDFLAGS) -o $@

$(O)/tests/test_Cli: $(O)/tests/test_Cli.o $(O)/Algos.o $(O)/TermColor.o \
Expand Down
108 changes: 108 additions & 0 deletions src/Dependency.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#include "Dependency.hpp"

#include "Algos.hpp"
#include "Command.hpp"
#include "Git2.hpp"
#include "Logger.hpp"

#include <cstdlib>
#include <filesystem>
#include <string>

namespace cabin {

namespace fs = std::filesystem;

static fs::path
getXdgCacheHome() noexcept {
if (const char* envP = std::getenv("XDG_CACHE_HOME")) {
return envP;
}
const fs::path userDir = std::getenv("HOME");
return userDir / ".cache";
}

static const fs::path CACHE_DIR(getXdgCacheHome() / "cabin");
static const fs::path GIT_DIR(CACHE_DIR / "git");
static const fs::path GIT_SRC_DIR(GIT_DIR / "src");

Result<DepMetadata>
GitDependency::install() const {
fs::path installDir = GIT_SRC_DIR / name;
if (target.has_value()) {
installDir += '-' + target.value();
}

if (fs::exists(installDir) && !fs::is_empty(installDir)) {
logger::debug("{} is already installed", name);
} else {
git2::Repository repo;
repo.clone(url, installDir.string());

if (target.has_value()) {
// Checkout to target.
const std::string target = this->target.value();
const git2::Object obj = repo.revparseSingle(target);
repo.setHeadDetached(obj.id());
repo.checkoutHead(true);
}

logger::info(
"Downloaded", "{} {}", name, target.has_value() ? target.value() : url
);
}

const fs::path includeDir = installDir / "include";
std::string includes = "-isystem";

if (fs::exists(includeDir) && fs::is_directory(includeDir)
&& !fs::is_empty(includeDir)) {
includes += includeDir.string();
} else {
includes += installDir.string();
}

// Currently, no libs are supported.
return Ok(DepMetadata{ .includes = includes, .libs = "" });
}

Result<DepMetadata>
PathDependency::install() const {
const fs::path installDir = fs::weakly_canonical(path);
if (fs::exists(installDir) && !fs::is_empty(installDir)) {
logger::debug("{} is already installed", name);
} else {
Bail("{} can't be accessible as directory", installDir.string());
}

const fs::path includeDir = installDir / "include";
std::string includes = "-isystem";

if (fs::exists(includeDir) && fs::is_directory(includeDir)
&& !fs::is_empty(includeDir)) {
includes += includeDir.string();
} else {
includes += installDir.string();
}

// Currently, no libs are supported.
return Ok(DepMetadata{ .includes = includes, .libs = "" });
}

Result<DepMetadata>
SystemDependency::install() const {
const std::string pkgConfigVer = versionReq.toPkgConfigString(name);
const Command cflagsCmd =
Command("pkg-config").addArg("--cflags").addArg(pkgConfigVer);
const Command libsCmd =
Command("pkg-config").addArg("--libs").addArg(pkgConfigVer);

std::string cflags = Try(getCmdOutput(cflagsCmd));
cflags.pop_back(); // remove '\n'
std::string libs = Try(getCmdOutput(libsCmd));
libs.pop_back(); // remove '\n'

return Ok(DepMetadata{ .includes = cflags, .libs = libs });
}

} // namespace cabin
54 changes: 54 additions & 0 deletions src/Dependency.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#pragma once

#include "Rustify/Result.hpp"
#include "VersionReq.hpp"

#include <optional>
#include <string>
#include <utility>
#include <variant>

namespace cabin {

struct DepMetadata {
const std::string includes; // -Isomething
const std::string libs; // -Lsomething -lsomething
};

struct GitDependency {
const std::string name;
const std::string url;
const std::optional<std::string> target;

Result<DepMetadata> install() const;

GitDependency(
std::string name, std::string url, std::optional<std::string> target
)
: name(std::move(name)), url(std::move(url)), target(std::move(target)) {}
};

struct PathDependency {
const std::string name;
const std::string path;

Result<DepMetadata> install() const;

PathDependency(std::string name, std::string path)
: name(std::move(name)), path(std::move(path)) {}
};

struct SystemDependency {
const std::string name;
const VersionReq versionReq;

Result<DepMetadata> install() const;

SystemDependency(std::string name, VersionReq versionReq)
: name(std::move(name)), versionReq(std::move(versionReq)) {};
};

using Dependency =
std::variant<GitDependency, PathDependency, SystemDependency>;

} // namespace cabin
97 changes: 1 addition & 96 deletions src/Manifest.cc
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
#include "Manifest.hpp"

#include "Algos.hpp"
#include "Command.hpp"
#include "Git2.hpp"
#include "Logger.hpp"
#include "Rustify/Result.hpp"
#include "Semver.hpp"
Expand All @@ -24,19 +21,6 @@

namespace cabin {

static fs::path
getXdgCacheHome() noexcept {
if (const char* envP = std::getenv("XDG_CACHE_HOME")) {
return envP;
}
const fs::path userDir = std::getenv("HOME");
return userDir / ".cache";
}

static const fs::path CACHE_DIR(getXdgCacheHome() / "cabin");
static const fs::path GIT_DIR(CACHE_DIR / "git");
static const fs::path GIT_SRC_DIR(GIT_DIR / "src");

static const std::unordered_set<char> ALLOWED_CHARS = {
'-', '_', '/', '.', '+' // allowed in the dependency name
};
Expand Down Expand Up @@ -383,85 +367,6 @@ parseDependencies(const toml::value& val, const char* key) noexcept {
return Ok(deps);
}

Result<DepMetadata>
GitDependency::install() const {
fs::path installDir = GIT_SRC_DIR / name;
if (target.has_value()) {
installDir += '-' + target.value();
}

if (fs::exists(installDir) && !fs::is_empty(installDir)) {
logger::debug("{} is already installed", name);
} else {
git2::Repository repo;
repo.clone(url, installDir.string());

if (target.has_value()) {
// Checkout to target.
const std::string target = this->target.value();
const git2::Object obj = repo.revparseSingle(target);
repo.setHeadDetached(obj.id());
repo.checkoutHead(true);
}

logger::info(
"Downloaded", "{} {}", name, target.has_value() ? target.value() : url
);
}

const fs::path includeDir = installDir / "include";
std::string includes = "-isystem";

if (fs::exists(includeDir) && fs::is_directory(includeDir)
&& !fs::is_empty(includeDir)) {
includes += includeDir.string();
} else {
includes += installDir.string();
}

// Currently, no libs are supported.
return Ok(DepMetadata{ .includes = includes, .libs = "" });
}

Result<DepMetadata>
PathDependency::install() const {
const fs::path installDir = fs::weakly_canonical(path);
if (fs::exists(installDir) && !fs::is_empty(installDir)) {
logger::debug("{} is already installed", name);
} else {
Bail("{} can't be accessible as directory", installDir.string());
}

const fs::path includeDir = installDir / "include";
std::string includes = "-isystem";

if (fs::exists(includeDir) && fs::is_directory(includeDir)
&& !fs::is_empty(includeDir)) {
includes += includeDir.string();
} else {
includes += installDir.string();
}

// Currently, no libs are supported.
return Ok(DepMetadata{ .includes = includes, .libs = "" });
}

Result<DepMetadata>
SystemDependency::install() const {
const std::string pkgConfigVer = versionReq.toPkgConfigString(name);
const Command cflagsCmd =
Command("pkg-config").addArg("--cflags").addArg(pkgConfigVer);
const Command libsCmd =
Command("pkg-config").addArg("--libs").addArg(pkgConfigVer);

std::string cflags = Try(getCmdOutput(cflagsCmd));
cflags.pop_back(); // remove '\n'
std::string libs = Try(getCmdOutput(libsCmd));
libs.pop_back(); // remove '\n'

return Ok(DepMetadata{ .includes = cflags, .libs = libs });
}

Result<Manifest>
Manifest::tryParse(fs::path path, const bool findParents) noexcept {
if (findParents) {
Expand Down Expand Up @@ -561,7 +466,7 @@ validatePackageName(const std::string_view name) noexcept {
#ifdef CABIN_TEST

# include "Rustify/Tests.hpp"
# include "TermColor.hpp"
# include "TermColor.hpp"

# include <climits>
# include <fmt/ranges.h>
Expand Down
45 changes: 1 addition & 44 deletions src/Manifest.hpp
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
#pragma once

#include "Dependency.hpp"
#include "Rustify/Result.hpp"
#include "Semver.hpp"
#include "VersionReq.hpp"

#include <cstddef>
#include <cstdint>
#include <filesystem>
#include <fmt/ostream.h>
#include <fmt/ranges.h>
#include <optional>
#include <string>
#include <string_view>
#include <toml.hpp>
#include <unordered_map>
#include <utility>
#include <variant>
#include <vector>

namespace cabin {
Expand Down Expand Up @@ -146,47 +144,6 @@ struct Lint {
explicit Lint(Cpplint cpplint) noexcept : cpplint(std::move(cpplint)) {}
};

struct DepMetadata {
const std::string includes; // -Isomething
const std::string libs; // -Lsomething -lsomething
};

struct GitDependency {
const std::string name;
const std::string url;
const std::optional<std::string> target;

Result<DepMetadata> install() const;

GitDependency(
std::string name, std::string url, std::optional<std::string> target
)
: name(std::move(name)), url(std::move(url)), target(std::move(target)) {}
};

struct PathDependency {
const std::string name;
const std::string path;

Result<DepMetadata> install() const;

PathDependency(std::string name, std::string path)
: name(std::move(name)), path(std::move(path)) {}
};

struct SystemDependency {
const std::string name;
const VersionReq versionReq;

Result<DepMetadata> install() const;

SystemDependency(std::string name, VersionReq versionReq)
: name(std::move(name)), versionReq(std::move(versionReq)) {};
};

using Dependency =
std::variant<GitDependency, PathDependency, SystemDependency>;

class Manifest {
public:
static constexpr const char* FILE_NAME = "cabin.toml";
Expand Down

0 comments on commit 20fd646

Please sign in to comment.