1 : // -*- mode: c++; tab-width: 4; indent-tabs-mode: t -*-
2 : /* @file
3 : * @author Enrico Zini (enrico) <enrico@enricozini.org>
4 : */
5 :
6 : /*
7 : * libpkg Debtags data provider
8 : *
9 : * Copyright (C) 2003-2007 Enrico Zini <enrico@debian.org>
10 : *
11 : * This program is free software; you can redistribute it and/or modify
12 : * it under the terms of the GNU General Public License as published by
13 : * the Free Software Foundation; either version 2 of the License, or
14 : * (at your option) any later version.
15 : *
16 : * This program is distributed in the hope that it will be useful,
17 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : * GNU General Public License for more details.
20 : *
21 : * You should have received a copy of the GNU General Public License
22 : * along with this program; if not, write to the Free Software
23 : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 : */
25 :
26 : #ifndef EPT_DEBTAGS_DEBTAGS_H
27 : #define EPT_DEBTAGS_DEBTAGS_H
28 :
29 : #include <ept/debtags/tag.h>
30 : #include <ept/debtags/vocabulary.h>
31 : #include <ept/debtags/maint/pkgid.h>
32 :
33 : #include <tagcoll/coll/base.h>
34 : #include <tagcoll/coll/intdiskindex.h>
35 : #include <tagcoll/coll/patched.h>
36 :
37 : namespace ept {
38 : namespace debtags {
39 : class Debtags;
40 : }
41 : }
42 :
43 : namespace tagcoll {
44 : template< typename _, typename _1 > class PatchList;
45 :
46 : namespace coll {
47 :
48 : template<>
49 : struct coll_traits< ept::debtags::Debtags >
50 : {
51 : typedef std::string item_type;
52 : typedef ept::debtags::Tag tag_type;
53 : typedef std::set< ept::debtags::Tag > tagset_type;
54 : typedef std::set< std::string > itemset_type;
55 : };
56 :
57 : }
58 : }
59 :
60 : namespace ept {
61 : namespace debtags {
62 :
63 : /**
64 : * Access the on-disk Debtags tag database.
65 : *
66 : * The database is normally found in /var/lib/debtags.
67 : *
68 : * Tags and Facets are returned as Tag and Facet objects. The objects follow
69 : * the flyweight pattern and access the data contained in the Vocabulary
70 : * instantiated inside Debtags.
71 : *
72 : * It is possible to get a reference to the Vocabulary object using the
73 : * vocabulary() method.
74 : */
75 : class Debtags : public tagcoll::coll::Collection<Debtags>
76 : {
77 : protected:
78 : // Master mmap index container
79 : tagcoll::diskindex::MasterMMap mastermmap;
80 :
81 : // Debtags database
82 : tagcoll::coll::IntDiskIndex m_rocoll;
83 : tagcoll::coll::Patched< tagcoll::coll::IntDiskIndex > m_coll;
84 :
85 : // Package name to ID mapping
86 : PkgId m_pkgid;
87 :
88 : // Tag vocabulary
89 : Vocabulary m_voc;
90 :
91 : // User rc directory to store patches
92 : std::string rcdir;
93 :
94 : // Last modification timestamp of the index
95 : time_t m_timestamp;
96 :
97 84710 : std::string packageByID(int id) const
98 : {
99 84710 : return m_pkgid.byID(id);
100 : }
101 :
102 : template<typename IDS>
103 2 : std::set<std::string> packagesById(const IDS& ids) const
104 : {
105 2 : std::set<std::string> pkgs;
106 130 : for (typename IDS::const_iterator i = ids.begin();
107 : i != ids.end(); ++i)
108 128 : pkgs.insert(packageByID(*i));
109 0 : return pkgs;
110 : }
111 :
112 8 : int idByPackage(const std::string& pkg) const
113 : {
114 8 : return m_pkgid.byName(pkg);
115 : }
116 :
117 : template<typename PKGS>
118 1 : std::set<int> idsByPackages(const PKGS& pkgs) const
119 : {
120 1 : std::set<int> ids;
121 2 : for (typename PKGS::const_iterator i = pkgs.begin();
122 : i != pkgs.end(); ++i)
123 1 : ids.insert(idByPackage(*i));
124 0 : return ids;
125 : }
126 :
127 : public:
128 : typedef tagcoll::coll::Patched< tagcoll::coll::IntDiskIndex > coll_type;
129 : typedef std::pair< std::string, std::set<Tag> > value_type;
130 :
131 : class const_iterator
132 : {
133 : const Debtags& coll;
134 : Debtags::coll_type::const_iterator ci;
135 : mutable const Debtags::value_type* cached_val;
136 :
137 : protected:
138 : const_iterator(const Debtags& coll,
139 63443 : const Debtags::coll_type::const_iterator& ci)
140 63443 : : coll(coll), ci(ci), cached_val(0) {}
141 :
142 : public:
143 63443 : ~const_iterator()
144 : {
145 63443 : if (cached_val)
146 0 : delete cached_val;
147 63443 : }
148 84580 : const Debtags::value_type operator*() const
149 : {
150 84580 : if (cached_val)
151 0 : return *cached_val;
152 :
153 84580 : return make_pair(coll.packageByID(ci->first), coll.vocabulary().tagsByID(ci->second));
154 : }
155 105725 : const Debtags::value_type* operator->() const
156 : {
157 105725 : if (cached_val)
158 42290 : return cached_val;
159 63435 : return cached_val = new Debtags::value_type(*(*this));
160 : }
161 63435 : const_iterator& operator++()
162 : {
163 63435 : ++ci;
164 63435 : if (cached_val)
165 : {
166 63435 : delete cached_val;
167 63435 : cached_val = 0;
168 : }
169 63435 : return *this;
170 : }
171 1 : bool operator==(const const_iterator& iter) const
172 : {
173 1 : return ci == iter.ci;
174 : }
175 63438 : bool operator!=(const const_iterator& iter) const
176 : {
177 63438 : return ci != iter.ci;
178 : }
179 :
180 : friend class Debtags;
181 : };
182 4 : const_iterator begin() const { return const_iterator(*this, m_coll.begin()); }
183 63439 : const_iterator end() const { return const_iterator(*this, m_coll.end()); }
184 :
185 : /**
186 : * Create a new accessor for the on-disk Debtags database
187 : *
188 : * \param editable
189 : * Specifies if recording of modifications should be enabled. If editable
190 : * is true, then the local state directory will be created when the object
191 : * is instantiated.
192 : */
193 : Debtags(bool editable = false);
194 10 : ~Debtags() {}
195 :
196 : /// Get the timestamp of when the index was last updated
197 1 : time_t timestamp() const { return m_timestamp; }
198 :
199 : /// Return true if this data source has data, false if it's empty
200 1 : bool hasData() const { return m_timestamp != 0; }
201 :
202 : coll_type& tagdb() { return m_coll; }
203 : const coll_type& tagdb() const { return m_coll; }
204 : tagcoll::PatchList<std::string, Tag> changes() const;
205 :
206 : #if 0
207 : template<typename ITEMS, typename TAGS>
208 : void insert(const ITEMS& items, const TAGS& tags)
209 : {
210 : for (typename ITEMS::const_iterator i = items.begin();
211 : i != items.end(); ++i)
212 : m_changes.addPatch(Patch(*i, tags, TagSet()));
213 : }
214 :
215 : template<typename ITEMS>
216 : void insert(const ITEMS& items, const wibble::Empty<Tag>& tags)
217 : {
218 : // Nothing to do in this case
219 : }
220 :
221 : /**
222 : * Get the changes that have been applied to this collection
223 : */
224 : const Patches& changes() const { return m_changes; }
225 :
226 : /**
227 : * Throw away all changes previously applied to this collection
228 : */
229 : void resetChanges() { m_changes.clear(); }
230 :
231 : /**
232 : * Set the changes list to a specific patch list
233 : */
234 : void setChanges(const Patches& changes);
235 :
236 : /**
237 : * Add a specific patch list to the changes list
238 : */
239 : void addChanges(const Patches& changes);
240 : #endif
241 :
242 : bool hasTag(const Tag& tag) const { return m_coll.hasTag(tag.id()); }
243 :
244 5 : std::set<Tag> getTagsOfItem(const std::string& item) const
245 : {
246 5 : int id = idByPackage(item);
247 5 : if (id == -1) return std::set<Tag>();
248 4 : return vocabulary().tagsByID(m_coll.getTagsOfItem(id));
249 : }
250 :
251 : template<typename ITEMS>
252 1 : std::set<Tag> getTagsOfItems(const ITEMS& items) const
253 : {
254 1 : return vocabulary().tagsByID(m_coll.getTagsOfItems(idsByPackages(items)));
255 : }
256 :
257 : std::set<std::string> getItemsHavingTag(const Tag& tag) const
258 : {
259 : return packagesById(m_coll.getItemsHavingTag(tag.id()));
260 : }
261 : template<typename TAGS>
262 2 : std::set<std::string> getItemsHavingTags(const TAGS& tags) const
263 : {
264 2 : std::set<int> itags;
265 11 : for (typename TAGS::const_iterator i = tags.begin();
266 : i != tags.end(); ++i)
267 9 : itags.insert(i->id());
268 2 : return packagesById(m_coll.getItemsHavingTags(itags));
269 : }
270 :
271 : #if 0
272 : ItemSet getTaggedItems() const;
273 : #endif
274 1 : std::set<Tag> getAllTags() const
275 : {
276 1 : return vocabulary().tagsByID(m_coll.getAllTags());
277 : }
278 :
279 : /// Access the vocabulary in use
280 27 : Vocabulary& vocabulary() { return m_voc; }
281 : /// Access the vocabulary in use
282 84590 : const Vocabulary& vocabulary() const { return m_voc; }
283 :
284 : /**
285 : * Access the PkgId in use.
286 : *
287 : * \note Future implementations may not rely on a PkgId
288 : */
289 4 : PkgId& pkgid() { return m_pkgid; }
290 : /**
291 : * Access the PkgId in use.
292 : *
293 : * \note Future implementations may not rely on a PkgId
294 : */
295 : const PkgId& pkgid() const { return m_pkgid; }
296 :
297 : int getCardinality(const Tag& tag) const
298 : {
299 : return m_coll.getCardinality(tag.id());
300 : }
301 :
302 2 : void applyChange(const tagcoll::PatchList<std::string, Tag>& change)
303 : {
304 : using namespace tagcoll;
305 2 : PatchList<int, int> intp;
306 4 : for (PatchList<std::string, Tag>::const_iterator i = change.begin();
307 : i != change.end(); ++i)
308 : {
309 2 : Patch<int, int> p(idByPackage(i->first));
310 4 : for (std::set<Tag>::const_iterator j = i->second.added.begin();
311 : j != i->second.added.end(); ++j)
312 2 : p.add(j->id());
313 2 : for (std::set<Tag>::const_iterator j = i->second.removed.begin();
314 : j != i->second.removed.end(); ++j)
315 0 : p.remove(j->id());
316 2 : intp.addPatch(p);
317 : }
318 2 : m_coll.applyChange(intp);
319 2 : }
320 :
321 : #if 0
322 : template<typename OUT>
323 : void output(OUT out) const
324 : {
325 : for (const_iterator i = begin(); i != end(); ++i)
326 : {
327 : *out = *i;
328 : ++out;
329 : }
330 : }
331 : #endif
332 :
333 :
334 :
335 : /**
336 : * Check if the tag database has been created (i.e. if something
337 : * equivalend to debtags update has been run)
338 : */
339 : //static bool hasTagDatabase();
340 :
341 :
342 : /**
343 : * Save in the state storage directory a patch that can be used to turn
344 : * the system database into the collection given
345 : */
346 : void savePatch();
347 :
348 : /**
349 : * Save in the state storage directory a patch to turn the system database
350 : * into the collection given
351 : */
352 : void savePatch(const tagcoll::PatchList<std::string, std::string>& patch);
353 :
354 : /**
355 : * Save in the state storage directory a patch to turn the system database
356 : * into the collection given
357 : */
358 : void savePatch(const tagcoll::PatchList<std::string, Tag>& patch);
359 :
360 : /**
361 : * Send to the central archive a patch that can be used to turn
362 : * the system database into the collection given
363 : */
364 : void sendPatch();
365 :
366 : /**
367 : * Send the given patch to the central archive
368 : */
369 : void sendPatch(const tagcoll::PatchList<std::string, std::string>& patch);
370 :
371 : /**
372 : * Send the given patch to the central archive
373 : */
374 : void sendPatch(const tagcoll::PatchList<std::string, Tag>& patch);
375 :
376 :
377 : /**
378 : * Output the current Debian tags database to a consumer of <std::string, Tag>
379 : *
380 : * \note The collection is sent to 'cons' without merging repeated items
381 : */
382 : template<typename OUT>
383 2 : void outputSystem(const OUT& cons);
384 :
385 : /**
386 : * Output the given tag file to a consumer of <std::string, Tag>
387 : *
388 : * \note The collection is sent to 'cons' without merging repeated items
389 : */
390 : template<typename OUT>
391 : void outputSystem(const std::string& filename, const OUT& out);
392 :
393 : /**
394 : * Output the current Debian tags database, patched with local patch,
395 : * to a Consumer of <std::string, Tag>
396 : *
397 : * \note The collection is sent to 'cons' without merging repeated items
398 : */
399 : template<typename OUT>
400 2 : void outputPatched(const OUT& cons);
401 :
402 : /**
403 : * Output the given tag file, patched with local patch,
404 : * to a Consumer of <std::string, Tag>
405 : *
406 : * \note The collection is sent to 'cons' without merging repeated items
407 : */
408 : template<typename OUT>
409 : void outputPatched(const std::string& filename, const OUT& out);
410 : };
411 :
412 :
413 : }
414 : }
415 :
416 : // vim:set ts=4 sw=4:
417 : #endif
|