Skip to content

Commit 154c5de

Browse files
committed
Merge branch 'dev'
2 parents 3bbe398 + 5f5e90f commit 154c5de

1 file changed

Lines changed: 83 additions & 72 deletions

File tree

src/commands/PublishCommand.cpp

Lines changed: 83 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
#include <string>
3131
#include <vector>
3232
#include <cstdio>
33+
#include <chrono>
34+
#include <iomanip>
3335

3436
#if defined(_WIN32)
3537
#define vix_popen _popen
@@ -95,14 +97,34 @@ namespace vix::commands
9597

9698
static fs::path registry_repo_dir()
9799
{
100+
// vix registry sync clones into ~/.vix/registry/index
98101
return vix_root() / "registry" / "index";
99102
}
100103

101104
static fs::path registry_index_dir()
102105
{
106+
// entries folder inside the registry repo: ~/.vix/registry/index/index
103107
return registry_repo_dir() / "index";
104108
}
105109

110+
static std::string iso_utc_now()
111+
{
112+
using namespace std::chrono;
113+
const auto now = system_clock::now();
114+
const std::time_t t = system_clock::to_time_t(now);
115+
116+
std::tm tm{};
117+
#if defined(_WIN32)
118+
gmtime_s(&tm, &t);
119+
#else
120+
gmtime_r(&t, &tm);
121+
#endif
122+
123+
std::ostringstream oss;
124+
oss << std::put_time(&tm, "%Y-%m-%dT%H:%M:%SZ");
125+
return oss.str();
126+
}
127+
106128
static bool file_exists_nonempty(const fs::path &p)
107129
{
108130
std::error_code ec;
@@ -281,6 +303,21 @@ namespace vix::commands
281303
return std::make_pair(lower_copy(ns), lower_copy(name));
282304
}
283305

306+
static void mark_version_published_or_throw(
307+
const fs::path &entryPath,
308+
json &entry,
309+
const std::string &version)
310+
{
311+
if (!entry.contains("versions") || !entry["versions"].is_object())
312+
entry["versions"] = json::object();
313+
314+
if (!entry["versions"].contains(version) || !entry["versions"][version].is_object())
315+
entry["versions"][version] = json::object();
316+
317+
entry["versions"][version]["status"] = "published";
318+
write_json_or_throw(entryPath, entry);
319+
}
320+
284321
static PublishOptions parse_args_or_throw(const std::vector<std::string> &args)
285322
{
286323
PublishOptions opt;
@@ -364,62 +401,6 @@ namespace vix::commands
364401
return b;
365402
}
366403

367-
static std::vector<int> parse_version_nums(const std::string &s)
368-
{
369-
std::vector<int> out;
370-
std::string cur;
371-
for (char ch : s)
372-
{
373-
if (std::isdigit(static_cast<unsigned char>(ch)))
374-
{
375-
cur.push_back(ch);
376-
continue;
377-
}
378-
if (ch == '.')
379-
{
380-
if (!cur.empty())
381-
{
382-
out.push_back(std::stoi(cur));
383-
cur.clear();
384-
}
385-
continue;
386-
}
387-
break;
388-
}
389-
if (!cur.empty())
390-
out.push_back(std::stoi(cur));
391-
while (out.size() < 3)
392-
out.push_back(0);
393-
return out;
394-
}
395-
396-
static int compare_versions(const std::string &a, const std::string &b)
397-
{
398-
const auto va = parse_version_nums(a);
399-
const auto vb = parse_version_nums(b);
400-
const size_t n = std::max(va.size(), vb.size());
401-
for (size_t i = 0; i < n; ++i)
402-
{
403-
const int ia = (i < va.size() ? va[i] : 0);
404-
const int ib = (i < vb.size() ? vb[i] : 0);
405-
if (ia < ib)
406-
return -1;
407-
if (ia > ib)
408-
return 1;
409-
}
410-
return 0;
411-
}
412-
413-
static void update_latest_if_newer(json &entry, const std::string &newVersion)
414-
{
415-
std::string cur;
416-
if (entry.contains("latest") && entry["latest"].is_string())
417-
cur = entry["latest"].get<std::string>();
418-
419-
if (cur.empty() || compare_versions(newVersion, cur) > 0)
420-
entry["latest"] = newVersion;
421-
}
422-
423404
static int publish_impl(const PublishOptions &opt)
424405
{
425406
vix::cli::util::section(std::cout, "Publish");
@@ -552,7 +533,6 @@ namespace vix::commands
552533
entry["type"] = "header-only";
553534
entry["manifestPath"] = "vix.json";
554535
entry["homepage"] = httpsUrl;
555-
entry["maintainers"] = json::array({json::object({{"name", ""}, {"github", ""}})});
556536
entry["versions"] = json::object();
557537
}
558538

