diff --git a/src/ReportBase/_CommandLineReport.py b/src/ReportBase/_CommandLineReport.py index afe7f8b84..29ef63b48 100644 --- a/src/ReportBase/_CommandLineReport.py +++ b/src/ReportBase/_CommandLineReport.py @@ -371,21 +371,26 @@ class CommandLineReport(object): opt = self.options_help[key] # Make the output nicer to read, assume that tab has 8 spaces tabs = '\t' if len(key) < 10 else '\t'*2 - print " %s%s%s (%s)" % (key, tabs, opt[1], opt[0]) + optmsg = " %s%s%s (%s)" % (key, tabs, opt[1], opt[0]) + print optmsg.encode(sys.getfilesystemencoding()) else: - print " %s" % key + optmsg = " %s" % key + print optmsg.encode(sys.getfilesystemencoding()) print " Use 'show=option' to see description and acceptable values" elif self.show in self.options_help: opt = self.options_help[self.show] tabs = '\t' if len(self.show) < 10 else '\t'*2 - print ' %s%s%s%s' % (self.show, tabs, opt[0], opt[1]) + optmsg = ' %s%s%s%s' % (self.show, tabs, opt[0], opt[1]) + print optmsg.encode(sys.getfilesystemencoding()) print " Available values are:" vals = opt[2] if isinstance(vals, (list, tuple)): for val in vals: - print " %s" % val + optmsg = " %s" % val + print optmsg.encode(sys.getfilesystemencoding()) else: - print " %s" % opt[2] + optmsg = " %s" % opt[2] + print optmsg.encode(sys.getfilesystemencoding()) else: #there was a show option given, but the option is invalid diff --git a/src/cli/arghandler.py b/src/cli/arghandler.py index 8525e1e90..bfe89b767 100644 --- a/src/cli/arghandler.py +++ b/src/cli/arghandler.py @@ -94,7 +94,9 @@ class ArgHandler(object): if self.errorfunc: self.errorfunc(string) else: - print string + # Need to convert to str before printing + # For non latin characters in Windows path/file/user names + print string.encode(sys.getfilesystemencoding()) #------------------------------------------------------------------------- # Argument parser: sorts out given arguments @@ -115,8 +117,8 @@ class ArgHandler(object): """ if value is None: return None + value = Utils.get_unicode_path_from_env_var(value) db_path = self.__deduce_db_path(value) - if db_path: # We have a potential database path. # Check if it is good. @@ -134,6 +136,9 @@ class ArgHandler(object): Handle the "-i" or "--import" option. Only Files supported by a plugin can be imported, so not Family Trees. """ + # Need to convert path/filename to unicode before openingh + # For non latin characters in Windows path/file/user names + value = Utils.get_unicode_path_from_env_var(value) fname = value fullpath = os.path.abspath(os.path.expanduser(fname)) if not os.path.exists(fullpath): @@ -168,6 +173,9 @@ class ArgHandler(object): """ if self.gui: return + # Need to covert path/filename to unicode before openingh + # For non latin characters in Windows path/file/user names + value = Utils.get_unicode_path_from_env_var(value) fname = value fullpath = os.path.abspath(os.path.expanduser(fname)) if os.path.exists(fullpath): @@ -176,8 +184,9 @@ class ArgHandler(object): {'name' : fullpath}) answer = None while not answer: - answer = raw_input(_('OK to overwrite? (yes/no) ')) - if answer.upper() in ('Y', 'YES', _('YES')): + answer = raw_input(_('OK to overwrite? (yes/no) ') \ + .encode(sys.getfilesystemencoding())) + if answer.upper() in ('Y', 'YES', _('YES').upper()): self.__error( _("Will overwrite the existing file: %s") % fullpath) else: @@ -310,7 +319,11 @@ class ArgHandler(object): self.cl_action(action, options_str) for expt in self.exports: - print "Exporting: file %s, format %s." % expt + # Need to convert path/filename to str before printing + # For non latin characters in Windows path/file/user names + fn = expt[0].encode(sys.getfilesystemencoding()) + fmt = str(expt[1]) + print "Exporting: file %s, format %s." % (fn, fmt) self.cl_export(expt[0], expt[1]) if cleanup: @@ -356,7 +369,11 @@ class ArgHandler(object): sys.exit(0) for imp in self.imports: - print "Importing: file %s, format %s." % imp + # Need to covert path/filename to str before printing + # For non latin characters in Windows path/file/user names + fn = imp[0].encode(sys.getfilesystemencoding()) + fmt = str(imp[1]) + print "Importing: file %s, format %s." % (fn , fmt) self.cl_import(imp[0], imp[1]) def __open_action(self): @@ -480,9 +497,9 @@ class ArgHandler(object): if len(pdata.id) <= 25: print " %s%s- %s" % ( pdata.id, " " * (26 - len(pdata.id)), - pdata.name) + pdata.name.encode(sys.getfilesystemencoding())) else: - print " %s\t- %s" % (pdata.id, pdata.name) + print " %s\t- %s" % (pdata.id, pdata.name.encode(sys.getfilesystemencoding()) ) elif action == "tool": try: @@ -517,9 +534,9 @@ class ArgHandler(object): if len(pdata.id) <= 25: print " %s%s- %s" % ( pdata.id, " " * (26 - len(pdata.id)), - pdata.name) + pdata.name.encode(sys.getfilesystemencoding())) else: - print " %s\t- %s" % (pdata.id, pdata.name) + print " %s\t- %s" % (pdata.id, pdata.name.encode(sys.getfilesystemencoding())) else: print "Unknown action: %s." % action sys.exit(0) diff --git a/src/cli/argparser.py b/src/cli/argparser.py index 1dc892e9c..eb28187d5 100644 --- a/src/cli/argparser.py +++ b/src/cli/argparser.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Gramps - a GTK+/GNOME based genealogy program # @@ -44,6 +45,7 @@ import logging # #------------------------------------------------------------------------- import const +import Utils # Note: Make sure to edit const.py POPT_TABLE too! @@ -68,6 +70,51 @@ Application options -u, --force-unlock Force unlock of family tree """) +_USAGE = _(""" +Example of usage of Gramps command line interface + +1. To import four databases (whose formats can be determined from their names) +and then check the resulting database for errors, one may type: +gramps -i file1.ged -i file2.gpkg -i ~/db3.gramps -i file4.wft -a check + +2. To explicitly specify the formats in the above example, append filenames with appropriate -f options: +gramps -i file1.ged -f gedcom -i file2.gpkg -f gramps-pkg -i ~/db3.gramps -f gramps-xml -i file4.wft -f wft -a check + +3. To record the database resulting from all imports, supply -e flag +(use -f if the filename does not allow GRAMPS to guess the format): +gramps -i file1.ged -i file2.gpkg -e ~/new-package -f gramps-pkg + +4. To save any error messages of the above example into files outfile and errfile, run: +gramps -i file1.ged -i file2.dpkg -e ~/new-package -f gramps-pkg >outfile 2>errfile + +5. To import three databases and start interactive GRAMPS session with the result: +gramps -i file1.ged -i file2.gpkg -i ~/db3.gramps + +6. To open a database and, based on that data, generate timeline report in PDF format +putting the output into the my_timeline.pdf file: +gramps -O 'Family Tree 1' -a report -p name=timeline,off=pdf,of=my_timeline.pdf + +7. To generate a summary of a database: +gramps -O 'Family Tree 1' -a report -p name=summary + +8. Listing report options +Use the name=timeline,show=all to find out about all available options for the timeline report. +To find out details of a particular option, use show=option_name , e.g. name=timeline,show=off string. +To learn about available report names, use name=show string. + +9. To convert a family tree on the fly to a .gramps xml file: +gramps -O 'Family Tree 1' -e output.gramps -f gramps-xml + +10. To generate a web site into an other locale (in german): +LANGUAGE=de_DE; LANG=de_DE.UTF-8 gramps -O 'Family Tree 1' -a report -p name=navwebpage,target=/../de + +11. Finally, to start normal interactive session type: +gramps + +Note: These examples are for bash shell. +Syntax may be different for other shells and for Windows. +""") + #------------------------------------------------------------------------- # ArgParser #------------------------------------------------------------------------- @@ -121,6 +168,7 @@ class ArgParser(object): self.list = False self.list_more = False self.help = False + self.usage = False self.force_unlock = False self.errors = [] @@ -150,14 +198,30 @@ class ArgParser(object): """ try: + # Convert arguments to unicode, otherwise getopt will not work + # if a non latin character is used as an option (by mistake). + # getopt will try to treat the first char in an utf-8 sequence. Example: + # -Ärik is '-\xc3\x84rik' and getopt will respond : + # option -\xc3 not recognized + for arg in range(len(self.args) - 1): + self.args[arg+1] = Utils.get_unicode_path_from_env_var(self.args[arg + 1]) options, leftargs = getopt.getopt(self.args[1:], const.SHORTOPTS, const.LONGOPTS) except getopt.GetoptError, msg: + # Extract the arguments in the list. + # The % operator replaces the list elements with repr() of the list elemements + # which is OK for latin characters, but not for non latin characters in list elements + cliargs = "[ " + for arg in range(len(self.args) - 1): + cliargs += self.args[arg + 1] + " " + cliargs += "]" + # Must first do str() of the msg object. + msg = unicode(str(msg)) self.errors += [(_('Error parsing the arguments'), - str(msg) + '\n' + + msg + '\n' + _("Error parsing the arguments: %s \n" "Type gramps --help for an overview of commands, or " - "read the manual pages.") % self.args[1:])] + "read the manual pages.") % cliargs)] return if leftargs: @@ -214,7 +278,9 @@ class ArgParser(object): self.help = True elif option in ('-u', '--force-unlock'): self.force_unlock = True - + elif option in ('--usage'): + self.usage = True + #clean options list cleandbg.reverse() for ind in cleandbg: @@ -222,10 +288,17 @@ class ArgParser(object): if len(options) > 0 and self.open is None and self.imports == [] \ and not (self.list or self.list_more or self.help): + # Extract and convert to unicode the arguments in the list. + # The % operator replaces the list elements with repr() of the list elemements + # which is OK for latin characters, but not for non latin characters in list elements + cliargs = "[ " + for arg in range(len(self.args) - 1): + cliargs += Utils.get_unicode_path_from_env_var(self.args[arg + 1]) + " " + cliargs += "]" self.errors += [(_('Error parsing the arguments'), _("Error parsing the arguments: %s \n" "To use in the command-line mode," \ - "supply at least one input file to process.") % self.args[1:])] + "supply at least one input file to process.") % cliargs)] #------------------------------------------------------------------------- # Determine the need for GUI @@ -262,6 +335,15 @@ class ArgParser(object): If the user gives the --help or -h option, print the output to terminal. """ if self.help: - print _HELP + # Convert Help messages to file system encoding before printing + print _HELP.encode(sys.getfilesystemencoding()) sys.exit(0) + def print_usage(self): + """ + If the user gives the --usage print the output to terminal. + """ + if self.usage: + # Convert Help messages to file system encoding before printing + print _USAGE.encode(sys.getfilesystemencoding()) + sys.exit(0) diff --git a/src/cli/grampscli.py b/src/cli/grampscli.py index 810041cec..7ffa67970 100644 --- a/src/cli/grampscli.py +++ b/src/cli/grampscli.py @@ -297,14 +297,24 @@ def startcli(errors, argparser): """ if errors: #already errors encountered. Show first one on terminal and exit - print _('Error encountered: %s') % errors[0][0] - print _(' Details: %s') % errors[0][1] + # Convert error message to file system encoding before print + errmsg = _('Error encountered: %s') % errors[0][0] + errmsg = errmsg.encode(sys.getfilesystemencoding()) + print errmsg + errmsg = _(' Details: %s') % errors[0][1] + errmsg = errmsg.encode(sys.getfilesystemencoding()) + print errmsg sys.exit(1) if argparser.errors: - print _('Error encountered in argument parsing: %s') \ + # Convert error message to file system encoding before print + errmsg = _('Error encountered in argument parsing: %s') \ % argparser.errors[0][0] - print _(' Details: %s') % argparser.errors[0][1] + errmsg = errmsg.encode(sys.getfilesystemencoding()) + print errmsg + errmsg = _(' Details: %s') % argparser.errors[0][1] + errmsg = errmsg.encode(sys.getfilesystemencoding()) + print errmsg sys.exit(1) #we need to keep track of the db state diff --git a/src/gramps.py b/src/gramps.py index 0a76dc91d..112334c99 100644 --- a/src/gramps.py +++ b/src/gramps.py @@ -181,6 +181,7 @@ def run(): else: #CLI use of GRAMPS argpars.print_help() + argpars.print_usage() from cli.grampscli import startcli startcli(error, argpars) diff --git a/src/plugins/tool/Check.py b/src/plugins/tool/Check.py index 997a9e02f..164a554b9 100644 --- a/src/plugins/tool/Check.py +++ b/src/plugins/tool/Check.py @@ -30,6 +30,7 @@ #------------------------------------------------------------------------- from __future__ import with_statement import os +import sys import cStringIO from gen.ggettext import gettext as _ @@ -552,8 +553,10 @@ class CheckIntegrity(object): photo_name = Utils.media_path_full(self.db, obj.get_path()) if photo_name is not None and photo_name != "" and not Utils.find_file(photo_name): if cl: + # Convert to file system encoding before prining + fn = os.path.basename(photo_name).encode(sys.getfilesystemencoding()) print "Warning: media file %s was not found." \ - % os.path.basename(photo_name) + % fn self.bad_photo.append(ObjectId) else: if missmedia_action == 0: @@ -1627,7 +1630,8 @@ class Report(ManagedWindow.ManagedWindow): def __init__(self, uistate, text, cl=0): if cl: - print text + # Convert to file system encoding before prining + print text.encode(sys.getfilesystemencoding()) return ManagedWindow.ManagedWindow.__init__(self, uistate, [], self)