source: trunk/debathena/third/schroot/bin/csbuild/csbuild-debian-changes.h @ 24167

Revision 24167, 24.2 KB checked in by broder, 15 years ago (diff)
Import schroot upstream into subversion.
Line 
1/* Copyright © 2005-2007  Roger Leigh <rleigh@debian.org>
2 *
3 * schroot is free software: you can redistribute it and/or modify it
4 * under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * schroot is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 * 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, see
15 * <http://www.gnu.org/licenses/>.
16 *
17 *********************************************************************/
18
19#ifndef CSBUILD_DEBIAN_CHANGES_H
20#define CSBUILD_DEBIAN_CHANGES_H
21
22#include <sbuild/sbuild-i18n.h>
23#include <sbuild/sbuild-log.h>
24#include <sbuild/sbuild-parse-error.h>
25#include <sbuild/sbuild-parse-value.h>
26#include <sbuild/sbuild-types.h>
27#include <sbuild/sbuild-tr1types.h>
28#include <sbuild/sbuild-util.h>
29
30#include <cassert>
31#include <map>
32#include <string>
33#include <sstream>
34
35#include <boost/format.hpp>
36
37namespace csbuild
38{
39
40  /**
41   * Debian changes file parser.  This class is a generic parser for
42   * the file format used in Debian changes files for binary and
43   * source uploads (.changes and .dsc files).
44   */
45  class debian_changes
46  {
47  private:
48    typedef std::string key_type;
49    typedef std::vector<std::string> value_type;
50    typedef unsigned int size_type;
51
52    /// Key-value-line tuple.
53    typedef std::tr1::tuple<key_type,value_type,size_type>
54    item_type;
55
56    /// Map between key name and key-value-comment tuple.
57    typedef std::map<key_type,item_type> item_map_type;
58
59  public:
60    /// Configuration parameter priority.
61    enum priority
62      {
63        PRIORITY_OPTIONAL,   ///< The parameter is optional.
64        PRIORITY_REQUIRED,   ///< The parameter is required.
65        PRIORITY_DISALLOWED, ///< The parameter is not allowed in this context.
66        PRIORITY_DEPRECATED, ///< The parameter is deprecated, but functional.
67        PRIORITY_OBSOLETE    ///< The parameter is obsolete, and not functional.
68      };
69
70    /// Error codes.
71    enum error_code
72      {
73        BAD_FILE,          ///< The file to parse couldn't be opened.
74        DEPRECATED_KEY,    ///< The key is deprecated.
75        DEPRECATED_KEY_NL, ///< The key is deprecated (no line specified).
76        DISALLOWED_KEY,    ///< The key is not allowed.
77        DISALLOWED_KEY_NL, ///< The key is not allowed (no line specified).
78        DUPLICATE_KEY,     ///< The key is a duplicate.
79        INVALID_LINE,      ///< The line is invalid.
80        MISSING_KEY,       ///< The key is missing.
81        MISSING_KEY_NL,    ///< The key is missing (no line specified).
82        NO_KEY,            ///< No key was specified.
83        OBSOLETE_KEY,      ///< The key is obsolete.
84        OBSOLETE_KEY_NL,   ///< The key is obsolete (no line specified).
85        PASSTHROUGH_K,    ///< Pass through exception with key.
86        PASSTHROUGH_LK    ///< Pass through exception with line and key.
87      };
88
89    /// Exception type.
90    typedef sbuild::parse_error<error_code> error;
91
92    /// The constructor.
93    debian_changes ();
94
95    /**
96     * The constructor.
97     *
98     * @param file the file to load the configuration from.
99     */
100    debian_changes (std::string const& file);
101
102    /**
103     * The constructor.
104     *
105     * @param stream the stream to load the configuration from.
106     */
107    debian_changes (std::istream& stream);
108
109    /// The destructor.
110    virtual ~debian_changes ();
111
112    /**
113     * Get a list of keys.
114     * @returns a list of keys.
115     */
116    sbuild::string_list
117    get_keys () const;
118
119    /**
120     * Check if a key exists.
121     *
122     * @param key the key to check for.
123     * @returns true if the key exists, otherwise false.
124     */
125    bool
126    has_key (key_type const& key) const;
127
128    /**
129     * Get a key line number.
130     *
131     * @param key the key to find.
132     * @returns the line number, or 0 if not available.
133     */
134    size_type
135    get_line (key_type const& key) const;
136
137    /**
138     * Get a key value.
139     *
140     * @param key the key to get.
141     * @param value the value to store the key's value in.  This must
142     * be settable from an istream and be copyable.
143     * @returns true if the key was found, otherwise false (in which
144     * case value will be unchanged).
145     */
146    template <typename T>
147    bool
148    get_value (key_type const& key,
149               T&              value) const
150    {
151      sbuild::log_debug(sbuild::DEBUG_INFO)
152        << "Getting debian_changes key=" << key << std::endl;
153      const item_type *found_item = find_item(key);
154      if (found_item)
155        {
156          value_type const& strval(std::tr1::get<1>(*found_item));
157          try
158            {
159              sbuild::parse_value(strval, value);
160              return true;
161            }
162          catch (sbuild::parse_value_error const& e)
163            {
164              size_type line = get_line(key);
165              if (line)
166                {
167                  error ep(line, key, PASSTHROUGH_LK, e);
168                  log_exception_warning(ep);
169                }
170              else
171                {
172                  error ep(key, PASSTHROUGH_K, e);
173                  log_exception_warning(ep);
174                }
175              return false;
176            }
177        }
178      sbuild::log_debug(sbuild::DEBUG_NOTICE)
179        << "key not found" << std::endl;
180      return false;
181    }
182
183    /**
184     * Get a key value.  If the value does not exist, is deprecated or
185     * obsolete, warn appropriately.
186     *
187     * @param key the key to get.
188     * @param priority the priority of the option.
189     * @param value the value to store the key's value in.  This must
190     * be settable from an istream and be copyable.
191     * @returns true if the key was found, otherwise false (in which
192     * case value will be unchanged).
193     */
194    template <typename T>
195    bool
196    get_value (key_type const& key,
197               priority        priority,
198               T&              value) const
199    {
200      bool status = get_value(key, value);
201      check_priority(key, priority, status);
202      return status;
203    }
204
205    /**
206     * Get a key value.
207     *
208     * @param key the key to get.
209     * @param value the value to store the key's value in.
210     * @returns true if the key was found, otherwise false (in which
211     * case value will be unchanged).
212     */
213    bool
214    get_value (key_type const& key,
215               value_type&     value) const;
216
217    /**
218     * Get a key value.  If the value does not exist, is deprecated or
219     * obsolete, warn appropriately.
220     *
221     * @param key the key to get.
222     * @param priority the priority of the option.
223     * @param value the value to store the key's value in.
224     * @returns true if the key was found, otherwise false (in which
225     * case value will be unchanged).
226     */
227    bool
228    get_value (key_type const& key,
229               priority        priority,
230               value_type&     value) const;
231
232    /**
233     * Get a key value as a list.
234     *
235     * @param key the key to get.  Note that if the key contains
236     * multiple lines, each line will be split using the separator.
237     * @param container the container to store the key's value in.
238     * The value type must be settable from an istream and be
239     * copyable.  The list must be a container with a standard insert
240     * method.
241     * @param separator the characters to separate the values.
242     * @returns true if the key was found, otherwise false (in which
243     * case value will be undefined).
244     */
245    template <typename C>
246    bool
247    get_list_value (key_type const&    key,
248                    C&                 container,
249                    std::string const& separator) const
250    {
251      value_type item_value;
252      if (get_value(key, item_value))
253        {
254          for (value_type::const_iterator vpos = item_value.begin();
255               vpos != item_value.end();
256               ++vpos)
257            {
258              sbuild::string_list items =
259                sbuild::split_string(*vpos, std::string(1, separator));
260              for (sbuild::string_list::const_iterator pos = items.begin();
261                   pos != items.end();
262                   ++pos
263                   )
264                {
265                  typename C::value_type tmp;
266
267                  try
268                    {
269                      sbuild::parse_value(*pos, tmp);
270                    }
271                  catch (sbuild::parse_value_error const& e)
272                    {
273                      size_type line = get_line(key);
274                      if (line)
275                        {
276                          error ep(line, key, PASSTHROUGH_LK, e);
277                          log_exception_warning(ep);
278                        }
279                      else
280                        {
281                          error ep(key, PASSTHROUGH_K, e);
282                          log_exception_warning(ep);
283                        }
284                      return false;
285                    }
286
287                  container.push_back(tmp);
288                }
289            }
290          return true;
291        }
292      return false;
293    }
294
295    /**
296     * Get a key value as a list.  If the value does not exist, is
297     * deprecated or obsolete, warn appropriately.
298     *
299     * @param key the key to get.
300     * @param priority the priority of the option.
301     * @param container the container to store the key's value in.
302     * The value type must be settable from an istream and be
303     * copyable.  The list must be a container with a standard insert
304     * method.
305     * @returns true if the key was found, otherwise false (in which
306     * case value will be undefined).
307     */
308    template <typename C>
309    bool
310    get_list_value (key_type const& key,
311                    priority        priority,
312                    C&              container) const
313    {
314      bool status = get_list_value(key, container);
315      check_priority(key, priority, status);
316      return status;
317    }
318
319    /**
320     * Set a key value.
321     *
322     * @param key the key to set.
323     * @param value the value to get the key's value from.  This must
324     * allow output to an ostream.
325     */
326    template <typename T>
327    void
328    set_value (key_type const& key,
329               T const&        value)
330    {
331      set_value(key, value, 0);
332    }
333
334    /**
335     * Set a key value.
336     *
337     * @param key the key to set.
338     * @param value the value to get the key's value from.  This must
339     * allow output to an ostream.
340     * @param line the line number in the input file, or 0 otherwise.
341     */
342    template <typename T>
343    void
344    set_value (key_type const& key,
345               T const&        value,
346               size_type       line)
347    {
348      std::ostringstream os;
349      os.imbue(std::locale::classic());
350      os << std::boolalpha << value;
351      value_type val;
352      val.push_back(os.str());
353
354      item_map_type::iterator pos = items.find(key);
355      if (pos != items.end())
356        items.erase(pos);
357      items.insert
358        (item_map_type::value_type(key,
359                                   item_type(key, val, line)));
360    }
361
362    /**
363     * Set a key value.
364     *
365     * @param key the key to set.
366     * @param value the value to get the key's value from.
367     */
368    void
369    set_value (key_type const&   key,
370               value_type const& value)
371    {
372      set_value(key, value, 0);
373    }
374
375    /**
376     * Set a key value.
377     *
378     * @param key the key to set.
379     * @param value the value to get the key's value from.
380     * @param line the line number in the input file, or 0 otherwise.
381     */
382    void
383    set_value (key_type const&   key,
384               value_type const& value,
385               size_type         line);
386
387    /**
388     * Set a key value from a list.
389     *
390     * @param key the key to set.
391     * @param begin an iterator referring to the start of the
392     * list. The value type must allow output to an ostream.
393     * @param end an iterator referring to the end of the list.
394     */
395    template <typename I>
396    void
397    set_list_value (key_type const& key,
398                    I               begin,
399                    I               end)
400    {
401      set_list_value (key, begin, end, 0);
402    }
403
404    /**
405     * Set a key value from a list.
406     *
407     * @param key the key to set.
408     * @param begin an iterator referring to the start of the
409     * list. The value type must allow output to an ostream.
410     * @param end an iterator referring to the end of the list.
411     * @param separator the characters to separate the values.
412     * @param line the line number in the input file, or 0 otherwise.
413     */
414    template <typename I>
415    void
416    set_list_value (key_type const&    key,
417                    I                  begin,
418                    I                  end,
419                    std::string const& separator,
420                    size_type          line)
421    {
422      std::string strval;
423
424      for (I pos = begin; pos != end; ++ pos)
425        {
426          std::ostringstream os;
427          os.imbue(std::locale::classic());
428          os << std::boolalpha << *pos;
429          if (os)
430            {
431              strval += os.str();
432              if (pos + 1 != end)
433                strval += separator;
434            }
435        }
436
437      set_value (key, strval, line);
438    }
439
440    /**
441     * Remove a key.
442     *
443     * @param key the key to remove.
444     */
445    void
446    remove_key (key_type const& key);
447
448    /**
449     * Add a debian_changes to the debian_changes.
450     *
451     * @param rhs the debian_changes to add.
452     * @returns the modified debian_changes.
453     */
454    debian_changes&
455    operator += (debian_changes const& rhs);
456
457    /**
458     * Add a debian_changes to the debian_changes.
459     *
460     * @param lhs the debian_changes to add to.
461     * @param rhs the values to add.
462     * @returns the new debian_changes.
463     */
464    friend debian_changes
465    operator + (debian_changes const& lhs,
466                debian_changes const& rhs);
467
468    /**
469     * debian_changes initialisation from an istream.
470     *
471     * @param stream the stream to input from.
472     * @param dc the debian_changes to set.
473     * @returns the stream.
474     */
475    template <class charT, class traits>
476    friend
477    std::basic_istream<charT,traits>&
478    operator >> (std::basic_istream<charT,traits>& stream,
479                 debian_changes&                   dc)
480    {
481      debian_changes tmp;
482      size_t linecount = 0;
483      std::string line;
484      std::string key;
485      std::string value;
486
487      while (std::getline(stream, line))
488      {
489        linecount++;
490
491        if (line.length() == 0)
492          {
493            // Empty line; do nothing.
494          }
495        else // Item
496          {
497            std::string::size_type pos = line.find_first_of('=');
498            if (pos == std::string::npos)
499              throw error(linecount, INVALID_LINE, line);
500            if (pos == 0)
501              throw error(linecount, NO_KEY, line);
502            key = line.substr(0, pos);
503            if (pos == line.length() - 1)
504              value = "";
505            else
506              value = line.substr(pos + 1);
507
508            // Insert item
509            if (tmp.has_key(key))
510              throw error(linecount, DUPLICATE_KEY, key);
511            else
512              tmp.set_value(key, value, linecount);
513          }
514      }
515
516      dc += tmp;
517
518      return stream;
519    }
520
521    /**
522     * debian_changes output to an ostream.
523     *
524     * @param stream the stream to output to.
525     * @param dc the debian_changes to output.
526     * @returns the stream.
527     */
528    template <class charT, class traits>
529    friend
530    std::basic_ostream<charT,traits>&
531    operator << (std::basic_ostream<charT,traits>& stream,
532                 debian_changes const&             dc)
533    {
534      size_type group_count = 0;
535
536      for (item_map_type::const_iterator it = dc.items.begin();
537           it != dc.items.end();
538           ++it)
539        {
540          item_type const& item = it->second;
541          key_type const& key(std::tr1::get<0>(item));
542          value_type const& value(std::tr1::get<1>(item));
543
544          stream << key << '=' << value << '\n';
545        }
546
547      return stream;
548    }
549
550  private:
551    /**
552     * Find a key by its name.
553     *
554     * @param key the key to find
555     * @returns the key, or 0 if not found.
556     */
557    const item_type *
558    find_item (key_type const& key) const;
559
560    /**
561     * Find a key by its name.
562     *
563     * @param key the key to find
564     * @returns the key, or 0 if not found.
565     */
566    item_type *
567    find_item (key_type const& key);
568
569    /**
570     * Check if a key is missing or present when not permitted.
571     *
572     * @param key the key to get.
573     * @param priority the key priority.
574     * @param valid true if key exists, false if not existing.
575     */
576    void
577    check_priority (key_type const& key,
578                    priority        priority,
579                    bool            valid) const;
580
581    /// The top-level items.
582    item_map_type items;
583
584  public:
585    /**
586     * Set a key value from an object method return value.  This is
587     * the same as calling set_value directly, but handles exceptions
588     * being thrown by the object method, which are turned into error
589     * exceptions.
590     *
591     * @param object the object to use.
592     * @param method the object method to call.
593     * @param debian_changes the debian_changes to use.
594     * @param key the key to set.
595     */
596    template<class C, typename T>
597    static void
598    set_object_value (C const&                        object,
599                      T                         (C::* method)() const,
600                      debian_changes&                 debian_changes,
601                      debian_changes::key_type const& key)
602    {
603      try
604        {
605          debian_changes.set_value(key, (object.*method)());
606        }
607      catch (std::runtime_error const& e)
608        {
609          throw error(key, PASSTHROUGH_K, e);
610        }
611    }
612
613    /**
614     * Set a key value from an object method return value reference.
615     * This is the same as calling set_value directly, but handles
616     * exceptions being thrown by the object method, which are turned
617     * into error exceptions.
618     *
619     * @param object the object to use.
620     * @param method the object method to call.
621     * @param debian_changes the debian_changes to use.
622     * @param key the key to set.
623     */
624    template<class C, typename T>
625    static void
626    set_object_value (C const&                        object,
627                      T const&                  (C::* method)() const,
628                      debian_changes&                 debian_changes,
629                      debian_changes::key_type const& key)
630    {
631      try
632        {
633          debian_changes.set_value(key, (object.*method)());
634        }
635      catch (std::runtime_error const& e)
636        {
637          throw error(key, PASSTHROUGH_K, e);
638        }
639    }
640
641    /**
642     * Set a key list value from an object method return value.  The
643     * method must return a container with begin() and end() methods
644     * which return forward iterators.  This is the same as calling
645     * set_list_value directly, but handles exceptions being thrown by
646     * the object method, which are turned into error exceptions.
647     *
648     * @param object the object to use.
649     * @param method the object method to call.
650     * @param debian_changes the debian_changes to use.
651     * @param key the key to set.
652     */
653    template<class C, typename T>
654    static void
655    set_object_list_value (C const&                        object,
656                           T                         (C::* method)() const,
657                           debian_changes&                 debian_changes,
658                           debian_changes::key_type const& key)
659    {
660      try
661        {
662          debian_changes.set_list_value(key,
663                                 (object.*method)().begin(),
664                                 (object.*method)().end());
665        }
666      catch (std::runtime_error const& e)
667        {
668          throw error(key, PASSTHROUGH_K, e);
669        }
670    }
671
672    /**
673     * Set a key list value from an object method return value.  The
674     * method must return a container reference with begin() and end()
675     * methods which return forward iterators.  This is the same as
676     * calling set_list_value directly, but handles exceptions being
677     * thrown by the object method, which are turned into error
678     * exceptions.
679     *
680     * @param object the object to use.
681     * @param method the object method to call.
682     * @param debian_changes the debian_changes to use.
683     * @param key the key to set.
684     */
685    template<class C, typename T>
686    static void
687    set_object_list_value (C const&                        object,
688                           T const&                  (C::* method)() const,
689                           debian_changes&                 debian_changes,
690                           debian_changes::key_type const& key)
691    {
692      try
693        {
694          debian_changes.set_list_value(key,
695                                 (object.*method)().begin(),
696                                 (object.*method)().end());
697        }
698      catch (std::runtime_error const& e)
699        {
700          throw error(key, PASSTHROUGH_K, e);
701        }
702    }
703
704    /**
705     * Get a key value and set it in an object using an object method.
706     * This is the same as calling get_value directly, but handles
707     * exceptions being thrown by the object method, and
708     * deserialisation errors, which are turned into error exceptions
709     * pointing to the key and line number in the input file.
710     *
711     * @param object the object to use.
712     * @param method the object method to call.
713     * @param debian_changes the debian_changes to use.
714     * @param key the key to set.
715     * @param priority the key priority.
716     */
717    template<class C, typename T>
718    static void
719    get_object_value (C&                              object,
720                      void                      (C::* method)(T param),
721                      debian_changes const&           debian_changes,
722                      debian_changes::key_type const& key,
723                      debian_changes::priority        priority)
724    {
725      try
726        {
727          T value;
728          if (debian_changes.get_value(key, priority, value))
729            (object.*method)(value);
730        }
731      catch (std::runtime_error const& e)
732        {
733          size_type line = debian_changes.get_line(key);
734          if (line)
735            throw error(line, key, PASSTHROUGH_LK, e);
736          else
737            throw error(key, PASSTHROUGH_K, e);
738        }
739    }
740
741    /**
742     * Get a key value and set it by reference in an object using an
743     * object method.  This is the same as calling get_value directly,
744     * but handles exceptions being thrown by the object method, and
745     * deserialisation errors, which are turned into error exceptions
746     * pointing to the key and line number in the input file.
747     *
748     * @param object the object to use.
749     * @param method the object method to call.
750     * @param debian_changes the debian_changes to use.
751     * @param key the key to set.
752     * @param priority the key priority.
753     */
754    template<class C, typename T>
755    static void
756    get_object_value (C&                              object,
757                      void                      (C::* method)(T const& param),
758                      debian_changes const&           debian_changes,
759                      debian_changes::key_type const& key,
760                      debian_changes::priority        priority)
761    {
762      try
763        {
764          T value;
765          if (debian_changes.get_value(key, priority, value))
766            (object.*method)(value);
767        }
768      catch (std::runtime_error const& e)
769        {
770          size_type line = debian_changes.get_line(key);
771          if (line)
772            throw error(line, key, PASSTHROUGH_LK, e);
773          else
774            throw error(key, PASSTHROUGH_K, e);
775        }
776    }
777
778    /**
779     * Get a key list value and set it in an object using an object
780     * method.  This is the same as calling get_list_value directly,
781     * but handles exceptions being thrown by the object method, and
782     * deserialisation errors, which are turned into error exceptions
783     * pointing to the key and line number in the input file.
784     *
785     * @param object the object to use.
786     * @param method the object method to call.
787     * @param debian_changes the debian_changes to use.
788     * @param key the key to set.
789     * @param priority the key priority.
790     */
791    template<class C, typename T>
792    static void
793    get_object_list_value (C&                              object,
794                           void                      (C::* method)(T param),
795                           debian_changes const&           debian_changes,
796                           debian_changes::key_type const& key,
797                           debian_changes::priority        priority)
798    {
799      try
800        {
801          T value;
802          if (debian_changes.get_list_value(key, priority, value))
803            (object.*method)(value);
804        }
805      catch (std::runtime_error const& e)
806        {
807          size_type line = debian_changes.get_line(key);
808          if (line)
809            throw error(line, key, PASSTHROUGH_LK, e);
810          else
811            throw error(key, PASSTHROUGH_K, e);
812          throw error(debian_changes.get_line(key),
813                      key, e);
814        }
815    }
816
817    /**
818     * Get a key list value and set it by reference in an object using
819     * an object method.  This is the same as calling get_list_value
820     * directly, but handles exceptions being thrown by the object
821     * method, and deserialisation errors, which are turned into error
822     * exceptions pointing to the key and line number in the
823     * input file.
824     *
825     * @param object the object to use.
826     * @param method the object method to call.
827     * @param debian_changes the debian_changes to use.
828     * @param key the key to set.
829     * @param priority the key priority.
830     */
831    template<class C, typename T>
832    static void
833    get_object_list_value (C&                              object,
834                           void                      (C::* method)(T const& param),
835                           debian_changes const&           debian_changes,
836                           debian_changes::key_type const& key,
837                           debian_changes::priority        priority)
838    {
839      try
840        {
841          T value;
842          if (debian_changes.get_list_value(key, priority, value))
843            (object.*method)(value);
844        }
845      catch (std::runtime_error const& e)
846        {
847          size_type line = debian_changes.get_line(key);
848          if (line)
849            throw error(line, key, PASSTHROUGH_LK, e);
850          else
851            throw error(key, PASSTHROUGH_K, e);
852          throw error(debian_changes.get_line(key),
853                      key, e);
854        }
855    }
856  };
857
858}
859
860#endif /* CSBUILD_DEBIAN_CHANGES_H */
861
862/*
863 * Local Variables:
864 * mode:C++
865 * End:
866 */
Note: See TracBrowser for help on using the repository browser.