@@ -567,24 +547,30 @@ namespace vix::commands
567547

568548
if (entry["versions"].contains(opt.version))
569549
{
570-
std::string latest;
571-
if (entry.contains("latest") && entry["latest"].is_string())
572-
latest = entry["latest"].get<std::string>();
573-
vix::cli::util::err_line(std::cerr, "version already exists in registry entry: " + opt.version);
574-
if (!latest.empty())
575-
vix::cli::util::warn_line(std::cerr, "current latest: " + latest);
576-
return 1;
550+
const json &existing = entry["versions"][opt.version];
551+
const std::string status = (existing.contains("status") && existing["status"].is_string())
552+
? existing["status"].get<std::string>()
553+
: std::string();
554+
555+
if (status == "published")
556+
{
557+
vix::cli::util::err_line(std::cerr, "version already published in registry: " + opt.version);
558+
return 1;
559+
}
560+
561+
// pending or unknown -> resume
562+
vix::cli::util::warn_line(std::cout, "found existing pending entry, resuming publish for: " + opt.version);
577563
}
578564

579565
json v = json::object();
580566
v["tag"] = tag;
581567
v["commit"] = commit;
568+
v["publishedAt"] = iso_utc_now();
569+
v["status"] = "pending";
582570
if (!opt.notes.empty())
583571
v["notes"] = opt.notes;
584572

585573
entry["versions"][opt.version] = v;
586-
update_latest_if_newer(entry, opt.version);
587-
588574
if (opt.dryRun)
589575
{
590576
vix::cli::util::ok_line(std::cout, "dry-run: would update: " + entryPath.string());
@@ -632,8 +618,9 @@ namespace vix::commands
632618
}
633619

634620
{
635-
const std::string cmd =
636-
"git -C " + regRepo.string() + " add " + entryPath.string();
621+
const std::string relEntry = (fs::path("index") / registry_file_name(*ns, *name)).generic_string();
622+
const std::string cmd = "git -C " + regRepo.string() + " add " + relEntry;
623+
637624
const int rc = vix::cli::util::run_cmd_retry_debug(cmd);
638625
if (rc != 0)
639626
return rc;
@@ -678,13 +665,37 @@ namespace vix::commands
678665
}
679666
}
680667

668+
// Mark as published locally after successful push.
669+
try
670+
{
671+
entry = read_json_or_throw(entryPath);
672+
mark_version_published_or_throw(entryPath, entry, opt.version);
673+
674+
const std::string relEntry =
675+
(fs::path("index") / registry_file_name(*ns, *name)).generic_string();
676+
677+
(void)vix::cli::util::run_cmd_retry_debug("git -C " + regRepo.string() + " add " + relEntry);
678+
(void)vix::cli::util::run_cmd_retry_debug(
679+
"git -C " + regRepo.string() +
680+
" commit -q -m \"registry: mark published " + pkgId + " v" + opt.version + "\"");
681+
(void)vix::cli::util::run_cmd_retry_debug("git -C " + regRepo.string() + " push");
682+
}
683+
catch (...)
684+
{
685+
// Not fatal: publish already pushed, only status update failed.
686+
vix::cli::util::warn_line(std::cout, "warning: could not mark version as published locally");
687+
}
688+
681689
bool prCreated = false;
682690

683691
if (command_exists("gh"))
684692
{
685-
std::string out;
686-
const int authRc = run_cmd_capture("gh auth status -h github.com >/dev/null 2>&1; echo $?", out);
687-
const bool ghAuthed = (authRc == 0 && out == "0");
693+
bool ghAuthed = false;
694+
{
695+
std::string out;
696+
const int rc = run_cmd_capture("gh auth status -h github.com 2>/dev/null", out);
697+
ghAuthed = (rc == 0);
698+
}
688699

689700
if (ghAuthed)
690701
{
@@ -753,7 +764,7 @@ namespace vix::commands
753764
<< " - Registry must be synced: vix registry sync\n\n"
754765
<< "Examples:\n"
755766
<< " vix publish 0.2.0\n"
756-
<< " vix publish 0.2.0 --notes \"Add count_leaves helper\"\n"
767+
<< " vix publish 0.2.0 --notes \"Add count_leaves helpers\"\n"
757768
<< " vix publish 0.2.0 --dry-run\n";
758769
return 0;
759770
}

0 commit comments

Comments
 (0)