File indexing completed on 2024-04-21 16:29:21

0001 # -*- coding: UTF-8 -*-
0002 
0003 """
0004 Set elements of the PO header.
0005 
0006 Documented in C{doc/user/sieving.docbook}.
0007 
0008 @author: Chusslove Illich (Часлав Илић) <caslav.ilic@gmx.net>
0009 @license: GPLv3
0010 """
0011 
0012 import time
0013 import re
0014 
0015 from pology import _, n_
0016 from pology.report import report, warning
0017 from pology.resolve import expand_vars
0018 from pology.sieve import SieveError
0019 
0020 
0021 def setup_sieve (p):
0022 
0023     p.set_desc(_("@info sieve discription",
0024     "Set elements of the PO header."
0025     "\n\n"
0026     "Sometimes a header field needs to be modified, added or removed "
0027     "in many catalogs, and this sieve serves that purpose."
0028     "\n\n"
0029     "%%-character in the value is used to expand known variables. "
0030     "Currently these are: %%%(var1)s - name of the catalog. "
0031     "If literal %% is needed (e.g. in plural forms header), "
0032     "it can be escaped as %%%%.",
0033     var1="poname"
0034     ))
0035 
0036     p.add_param("field", str, multival=True,
0037                 metavar=_("@info sieve parameter value placeholder", 
0038                           "FIELD:VALUE"),
0039                 desc=_("@info sieve parameter discription",
0040     "Set a header field to the given value. "
0041     "This parameter can be repeated, to set several fields in single run."
0042     ))
0043     p.add_param("create", bool, defval=False,
0044                 desc=_("@info sieve parameter discription",
0045     "Add the field if not present "
0046     "(by default the field value is set only if the field already exists "
0047     "in the header)."
0048     ))
0049     p.add_param("after", str,
0050                 metavar=_("@info sieve parameter value placeholder", "FIELD"),
0051                 desc=_("@info sieve parameter discription",
0052     "When the new field is being added, add it after this field. "
0053     "If such field does not exist, the new field is added as the last one."
0054     ))
0055     p.add_param("before", str,
0056                 metavar=_("@info sieve parameter value placeholder", "FIELD"),
0057                 desc=_("@info sieve parameter discription",
0058     "When the new field is being added, add it before this field. "
0059     "If such field does not exist, the new field is added as the last one."
0060     ))
0061     p.add_param("reorder", bool, defval=False,
0062                 desc=_("@info sieve parameter discription",
0063     "If the field to be set is present, but not in the order implied by "
0064     "'%(par1)s' and '%(par2)s' parameters, reinsert it accordingly.",
0065     par1="after", par2="before"
0066     ))
0067     p.add_param("remove", str, multival=True,
0068                 metavar=_("@info sieve parameter value placeholder", "FIELD"),
0069                 desc=_("@info sieve parameter discription",
0070     "Remove the field."
0071     ))
0072     p.add_param("removerx", str, multival=True,
0073                 metavar=_("@info sieve parameter value placeholder", "REGEX"),
0074                 desc=_("@info sieve parameter discription",
0075     "Remove all fields matching the regular expression. "
0076     "Matching is not case-sensitive."
0077     ))
0078     p.add_param("title", str, multival=True,
0079                 metavar=_("@info sieve parameter value placeholder", "VALUE"),
0080                 desc=_("@info sieve parameter discription",
0081     "Set title comment to the given value."
0082     "Can be repeated to set several title lines. "
0083     "All existing title lines are removed before setting the new ones."
0084     ))
0085     p.add_param("rmtitle", bool, defval=False,
0086                 desc=_("@info sieve parameter discription",
0087     "Remove title comments."
0088     ))
0089     p.add_param("copyright", str,
0090                 metavar=_("@info sieve parameter value placeholder", "VALUE"),
0091                 desc=_("@info sieve parameter discription",
0092     "Set copyright comment to the given value."
0093     ))
0094     p.add_param("rmcopyright", bool, defval=False,
0095                 desc=_("@info sieve parameter discription",
0096     "Remove the copyright comment."
0097     ))
0098     p.add_param("license", str,
0099                 metavar=_("@info sieve parameter value placeholder", "VALUE"),
0100                 desc=_("@info sieve parameter discription",
0101     "Set license comment to the given value."
0102     ))
0103     p.add_param("rmlicense", bool, defval=False,
0104                 desc=_("@info sieve parameter discription",
0105     "Remove the license comment."
0106     ))
0107     p.add_param("author", str, multival=True,
0108                 metavar=_("@info sieve parameter value placeholder", "VALUE"),
0109                 desc=_("@info sieve parameter discription",
0110     "Set author comment to the given value. "
0111     "Can be repeated to set several authors. "
0112     "All existing authors are removed before setting the new ones."
0113     ))
0114     p.add_param("rmauthor", bool, defval=False,
0115                 desc=_("@info sieve parameter discription",
0116     "Remove author comments."
0117     ))
0118     p.add_param("comment", str, multival=True,
0119                 metavar=_("@info sieve parameter value placeholder", "VALUE"),
0120                 desc=_("@info sieve parameter discription",
0121     "Set free comment to the given value. "
0122     "Can be repeated to set several free comment lines. "
0123     "All existing comment lines are removed before setting the new ones."
0124     ))
0125     p.add_param("rmcomment", bool, defval=False,
0126                 desc=_("@info sieve parameter discription",
0127     "Remove free comments."
0128     ))
0129     p.add_param("rmallcomm", bool, defval=False,
0130                 desc=_("@info sieve parameter discription",
0131     "Remove all header comments."
0132     ))
0133 
0134 
0135 class Sieve (object):
0136 
0137     def __init__ (self, params):
0138 
0139         # Parse field setting specifications.
0140         self.fields_values = []
0141         for field_value_str in (params.field or []):
0142             field_value = field_value_str.split(":", 1)
0143             if len(field_value) != 2:
0144                 raise SieveError(
0145                     _("@info",
0146                       "Invalid specification '%(spec)s' "
0147                       "of header field and value.",
0148                       spec=field_value_str))
0149             self.fields_values.append(field_value)
0150 
0151         # Set fields in reverse, so that 'after' and 'before' parameters
0152         # are followed by the order of appearance of fields in command line.
0153         if params.after or params.before:
0154             self.fields_values.reverse()
0155 
0156         # Prepare matching for field removal.
0157         if params.removerx is not None:
0158             rxs = []
0159             for rxstr in params.removerx:
0160                 try:
0161                     rx = re.compile(rxstr, re.U|re.I)
0162                 except:
0163                     raise SieveError(
0164                         _("@info",
0165                           "Invalid regular expression '%(regex)s' "
0166                           "for removing fields.",
0167                           regex=rxstr))
0168                 rxs.append(rx)
0169             params.removerx = rxs
0170 
0171         # Check validity of comment values.
0172         for title in (params.title or []):
0173             if re.search(r"copyright|©|\(C\)|license|<.*?@.*?>",
0174                          title, re.I|re.U):
0175                 raise SieveError(
0176                     _("@info",
0177                       "Invalid value '%(val)s' for title comment "
0178                       "(it contains some elements appropriate "
0179                       "for other types of comments).",
0180                       val=title))
0181         if params.copyright is not None:
0182             if not re.search(r"copyright|©|\(C\)", params.copyright, re.I|re.U):
0183                 raise SieveError(
0184                     _("@info",
0185                       "Invalid value '%(val)s' for copyright comment "
0186                       "(missing the word 'copyright'?).",
0187                       val=params.copyright))
0188         if params.license is not None:
0189             if not re.search(r"license", params.license, re.I):
0190                 raise SieveError(
0191                     _("@info",
0192                       "Invalid value '%(val)s' for license comment "
0193                       "(missing the word 'license'?).",
0194                       val=params.license))
0195         for author in (params.author or []):
0196             if not re.search(r"<.*?@.*?>", author):
0197                 raise SieveError(
0198                     _("@info",
0199                       "Invalid value '%(val)s' for author comment "
0200                       "(missing the email address?).",
0201                       val=author))
0202         self.p = params
0203 
0204 
0205     def process_header (self, hdr, cat):
0206 
0207         pvars = {"poname" : cat.name}
0208 
0209         for rmname in self.p.remove or []:
0210             hdr.remove_field(rmname)
0211         for rmrx in self.p.removerx or []:
0212             to_remove = set()
0213             for name, value in hdr.field:
0214                 if name not in to_remove and rmrx.search(name):
0215                     to_remove.add(name)
0216             for name in to_remove:
0217                 hdr.remove_field(name)
0218 
0219         for field, value in self.fields_values:
0220             if self.p.create or hdr.select_fields(field):
0221                 hdr.set_field(field, expand_vars(value, pvars),
0222                               after=self.p.after, before=self.p.before,
0223                               reorder=self.p.reorder)
0224 
0225         if self.p.rmtitle or self.p.rmallcomm:
0226             hdr.title[:] = []
0227         if self.p.title is not None:
0228             hdr.title[:] = [expand_vars(x, pvars) for x in self.p.title]
0229         if self.p.rmcopyright or self.p.rmallcomm:
0230             hdr.copyright = None
0231         if self.p.copyright is not None:
0232             hdr.copyright = expand_vars(self.p.copyright, pvars)
0233         if self.p.rmlicense or self.p.rmallcomm:
0234             hdr.license = None
0235         if self.p.license is not None:
0236             hdr.license = expand_vars(self.p.license, pvars)
0237         if self.p.rmauthor or self.p.rmallcomm:
0238             hdr.author[:] = []
0239         if self.p.author is not None:
0240             hdr.author[:] = [expand_vars(x, pvars) for x in self.p.author]
0241         if self.p.rmcomment or self.p.rmallcomm:
0242             hdr.comment[:] = []
0243         if self.p.comment is not None:
0244             hdr.comment[:] = [expand_vars(x, pvars) for x in self.p.comment]
0245