This file is indexed.

/usr/share/pyshared/translate/convert/convert.py is in translate-toolkit 1.10.0-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2004-2006 Zuza Software Foundation
#
# This file is part of translate.
#
# translate is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# translate is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.

"""Handles converting of files between formats (used by
:mod:`translate.convert` tools)."""

import os.path
try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO

from translate.misc import optrecurse
# don't import optparse ourselves, get the version from optrecurse
optparse = optrecurse.optparse


class ConvertOptionParser(optrecurse.RecursiveOptionParser, object):
    """A specialized Option Parser for convertor tools..."""

    def __init__(self, formats, usetemplates=False, usepots=False,
                 allowmissingtemplate=False, description=None):
        """construct the specialized Option Parser"""
        optrecurse.RecursiveOptionParser.__init__(self, formats, usetemplates,
                                                  allowmissingtemplate=allowmissingtemplate,
                                                  description=description)
        self.usepots = usepots
        self.setpotoption()
        self.set_usage()

    def add_fuzzy_option(self, default=False):
        """Adds an option to include / exclude fuzzy translations."""
        fuzzyhelp = "use translations marked fuzzy"
        nofuzzyhelp = "don't use translations marked fuzzy"
        if default:
            fuzzyhelp += " (default)"
        else:
            nofuzzyhelp += " (default)"
        self.add_option("", "--fuzzy", dest="includefuzzy",
                        action="store_true", default=default, help=fuzzyhelp)
        self.add_option("", "--nofuzzy", dest="includefuzzy",
                        action="store_false", default=default, help=nofuzzyhelp)
        self.passthrough.append("includefuzzy")

    def add_duplicates_option(self, default="msgctxt"):
        """Adds an option to say what to do with duplicate strings."""
        self.add_option(
            "", "--duplicates", dest="duplicatestyle", default=default,
            type="choice", choices=["msgctxt", "merge"],
            help="what to do with duplicate strings (identical source text): merge, msgctxt (default: '%s')" % \
                 default,
            metavar="DUPLICATESTYLE"
        )
        self.passthrough.append("duplicatestyle")

    def add_multifile_option(self, default="single"):
        """Adds an option to say how to split the po/pot files."""
        self.add_option(
            "", "--multifile",
            dest="multifilestyle", default=default,
            type="choice", choices=["single", "toplevel", "onefile"],
            help="how to split po/pot files (single, toplevel or onefile)",
            metavar="MULTIFILESTYLE"
        )
        self.passthrough.append("multifilestyle")

    def potifyformat(self, fileformat):
        """Converts a .po to a .pot where required."""
        if fileformat is None:
            return fileformat
        elif fileformat == "po":
            return "pot"
        elif fileformat.endswith(os.extsep + "po"):
            return fileformat + "t"
        else:
            return fileformat

    def getformathelp(self, formats):
        """Make a nice help string for describing formats..."""
        # include implicit pot options...
        helpformats = []
        for fileformat in formats:
            helpformats.append(fileformat)
            potformat = self.potifyformat(fileformat)
            if potformat != fileformat:
                helpformats.append(potformat)
        return super(ConvertOptionParser, self).getformathelp(helpformats)

    def filterinputformats(self, options):
        """Filters input formats, processing relevant switches in options."""
        if self.usepots and options.pot:
            return [self.potifyformat(inputformat) for inputformat in self.inputformats]
        else:
            return self.inputformats

    def filteroutputoptions(self, options):
        """Filters output options, processing relevant switches in options."""
        if self.usepots and options.pot:
            outputoptions = {}
            for (inputformat, templateformat), (outputformat, convertor) in self.outputoptions.iteritems():
                inputformat = self.potifyformat(inputformat)
                templateformat = self.potifyformat(templateformat)
                outputformat = self.potifyformat(outputformat)
                outputoptions[(inputformat, templateformat)] = (outputformat, convertor)
            return outputoptions
        else:
            return self.outputoptions

    def setpotoption(self):
        """Sets the ``-P``/``--pot`` option depending on input/output
        formats etc."""
        if self.usepots:
            potoption = optparse.Option(
                "-P", "--pot",
                action="store_true", dest="pot", default=False,
                help="output PO Templates (.pot) rather than PO files (.po)"
            )
            self.define_option(potoption)

    def verifyoptions(self, options):
        """Verifies that the options are valid (required options are
        present, etc)."""
        pass

    def run(self, argv=None):
        """Parses the command line options and runs the conversion."""
        (options, args) = self.parse_args(argv)
        options.inputformats = self.filterinputformats(options)
        options.outputoptions = self.filteroutputoptions(options)
        self.usepsyco(options)
        try:
            self.verifyoptions(options)
        except Exception, e:
            self.error(str(e))
        self.recursiveprocess(options)


def copyinput(inputfile, outputfile, templatefile, **kwargs):
    """Copies the input file to the output file."""
    outputfile.write(inputfile.read())
    return True


