Skip to content

Commit dae5e75

Browse files
committed
fix(cli): refine package listing and info output
1 parent 520b899 commit dae5e75

2 files changed

Lines changed: 258 additions & 15 deletions

File tree

src/commands/InfoCommand.cpp

Lines changed: 226 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -284,12 +284,204 @@ namespace vix::commands
284284
label,
285285
path_with_state(path));
286286
}
287+
288+
struct ParsedArgs
289+
{
290+
bool globalMode{false};
291+
std::string packageId;
292+
};
293+
294+
static fs::path project_lock_path()
295+
{
296+
return fs::current_path() / "vix.lock";
297+
}
298+
299+
static ParsedArgs parse_args(const std::vector<std::string> &args)
300+
{
301+
ParsedArgs parsed;
302+
303+
for (const auto &arg : args)
304+
{
305+
if (arg == "-g" || arg == "--global")
306+
{
307+
parsed.globalMode = true;
308+
continue;
309+
}
310+
311+
if (parsed.packageId.empty())
312+
parsed.packageId = arg;
313+
}
314+
315+
return parsed;
316+
}
317+
318+
static json read_json_or_throw(const fs::path &p)
319+
{
320+
std::ifstream in(p);
321+
if (!in)
322+
throw std::runtime_error("cannot open: " + p.string());
323+
324+
json j;
325+
in >> j;
326+
return j;
327+
}
328+
329+
static const json *get_packages_array(const json &root)
330+
{
331+
if (root.is_array())
332+
return &root;
333+
334+
if (root.is_object() && root.contains("packages") && root["packages"].is_array())
335+
return &root["packages"];
336+
337+
if (root.is_object() && root.contains("dependencies") && root["dependencies"].is_array())
338+
return &root["dependencies"];
339+
340+
return nullptr;
341+
}
342+
343+
static std::string package_version(const json &pkg)
344+
{
345+
if (pkg.contains("version") && pkg["version"].is_string())
346+
return pkg["version"].get<std::string>();
347+
348+
if (pkg.contains("tag") && pkg["tag"].is_string())
349+
{
350+
std::string tag = pkg["tag"].get<std::string>();
351+
if (!tag.empty() && tag.front() == 'v')
352+
tag.erase(tag.begin());
353+
return tag;
354+
}
355+
356+
return {};
357+
}
358+
359+
static std::string package_repo(const json &pkg)
360+
{
361+
if (!pkg.contains("repo"))
362+
return {};
363+
364+
if (pkg["repo"].is_string())
365+
return pkg["repo"].get<std::string>();
366+
367+
if (pkg["repo"].is_object())
368+
return pkg["repo"].value("url", "");
369+
370+
return {};
371+
}
372+
373+
static const json *find_package_by_id(const json &packages, const std::string &id)
374+
{
375+
for (const auto &pkg : packages)
376+
{
377+
if (pkg.value("id", "") == id)
378+
return &pkg;
379+
}
380+
381+
return nullptr;
382+
}
383+
384+
static void print_package_info(const json &pkg, bool globalMode)
385+
{
386+
const std::string id = pkg.value("id", "");
387+
const std::string version = package_version(pkg);
388+
const std::string commit = pkg.value("commit", "");
389+
const std::string repo = package_repo(pkg);
390+
const std::string type = pkg.value("type", "");
391+
const std::string include = pkg.value("include", "");
392+
const std::string installedPath = pkg.value("installed_path", "");
393+
394+
vix::cli::util::section(std::cout, globalMode ? "Global package" : "Project package");
395+
396+
if (!id.empty())
397+
vix::cli::util::kv(std::cout, "id", id);
398+
399+
if (!version.empty())
400+
vix::cli::util::kv(std::cout, "version", version);
401+
402+
if (!commit.empty())
403+
vix::cli::util::kv(std::cout, "commit", commit);
404+
405+
if (!repo.empty())
406+
vix::cli::util::kv(std::cout, "repo", repo);
407+
408+
if (!type.empty())
409+
vix::cli::util::kv(std::cout, "type", type);
410+
411+
if (!include.empty())
412+
vix::cli::util::kv(std::cout, "include", include);
413+
414+
if (!installedPath.empty())
415+
vix::cli::util::kv(std::cout, "path", installedPath);
416+
417+
vix::cli::util::one_line_spacer(std::cout);
418+
vix::cli::util::ok_line(std::cout, "Package info loaded");
419+
}
420+
421+
static int print_package_info_from_file(
422+
const fs::path &path,
423+
const std::string &packageId,
424+
bool globalMode)
425+
{
426+
if (!is_regular_file_path(path))
427+
{
428+
vix::cli::util::err_line(
429+
std::cerr,
430+
globalMode ? "global package manifest not found" : "project lock file not found");
431+
return 1;
432+
}
433+
434+
json root;
435+
try
436+
{
437+
root = read_json_or_throw(path);
438+
}
439+
catch (const std::exception &ex)
440+
{
441+
vix::cli::util::err_line(std::cerr, std::string("failed to read package data: ") + ex.what());
442+
return 1;
443+
}
444+
445+
const json *packages = get_packages_array(root);
446+
if (!packages)
447+
{
448+
vix::cli::util::err_line(
449+
std::cerr,
450+
globalMode ? "invalid global manifest" : "invalid project lock file");
451+
return 1;
452+
}
453+
454+
const json *pkg = find_package_by_id(*packages, packageId);
455+
if (!pkg)
456+
{
457+
vix::cli::util::err_line(std::cerr, "package not found: " + packageId);
458+
return 1;
459+
}
460+
461+
print_package_info(*pkg, globalMode);
462+
return 0;
463+
}
287464
}
288465

