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

manifest: support path dependencies #1048

Merged
merged 6 commits into from
Dec 24, 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
21 changes: 20 additions & 1 deletion docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ Poac uses a cache since we executed the command with no changes.

## Install dependencies

Like Cargo does, Poac installs dependencies at build time. Poac currently supports Git and system dependencies. You can use the `poac add` command to add dependencies to your project.
Like Cargo does, Poac installs dependencies at build time. Poac currently supports Git, path, and system dependencies. You can use two ways to add dependencies to your project: using the `poac add` command and editing `poac.toml` directly.

### `poac add`

The `poac add` command accepts the following arguments:

Expand All @@ -69,6 +71,23 @@ poac add libgit2 --sys --version "1.1.0"
poac add "ToruNiina/toml11" --rev "846abd9a49082fe51440aa07005c360f13a67bbf"
```

### Editing `poac.toml` directly

The syntax for `poac.toml` is as follows:

```toml
[dependencies]

# git dependency
"ToruNiina/toml11" = { git = "https://github.com/ToruNiina/toml11.git", rev = "846abd9a49082fe51440aa07005c360f13a67bbf" }

# path dependency
local_lib = { path = "../local_lib" }

# system dependency
fmt = { version = ">= 9", system = true }
```

If `tag`, `branch`, or `rev` is unspecified for git dependencies, Poac will use the latest revision of the default branch. System dependency names must be acceptable by `pkg-config`. The version requirement syntax is specified in [src/VersionReq.hpp](https://github.com/poac-dev/poac/blob/main/src/VersionReq.hpp).

After adding dependencies, executing the `build` command will install the package and its dependencies.
Expand Down
60 changes: 53 additions & 7 deletions src/Manifest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <toml.hpp>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <variant>
#include <vector>

Expand Down Expand Up @@ -126,13 +127,23 @@ struct GitDependency {
DepMetadata install() const;
};

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

DepMetadata install() const;
};

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

DepMetadata install() const;
};

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

void
Profile::merge(const Profile& other) {
cxxflags.insert(other.cxxflags.begin(), other.cxxflags.end());
Expand Down Expand Up @@ -166,10 +177,8 @@ struct Manifest {
std::optional<toml::value> data = std::nullopt;

std::optional<Package> package = std::nullopt;
std::optional<std::vector<std::variant<GitDependency, SystemDependency>>>
dependencies = std::nullopt;
std::optional<std::vector<std::variant<GitDependency, SystemDependency>>>
devDependencies = std::nullopt;
std::optional<std::vector<Dependency>> dependencies = std::nullopt;
std::optional<std::vector<Dependency>> devDependencies = std::nullopt;

std::optional<Profile> profile = std::nullopt;
std::optional<Profile> devProfile = std::nullopt;
Expand Down Expand Up @@ -536,6 +545,16 @@ parseGitDep(const std::string& name, const toml::table& info) {
return { .name = name, .url = gitUrlStr, .target = target };
}

static PathDependency
parsePathDep(const std::string& name, const toml::table& info) {
validateDepName(name);
const auto& path = info.at("path");
if (!path.is_string()) {
throw PoacError("path dependency must be a string");
}
return { .name = name, .path = path.as_string() };
}

static SystemDependency
parseSystemDep(const std::string& name, const toml::table& info) {
validateDepName(name);
Expand All @@ -548,7 +567,7 @@ parseSystemDep(const std::string& name, const toml::table& info) {
return { .name = name, .versionReq = VersionReq::parse(versionReq) };
}

static std::optional<std::vector<std::variant<GitDependency, SystemDependency>>>
static std::optional<std::vector<Dependency>>
parseDependencies(const char* key) {
Manifest& manifest = Manifest::instance();
const auto& table = toml::get<toml::table>(manifest.data.value());
Expand All @@ -558,7 +577,7 @@ parseDependencies(const char* key) {
}
const auto tomlDeps = toml::find<toml::table>(manifest.data.value(), key);

std::vector<std::variant<GitDependency, SystemDependency>> deps;
std::vector<Dependency> deps;
for (const auto& dep : tomlDeps) {
if (dep.second.is_table()) {
const auto& info = dep.second.as_table();
Expand All @@ -568,11 +587,15 @@ parseDependencies(const char* key) {
} else if (info.contains("system") && info.at("system").as_boolean()) {
deps.emplace_back(parseSystemDep(dep.first, info));
continue;
} else if (info.contains("path")) {
deps.emplace_back(parsePathDep(dep.first, info));
continue;
}
}

throw PoacError(
"Only Git dependency and system dependency are supported for now: ",
"Only Git dependency, path dependency, and system dependency are "
"supported for now: ",
dep.first
);
}
Expand Down Expand Up @@ -619,6 +642,29 @@ GitDependency::install() const {
return { .includes = includes, .libs = "" };
}

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 {
throw PoacError(installDir.string() + " can't be accessible as directory");
}

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 { .includes = includes, .libs = "" };
}

DepMetadata
SystemDependency::install() const {
const std::string pkgConfigVer = versionReq.toPkgConfigString(name);
Expand Down
Loading