'Subcommand for extracting messages from source files and generating
a POT file.
:param argv: the command arguments'

def extract(self, argv):

    parser = OptionParser(usage=(self.usage % ('extract', 'dir1    <dir2>    ...')), description=self.commands['extract'])
    parser.add_option('--charset', dest='charset', help='charset    to    use    in    the    output    (default    "%default")')
    parser.add_option('-k', '--keyword', dest='keywords', action='append', help='keywords    to    look    for    in    addition    to    the    defaults.    You    can    specify    multiple    -k    flags    on    the    command    line.')
    parser.add_option('--no-default-keywords', dest='no_default_keywords', action='store_true', help='do    not    include    the    default    keywords')
    parser.add_option('--mapping', '-F', dest='mapping_file', help='path    to    the    extraction    mapping    file')
    parser.add_option('--no-location', dest='no_location', action='store_true', help='do    not    include    location    comments    with    filename    and    line    number')
    parser.add_option('--omit-header', dest='omit_header', action='store_true', help='do    not    include    msgid    ""    entry    in    header')
    parser.add_option('-o', '--output', dest='output', help='path    to    the    output    POT    file')
    parser.add_option('-w', '--width', dest='width', type='int', help='set    output    line    width    (default    76)')
    parser.add_option('--no-wrap', dest='no_wrap', action='store_true', help='do    not    break    long    message    lines,    longer    than    the    output    line    width,    into    several    lines')
    parser.add_option('--sort-output', dest='sort_output', action='store_true', help='generate    sorted    output    (default    False)')
    parser.add_option('--sort-by-file', dest='sort_by_file', action='store_true', help='sort    output    by    file    location    (default    False)')
    parser.add_option('--msgid-bugs-address', dest='msgid_bugs_address', metavar='EMAIL@ADDRESS', help='set    report    address    for    msgid')
    parser.add_option('--copyright-holder', dest='copyright_holder', help='set    copyright    holder    in    output')
    parser.add_option('--project', dest='project', help='set    project    name    in    output')
    parser.add_option('--version', dest='version', help='set    project    version    in    output')
    parser.add_option('--add-comments', '-c', dest='comment_tags', metavar='TAG', action='append', help='place    comment    block    with    TAG    (or    those    preceding    keyword    lines)    in    output    file.    One    TAG    per    argument    call')
    parser.add_option('--strip-comment-tags', '-s', dest='strip_comment_tags', action='store_true', help='Strip    the    comment    tags    from    the    comments.')
    parser.set_defaults(charset='utf-8', keywords=[], no_default_keywords=False, no_location=False, omit_header=False, width=None, no_wrap=False, sort_output=False, sort_by_file=False, comment_tags=[], strip_comment_tags=False)
    (options, args) = parser.parse_args(argv)
    if (not args):
        parser.error('incorrect    number    of    arguments')
    if (options.output not in (None, '-')):
        outfile = open(options.output, 'w')
    else:
        outfile = sys.stdout
    keywords = DEFAULT_KEYWORDS.copy()
    if options.no_default_keywords:
        if (not options.keywords):
            parser.error('you    must    specify    new    keywords    if    you    disable    the    default    ones')
        keywords = {}
    if options.keywords:
        keywords.update(parse_keywords(options.keywords))
    if options.mapping_file:
        fileobj = open(options.mapping_file, 'U')
        try:
            (method_map, options_map) = parse_mapping(fileobj)
        finally:
            fileobj.close()
    else:
        method_map = DEFAULT_MAPPING
        options_map = {}
    if (options.width and options.no_wrap):
        parser.error("'--no-wrap'    and    '--width'    are    mutually    exclusive.")
    elif ((not options.width) and (not options.no_wrap)):
        options.width = 76
    if (options.sort_output and options.sort_by_file):
        parser.error("'--sort-output'    and    '--sort-by-file'    are    mutually    exclusive")
    try:
        catalog = Catalog(project=options.project, version=options.version, msgid_bugs_address=options.msgid_bugs_address, copyright_holder=options.copyright_holder, charset=options.charset)
        for dirname in args:
            if (not os.path.isdir(dirname)):
                parser.error(('%r    is    not    a    directory' % dirname))
            def callback(filename, method, options):
                if (method == 'ignore'):
                    return
                filepath = os.path.normpath(os.path.join(dirname, filename))
                optstr = ''
                if options:
                    optstr = ('    (%s)' % ',    '.join([('%s="%s"' % (k, v)) for (k, v) in options.items()]))
                self.log.info('extracting    messages    from    %s%s', filepath, optstr)
            extracted = extract_from_dir(dirname, method_map, options_map, keywords, options.comment_tags, callback=callback, strip_comment_tags=options.strip_comment_tags)
            for (filename, lineno, message, comments) in extracted:
                filepath = os.path.normpath(os.path.join(dirname, filename))
                catalog.add(message, None, [(filepath, lineno)], auto_comments=comments)
        if (options.output not in (None, '-')):
            self.log.info(('writing    PO    template    file    to    %s' % options.output))
        write_po(outfile, catalog, width=options.width, no_location=options.no_location, omit_header=options.omit_header, sort_output=options.sort_output, sort_by_file=options.sort_by_file)
    finally:
        if options.output:
            outfile.close()
