]> git.mxchange.org Git - simgear.git/blob - simgear/package/Package.cxx
Fix platform check for strerror_r on Mac
[simgear.git] / simgear / package / Package.cxx
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/package/Package.hxx>
19
20 #include <cassert>
21 #include <boost/foreach.hpp>
22 #include <boost/algorithm/string/case_conv.hpp>
23
24 #include <simgear/debug/logstream.hxx> 
25 #include <simgear/structure/exception.hxx>
26
27 #include <simgear/package/Catalog.hxx>
28 #include <simgear/package/Install.hxx>
29 #include <simgear/package/Root.hxx>
30
31 namespace simgear {
32     
33 namespace pkg {
34
35 Package::Package(const SGPropertyNode* aProps, CatalogRef aCatalog) :
36     m_catalog(aCatalog)
37 {
38     initWithProps(aProps);
39 }
40
41 void Package::initWithProps(const SGPropertyNode* aProps)
42 {
43     m_props = const_cast<SGPropertyNode*>(aProps);
44 // cache tag values
45     BOOST_FOREACH(const SGPropertyNode* c, aProps->getChildren("tag")) {
46       std::string t(c->getStringValue());
47       m_tags.insert(boost::to_lower_copy(t));
48     }
49
50     m_id = m_props->getStringValue("id");
51 }
52
53 void Package::updateFromProps(const SGPropertyNode* aProps)
54 {
55     m_tags.clear();
56     initWithProps(aProps);
57 }
58
59 bool Package::matches(const SGPropertyNode* aFilter) const
60 {
61     int nChildren = aFilter->nChildren();
62     for (int i = 0; i < nChildren; i++) {
63         const SGPropertyNode* c = aFilter->getChild(i);
64         const std::string& filter_name = c->getNameString();
65
66         if (strutils::starts_with(filter_name, "rating-")) {
67             int minRating = c->getIntValue();
68             std::string rname = c->getName() + 7;
69             int ourRating = m_props->getChild("rating")->getIntValue(rname, 0);
70             if (ourRating < minRating) {
71                 return false;
72             }
73         }
74         else if (filter_name == "tag") {
75             std::string tag(c->getStringValue());
76             boost::to_lower(tag);
77             if (m_tags.find(tag) == m_tags.end()) {
78                 return false;
79             }
80         }
81         // substring search of name, description
82         else if (filter_name == "name") {
83           std::string n(c->getStringValue());
84           boost::to_lower(n);
85           size_t pos = boost::to_lower_copy(name()).find(n);
86           if (pos == std::string::npos) {
87             return false;
88           }
89         }
90         else if (filter_name == "description") {
91           std::string n(c->getStringValue());
92           boost::to_lower(n);
93           size_t pos = boost::to_lower_copy(description()).find(n);
94           if (pos == std::string::npos) {
95             return false;
96           }
97         }
98         else if (filter_name == "installed") {
99           if (isInstalled() != c->getBoolValue()) {
100             return false;
101           }
102         }
103         else
104           SG_LOG(SG_GENERAL, SG_WARN, "unknown filter term:" << filter_name);
105     } // of filter props iteration
106     
107     return true;
108 }
109
110 bool Package::isInstalled() const
111 {
112     // anything to check for? look for a valid revision file?
113     return pathOnDisk().exists();
114 }
115
116 SGPath Package::pathOnDisk() const
117 {
118     SGPath p(m_catalog->installRoot());
119     p.append("Aircraft");
120     p.append(dirName());
121     return p;
122 }
123
124 InstallRef Package::install()
125 {
126     InstallRef ins = existingInstall();
127     if (ins) {
128         return ins;
129     }
130   
131   // start a new install
132     ins = new Install(this, pathOnDisk());
133     m_catalog->root()->scheduleToUpdate(ins);
134
135     _install_cb(this, ins);
136
137     return ins;
138 }
139
140 InstallRef Package::existingInstall(const InstallCallback& cb) const
141 {
142     InstallRef install;
143     try {
144         install = m_catalog->root()->existingInstallForPackage(const_cast<Package*>(this));
145     } catch (std::exception& ) {
146         return InstallRef();
147     }
148
149   if( cb )
150   {
151     _install_cb.push_back(cb);
152
153     if( install )
154       cb(const_cast<Package*>(this), install);
155   }
156
157   return install;
158 }
159
160 std::string Package::id() const
161 {
162     return m_id;
163 }
164
165 std::string Package::qualifiedId() const
166 {
167     return m_catalog->id() + "." + id();
168 }
169
170 std::string Package::qualifiedVariantId(const unsigned int variantIndex) const
171 {
172     return m_catalog->id() + "." + variants()[variantIndex];
173 }
174
175 std::string Package::md5() const
176 {
177     return m_props->getStringValue("md5");
178 }
179
180 std::string Package::dirName() const
181 {
182     std::string r(m_props->getStringValue("dir"));
183     if (r.empty())
184         throw sg_exception("missing dir property on catalog package entry for " + m_id);
185     return r;
186 }
187
188 unsigned int Package::revision() const
189 {
190     if (!m_props) {
191         return 0;
192     }
193     
194     return m_props->getIntValue("revision");
195 }
196     
197 std::string Package::name() const
198 {
199     return m_props->getStringValue("name");
200 }
201
202 size_t Package::fileSizeBytes() const
203 {
204     return m_props->getIntValue("file-size-bytes");
205 }
206   
207 std::string Package::description() const
208 {
209     return getLocalisedProp("description");
210 }
211
212 string_set Package::tags() const
213 {
214     return m_tags;
215 }
216     
217 SGPropertyNode* Package::properties() const
218 {
219     return m_props.ptr();
220 }
221
222 string_list Package::thumbnailUrls() const
223 {
224     string_list r;
225     if (!m_props) {
226         return r;
227     }
228     
229     BOOST_FOREACH(SGPropertyNode* dl, m_props->getChildren("thumbnail")) {
230         r.push_back(dl->getStringValue());
231     }
232     return r;
233 }
234
235 string_list Package::thumbnails() const
236 {
237     string_list r;
238     if (!m_props) {
239         return r;
240     }
241     
242     BOOST_FOREACH(SGPropertyNode* dl, m_props->getChildren("thumbnail-path")) {
243         r.push_back(dl->getStringValue());
244     }
245     return r;
246 }
247     
248 string_list Package::downloadUrls() const
249 {
250     string_list r;
251     if (!m_props) {
252         return r;
253     }
254     
255     BOOST_FOREACH(SGPropertyNode* dl, m_props->getChildren("url")) {
256         r.push_back(dl->getStringValue());
257     }
258     return r;
259 }
260
261 std::string Package::getLocalisedProp(const std::string& aName) const
262 {
263     return getLocalisedString(m_props, aName.c_str());
264 }
265
266 std::string Package::getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const
267 {
268     std::string locale = m_catalog->root()->getLocale();
269     if (aRoot->hasChild(locale)) {
270         const SGPropertyNode* localeRoot = aRoot->getChild(locale.c_str());
271         if (localeRoot->hasChild(aName)) {
272             return localeRoot->getStringValue(aName);
273         }
274     }
275     
276     return aRoot->getStringValue(aName);
277 }
278
279 PackageList Package::dependencies() const
280 {
281     PackageList result;
282     
283     BOOST_FOREACH(SGPropertyNode* dep, m_props->getChildren("depends")) {
284         std::string depName = dep->getStringValue("id");
285         unsigned int rev = dep->getIntValue("revision", 0);
286         
287     // prefer local hangar package if possible, in case someone does something
288     // silly with naming. Of course flightgear's aircraft search doesn't know
289     // about hangars, so names still need to be unique.
290         PackageRef depPkg = m_catalog->getPackageById(depName);
291         if (!depPkg) {   
292             Root* rt = m_catalog->root();
293             depPkg = rt->getPackageById(depName);
294             if (!depPkg) {
295                 throw sg_exception("Couldn't satisfy dependency of " + id() + " : " + depName);
296             }
297         }
298         
299         if (depPkg->revision() < rev) {
300             throw sg_range_exception("Couldn't find suitable revision of " + depName);
301         }
302     
303     // forbid recursive dependency graphs, we don't need that level
304     // of complexity for aircraft resources
305         assert(depPkg->dependencies() == PackageList());
306         
307         result.push_back(depPkg);
308     }
309     
310     return result;
311 }
312
313 string_list Package::variants() const
314 {
315     string_list result;
316     result.push_back(id());
317
318     BOOST_FOREACH(SGPropertyNode* var, m_props->getChildren("variant")) {
319         result.push_back(var->getStringValue("id"));
320     }
321
322     return result;
323 }
324
325 std::string Package::nameForVariant(const std::string& vid) const
326 {
327     if (vid == id()) {
328         return name();
329     }
330
331     BOOST_FOREACH(SGPropertyNode* var, m_props->getChildren("variant")) {
332         if (vid == var->getStringValue("id")) {
333             return var->getStringValue("name");
334         }
335     }
336
337
338     throw sg_exception("Unknow variant +" + vid + " in package " + id());
339 }
340
341 std::string Package::nameForVariant(const unsigned int vIndex) const
342 {
343     if (vIndex == 0)
344         return name();
345
346     // offset by minus one to allow for index 0 being the primary
347     SGPropertyNode_ptr var = m_props->getChild("variant", vIndex - 1);
348     if (var)
349         return var->getStringValue("name");
350
351     throw sg_exception("Unknow variant in package " + id());
352 }
353
354
355 } // of namespace pkg
356
357 } // of namespace simgear