feat: add repos DSL, index format, and kappa index command
- Add repos { } block to system config with named repos, channels,
mirrors, and priority
- Add index "name" { } file format for package indexes
- Add kappa index <dir> subcommand that scans .kap files and
generates index.kap
- parse_index() and build_index() in DSL module
- format_index() roundtrip support in tools module
- validate and format subcommands handle all three formats
(package, config, index) with automatic detection
- Backward compatible: remotes = [...] still works unchanged
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
index "local" {
|
||||||
|
foo { version = "1.2.3" }
|
||||||
|
postgresql { version = "16.3" }
|
||||||
|
make { version = "4.4.1" }
|
||||||
|
}
|
||||||
@@ -93,4 +93,14 @@ struct PackageDef {
|
|||||||
Phase uninstall;
|
Phase uninstall;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct IndexEntry {
|
||||||
|
std::string name;
|
||||||
|
std::string version;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IndexDef {
|
||||||
|
std::string name; // "kappa-os/stable"
|
||||||
|
std::vector<IndexEntry> packages;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace kappa::dsl
|
} // namespace kappa::dsl
|
||||||
|
|||||||
@@ -57,9 +57,18 @@ struct ServiceRef {
|
|||||||
std::unordered_map<std::string, std::string> config;
|
std::unordered_map<std::string, std::string> config;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RepoDef {
|
||||||
|
std::string name;
|
||||||
|
std::string url;
|
||||||
|
std::vector<std::string> channels;
|
||||||
|
std::vector<std::string> mirrors;
|
||||||
|
int priority = 50;
|
||||||
|
};
|
||||||
|
|
||||||
struct SystemConfig {
|
struct SystemConfig {
|
||||||
std::vector<std::string> imports;
|
std::vector<std::string> imports;
|
||||||
std::vector<std::string> remotes;
|
std::vector<std::string> remotes; // legacy — flat URL list
|
||||||
|
std::vector<RepoDef> repos; // named repos with channels/mirrors
|
||||||
SystemBlock system;
|
SystemBlock system;
|
||||||
std::vector<PackageRef> packages;
|
std::vector<PackageRef> packages;
|
||||||
std::vector<ServiceRef> services;
|
std::vector<ServiceRef> services;
|
||||||
@@ -72,4 +81,7 @@ struct SystemConfig {
|
|||||||
SystemConfig parse_system_config(std::string_view source);
|
SystemConfig parse_system_config(std::string_view source);
|
||||||
SystemConfig resolve_imports(const SystemConfig& cfg, const std::string& base_dir);
|
SystemConfig resolve_imports(const SystemConfig& cfg, const std::string& base_dir);
|
||||||
|
|
||||||
|
IndexDef parse_index(std::string_view source);
|
||||||
|
IndexDef build_index(const std::string& directory);
|
||||||
|
|
||||||
} // namespace kappa::dsl
|
} // namespace kappa::dsl
|
||||||
|
|||||||
@@ -49,6 +49,10 @@ enum class TokenType {
|
|||||||
KwUninstall,
|
KwUninstall,
|
||||||
KwTrue,
|
KwTrue,
|
||||||
KwFalse,
|
KwFalse,
|
||||||
|
|
||||||
|
// Repo / index
|
||||||
|
KwIndex,
|
||||||
|
KwRepos,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Token {
|
struct Token {
|
||||||
|
|||||||
@@ -9,5 +9,6 @@ namespace kappa::tools {
|
|||||||
|
|
||||||
void format_package(std::ostream& os, const dsl::PackageDef& pkg);
|
void format_package(std::ostream& os, const dsl::PackageDef& pkg);
|
||||||
void format_config(std::ostream& os, const dsl::SystemConfig& cfg);
|
void format_config(std::ostream& os, const dsl::SystemConfig& cfg);
|
||||||
|
void format_index(std::ostream& os, const dsl::IndexDef& idx);
|
||||||
|
|
||||||
} // namespace kappa::tools
|
} // namespace kappa::tools
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ static const std::unordered_map<std::string_view, TokenType> keywords = {
|
|||||||
{"uninstall", TokenType::KwUninstall},
|
{"uninstall", TokenType::KwUninstall},
|
||||||
{"true", TokenType::KwTrue},
|
{"true", TokenType::KwTrue},
|
||||||
{"false", TokenType::KwFalse},
|
{"false", TokenType::KwFalse},
|
||||||
|
{"index", TokenType::KwIndex},
|
||||||
|
{"repos", TokenType::KwRepos},
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string_view token_name(TokenType type) {
|
std::string_view token_name(TokenType type) {
|
||||||
@@ -74,6 +76,8 @@ std::string_view token_name(TokenType type) {
|
|||||||
case TokenType::KwUninstall: return "uninstall";
|
case TokenType::KwUninstall: return "uninstall";
|
||||||
case TokenType::KwTrue: return "true";
|
case TokenType::KwTrue: return "true";
|
||||||
case TokenType::KwFalse: return "false";
|
case TokenType::KwFalse: return "false";
|
||||||
|
case TokenType::KwIndex: return "index";
|
||||||
|
case TokenType::KwRepos: return "repos";
|
||||||
}
|
}
|
||||||
return "?";
|
return "?";
|
||||||
}
|
}
|
||||||
|
|||||||
+157
-1
@@ -1,6 +1,7 @@
|
|||||||
#include "kappa/dsl/system.hpp"
|
#include "kappa/dsl/system.hpp"
|
||||||
#include "kappa/dsl/error.hpp"
|
#include "kappa/dsl/error.hpp"
|
||||||
#include "kappa/dsl/lexer.hpp"
|
#include "kappa/dsl/lexer.hpp"
|
||||||
|
#include "kappa/dsl/parser.hpp"
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <format>
|
#include <format>
|
||||||
@@ -29,6 +30,7 @@ private:
|
|||||||
void parse_boot_block(SystemConfig& cfg);
|
void parse_boot_block(SystemConfig& cfg);
|
||||||
void parse_users_block(SystemConfig& cfg);
|
void parse_users_block(SystemConfig& cfg);
|
||||||
void parse_groups_block(SystemConfig& cfg);
|
void parse_groups_block(SystemConfig& cfg);
|
||||||
|
void parse_repos_block(SystemConfig& cfg);
|
||||||
|
|
||||||
std::string consume_ident();
|
std::string consume_ident();
|
||||||
std::string consume_string();
|
std::string consume_string();
|
||||||
@@ -85,7 +87,9 @@ std::string SysParser::consume_ident() {
|
|||||||
at(TokenType::KwCheck) ||
|
at(TokenType::KwCheck) ||
|
||||||
at(TokenType::KwInstall) ||
|
at(TokenType::KwInstall) ||
|
||||||
at(TokenType::KwTrue) ||
|
at(TokenType::KwTrue) ||
|
||||||
at(TokenType::KwFalse)) {
|
at(TokenType::KwFalse) ||
|
||||||
|
at(TokenType::KwIndex) ||
|
||||||
|
at(TokenType::KwRepos)) {
|
||||||
auto lexeme = current_.lexeme;
|
auto lexeme = current_.lexeme;
|
||||||
advance();
|
advance();
|
||||||
return lexeme;
|
return lexeme;
|
||||||
@@ -184,6 +188,7 @@ SystemConfig SysParser::parse() {
|
|||||||
else if (kw == "boot") { parse_boot_block(cfg); }
|
else if (kw == "boot") { parse_boot_block(cfg); }
|
||||||
else if (kw == "users") { parse_users_block(cfg); }
|
else if (kw == "users") { parse_users_block(cfg); }
|
||||||
else if (kw == "groups") { parse_groups_block(cfg); }
|
else if (kw == "groups") { parse_groups_block(cfg); }
|
||||||
|
else if (kw == "repos") { parse_repos_block(cfg); }
|
||||||
else {
|
else {
|
||||||
throw ParseError(current_.line, current_.col,
|
throw ParseError(current_.line, current_.col,
|
||||||
std::format("unknown section '{}'", kw));
|
std::format("unknown section '{}'", kw));
|
||||||
@@ -456,6 +461,63 @@ void SysParser::parse_groups_block(SystemConfig& cfg) {
|
|||||||
consume(TokenType::Rbrace);
|
consume(TokenType::Rbrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SysParser::parse_repos_block(SystemConfig& cfg) {
|
||||||
|
consume(TokenType::Lbrace);
|
||||||
|
skip_newlines();
|
||||||
|
|
||||||
|
while (!at(TokenType::Rbrace) && !at(TokenType::Eof)) {
|
||||||
|
skip_newlines();
|
||||||
|
if (at(TokenType::Rbrace)) break;
|
||||||
|
|
||||||
|
RepoDef repo;
|
||||||
|
repo.name = consume_ident();
|
||||||
|
|
||||||
|
if (at(TokenType::Lbrace)) {
|
||||||
|
consume(TokenType::Lbrace);
|
||||||
|
skip_newlines();
|
||||||
|
while (!at(TokenType::Rbrace) && !at(TokenType::Eof)) {
|
||||||
|
if (at(TokenType::Newline)) { advance(); continue; }
|
||||||
|
auto key = consume_ident();
|
||||||
|
if (key == "url") {
|
||||||
|
consume(TokenType::Equals);
|
||||||
|
repo.url = consume_string();
|
||||||
|
} else if (key == "channels") {
|
||||||
|
consume(TokenType::Equals);
|
||||||
|
consume(TokenType::Lbracket);
|
||||||
|
skip_newlines();
|
||||||
|
while (!at(TokenType::Rbracket) && !at(TokenType::Eof)) {
|
||||||
|
repo.channels.push_back(consume_string());
|
||||||
|
skip_newlines();
|
||||||
|
if (at(TokenType::Comma)) { consume(TokenType::Comma); }
|
||||||
|
skip_newlines();
|
||||||
|
}
|
||||||
|
consume(TokenType::Rbracket);
|
||||||
|
} else if (key == "mirrors") {
|
||||||
|
consume(TokenType::Equals);
|
||||||
|
consume(TokenType::Lbracket);
|
||||||
|
skip_newlines();
|
||||||
|
while (!at(TokenType::Rbracket) && !at(TokenType::Eof)) {
|
||||||
|
repo.mirrors.push_back(consume_string());
|
||||||
|
skip_newlines();
|
||||||
|
if (at(TokenType::Comma)) { consume(TokenType::Comma); }
|
||||||
|
skip_newlines();
|
||||||
|
}
|
||||||
|
consume(TokenType::Rbracket);
|
||||||
|
} else if (key == "priority") {
|
||||||
|
consume(TokenType::Equals);
|
||||||
|
repo.priority = parse_int(current_.line, current_.col,
|
||||||
|
current_.lexeme);
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
skip_newlines();
|
||||||
|
}
|
||||||
|
consume(TokenType::Rbrace);
|
||||||
|
}
|
||||||
|
cfg.repos.push_back(std::move(repo));
|
||||||
|
}
|
||||||
|
consume(TokenType::Rbrace);
|
||||||
|
}
|
||||||
|
|
||||||
SystemConfig parse_system_config(std::string_view source) {
|
SystemConfig parse_system_config(std::string_view source) {
|
||||||
SysParser p(source);
|
SysParser p(source);
|
||||||
return p.parse();
|
return p.parse();
|
||||||
@@ -466,6 +528,7 @@ static void merge_config(SystemConfig& base, SystemConfig&& imported) {
|
|||||||
if (!imported.system.timezone.empty()) { base.system.timezone = std::move(imported.system.timezone); }
|
if (!imported.system.timezone.empty()) { base.system.timezone = std::move(imported.system.timezone); }
|
||||||
for (auto& e : imported.system.env) { base.system.env.push_back(std::move(e)); }
|
for (auto& e : imported.system.env) { base.system.env.push_back(std::move(e)); }
|
||||||
for (auto& r : imported.remotes) { base.remotes.push_back(std::move(r)); }
|
for (auto& r : imported.remotes) { base.remotes.push_back(std::move(r)); }
|
||||||
|
for (auto& r : imported.repos) { base.repos.push_back(std::move(r)); }
|
||||||
for (auto& [k, v] : imported.system.config) { base.system.config[k] = std::move(v); }
|
for (auto& [k, v] : imported.system.config) { base.system.config[k] = std::move(v); }
|
||||||
for (auto& [k, v] : imported.system.features) { base.system.features[k] = std::move(v); }
|
for (auto& [k, v] : imported.system.features) { base.system.features[k] = std::move(v); }
|
||||||
if (imported.system.rollback.keep > 0) { base.system.rollback.keep = imported.system.rollback.keep; }
|
if (imported.system.rollback.keep > 0) { base.system.rollback.keep = imported.system.rollback.keep; }
|
||||||
@@ -497,4 +560,97 @@ SystemConfig resolve_imports(const SystemConfig& cfg, const std::string& base_di
|
|||||||
return resolved;
|
return resolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IndexDef parse_index(std::string_view source) {
|
||||||
|
Lexer lexer(source);
|
||||||
|
Token current;
|
||||||
|
auto advance = [&] { current = lexer.next(); };
|
||||||
|
advance();
|
||||||
|
|
||||||
|
auto skip_newlines = [&] {
|
||||||
|
while (current.type == TokenType::Newline) { advance(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
auto consume = [&](TokenType type) -> Token {
|
||||||
|
if (current.type != type) {
|
||||||
|
throw ParseError(current.line, current.col,
|
||||||
|
msg_expected(token_name(type),
|
||||||
|
token_name(current.type)));
|
||||||
|
}
|
||||||
|
Token t = std::move(current);
|
||||||
|
advance();
|
||||||
|
return t;
|
||||||
|
};
|
||||||
|
|
||||||
|
skip_newlines();
|
||||||
|
consume(TokenType::KwIndex);
|
||||||
|
|
||||||
|
// index "kappa-os/stable" { ... }
|
||||||
|
auto name_tok = consume(TokenType::String);
|
||||||
|
consume(TokenType::Lbrace);
|
||||||
|
|
||||||
|
IndexDef idx;
|
||||||
|
idx.name = std::move(name_tok.lexeme);
|
||||||
|
|
||||||
|
skip_newlines();
|
||||||
|
while (current.type != TokenType::Rbrace && current.type != TokenType::Eof) {
|
||||||
|
skip_newlines();
|
||||||
|
if (current.type == TokenType::Rbrace) break;
|
||||||
|
|
||||||
|
IndexEntry entry;
|
||||||
|
entry.name = current.lexeme;
|
||||||
|
advance();
|
||||||
|
|
||||||
|
if (current.type == TokenType::Lbrace) {
|
||||||
|
advance();
|
||||||
|
skip_newlines();
|
||||||
|
while (current.type != TokenType::Rbrace && current.type != TokenType::Eof) {
|
||||||
|
if (current.type == TokenType::Newline) { advance(); continue; }
|
||||||
|
auto key = current.lexeme;
|
||||||
|
advance();
|
||||||
|
consume(TokenType::Equals);
|
||||||
|
if (key == "version") {
|
||||||
|
entry.version = consume(TokenType::String).lexeme;
|
||||||
|
}
|
||||||
|
skip_newlines();
|
||||||
|
}
|
||||||
|
consume(TokenType::Rbrace);
|
||||||
|
}
|
||||||
|
idx.packages.push_back(std::move(entry));
|
||||||
|
skip_newlines();
|
||||||
|
}
|
||||||
|
consume(TokenType::Rbrace);
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexDef build_index(const std::string& directory) {
|
||||||
|
IndexDef idx;
|
||||||
|
auto dirname = std::filesystem::path(directory).filename().string();
|
||||||
|
// If the directory is empty, drop the "."
|
||||||
|
if (dirname.empty() || dirname == ".") {
|
||||||
|
dirname = "local";
|
||||||
|
}
|
||||||
|
idx.name = dirname;
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
for (auto& entry : std::filesystem::directory_iterator(directory, ec)) {
|
||||||
|
if (ec) break;
|
||||||
|
if (!entry.is_regular_file()) continue;
|
||||||
|
auto ext = entry.path().extension().string();
|
||||||
|
if (ext != ".kap") continue;
|
||||||
|
|
||||||
|
std::ifstream in(entry.path());
|
||||||
|
if (!in) continue;
|
||||||
|
std::ostringstream buf;
|
||||||
|
buf << in.rdbuf();
|
||||||
|
|
||||||
|
try {
|
||||||
|
auto pkg = parse(buf.str());
|
||||||
|
idx.packages.push_back({pkg.name, pkg.version});
|
||||||
|
} catch (...) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace kappa::dsl
|
} // namespace kappa::dsl
|
||||||
|
|||||||
+48
-2
@@ -52,6 +52,7 @@ Subcommands:
|
|||||||
rebuild <config> Compare config to installed state, rebuild changed
|
rebuild <config> Compare config to installed state, rebuild changed
|
||||||
list List installed packages
|
list List installed packages
|
||||||
rollback Show available generations
|
rollback Show available generations
|
||||||
|
index <dir> Build an index.kap from .kap files in a directory
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-h, --help Show this help message
|
-h, --help Show this help message
|
||||||
@@ -197,7 +198,8 @@ int main(int argc, char* argv[]) {
|
|||||||
|| (subcommand == "rebuild")
|
|| (subcommand == "rebuild")
|
||||||
|| (subcommand == "list")
|
|| (subcommand == "list")
|
||||||
|| (subcommand == "fetch-package")
|
|| (subcommand == "fetch-package")
|
||||||
|| (subcommand == "rollback");
|
|| (subcommand == "rollback")
|
||||||
|
|| (subcommand == "index");
|
||||||
|
|
||||||
if (!valid_subcommand) {
|
if (!valid_subcommand) {
|
||||||
std::cerr << "error: unknown subcommand '" << subcommand << "'\n\n";
|
std::cerr << "error: unknown subcommand '" << subcommand << "'\n\n";
|
||||||
@@ -276,6 +278,29 @@ int main(int argc, char* argv[]) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (subcommand == "index") {
|
||||||
|
if (file_arg == nullptr) {
|
||||||
|
std::cerr << "error: no directory specified\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
auto idx = dsl::build_index(file_arg);
|
||||||
|
auto out_path = std::filesystem::path(file_arg) / "index.kap";
|
||||||
|
std::ofstream out(out_path);
|
||||||
|
if (!out) {
|
||||||
|
std::cerr << "error: cannot write " << out_path.string() << "\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
tools::format_index(out, idx);
|
||||||
|
std::cout << idx.packages.size() << " packages indexed → "
|
||||||
|
<< out_path.string() << "\n";
|
||||||
|
return 0;
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
std::cerr << "index error: " << e.what() << "\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (subcommand == "fetch-package") {
|
if (subcommand == "fetch-package") {
|
||||||
if (file_arg == nullptr) {
|
if (file_arg == nullptr) {
|
||||||
std::cerr << "error: no package name specified\n";
|
std::cerr << "error: no package name specified\n";
|
||||||
@@ -331,7 +356,8 @@ int main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
if (file_arg == nullptr
|
if (file_arg == nullptr
|
||||||
&& subcommand != "list"
|
&& subcommand != "list"
|
||||||
&& subcommand != "rollback") {
|
&& subcommand != "rollback"
|
||||||
|
&& subcommand != "index") {
|
||||||
std::cerr << "error: no input file specified\n";
|
std::cerr << "error: no input file specified\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -378,6 +404,12 @@ int main(int argc, char* argv[]) {
|
|||||||
}
|
}
|
||||||
std::cout << "\n";
|
std::cout << "\n";
|
||||||
}
|
}
|
||||||
|
if (!cfg.repos.empty()) {
|
||||||
|
int total_channels = 0;
|
||||||
|
for (auto& r : cfg.repos) total_channels += r.channels.size();
|
||||||
|
std::cout << " repos: " << cfg.repos.size()
|
||||||
|
<< " (" << total_channels << " channels)\n";
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} catch (const std::runtime_error& e) {
|
} catch (const std::runtime_error& e) {
|
||||||
handle_parse_error(file_arg, source, e);
|
handle_parse_error(file_arg, source, e);
|
||||||
@@ -414,12 +446,20 @@ int main(int argc, char* argv[]) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
} catch (const std::runtime_error&) {
|
||||||
|
try {
|
||||||
|
auto idx = dsl::parse_index(source);
|
||||||
|
std::cout << file_arg << ": valid index ("
|
||||||
|
<< idx.name << ", "
|
||||||
|
<< idx.packages.size() << " packages)\n";
|
||||||
|
return 0;
|
||||||
} catch (const std::runtime_error& e) {
|
} catch (const std::runtime_error& e) {
|
||||||
handle_parse_error(file_arg, source, e);
|
handle_parse_error(file_arg, source, e);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (subcommand == "build") {
|
if (subcommand == "build") {
|
||||||
try {
|
try {
|
||||||
@@ -472,12 +512,18 @@ int main(int argc, char* argv[]) {
|
|||||||
auto cfg = dsl::parse_system_config(source);
|
auto cfg = dsl::parse_system_config(source);
|
||||||
tools::format_config(std::cout, cfg);
|
tools::format_config(std::cout, cfg);
|
||||||
return 0;
|
return 0;
|
||||||
|
} catch (const std::runtime_error&) {
|
||||||
|
try {
|
||||||
|
auto idx = dsl::parse_index(source);
|
||||||
|
tools::format_index(std::cout, idx);
|
||||||
|
return 0;
|
||||||
} catch (const std::runtime_error& e) {
|
} catch (const std::runtime_error& e) {
|
||||||
handle_parse_error(file_arg, source, e);
|
handle_parse_error(file_arg, source, e);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (subcommand == "doctor") {
|
if (subcommand == "doctor") {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -237,6 +237,34 @@ void format_config(std::ostream& os, const dsl::SystemConfig& cfg) {
|
|||||||
os << "]\n\n";
|
os << "]\n\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!cfg.repos.empty()) {
|
||||||
|
os << "repos {\n";
|
||||||
|
for (auto& repo : cfg.repos) {
|
||||||
|
os << " " << repo.name << " {\n";
|
||||||
|
os << " url = \"" << repo.url << "\"\n";
|
||||||
|
if (!repo.channels.empty()) {
|
||||||
|
os << " channels = [";
|
||||||
|
for (std::size_t i = 0; i < repo.channels.size(); ++i) {
|
||||||
|
if (i > 0) { os << ", "; }
|
||||||
|
os << '"' << repo.channels[i] << '"';
|
||||||
|
}
|
||||||
|
os << "]\n";
|
||||||
|
}
|
||||||
|
if (!repo.mirrors.empty()) {
|
||||||
|
os << " mirrors = [\n";
|
||||||
|
for (auto& m : repo.mirrors) {
|
||||||
|
os << " \"" << m << "\",\n";
|
||||||
|
}
|
||||||
|
os << " ]\n";
|
||||||
|
}
|
||||||
|
if (repo.priority != 50) {
|
||||||
|
os << " priority = " << repo.priority << "\n";
|
||||||
|
}
|
||||||
|
os << " }\n";
|
||||||
|
}
|
||||||
|
os << "}\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
if (!cfg.assertions.empty()) {
|
if (!cfg.assertions.empty()) {
|
||||||
os << "assert {\n";
|
os << "assert {\n";
|
||||||
for (auto& a : cfg.assertions) {
|
for (auto& a : cfg.assertions) {
|
||||||
@@ -345,4 +373,12 @@ void format_config(std::ostream& os, const dsl::SystemConfig& cfg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void format_index(std::ostream& os, const dsl::IndexDef& idx) {
|
||||||
|
os << "index \"" << idx.name << "\" {\n";
|
||||||
|
for (auto& pkg : idx.packages) {
|
||||||
|
os << " " << pkg.name << " { version = \"" << pkg.version << "\" }\n";
|
||||||
|
}
|
||||||
|
os << "}\n";
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace kappa::tools
|
} // namespace kappa::tools
|
||||||
|
|||||||
Reference in New Issue
Block a user