ultimatepp/uppsrc/umk/UppHub.cpp

247 lines
5.7 KiB
C++

#include "umake.h"
struct UppHubNest : Moveable<UppHubNest> {
int tier = -1;
String name;
Vector<String> packages;
String description;
String repo;
String website;
String status = "unknown";
String category;
String list_name;
String readme;
String branch;
};
struct UppHubDlg {
VectorMap<String, UppHubNest> upv;
Index<String> loaded;
Value LoadJson(const String& url);
void Load(int tier, const String& url);
void Load();
void Install(const Index<String>& ii, bool update = false);
};
Value UppHubDlg::LoadJson(const String& url)
{
String s = LoadFile(url);
if(IsNull(s)) {
PutVerbose("Fetching UppHub metadata from " << url);
#ifdef PLATFORM_POSIX
s = Sys("curl --silent " + url);
if (IsNull(s)) {
String msg = "Failed to execute UppHub download nests request.";
return ErrorValue(msg);
}
#else
HttpRequest r(url);
r.Execute();
if (!r.IsSuccess()) {
String msg = "Failed to execute UppHub download nests request with error code " + IntStr(r.GetStatusCode()) + ".";
return ErrorValue(msg);
}
s = r.GetContent();
#endif
}
Value v = ParseJSON(s);
if(v.IsError()) {
s.Replace("&quot;", "\"");
s.Replace("&amp;", "&");
v = ParseJSON(s);
if (v.IsError()) {
String msg = "Failed to parse Json file.";
return ErrorValue(msg);
}
}
return v;
}
void UppHubDlg::Load(int tier, const String& url)
{
if(loaded.Find(url) >= 0)
return;
loaded.Add(url);
Value v = LoadJson(url);
if (v.IsError()) {
auto error_text = GetErrorText(v);
if (!error_text.IsEmpty()) {
PutConsole("Failed to load nests file with error \"" + GetErrorText(v) + "\".");
}
return;
}
try {
String list_name = v["name"];
for(Value ns : v["nests"]) {
String url = ns["url"];
if(url.GetCount())
ns = LoadJson(url);
String name = ns["name"];
UppHubNest& n = upv.GetAdd(name);
n.name = name;
bool tt = tier > n.tier;
if(tt || n.packages.GetCount() == 0)
for(Value p : ns["packages"])
n.packages.Add(p);
auto Attr = [&](String& a, const char *id) {
if(tt || IsNull(a))
a = ns[id];
};
Attr(n.description, "description");
Attr(n.repo, "repository");
Attr(n.website, "website");
if(IsNull(n.website))
n.website = TrimRight(".git", n.repo);
Attr(n.category, "category");
Attr(n.status, "status");
Attr(n.readme, "readme");
Attr(n.branch, "branch");
n.list_name = list_name;
}
for(Value l : v["links"]) {
Load(tier + 1, l);
}
}
catch(ValueTypeError) {}
}
void UppHubDlg::Load()
{
String url = Nvl(LoadFile(ConfigFile("upphub_root")),
(String)"https://raw.githubusercontent.com/ultimatepp/UppHub/main/nests.json");
Load(0, url);
}
void UppHubDlg::Install(const Index<String>& ii_, bool update)
{
Index<String> ii = clone(ii_);
if(ii.GetCount()) {
int i = 0;
while(i < ii.GetCount()) {
String ns = ii[i++];
UppHubNest *n = upv.FindPtr(ns);
if(n) {
String dir = GetHubDir() + '/' + n->name;
if(!DirectoryExists(dir)) {
String cmd = GetGitPath() + " clone ";
if(n->branch.GetCount())
cmd << "-b " + n->branch << ' ';
cmd << n->repo;
cmd << ' ' << dir;
PutConsole(cmd);
system(cmd);
for(String p : FindAllPaths(dir, "*.upp")) {
Package pkg;
pkg.Load(p);
for(const auto& u : pkg.uses)
for(const UppHubNest& n : upv)
for(const String& p : n.packages)
if(u.text == p) {
ii.FindAdd(n.name);
break;
}
}
} else if (update) {
String cmd = GetGitPath() + " -C ";
cmd << dir << " clean -fxd";
PutConsole(cmd);
system(cmd);
cmd = GetGitPath() + " -C ";
cmd << dir << " pull";
PutConsole(cmd);
system(cmd);
}
}
}
InvalidatePackageCache();
}
ResetBlitz();
}
bool UppHubAuto(const String& main)
{
Index<String> pmissing;
for(;;) {
Workspace wspc;
wspc.Scan(main);
Index<String> missing;
for(int i = 0; i < wspc.GetCount(); i++) {
String p = wspc[i];
if(!FileExists(PackageFile(p)))
missing.FindAdd(p);
}
if(missing.GetCount() == 0)
return true;
UppHubDlg dlg;
dlg.Load();
Index<String> found;
for(const UppHubNest& n : dlg.upv)
for(const String& p : n.packages)
if(missing.Find(p) >= 0)
found.FindAdd(n.name);
if(missing != pmissing) {
dlg.Install(found);
pmissing = clone(missing);
continue;
}
return false;
}
return true;
}
void UppHubUpdate(const String& main)
{
UppHubDlg dlg;
dlg.Load();
Workspace wspc;
wspc.Scan(main);
Index<String> packages;
for(int i = 0; i < wspc.GetCount(); i++) {
String pkg = wspc[i];
for(const UppHubNest& n : dlg.upv)
for(const String& p : n.packages) {
if (pkg == p && pkg != main)
packages.FindAdd(n.name);
}
}
dlg.Install(packages, true);
}
void UppHubSetupDirForUmk(const String& hub_dir, const bool auto_hub)
{
if(!hub_dir.IsEmpty()) {
OverrideHubDir(hub_dir);
return;
}
if(auto_hub) {
// NOTE: In auto_hub mode we don't want to change default directory or reuse these
// belonging to umk or ide.
DeleteFolderDeep(GetHubDir());
return;
}
String cfgdir = GetFileFolder(GetFileFolder(ConfigFile("x")));
for(const char *q : { "umk", "theide", "ide" }) {
String dir = cfgdir + "/" + q + "/UppHub";
if(DirectoryExists(dir)) {
for(FindFile ff(dir + "/*"); ff; ff.Next())
if(ff.IsFolder() && *ff.GetName() != '.') {
OverrideHubDir(dir);
return;
}
}
}
}