]> git.mxchange.org Git - simgear.git/blob - simgear/package/Catalog.cxx
Package dependencies.
[simgear.git] / simgear / package / Catalog.cxx
1
2
3 #include <simgear/package/Catalog.hxx>
4
5 #include <boost/foreach.hpp>
6 #include <algorithm>
7 #include <fstream>
8 #include <cstring>
9
10 #include <simgear/debug/logstream.hxx>
11 #include <simgear/props/props_io.hxx>
12 #include <simgear/io/HTTPRequest.hxx>
13 #include <simgear/io/HTTPClient.hxx>
14 #include <simgear/misc/sg_dir.hxx>
15 #include <simgear/structure/exception.hxx>
16 #include <simgear/package/Package.hxx>
17 #include <simgear/package/Root.hxx>
18 #include <simgear/package/Install.hxx>
19
20 namespace simgear {
21     
22 namespace pkg {
23
24 CatalogList static_catalogs;
25
26 //////////////////////////////////////////////////////////////////////////////
27
28 class Catalog::Downloader : public HTTP::Request
29 {
30 public:
31     Downloader(Catalog* aOwner, const std::string& aUrl) :
32         HTTP::Request(aUrl),
33         m_owner(aOwner)
34     {        
35     }
36     
37 protected:
38     virtual void responseHeadersComplete()
39     {
40         
41     }
42     
43     virtual void gotBodyData(const char* s, int n)
44     {
45         m_buffer += std::string(s, n);
46     }
47     
48     virtual void responseComplete()
49     {        
50         if (responseCode() != 200) {
51             SG_LOG(SG_GENERAL, SG_ALERT, "catalog download failure:" << m_owner->url());
52             m_owner->refreshComplete(false);
53             return;
54         }
55         
56         SGPropertyNode* props = new SGPropertyNode;
57         
58         try {
59             readProperties(m_buffer.data(), m_buffer.size(), props);
60             m_owner->parseProps(props);
61         } catch (sg_exception& e) {
62             SG_LOG(SG_GENERAL, SG_ALERT, "catalog parse failure:" << m_owner->url());
63             m_owner->refreshComplete(false);
64             return;
65         }
66         
67         // cache the catalog data, now we have a valid install root
68         Dir d(m_owner->installRoot());
69         SGPath p = d.file("catalog.xml");
70
71         std::ofstream f(p.c_str(), std::ios::out | std::ios::trunc);
72         f.write(m_buffer.data(), m_buffer.size());
73         f.close();
74         
75         time(&m_owner->m_retrievedTime);
76         m_owner->writeTimestamp();
77         m_owner->refreshComplete(true);
78     }
79     
80 private:
81     Catalog* m_owner;  
82     std::string m_buffer;
83 };
84
85 //////////////////////////////////////////////////////////////////////////////
86
87 CatalogList Catalog::allCatalogs()
88 {
89     return static_catalogs;
90 }
91
92 Catalog::Catalog(Root *aRoot) :
93     m_root(aRoot),
94     m_retrievedTime(0)
95 {
96     static_catalogs.push_back(this);
97 }
98
99 Catalog::~Catalog()
100 {
101     CatalogList::iterator it = std::find(static_catalogs.begin(), static_catalogs.end(), this);
102     static_catalogs.erase(it);
103 }
104
105 Catalog* Catalog::createFromUrl(Root* aRoot, const std::string& aUrl)
106 {
107     Catalog* c = new Catalog(aRoot);
108     Downloader* dl = new Downloader(c, aUrl);
109     aRoot->getHTTPClient()->makeRequest(dl);
110     
111     return c;
112 }
113     
114 Catalog* Catalog::createFromPath(Root* aRoot, const SGPath& aPath)
115 {
116     SGPath xml = aPath;
117     xml.append("catalog.xml");
118     if (!xml.exists()) {
119         return NULL;
120     }
121     
122     SGPropertyNode_ptr props;
123     try {
124         props = new SGPropertyNode;
125         readProperties(xml.str(), props);
126     } catch (sg_exception& e) {
127         return NULL;    
128     }
129     
130     Catalog* c = new Catalog(aRoot);
131     c->m_installRoot = aPath;
132     c->parseProps(props);
133     c->parseTimestamp();
134     
135     return c;
136 }
137
138 PackageList
139 Catalog::packagesMatching(const SGPropertyNode* aFilter) const
140 {
141     PackageList r;
142     BOOST_FOREACH(Package* p, m_packages) {
143         if (p->matches(aFilter)) {
144             r.push_back(p);
145         }
146     }
147     return r;
148 }
149
150 PackageList
151 Catalog::packagesNeedingUpdate() const
152 {
153     PackageList r;
154     BOOST_FOREACH(Package* p, m_packages) {
155         if (!p->isInstalled()) {
156             continue;
157         }
158         
159         if (p->install()->hasUpdate()) {
160             r.push_back(p);
161         }
162     }
163     return r;
164 }
165
166 void Catalog::refresh()
167 {
168     Downloader* dl = new Downloader(this, url());
169     m_root->getHTTPClient()->makeRequest(dl);
170     m_root->catalogRefreshBegin(this);
171 }
172
173 void Catalog::parseProps(const SGPropertyNode* aProps)
174 {
175     // copy everything except package children?
176     m_props = new SGPropertyNode;
177     
178     int nChildren = aProps->nChildren();
179     for (int i = 0; i < nChildren; i++) {
180         const SGPropertyNode* pkgProps = aProps->getChild(i);
181         if (strcmp(pkgProps->getName(), "package") == 0) {
182             Package* p = new Package(pkgProps, this);
183             m_packages.push_back(p);   
184         } else {
185             SGPropertyNode* c = m_props->getChild(pkgProps->getName(), pkgProps->getIndex(), true);
186             copyProperties(pkgProps, c);
187         }
188     } // of children iteration
189     
190     if (m_installRoot.isNull()) {
191         m_installRoot = m_root->path();
192         m_installRoot.append(id());
193         
194         Dir d(m_installRoot);
195         d.create(0755);
196     }
197 }
198
199 Package* Catalog::getPackageById(const std::string& aId) const
200 {
201     BOOST_FOREACH(Package* p, m_packages) {
202         if (p->id() == aId) {
203             return p;
204         }
205     }
206     
207     return NULL; // not found
208 }
209
210 std::string Catalog::id() const
211 {
212     return m_props->getStringValue("id");
213 }
214
215 std::string Catalog::url() const
216 {
217     return m_props->getStringValue("url");
218 }
219
220 std::string Catalog::description() const
221 {
222     return getLocalisedString(m_props, "description");
223 }
224     
225 SGPropertyNode* Catalog::properties() const
226 {
227     return m_props.ptr();
228 }
229
230 void Catalog::parseTimestamp()
231 {
232     SGPath timestampFile = m_installRoot;
233     timestampFile.append(".timestamp");
234     std::ifstream f(timestampFile.c_str(), std::ios::in);
235     f >> m_retrievedTime;
236 }
237
238 void Catalog::writeTimestamp()
239 {
240     SGPath timestampFile = m_installRoot;
241     timestampFile.append(".timestamp");
242     std::ofstream f(timestampFile.c_str(), std::ios::out | std::ios::trunc);
243     f << m_retrievedTime << std::endl;
244 }
245
246 unsigned int Catalog::ageInSeconds() const
247 {
248     time_t now;
249     time(&now);
250     int diff = ::difftime(now, m_retrievedTime);
251     return (diff < 0) ? 0 : diff;
252 }
253
254 std::string Catalog::getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const
255 {
256     if (aRoot->hasChild(m_root->getLocale())) {
257         const SGPropertyNode* localeRoot = aRoot->getChild(m_root->getLocale().c_str());
258         if (localeRoot->hasChild(aName)) {
259             return localeRoot->getStringValue(aName);
260         }
261     }
262     
263     return aRoot->getStringValue(aName);
264 }
265
266 void Catalog::refreshComplete(bool aSuccess)
267 {
268     m_root->catalogRefreshComplete(this, aSuccess);
269 }
270
271
272 } // of namespace pkg
273
274 } // of namespace simgear