summaryrefslogtreecommitdiff
path: root/engine/SCons/Tool/xgettext.py
diff options
context:
space:
mode:
Diffstat (limited to 'engine/SCons/Tool/xgettext.py')
-rw-r--r--engine/SCons/Tool/xgettext.py555
1 files changed, 289 insertions, 266 deletions
diff --git a/engine/SCons/Tool/xgettext.py b/engine/SCons/Tool/xgettext.py
index b05df26..2e2934b 100644
--- a/engine/SCons/Tool/xgettext.py
+++ b/engine/SCons/Tool/xgettext.py
@@ -1,10 +1,10 @@
-""" xgettext tool
+""" xgettext tool
Tool specific initialization of `xgettext` tool.
"""
-# Copyright (c) 2001 - 2016 The SCons Foundation
-#
+# Copyright (c) 2001 - 2017 The SCons Foundation
+#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
@@ -12,10 +12,10 @@ Tool specific initialization of `xgettext` tool.
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
-#
+#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
-#
+#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -24,312 +24,335 @@ Tool specific initialization of `xgettext` tool.
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-__revision__ = "src/engine/SCons/Tool/xgettext.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/xgettext.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+
#############################################################################
class _CmdRunner(object):
- """ Callabe object, which runs shell command storing its stdout and stderr to
- variables. It also provides `strfunction()` method, which shall be used by
- scons Action objects to print command string. """
-
- def __init__( self, command, commandstr = None):
- self.out = None
- self.err = None
- self.status = None
- self.command = command
- self.commandstr = commandstr
-
- def __call__(self, target, source, env):
- import SCons.Action
- import subprocess
- import os
- import sys
- kw = {
- 'stdin' : 'devnull',
- 'stdout' : subprocess.PIPE,
- 'stderr' : subprocess.PIPE,
- 'universal_newlines' : True,
- 'shell' : True
- }
- command = env.subst(self.command, target = target, source = source)
- proc = SCons.Action._subproc(env, command, **kw)
- self.out, self.err = proc.communicate()
- self.status = proc.wait()
- if self.err: sys.stderr.write(unicode(self.err))
- return self.status
-
- def strfunction(self, target, source, env):
- import os
- comstr = self.commandstr
- if env.subst(comstr, target = target, source = source) == "":
- comstr = self.command
- s = env.subst(comstr, target = target, source = source)
- return s
+ """ Callable object, which runs shell command storing its stdout and stderr to
+ variables. It also provides `strfunction()` method, which shall be used by
+ scons Action objects to print command string. """
+
+ def __init__(self, command, commandstr=None):
+ self.out = None
+ self.err = None
+ self.status = None
+ self.command = command
+ self.commandstr = commandstr
+
+ def __call__(self, target, source, env):
+ import SCons.Action
+ import subprocess
+ import os
+ import sys
+ kw = {
+ 'stdin': 'devnull',
+ 'stdout': subprocess.PIPE,
+ 'stderr': subprocess.PIPE,
+ 'universal_newlines': True,
+ 'shell': True
+ }
+ command = env.subst(self.command, target=target, source=source)
+ proc = SCons.Action._subproc(env, command, **kw)
+ self.out, self.err = proc.communicate()
+ self.status = proc.wait()
+ if self.err:
+ sys.stderr.write(unicode(self.err))
+ return self.status
+
+ def strfunction(self, target, source, env):
+ import os
+ comstr = self.commandstr
+ if env.subst(comstr, target=target, source=source) == "":
+ comstr = self.command
+ s = env.subst(comstr, target=target, source=source)
+ return s
+
+
#############################################################################
#############################################################################
def _update_pot_file(target, source, env):
- """ Action function for `POTUpdate` builder """
- import re
- import os
- import SCons.Action
- nop = lambda target, source, env : 0
-
- # Save scons cwd and os cwd (NOTE: they may be different. After the job, we
- # revert each one to its original state).
- save_cwd = env.fs.getcwd()
- save_os_cwd = os.getcwd()
- chdir = target[0].dir
- chdir_str = repr(chdir.get_abspath())
- # Print chdir message (employ SCons.Action.Action for that. It knows better
- # than me how to to this correctly).
- env.Execute(SCons.Action.Action(nop, "Entering " + chdir_str))
- # Go to target's directory and do our job
- env.fs.chdir(chdir, 1) # Go into target's directory
- try:
- cmd = _CmdRunner('$XGETTEXTCOM', '$XGETTEXTCOMSTR')
- action = SCons.Action.Action(cmd, strfunction=cmd.strfunction)
- status = action([ target[0] ], source, env)
- except:
- # Something went wrong.
+ """ Action function for `POTUpdate` builder """
+ import re
+ import os
+ import SCons.Action
+ nop = lambda target, source, env: 0
+
+ # Save scons cwd and os cwd (NOTE: they may be different. After the job, we
+ # revert each one to its original state).
+ save_cwd = env.fs.getcwd()
+ save_os_cwd = os.getcwd()
+ chdir = target[0].dir
+ chdir_str = repr(chdir.get_abspath())
+ # Print chdir message (employ SCons.Action.Action for that. It knows better
+ # than me how to to this correctly).
+ env.Execute(SCons.Action.Action(nop, "Entering " + chdir_str))
+ # Go to target's directory and do our job
+ env.fs.chdir(chdir, 1) # Go into target's directory
+ try:
+ cmd = _CmdRunner('$XGETTEXTCOM', '$XGETTEXTCOMSTR')
+ action = SCons.Action.Action(cmd, strfunction=cmd.strfunction)
+ status = action([target[0]], source, env)
+ except:
+ # Something went wrong.
+ env.Execute(SCons.Action.Action(nop, "Leaving " + chdir_str))
+ # Revert working dirs to previous state and re-throw exception.
+ env.fs.chdir(save_cwd, 0)
+ os.chdir(save_os_cwd)
+ raise
+ # Print chdir message.
env.Execute(SCons.Action.Action(nop, "Leaving " + chdir_str))
- # Revert working dirs to previous state and re-throw exception.
+ # Revert working dirs to previous state.
env.fs.chdir(save_cwd, 0)
os.chdir(save_os_cwd)
- raise
- # Print chdir message.
- env.Execute(SCons.Action.Action(nop, "Leaving " + chdir_str))
- # Revert working dirs to previous state.
- env.fs.chdir(save_cwd, 0)
- os.chdir(save_os_cwd)
- # If the command was not successfull, return error code.
- if status: return status
-
- new_content = cmd.out
-
- if not new_content:
- # When xgettext finds no internationalized messages, no *.pot is created
- # (because we don't want to bother translators with empty POT files).
- needs_update = False
- explain = "no internationalized messages encountered"
- else:
- if target[0].exists():
- # If the file already exists, it's left unaltered unless its messages
- # are outdated (w.r.t. to these recovered by xgettext from sources).
- old_content = target[0].get_text_contents()
- re_cdate = re.compile(r'^"POT-Creation-Date: .*"$[\r\n]?', re.M)
- old_content_nocdate = re.sub(re_cdate,"",old_content)
- new_content_nocdate = re.sub(re_cdate,"",new_content)
- if(old_content_nocdate == new_content_nocdate):
- # Messages are up-to-date
+ # If the command was not successfull, return error code.
+ if status: return status
+
+ new_content = cmd.out
+
+ if not new_content:
+ # When xgettext finds no internationalized messages, no *.pot is created
+ # (because we don't want to bother translators with empty POT files).
needs_update = False
- explain = "messages in file found to be up-to-date"
- else:
- # Messages are outdated
- needs_update = True
- explain = "messages in file were outdated"
+ explain = "no internationalized messages encountered"
else:
- # No POT file found, create new one
- needs_update = True
- explain = "new file"
- if needs_update:
- # Print message employing SCons.Action.Action for that.
- msg = "Writing " + repr(str(target[0])) + " (" + explain + ")"
- env.Execute(SCons.Action.Action(nop, msg))
- f = open(str(target[0]),"w")
- f.write(new_content)
- f.close()
- return 0
- else:
- # Print message employing SCons.Action.Action for that.
- msg = "Not writing " + repr(str(target[0])) + " (" + explain + ")"
- env.Execute(SCons.Action.Action(nop, msg))
- return 0
+ if target[0].exists():
+ # If the file already exists, it's left unaltered unless its messages
+ # are outdated (w.r.t. to these recovered by xgettext from sources).
+ old_content = target[0].get_text_contents()
+ re_cdate = re.compile(r'^"POT-Creation-Date: .*"$[\r\n]?', re.M)
+ old_content_nocdate = re.sub(re_cdate, "", old_content)
+ new_content_nocdate = re.sub(re_cdate, "", new_content)
+ if (old_content_nocdate == new_content_nocdate):
+ # Messages are up-to-date
+ needs_update = False
+ explain = "messages in file found to be up-to-date"
+ else:
+ # Messages are outdated
+ needs_update = True
+ explain = "messages in file were outdated"
+ else:
+ # No POT file found, create new one
+ needs_update = True
+ explain = "new file"
+ if needs_update:
+ # Print message employing SCons.Action.Action for that.
+ msg = "Writing " + repr(str(target[0])) + " (" + explain + ")"
+ env.Execute(SCons.Action.Action(nop, msg))
+ f = open(str(target[0]), "w")
+ f.write(new_content)
+ f.close()
+ return 0
+ else:
+ # Print message employing SCons.Action.Action for that.
+ msg = "Not writing " + repr(str(target[0])) + " (" + explain + ")"
+ env.Execute(SCons.Action.Action(nop, msg))
+ return 0
+
+
#############################################################################
#############################################################################
from SCons.Builder import BuilderBase
+
+
#############################################################################
class _POTBuilder(BuilderBase):
- def _execute(self, env, target, source, *args):
- if not target:
- if env.has_key('POTDOMAIN') and env['POTDOMAIN']:
- domain = env['POTDOMAIN']
- else:
- domain = 'messages'
- target = [ domain ]
- return BuilderBase._execute(self, env, target, source, *args)
+ def _execute(self, env, target, source, *args):
+ if not target:
+ if 'POTDOMAIN' in env and env['POTDOMAIN']:
+ domain = env['POTDOMAIN']
+ else:
+ domain = 'messages'
+ target = [domain]
+ return BuilderBase._execute(self, env, target, source, *args)
+
+
#############################################################################
#############################################################################
-def _scan_xgettext_from_files(target, source, env, files = None, path = None):
- """ Parses `POTFILES.in`-like file and returns list of extracted file names.
- """
- import re
- import SCons.Util
- import SCons.Node.FS
-
- if files is None:
+def _scan_xgettext_from_files(target, source, env, files=None, path=None):
+ """ Parses `POTFILES.in`-like file and returns list of extracted file names.
+ """
+ import re
+ import SCons.Util
+ import SCons.Node.FS
+
+ if files is None:
+ return 0
+ if not SCons.Util.is_List(files):
+ files = [files]
+
+ if path is None:
+ if 'XGETTEXTPATH' in env:
+ path = env['XGETTEXTPATH']
+ else:
+ path = []
+ if not SCons.Util.is_List(path):
+ path = [path]
+
+ path = SCons.Util.flatten(path)
+
+ dirs = ()
+ for p in path:
+ if not isinstance(p, SCons.Node.FS.Base):
+ if SCons.Util.is_String(p):
+ p = env.subst(p, source=source, target=target)
+ p = env.arg2nodes(p, env.fs.Dir)
+ dirs += tuple(p)
+ # cwd is the default search path (when no path is defined by user)
+ if not dirs:
+ dirs = (env.fs.getcwd(),)
+
+ # Parse 'POTFILE.in' files.
+ re_comment = re.compile(r'^#[^\n\r]*$\r?\n?', re.M)
+ re_emptyln = re.compile(r'^[ \t\r]*$\r?\n?', re.M)
+ re_trailws = re.compile(r'[ \t\r]+$')
+ for f in files:
+ # Find files in search path $XGETTEXTPATH
+ if isinstance(f, SCons.Node.FS.Base) and f.rexists():
+ contents = f.get_text_contents()
+ contents = re_comment.sub("", contents)
+ contents = re_emptyln.sub("", contents)
+ contents = re_trailws.sub("", contents)
+ depnames = contents.splitlines()
+ for depname in depnames:
+ depfile = SCons.Node.FS.find_file(depname, dirs)
+ if not depfile:
+ depfile = env.arg2nodes(depname, dirs[0].File)
+ env.Depends(target, depfile)
return 0
- if not SCons.Util.is_List(files):
- files = [ files ]
- if path is None:
- if env.has_key('XGETTEXTPATH'):
- path = env['XGETTEXTPATH']
- else:
- path = []
- if not SCons.Util.is_List(path):
- path = [ path ]
-
- path = SCons.Util.flatten(path)
-
- dirs = ()
- for p in path:
- if not isinstance(p, SCons.Node.FS.Base):
- if SCons.Util.is_String(p):
- p = env.subst(p, source = source, target = target)
- p = env.arg2nodes(p, env.fs.Dir)
- dirs += tuple(p)
- # cwd is the default search path (when no path is defined by user)
- if not dirs:
- dirs = (env.fs.getcwd(),)
-
- # Parse 'POTFILE.in' files.
- re_comment = re.compile(r'^#[^\n\r]*$\r?\n?', re.M)
- re_emptyln = re.compile(r'^[ \t\r]*$\r?\n?', re.M)
- re_trailws = re.compile(r'[ \t\r]+$')
- for f in files:
- # Find files in search path $XGETTEXTPATH
- if isinstance(f, SCons.Node.FS.Base) and f.rexists():
- contents = f.get_text_contents()
- contents = re_comment.sub("", contents)
- contents = re_emptyln.sub("", contents)
- contents = re_trailws.sub("", contents)
- depnames = contents.splitlines()
- for depname in depnames:
- depfile = SCons.Node.FS.find_file(depname, dirs)
- if not depfile:
- depfile = env.arg2nodes(depname, dirs[0].File)
- env.Depends(target, depfile)
- return 0
+
#############################################################################
#############################################################################
def _pot_update_emitter(target, source, env):
- """ Emitter function for `POTUpdate` builder """
- from SCons.Tool.GettextCommon import _POTargetFactory
- import SCons.Util
- import SCons.Node.FS
-
- if env.has_key('XGETTEXTFROM'):
- xfrom = env['XGETTEXTFROM']
- else:
+ """ Emitter function for `POTUpdate` builder """
+ from SCons.Tool.GettextCommon import _POTargetFactory
+ import SCons.Util
+ import SCons.Node.FS
+
+ if 'XGETTEXTFROM' in env:
+ xfrom = env['XGETTEXTFROM']
+ else:
+ return target, source
+ if not SCons.Util.is_List(xfrom):
+ xfrom = [xfrom]
+
+ xfrom = SCons.Util.flatten(xfrom)
+
+ # Prepare list of 'POTFILE.in' files.
+ files = []
+ for xf in xfrom:
+ if not isinstance(xf, SCons.Node.FS.Base):
+ if SCons.Util.is_String(xf):
+ # Interpolate variables in strings
+ xf = env.subst(xf, source=source, target=target)
+ xf = env.arg2nodes(xf)
+ files.extend(xf)
+ if files:
+ env.Depends(target, files)
+ _scan_xgettext_from_files(target, source, env, files)
return target, source
- if not SCons.Util.is_List(xfrom):
- xfrom = [ xfrom ]
-
- xfrom = SCons.Util.flatten(xfrom)
-
- # Prepare list of 'POTFILE.in' files.
- files = []
- for xf in xfrom:
- if not isinstance(xf, SCons.Node.FS.Base):
- if SCons.Util.is_String(xf):
- # Interpolate variables in strings
- xf = env.subst(xf, source = source, target = target)
- xf = env.arg2nodes(xf)
- files.extend(xf)
- if files:
- env.Depends(target, files)
- _scan_xgettext_from_files(target, source, env, files)
- return target, source
+
+
#############################################################################
#############################################################################
from SCons.Environment import _null
+
+
#############################################################################
def _POTUpdateBuilderWrapper(env, target=None, source=_null, **kw):
- return env._POTUpdateBuilder(target, source, **kw)
+ return env._POTUpdateBuilder(target, source, **kw)
+
+
#############################################################################
#############################################################################
def _POTUpdateBuilder(env, **kw):
- """ Creates `POTUpdate` builder object """
- import SCons.Action
- from SCons.Tool.GettextCommon import _POTargetFactory
- kw['action'] = SCons.Action.Action(_update_pot_file, None)
- kw['suffix'] = '$POTSUFFIX'
- kw['target_factory'] = _POTargetFactory(env, alias='$POTUPDATE_ALIAS').File
- kw['emitter'] = _pot_update_emitter
- return _POTBuilder(**kw)
+ """ Creates `POTUpdate` builder object """
+ import SCons.Action
+ from SCons.Tool.GettextCommon import _POTargetFactory
+ kw['action'] = SCons.Action.Action(_update_pot_file, None)
+ kw['suffix'] = '$POTSUFFIX'
+ kw['target_factory'] = _POTargetFactory(env, alias='$POTUPDATE_ALIAS').File
+ kw['emitter'] = _pot_update_emitter
+ return _POTBuilder(**kw)
+
+
#############################################################################
#############################################################################
-def generate(env,**kw):
- """ Generate `xgettext` tool """
- import SCons.Util
- from SCons.Tool.GettextCommon import RPaths, _detect_xgettext
-
- try:
- env['XGETTEXT'] = _detect_xgettext(env)
- except:
- env['XGETTEXT'] = 'xgettext'
- # NOTE: sources="$SOURCES" would work as well. However, we use following
- # construction to convert absolute paths provided by scons onto paths
- # relative to current working dir. Note, that scons expands $SOURCE(S) to
- # absolute paths for sources $SOURCE(s) outside of current subtree (e.g. in
- # "../"). With source=$SOURCE these absolute paths would be written to the
- # resultant *.pot file (and its derived *.po files) as references to lines in
- # source code (e.g. referring lines in *.c files). Such references would be
- # correct (e.g. in poedit) only on machine on which *.pot was generated and
- # would be of no use on other hosts (having a copy of source code located
- # in different place in filesystem).
- sources = '$( ${_concat( "", SOURCES, "", __env__, XgettextRPaths, TARGET' \
- + ', SOURCES)} $)'
-
- # NOTE: the output from $XGETTEXTCOM command must go to stdout, not to a file.
- # This is required by the POTUpdate builder's action.
- xgettextcom = '$XGETTEXT $XGETTEXTFLAGS $_XGETTEXTPATHFLAGS' \
- + ' $_XGETTEXTFROMFLAGS -o - ' + sources
-
- xgettextpathflags = '$( ${_concat( XGETTEXTPATHPREFIX, XGETTEXTPATH' \
- + ', XGETTEXTPATHSUFFIX, __env__, RDirs, TARGET, SOURCES)} $)'
- xgettextfromflags = '$( ${_concat( XGETTEXTFROMPREFIX, XGETTEXTFROM' \
- + ', XGETTEXTFROMSUFFIX, __env__, target=TARGET, source=SOURCES)} $)'
-
- env.SetDefault(
- _XGETTEXTDOMAIN = '${TARGET.filebase}',
- XGETTEXTFLAGS = [ ],
- XGETTEXTCOM = xgettextcom,
- XGETTEXTCOMSTR = '',
- XGETTEXTPATH = [ ],
- XGETTEXTPATHPREFIX = '-D',
- XGETTEXTPATHSUFFIX = '',
- XGETTEXTFROM = None,
- XGETTEXTFROMPREFIX = '-f',
- XGETTEXTFROMSUFFIX = '',
- _XGETTEXTPATHFLAGS = xgettextpathflags,
- _XGETTEXTFROMFLAGS = xgettextfromflags,
- POTSUFFIX = ['.pot'],
- POTUPDATE_ALIAS = 'pot-update',
- XgettextRPaths = RPaths(env)
- )
- env.Append( BUILDERS = {
- '_POTUpdateBuilder' : _POTUpdateBuilder(env)
- } )
- env.AddMethod(_POTUpdateBuilderWrapper, 'POTUpdate')
- env.AlwaysBuild(env.Alias('$POTUPDATE_ALIAS'))
+def generate(env, **kw):
+ """ Generate `xgettext` tool """
+ import SCons.Util
+ from SCons.Tool.GettextCommon import RPaths, _detect_xgettext
+
+ try:
+ env['XGETTEXT'] = _detect_xgettext(env)
+ except:
+ env['XGETTEXT'] = 'xgettext'
+ # NOTE: sources="$SOURCES" would work as well. However, we use following
+ # construction to convert absolute paths provided by scons onto paths
+ # relative to current working dir. Note, that scons expands $SOURCE(S) to
+ # absolute paths for sources $SOURCE(s) outside of current subtree (e.g. in
+ # "../"). With source=$SOURCE these absolute paths would be written to the
+ # resultant *.pot file (and its derived *.po files) as references to lines in
+ # source code (e.g. referring lines in *.c files). Such references would be
+ # correct (e.g. in poedit) only on machine on which *.pot was generated and
+ # would be of no use on other hosts (having a copy of source code located
+ # in different place in filesystem).
+ sources = '$( ${_concat( "", SOURCES, "", __env__, XgettextRPaths, TARGET' \
+ + ', SOURCES)} $)'
+
+ # NOTE: the output from $XGETTEXTCOM command must go to stdout, not to a file.
+ # This is required by the POTUpdate builder's action.
+ xgettextcom = '$XGETTEXT $XGETTEXTFLAGS $_XGETTEXTPATHFLAGS' \
+ + ' $_XGETTEXTFROMFLAGS -o - ' + sources
+
+ xgettextpathflags = '$( ${_concat( XGETTEXTPATHPREFIX, XGETTEXTPATH' \
+ + ', XGETTEXTPATHSUFFIX, __env__, RDirs, TARGET, SOURCES)} $)'
+ xgettextfromflags = '$( ${_concat( XGETTEXTFROMPREFIX, XGETTEXTFROM' \
+ + ', XGETTEXTFROMSUFFIX, __env__, target=TARGET, source=SOURCES)} $)'
+
+ env.SetDefault(
+ _XGETTEXTDOMAIN='${TARGET.filebase}',
+ XGETTEXTFLAGS=[],
+ XGETTEXTCOM=xgettextcom,
+ XGETTEXTCOMSTR='',
+ XGETTEXTPATH=[],
+ XGETTEXTPATHPREFIX='-D',
+ XGETTEXTPATHSUFFIX='',
+ XGETTEXTFROM=None,
+ XGETTEXTFROMPREFIX='-f',
+ XGETTEXTFROMSUFFIX='',
+ _XGETTEXTPATHFLAGS=xgettextpathflags,
+ _XGETTEXTFROMFLAGS=xgettextfromflags,
+ POTSUFFIX=['.pot'],
+ POTUPDATE_ALIAS='pot-update',
+ XgettextRPaths=RPaths(env)
+ )
+ env.Append(BUILDERS={
+ '_POTUpdateBuilder': _POTUpdateBuilder(env)
+ })
+ env.AddMethod(_POTUpdateBuilderWrapper, 'POTUpdate')
+ env.AlwaysBuild(env.Alias('$POTUPDATE_ALIAS'))
+
+
#############################################################################
#############################################################################
def exists(env):
- """ Check, whether the tool exists """
- from SCons.Tool.GettextCommon import _xgettext_exists
- try:
- return _xgettext_exists(env)
- except:
- return False
+ """ Check, whether the tool exists """
+ from SCons.Tool.GettextCommon import _xgettext_exists
+ try:
+ return _xgettext_exists(env)
+ except:
+ return False
+
#############################################################################
# Local Variables: