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