diff --git a/uppsrc/ide/Core/Core.h b/uppsrc/ide/Core/Core.h index a19e5165b..b19b816b2 100644 --- a/uppsrc/ide/Core/Core.h +++ b/uppsrc/ide/Core/Core.h @@ -459,6 +459,7 @@ public: Array option; Array include; Array pkg_config; + Array external_dependency; Array file; Array config; Array custom; @@ -707,4 +708,19 @@ String CleanupPretty(const String& signature); Vector ParsePretty(const String& name, const String& signature, int *fn_info = NULL); +struct VcpkgInstalled : Moveable { + String name; + Index triplets; + String version; + String desc; +}; + +bool IsVcpkgInstalled(); +bool InstallVcpkg(Function sys); +String VcpkgExe(); +Vector VcpkgList(); +Vector RequiredExternalDependencies(const String& manager); +Vector VcpkgTriplets(); +bool VcpkgHasInstalled(Vector& items, const String& name, const String& triplet); + #endif \ No newline at end of file diff --git a/uppsrc/ide/Core/Core.upp b/uppsrc/ide/Core/Core.upp index 8eaa6b5f9..7e66d0604 100644 --- a/uppsrc/ide/Core/Core.upp +++ b/uppsrc/ide/Core/Core.upp @@ -21,6 +21,7 @@ file usc.cpp, BinObj.cpp, Signature.cpp, + Vcpkg.cpp, Host readonly separator, Host.h, Host.cpp, diff --git a/uppsrc/ide/Core/Package.cpp b/uppsrc/ide/Core/Package.cpp index a4c409039..5fa173123 100644 --- a/uppsrc/ide/Core/Package.cpp +++ b/uppsrc/ide/Core/Package.cpp @@ -226,6 +226,7 @@ bool Package::Load(const char *path) uses.Clear(); include.Clear(); pkg_config.Clear(); + external_dependency.Clear(); accepts.Clear(); file.Clear(); config.Clear(); @@ -248,7 +249,8 @@ bool Package::Load(const char *path) !LoadOpt(p, "target", target) && !LoadOpt(p, "uses", uses) && !LoadOpt(p, "include", include) && - !LoadOpt(p, "pkg_config", pkg_config)) { + !LoadOpt(p, "pkg_config", pkg_config) && + !LoadOpt(p, "external_dependency", external_dependency)) { if(p.Id("charset")) charset = CharsetByNameX(p.ReadString()); else @@ -482,6 +484,8 @@ bool Package::Save(const char *path) const { putopt(out, "link", link); putopt(out, "include", include); putopt(out, "pkg_config", pkg_config); + putopt(out, "external_dependency", external_dependency); + if(file.GetCount()) { out << "file\n"; int i; diff --git a/uppsrc/ide/Core/Vcpkg.cpp b/uppsrc/ide/Core/Vcpkg.cpp new file mode 100644 index 000000000..c6e80ea99 --- /dev/null +++ b/uppsrc/ide/Core/Vcpkg.cpp @@ -0,0 +1,81 @@ +#include "Core.h" + +String VcpkgExe() +{ + return GetExeFolder() + "/vcpkg/vcpkg.exe"; +} + +bool IsVcpkgInstalled() +{ + return FileExists(VcpkgExe()); +} + +bool InstallVcpkg(Function sys) +{ + String exedir = GetExeFolder(); + return sys("git clone https://github.com/microsoft/vcpkg.git", exedir) == 0 && + sys("cmd /c \"" + exedir + "/vcpkg/bootstrap-vcpkg.bat\"", Null) == 0; +} + +Vector VcpkgList() +{ + VectorMap ms; + for(Value l : ParseJSON(Sys(VcpkgExe() + " list --x-json"))) { + String name = ~l["package_name"]; + VcpkgInstalled& m = ms.GetAdd(name); + m.name = name; + m.triplets.FindAdd(~l["triplet"]); + m.version = ~l["version"]; + String p = ~l["port_version"]; + if(p != "0") + m.version << '#' << p; + if(l["desc"].GetCount()) + m.desc = l["desc"][0]; + } + return ms.PickValues(); +} + +Vector RequiredExternalDependencies(const String& manager) +{ + Vector required; + const Workspace& wspc = GetIdeWorkspace(); + for(int i = 0; i < wspc.GetCount(); i++) { + const Package& pkg = wspc.GetPackage(i); + for(const OptItem& m : pkg.external_dependency) { + if(IsNull(m.when) || m.when == manager) + required.Add(m.text); + } + } + Sort(required); + return required; +} + +Vector VcpkgTriplets() +{ + Index ts; + for(FindFile ff(ConfigFile("*.bm")); ff; ff.Next()) { + VectorMap vars; + String fn = ConfigFile(ff.GetName()); + if(LoadVarFile(fn, vars)) { + String builder = vars.Get("BUILDER", Null); + String compiler = vars.Get("COMPILER", Null); + + if(builder == "CLANG") + ts.FindAdd(compiler.Find("i686") >= 0 ? "x86-mingw-static-release" : "x64-mingw-static-release"); + if(builder.StartsWith("MSC")) + ts.FindAdd(builder.Find("64") >= 0 ? "x64-windows-static-md" : "x86-windows-static-md"); + } + } + + Vector triplets = ts.PickKeys(); + Sort(triplets); + return triplets; +} + +bool VcpkgHasInstalled(Vector& items, const String& name, const String& triplet) +{ + for(const VcpkgInstalled& m : items) + if(m.name == name && m.triplets.Find(triplet) >= 0) + return true; + return false; +} diff --git a/uppsrc/ide/Organizer.cpp b/uppsrc/ide/Organizer.cpp index 5d7ec6880..7b4c17e06 100644 --- a/uppsrc/ide/Organizer.cpp +++ b/uppsrc/ide/Organizer.cpp @@ -658,6 +658,7 @@ PackageEditor::PackageEditor() Add("Compiler options", actual.option); Add("Internal includes", actual.include); Add("pkg-config", actual.pkg_config); + Add("External dependency", actual.external_dependency); Init(option); option.WhenCursor = THISBACK(AdjustPackageOptionCursor); diff --git a/uppsrc/ide/RepoConsole.cpp b/uppsrc/ide/RepoConsole.cpp index e73039092..a8c595e55 100644 --- a/uppsrc/ide/RepoConsole.cpp +++ b/uppsrc/ide/RepoConsole.cpp @@ -49,7 +49,7 @@ void UrepoConsole::Log(const Value& s, Color ink) list.Add(AttrText(s).SetFont(font).NormalInk(ink), s); } -int UrepoConsole::System(const char *cmd) +int UrepoConsole::System(const char *cmd, const char *chdir) { if(!IsOpen()) Open(); @@ -67,6 +67,8 @@ int UrepoConsole::System(const char *cmd) return -1; Host host; ide->CreateHost(host, false, false); + if(chdir) + host.ChDir(chdir); LocalProcess p; if(!host.StartProcess(p, cmd)) { list.Add(AttrText("Failed to start the executable").SetFont(font().Bold()).Ink(SLtRed())); diff --git a/uppsrc/ide/UppDlg.h b/uppsrc/ide/UppDlg.h index 2ce8276da..51f7adc6b 100644 --- a/uppsrc/ide/UppDlg.h +++ b/uppsrc/ide/UppDlg.h @@ -438,8 +438,8 @@ struct PackageEditor : WorkspaceWork, WithUppLayout { virtual void PackageCursor(); enum OptionType { - FLAG = 0, USES, TARGET, LIBRARY, STATIC_LIBRARY, LINK, COMPILER, INCLUDE, PKG_CONFIG, - PKG_LAST = PKG_CONFIG, + FLAG = 0, USES, TARGET, LIBRARY, STATIC_LIBRARY, LINK, COMPILER, INCLUDE, PKG_CONFIG, EXTERNAL_DEPENDENCY, + PKG_LAST = EXTERNAL_DEPENDENCY, FILEOPTION, FILEDEPENDS }; diff --git a/uppsrc/ide/ide.h b/uppsrc/ide/ide.h index 6356263f0..939a8a7fb 100644 --- a/uppsrc/ide/ide.h +++ b/uppsrc/ide/ide.h @@ -1004,6 +1004,7 @@ public: void DoMacroManager(); void UpgradeTheIDE(); void InstallDesktop(); + void Vcpkg(); void SetupMobilePlatforms(Bar& bar); void SetupAndroidMobilePlatform(Bar& bar, const AndroidSDK& androidSDK); diff --git a/uppsrc/ide/ide.lay b/uppsrc/ide/ide.lay index 1761f182b..61d401ac0 100644 --- a/uppsrc/ide/ide.lay +++ b/uppsrc/ide/ide.lay @@ -1039,3 +1039,12 @@ LAYOUT(ClangTidyLayout, 624, 580) ITEM(Upp::Button, cancel, SetLabel(t_("Cancel")).RightPosZ(8, 64).BottomPosZ(8, 24)) END_LAYOUT +LAYOUT(VcpkgLayout, 1000, 700) + ITEM(Upp::ArrayCtrl, list, LeftPosZ(4, 992).TopPosZ(4, 468)) + ITEM(Upp::Button, exit, SetLabel(t_("Close")).RightPosZ(8, 64).BottomPosZ(8, 24)) + ITEM(Upp::Button, install_missing, SetLabel(t_("Install missing")).RightPosZ(564, 120).BottomPosZ(8, 24)) + ITEM(Upp::ArrayCtrl, required_list, LeftPosZ(4, 150).TopPosZ(476, 188)) + ITEM(Upp::ArrayCtrl, triplets_list, LeftPosZ(160, 150).TopPosZ(476, 188)) + ITEM(Upp::ArrayCtrl, missing_list, LeftPosZ(316, 368).TopPosZ(476, 188)) +END_LAYOUT + diff --git a/uppsrc/ide/ide.upp b/uppsrc/ide/ide.upp index 1562286ff..e626e9f99 100644 --- a/uppsrc/ide/ide.upp +++ b/uppsrc/ide/ide.upp @@ -92,6 +92,7 @@ file SetupGIT.cpp, Upgrade.cpp, UppHub.cpp, + vcpkg.cpp, Compile readonly separator, MethodsCtrls.h, MethodsCtrls.cpp, diff --git a/uppsrc/ide/idebar.cpp b/uppsrc/ide/idebar.cpp index 58bf0af71..552a9ceff 100644 --- a/uppsrc/ide/idebar.cpp +++ b/uppsrc/ide/idebar.cpp @@ -474,6 +474,10 @@ void Ide::Setup(Bar& menu) menu.Add("Install theide.desktop", [=] { InstallDesktop(); }); #endif +#ifdef PLATFORM_WIN32 + menu.Add("Vcpkg..", [=] { Vcpkg(); }); +#endif + if(menu.IsMenuBar()) SetupMobilePlatforms(menu); } diff --git a/uppsrc/ide/urepo.h b/uppsrc/ide/urepo.h index da522af52..f922f6866 100644 --- a/uppsrc/ide/urepo.h +++ b/uppsrc/ide/urepo.h @@ -9,7 +9,7 @@ class UrepoConsole : public WithUrepoConsoleLayout { int hide_password_to = 0; public: - int System(const char *s); + int System(const char *s, const char *chdir = nullptr); int CheckSystem(const char *s); int Git(const char *dir, const char *command, bool pwd = false); void HidePassword(int from, int to) { hide_password_from = from; hide_password_to = to; } diff --git a/uppsrc/ide/vcpkg.cpp b/uppsrc/ide/vcpkg.cpp new file mode 100644 index 000000000..dd725894a --- /dev/null +++ b/uppsrc/ide/vcpkg.cpp @@ -0,0 +1,100 @@ +#include "ide.h" + +#ifdef PLATFORM_WIN32 + +struct VcpkgDlg : WithVcpkgLayout { + Vector items; + + void SyncIde(); + void SyncList(); + void Perform(); + + VcpkgDlg(); +}; + +void VcpkgDlg::SyncIde() +{ + Vector triplets = VcpkgTriplets(); + + triplets_list.Clear(); + for(String s : triplets) + triplets_list.Add(s); + + Vector required = RequiredExternalDependencies("VCPKG"); + + required_list.Clear(); + for(String s : required) + required_list.Add(s); + + for(String r : required) + for(String t : triplets) + if(!VcpkgHasInstalled(items, r, t)) + missing_list.Add(r, t); + install_missing.Enable(missing_list.GetCount()); +} + +void VcpkgDlg::SyncList() +{ + items = VcpkgList(); + + list.Clear(); + for(const VcpkgInstalled& m : items) + list.Add(m.name, Join(m.triplets.GetKeys(), " "), m.version, m.desc); +} + +void VcpkgDlg::Perform() +{ + if(!IsVcpkgInstalled()) { + if(!PromptYesNo("Install vcpkg?")) + return; + UrepoConsole console; + if(!InstallVcpkg([&](const String& cmd, const String& chdir) { return console.System(cmd, chdir); })) { + Exclamation("Installation failed"); + return; + } + console.Log("Installation completed.", SGreen()); + console.Perform(); + } + SyncList(); + SyncIde(); + Execute(); +} + +VcpkgDlg::VcpkgDlg() +{ + CtrlLayoutExit(*this, "vcpkg"); + + list.AddColumn("Name"); + list.AddColumn("Triplets"); + list.AddColumn("Version"); + list.AddColumn("Description"); + list.ColumnWidths("140 396 79 281"); + + required_list.AddColumn("Required"); + + triplets_list.AddColumn("Triplets"); + + missing_list.AddColumn("Missing"); + missing_list.AddColumn("Triplet"); + + install_missing << [=] { + UrepoConsole console; + for(int i = 0; i < missing_list.GetCount(); i++) { + String name = missing_list.Get(i, 0); + String triplet = missing_list.Get(i, 1); + console.System(VcpkgExe() + " install " + name + ":" + triplet); + } + console.Log("Installation completed.", SGreen()); + console.Perform(); + SyncList(); + SyncIde(); + }; +} + +void Ide::Vcpkg() +{ + VcpkgDlg dlg; + dlg.Perform(); +} + +#endif