Skip to content

Commit

Permalink
manifest: support path dependencies (#1048)
Browse files Browse the repository at this point in the history
This PR introduces path dependency [like Cargo's
one](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#specifying-path-dependencies).
Path dependency specify a local directory as dependency.
[Unlike Cargo's
one](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#no-local-path-traversal),

- currently poac doesn't care about `poac.toml` in the path.
- Like git dependency, path dependency implemented by this PR supports
only header-only library.
- poac doesn't support `version` for published package.

This PR doesn't contain `poac add --path` sub-command option.

Poac with this PR can allow `poac.toml` like below:

```toml
[dependencies]
local_header_only_library = {path = "./path/to/library"}
```

---------

Co-authored-by: Ken Matsui <[email protected]>
  • Loading branch information
wx257osn2 and ken-matsui authored Dec 24, 2024
1 parent cabbdef commit a46d104
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 8 deletions.
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

0 comments on commit a46d104

Please sign in to comment.