1 // Copyright (C) 2013  James Turner - zakalawe@mac.com
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Library General Public
5 // License as published by the Free Software Foundation; either
6 // version 2 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Library General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16 //
17 
18 #include <simgear_config.h>
19 
20 #include <simgear/io/HTTPClient.hxx>
21 #include <simgear/package/Catalog.hxx>
22 #include <simgear/package/Package.hxx>
23 #include <simgear/package/Install.hxx>
24 #include <simgear/package/Root.hxx>
25 #include <simgear/misc/sg_dir.hxx>
26 
27 #include <iostream>
28 #include <cstring>
29 
30 using namespace simgear;
31 using namespace std;
32 
33 bool keepRunning = true;
34 
35 class MyDelegate : public pkg::Delegate
36 {
37 public:
catalogRefreshed(pkg::CatalogRef aCatalog,StatusCode aReason)38     virtual void catalogRefreshed(pkg::CatalogRef aCatalog, StatusCode aReason)
39     {
40         if (aReason == STATUS_REFRESHED) {
41             if (aCatalog.ptr() == NULL) {
42                 cout << "refreshed all catalogs" << endl;
43             } else {
44                 cout << "refreshed catalog " << aCatalog->url() << endl;
45             }
46         } else if (aReason == STATUS_IN_PROGRESS) {
47             cout << "started refresh of " << aCatalog->url() << endl;
48         } else {
49             cerr << "failed refresh of " << aCatalog->url() << ":" << aReason << endl;
50         }
51     }
52 
startInstall(pkg::InstallRef aInstall)53     virtual void startInstall(pkg::InstallRef aInstall)
54     {
55         _lastPercent = 999;
56         cout << "starting install of " << aInstall->package()->name() << endl;
57     }
58 
installProgress(pkg::InstallRef aInstall,unsigned int bytes,unsigned int total)59     virtual void installProgress(pkg::InstallRef aInstall, unsigned int bytes, unsigned int total)
60     {
61         size_t percent = (static_cast<size_t>(bytes) * 100) / total;
62         if (percent == _lastPercent) {
63             return;
64         }
65 
66         _lastPercent = percent;
67         cout << percent << "%" << endl;
68     }
69 
finishInstall(pkg::InstallRef aInstall,StatusCode aReason)70     virtual void finishInstall(pkg::InstallRef aInstall, StatusCode aReason)
71     {
72         if (aReason == STATUS_SUCCESS) {
73             cout << "done install of " << aInstall->package()->name() << endl;
74         } else {
75             cerr << "failed install of " << aInstall->package()->name() << endl;
76         }
77     }
78 
79 private:
80     size_t _lastPercent;
81 
82 };
83 
printRating(pkg::Package * pkg,const std::string & aRating,const std::string & aLabel)84 void printRating(pkg::Package* pkg, const std::string& aRating, const std::string& aLabel)
85 {
86     SGPropertyNode* ratings = pkg->properties()->getChild("rating");
87     cout << "\t" << aLabel << ":" << ratings->getIntValue(aRating) << endl;
88 }
89 
printPackageInfo(pkg::Package * pkg)90 void printPackageInfo(pkg::Package* pkg)
91 {
92     cout << "Package:" << pkg->catalog()->id() << "." << pkg->id() << endl;
93     cout << "Revision:" << pkg->revision() << endl;
94     cout << "Name:" << pkg->name() << endl;
95     cout << "Description:" << pkg->description() << endl;
96     cout << "Long description:\n" << pkg->getLocalisedProp("long-description") << endl << endl;
97 
98     if (pkg->properties()->hasChild("author")) {
99         cout << "Authors:" << endl;
100         for (auto author : pkg->properties()->getChildren("author")) {
101             if (author->hasChild("name")) {
102                 cout << "\t" << author->getStringValue("name") << endl;
103 
104             } else {
105                 // simple author structure
106                 cout << "\t" << author->getStringValue() << endl;
107             }
108 
109 
110         }
111 
112         cout << endl;
113     }
114 
115     cout << "Ratings:" << endl;
116     printRating(pkg, "fdm",     "Flight-model    ");
117     printRating(pkg, "cockpit", "Cockpit         ");
118     printRating(pkg, "model",   "3D model        ");
119     printRating(pkg, "systems", "Aircraft systems");
120 }
121 
main(int argc,char ** argv)122 int main(int argc, char** argv)
123 {
124     sglog().setLogLevels( SG_ALL, SG_INFO );
125 
126     HTTP::Client* http = new HTTP::Client();
127 
128     SGPath rootPath = SGPath::fromEnv("SG_PKG_ROOT", Dir::current().path());
129     pkg::Root* root = new pkg::Root(rootPath, "2019.1.1");
130 
131     MyDelegate dlg;
132     root->addDelegate(&dlg);
133 
134     cout << "Package root is:" << rootPath << endl;
135     cout << "have " << root->catalogs().size() << " catalog(s)" << endl;
136 
137     root->setHTTPClient(http);
138 
139     if (!strcmp(argv[1], "add")) {
140         std::string url(argv[2]);
141         pkg::Catalog::createFromUrl(root, url);
142     } else if (!strcmp(argv[1], "refresh")) {
143         root->refresh(true);
144     } else if (!strcmp(argv[1], "install")) {
145         pkg::PackageRef pkg = root->getPackageById(argv[2]);
146         if (!pkg) {
147             cerr << "unknown package:" << argv[2] << endl;
148             return EXIT_FAILURE;
149         }
150 
151         if (pkg->isInstalled()) {
152             cout << "package " << pkg->id() << " is already installed at " << pkg->install()->path() << endl;
153             return EXIT_SUCCESS;
154         }
155 
156         pkg::CatalogRef catalog = pkg->catalog();
157         cout << "Will install:" << pkg->id() << " from " << catalog->id() <<
158                 "(" << catalog->description() << ")" << endl;
159         pkg->install();
160     } else if (!strcmp(argv[1], "uninstall") || !strcmp(argv[1], "remove")) {
161         pkg::PackageRef pkg = root->getPackageById(argv[2]);
162         if (!pkg) {
163             cerr << "unknown package:" << argv[2] << endl;
164             return EXIT_FAILURE;
165         }
166 
167         if (!pkg->isInstalled()) {
168             cerr << "package " << argv[2] << " not installed" << endl;
169             return EXIT_FAILURE;
170         }
171 
172         cout << "Will uninstall:" << pkg->id() << endl;
173         pkg->install()->uninstall();
174     } else if (!strcmp(argv[1], "update-all")) {
175         pkg::PackageList updates = root->packagesNeedingUpdate();
176         for (auto p : updates) {
177             root->scheduleToUpdate(p->install());
178         }
179     } else if (!strcmp(argv[1], "list-updated")) {
180         pkg::PackageList updates = root->packagesNeedingUpdate();
181         if (updates.empty()) {
182             cout << "no packages with updates" << endl;
183             return EXIT_SUCCESS;
184         }
185 
186         cout << updates.size() << " packages have updates" << endl;
187         for (auto p : updates) {
188             cout << "\t" << p->id() << " " << p->getLocalisedProp("name") << endl;
189         }
190     } else if (!strcmp(argv[1], "info")) {
191         pkg::PackageRef pkg = root->getPackageById(argv[2]);
192         if (!pkg) {
193             cerr << "unknown package:" << argv[2] << endl;
194             return EXIT_FAILURE;
195         }
196 
197         printPackageInfo(pkg);
198     } else {
199         cerr << "unknown command:" << argv[1] << endl;
200         return EXIT_FAILURE;
201     }
202 
203     while (http->hasActiveRequests()) {
204         http->update();
205     }
206 
207     return EXIT_SUCCESS;
208 }
209