def copytemplate(inputfile, outputfile, templatefile, **kwargs):
    """Copies the template file to the output file."""
    outputfile.write(templatefile.read())
    return True


class Replacer:
    """An object that knows how to replace strings in files."""

    def __init__(self, searchstring, replacestring):
        self.searchstring = searchstring
        self.replacestring = replacestring

    def doreplace(self, text):
        """actually replace the text"""
        if self.searchstring is not None and self.replacestring is not None:
            return text.replace(self.searchstring, self.replacestring)
        else:
            return text

    def searchreplaceinput(self, inputfile, outputfile,
                           templatefile, **kwargs):
        """copies the input file to the output file, searching and replacing"""
        outputfile.write(self.doreplace(inputfile.read()))
        return True

    def searchreplacetemplate(self, inputfile, outputfile,
                              templatefile, **kwargs):
        """Copies the template file to the output file, searching and
        replacing."""
        outputfile.write(self.doreplace(templatefile.read()))
        return True

# archive files need to know how to:
# - openarchive: creates an archive object for the archivefilename
#   * requires a constructor that takes the filename
# - iterarchivefile: iterate through the names in the archivefile
#   * requires the default iterator to do this
# - archivefileexists: check if a given pathname exists inside the archivefile
#   * uses the in operator - requires __contains__ (or will use __iter__
#     by default)
# - openarchiveinputfile: returns an open input file from the archive, given
#   the path
#   * requires an archivefile.openinputfile method that takes the pathname
# - openarchiveoutputfile: returns an open output file from the archive, given
#   the path
#   * requires an archivefile.openoutputfile method that takes the pathname


