1# Copyright 2016 The Meson development team
2
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6
7#     http://www.apache.org/licenses/LICENSE-2.0
8
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import os
16import subprocess
17import shutil
18import argparse
19from .. import mlog
20from ..mesonlib import has_path_sep
21from . import destdir_join
22from .gettext import read_linguas
23
24parser = argparse.ArgumentParser()
25parser.add_argument('command')
26parser.add_argument('--id', dest='project_id')
27parser.add_argument('--subdir', dest='subdir')
28parser.add_argument('--installdir', dest='install_dir')
29parser.add_argument('--sources', dest='sources')
30parser.add_argument('--media', dest='media', default='')
31parser.add_argument('--langs', dest='langs', default='')
32parser.add_argument('--symlinks', type=bool, dest='symlinks', default=False)
33
34def build_pot(srcdir, project_id, sources):
35    # Must be relative paths
36    sources = [os.path.join('C', source) for source in sources]
37    outfile = os.path.join(srcdir, project_id + '.pot')
38    subprocess.call(['itstool', '-o', outfile] + sources)
39
40def update_po(srcdir, project_id, langs):
41    potfile = os.path.join(srcdir, project_id + '.pot')
42    for lang in langs:
43        pofile = os.path.join(srcdir, lang, lang + '.po')
44        subprocess.call(['msgmerge', '-q', '-o', pofile, pofile, potfile])
45
46def build_translations(srcdir, blddir, langs):
47    for lang in langs:
48        outdir = os.path.join(blddir, lang)
49        os.makedirs(outdir, exist_ok=True)
50        subprocess.call([
51            'msgfmt', os.path.join(srcdir, lang, lang + '.po'),
52            '-o', os.path.join(outdir, lang + '.gmo')
53        ])
54
55def merge_translations(blddir, sources, langs):
56    for lang in langs:
57        subprocess.call([
58            'itstool', '-m', os.path.join(blddir, lang, lang + '.gmo'),
59            '-o', os.path.join(blddir, lang)
60        ] + sources)
61
62def install_help(srcdir, blddir, sources, media, langs, install_dir, destdir, project_id, symlinks):
63    c_install_dir = os.path.join(install_dir, 'C', project_id)
64    for lang in langs + ['C']:
65        indir = destdir_join(destdir, os.path.join(install_dir, lang, project_id))
66        os.makedirs(indir, exist_ok=True)
67        for source in sources:
68            infile = os.path.join(srcdir if lang == 'C' else blddir, lang, source)
69            outfile = os.path.join(indir, source)
70            mlog.log('Installing %s to %s' % (infile, outfile))
71            shutil.copyfile(infile, outfile)
72            shutil.copystat(infile, outfile)
73        for m in media:
74            infile = os.path.join(srcdir, lang, m)
75            outfile = os.path.join(indir, m)
76            c_infile = os.path.join(srcdir, 'C', m)
77            if not os.path.exists(infile):
78                if not os.path.exists(c_infile):
79                    mlog.warning('Media file "%s" did not exist in C directory' % m)
80                    continue
81                elif symlinks:
82                    srcfile = os.path.join(c_install_dir, m)
83                    mlog.log('Symlinking %s to %s.' % (outfile, srcfile))
84                    if has_path_sep(m):
85                        os.makedirs(os.path.dirname(outfile), exist_ok=True)
86                    try:
87                        try:
88                            os.symlink(srcfile, outfile)
89                        except FileExistsError:
90                            os.remove(outfile)
91                            os.symlink(srcfile, outfile)
92                        continue
93                    except (NotImplementedError, OSError):
94                        mlog.warning('Symlinking not supported, falling back to copying')
95                        infile = c_infile
96                else:
97                    # Lang doesn't have media file so copy it over 'C' one
98                    infile = c_infile
99            mlog.log('Installing %s to %s' % (infile, outfile))
100            if has_path_sep(m):
101                os.makedirs(os.path.dirname(outfile), exist_ok=True)
102            shutil.copyfile(infile, outfile)
103            shutil.copystat(infile, outfile)
104
105def run(args):
106    options = parser.parse_args(args)
107    langs = options.langs.split('@@') if options.langs else []
108    media = options.media.split('@@') if options.media else []
109    sources = options.sources.split('@@')
110    destdir = os.environ.get('DESTDIR', '')
111    src_subdir = os.path.join(os.environ['MESON_SOURCE_ROOT'], options.subdir)
112    build_subdir = os.path.join(os.environ['MESON_BUILD_ROOT'], options.subdir)
113    abs_sources = [os.path.join(src_subdir, 'C', source) for source in sources]
114
115    if not langs:
116        langs = read_linguas(src_subdir)
117
118    if options.command == 'pot':
119        build_pot(src_subdir, options.project_id, sources)
120    elif options.command == 'update-po':
121        build_pot(src_subdir, options.project_id, sources)
122        update_po(src_subdir, options.project_id, langs)
123    elif options.command == 'build':
124        if langs:
125            build_translations(src_subdir, build_subdir, langs)
126    elif options.command == 'install':
127        install_dir = os.path.join(os.environ['MESON_INSTALL_PREFIX'], options.install_dir)
128        if langs:
129            build_translations(src_subdir, build_subdir, langs)
130            merge_translations(build_subdir, abs_sources, langs)
131        install_help(src_subdir, build_subdir, sources, media, langs, install_dir,
132                     destdir, options.project_id, options.symlinks)
133