289466
int InfoCommand::run(const std::vector<std::string> &args)
290467
{
291-
if (!args.empty())
292-
return help();
468+
const ParsedArgs parsed = parse_args(args);
469+
470+
if (!parsed.packageId.empty())
471+
{
472+
if (parsed.globalMode)
473+
{
474+
return print_package_info_from_file(
475+
global_manifest_path(),
476+
parsed.packageId,
477+
true);
478+
}
479+
480+
return print_package_info_from_file(
481+
project_lock_path(),
482+
parsed.packageId,
483+
false);
484+
}
293485

294486
const fs::path root = vix_root();
295487
const fs::path registry = registry_index_dir();
@@ -364,12 +556,26 @@ namespace vix::commands
364556
{
365557
std::cout
366558
<< "vix info\n"
367-
<< "Show Vix environment, paths, caches, and local state.\n\n"
559+
<< "Show Vix environment, package details, paths, caches, and local state.\n\n"
368560

369561
<< "Usage\n"
370-
<< " vix info\n\n"
371-
372-
<< "What it shows\n"
562+
<< " vix info\n"
563+
<< " vix info [@]namespace/name\n"
564+
<< " vix info -g [@]namespace/name\n"
565+
<< " vix info --global [@]namespace/name\n\n"
566+
567+
<< "Examples\n"
568+
<< " vix info\n"
569+
<< " vix info softadastra/json\n"
570+
<< " vix info -g softadastra/json\n"
571+
<< " vix info -g @softadastra/json\n\n"
572+
573+
<< "What happens\n"
574+
<< " • vix info shows the local Vix environment\n"
575+
<< " • vix info <package> shows details for a project dependency from vix.lock\n"
576+
<< " • vix info -g <package> shows details for a globally installed package\n\n"
577+
578+
<< "Environment info\n"
373579
<< " • Vix version\n"
374580
<< " • Vix root path\n"
375581
<< " • Registry index path and state\n"
@@ -380,7 +586,20 @@ namespace vix::commands
380586
<< " • Number of package directories in store/git\n"
381587
<< " • Number of cached commits in store/git\n"
382588
<< " • Disk usage of store/git\n"
383-
<< " • Disk usage of build artifact cache\n";
589+
<< " • Disk usage of build artifact cache\n\n"
590+
591+
<< "Package info\n"
592+
<< " • Package id\n"
593+
<< " • Version\n"
594+
<< " • Commit\n"
595+
<< " • Repository\n"
596+
<< " • Type\n"
597+
<< " • Include directory\n"
598+
<< " • Installed path, when available\n\n"
599+
600+
<< "Notes\n"
601+
<< " • Project package info is read from ./vix.lock\n"
602+
<< " • Global package info is read from ~/.vix/global/installed.json\n";
384603

385604
return 0;
386605
}

src/commands/ListCommand.cpp

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -137,18 +137,34 @@ namespace vix::commands
137137
const json &d,
138138
bool globalMode)
139139
{
140-
(void)globalMode;
141-
142140
const std::string id = d.value("id", "");
143141
const std::string ver = dep_version(d);
142+
const std::string commit = d.value("commit", "");
143+
144+
std::string repo;
145+
if (d.contains("repo"))
146+
{
147+
if (d["repo"].is_object())
148+
repo = d["repo"].value("url", "");
149+
else if (d["repo"].is_string())
150+
repo = d["repo"].get<std::string>();
151+
}
152+
153+
vix::cli::util::dep_line(std::cout, id, ver, commit, repo);
154+
155+
if (globalMode)
156+
{
157+
const std::string type = d.value("type", "");
158+
const std::string include = d.value("include", "");
159+
160+
if (!type.empty())
161+
vix::cli::util::kv(std::cout, "type", type);
144162

145-
if (id.empty())
146-
return;
163+
if (!include.empty())
164+
vix::cli::util::kv(std::cout, "include", include);
165+
}
147166

148-
if (!ver.empty())
149-
std::cout << id << "@" << ver << "\n";
150-
else
151-
std::cout << id << "\n";
167+
std::cout << "\n";
152168
}
153169

154170
} // namespace
@@ -159,6 +175,8 @@ namespace vix::commands
159175

160176
if (parsed.globalMode)
161177
{
178+
vix::cli::util::section(std::cout, "Global packages");
179+
162180
const fs::path p = global_manifest_path();
163181

164182
if (!fs::exists(p))
@@ -192,9 +210,15 @@ namespace vix::commands
192210
return 0;
193211
}
194212

213+
std::cout << "\n";
214+
195215
for (const auto &pkg : pkgs)
196216
print_dep_block(pkg, true);
197217

218+
vix::cli::util::ok_line(
219+
std::cout,
220+
"Found " + std::to_string(pkgs.size()) + " global package(s).");
221+
198222
return 0;
199223
}
200224

0 commit comments

Comments
 (0)