class ArchiveConvertOptionParser(ConvertOptionParser):
    """ConvertOptionParser that can handle recursing into single archive files.

    ``archiveformats`` maps extension to class. If the extension doesn't
    matter, it can be None.

    If the extension is only valid for input/output/template, it can be
    given as ``(extension, filepurpose)``."""

    def __init__(self, formats, usetemplates=False, usepots=False,
                 description=None, archiveformats=None):
        if archiveformats is None:
            self.archiveformats = {}
        else:
            self.archiveformats = archiveformats
        self.archiveoptions = {}
        ConvertOptionParser.__init__(self, formats, usetemplates, usepots,
                                     description=description)

    def setarchiveoptions(self, **kwargs):
        """Allows setting options that will always be passed to openarchive."""
        self.archiveoptions = kwargs

    def isrecursive(self, fileoption, filepurpose='input'):
        """Checks if **fileoption** is a recursive file."""
        if self.isarchive(fileoption, filepurpose):
            return True
        return super(ArchiveConvertOptionParser, self).isrecursive(fileoption,
                                                                   filepurpose)

    def isarchive(self, fileoption, filepurpose='input'):
        """Returns whether the file option is an archive file."""
        if not isinstance(fileoption, (str, unicode)):
            return False
        mustexist = (filepurpose != 'output')
        if mustexist and not os.path.isfile(fileoption):
            return False
        fileext = self.splitext(fileoption)[1]
        # if None is in the archive formats, then treat all non-directory
        # inputs as archives
        return self.getarchiveclass(fileext, filepurpose, os.path.isdir(fileoption)) is not None

    def getarchiveclass(self, fileext, filepurpose, isdir=False):
        """Returns the archiveclass for the given fileext and filepurpose"""
        archiveclass = self.archiveformats.get(fileext, None)
        if archiveclass is not None:
            return archiveclass
        archiveclass = self.archiveformats.get((fileext, filepurpose), None)
        if archiveclass is not None:
            return archiveclass
        if not isdir:
            archiveclass = self.archiveformats.get(None, None)
            if archiveclass is not None:
                return archiveclass
            archiveclass = self.archiveformats.get((None, filepurpose), None)
            if archiveclass is not None:
                return archiveclass
        return None

    def openarchive(self, archivefilename, filepurpose, **kwargs):
        """Creates an archive object for the given file."""
        archiveext = self.splitext(archivefilename)[1]
        archiveclass = self.getarchiveclass(archiveext, filepurpose,
                                            os.path.isdir(archivefilename))
        archiveoptions = self.archiveoptions.copy()
        archiveoptions.update(kwargs)
        return archiveclass(archivefilename, **archiveoptions)

    def recurseinputfiles(self, options):
        """Recurse through archive file / directories and return files
        to be converted."""
        if self.isarchive(options.input, 'input'):
            options.inputarchive = self.openarchive(options.input, 'input')
            return self.recursearchivefiles(options)
        else:
            return super(ArchiveConvertOptionParser, self).recurseinputfiles(options)

    def recursearchivefiles(self, options):
        """Recurse through archive files and convert files."""
        inputfiles = []
        for inputpath in options.inputarchive:
            if self.isexcluded(options, inputpath):
                continue
            top, name = os.path.split(inputpath)
            if not self.isvalidinputname(options, name):
                continue
            inputfiles.append(inputpath)
        return inputfiles

    def openinputfile(self, options, fullinputpath):
        """Opens the input file."""
        if self.isarchive(options.input, 'input'):
            return options.inputarchive.openinputfile(fullinputpath)
        else:
            return super(ArchiveConvertOptionParser, self).openinputfile(options, fullinputpath)

    def getfullinputpath(self, options, inputpath):
        """Gets the absolute path to an input file."""
        if self.isarchive(options.input, 'input'):
            return inputpath
        else:
            return os.path.join(options.input, inputpath)

    def opentemplatefile(self, options, fulltemplatepath):
        """Opens the template file (if required)."""
        if fulltemplatepath is not None:
            if (options.recursivetemplate and
                self.isarchive(options.template, 'template')):
                # TODO: deal with different names in input/template archives
                if fulltemplatepath in options.templatearchive:
                    return options.templatearchive.openinputfile(fulltemplatepath)
                else:
                    self.warning("missing template file %s" % fulltemplatepath)
        return super(ArchiveConvertOptionParser, self).opentemplatefile(options, fulltemplatepath)

    def getfulltemplatepath(self, options, templatepath):
        """Gets the absolute path to a template file."""
        if templatepath is not None and self.usetemplates and options.template:
            if self.isarchive(options.template, 'template'):
                return templatepath
            elif not options.recursivetemplate:
                return templatepath
            else:
                return os.path.join(options.template, templatepath)
        else:
            return None

    def templateexists(self, options, templatepath):
        """Returns whether the given template exists..."""
        if templatepath is not None:
            if self.isarchive(options.template, 'template'):
                # TODO: deal with different names in input/template archives
                return templatepath in options.templatearchive
        return super(ArchiveConvertOptionParser, self).templateexists(options, templatepath)

    def getfulloutputpath(self, options, outputpath):
        """Gets the absolute path to an output file."""
        if self.isarchive(options.output, 'output'):
            return outputpath
        elif options.recursiveoutput and options.output:
            return os.path.join(options.output, outputpath)
        else:
            return outputpath

    def checkoutputsubdir(self, options, subdir):
        """Checks to see if subdir under ``options.output`` needs to be
        created, creates if neccessary."""
        if not self.isarchive(options.output, 'output'):
            super(ArchiveConvertOptionParser, self).checkoutputsubdir(options, subdir)

    def openoutputfile(self, options, fulloutputpath):
        """Opens the output file."""
        if self.isarchive(options.output, 'output'):
            outputstream = options.outputarchive.openoutputfile(fulloutputpath)
            if outputstream is None:
                self.warning("Could not find where to put %s in output archive; writing to tmp" % fulloutputpath)
                return StringIO()
            return outputstream
        else:
            return super(ArchiveConvertOptionParser, self).openoutputfile(options, fulloutputpath)

    def inittemplatearchive(self, options):
        """Opens the ``templatearchive`` if not already open."""
        if not self.usetemplates:
            return
        if (options.template and
            self.isarchive(options.template, 'template') and
            not hasattr(options, "templatearchive")):
            options.templatearchive = self.openarchive(options.template,
                                                       'template')

    def initoutputarchive(self, options):
        """Creates an outputarchive if required."""
        if options.output and self.isarchive(options.output, 'output'):
            options.outputarchive = self.openarchive(options.output, 'output',
                                                     mode="w")

    def recursiveprocess(self, options):
        """Recurse through directories and convert files."""
        if hasattr(options, "multifilestyle"):
            self.setarchiveoptions(multifilestyle=options.multifilestyle)
            for filetype in ("input", "output", "template"):
                allowoption = "allowrecursive%s" % filetype
                if (options.multifilestyle == "onefile" and
                    getattr(options, allowoption, True)):
                    setattr(options, allowoption, False)
        self.inittemplatearchive(options)
        self.initoutputarchive(options)
        return super(ArchiveConvertOptionParser, self).recursiveprocess(options)

    def processfile(self, fileprocessor, options, fullinputpath,
                    fulloutputpath, fulltemplatepath):
        """Run an invidividual conversion."""
        if self.isarchive(options.output, 'output'):
            inputfile = self.openinputfile(options, fullinputpath)
            # TODO: handle writing back to same archive as input/template
            templatefile = self.opentemplatefile(options, fulltemplatepath)
            outputfile = self.openoutputfile(options, fulloutputpath)
            passthroughoptions = self.getpassthroughoptions(options)
            if fileprocessor(inputfile, outputfile, templatefile,
                             **passthroughoptions):
                if not outputfile.isatty():
                    outputfile.close()
                return True
            else:
                if fulloutputpath and os.path.isfile(fulloutputpath):
                    outputfile.close()
                    os.unlink(fulloutputpath)
                return False
        else:
            return super(ArchiveConvertOptionParser,
                        self).processfile(fileprocessor, options,
                                          fullinputpath, fulloutputpath,
                                          fulltemplatepath)


def main(argv=None):
    parser = ArchiveConvertOptionParser({}, description=__doc__)
    parser.run(argv)