[svn merge][r425] Made Diffuse's resource file parsing robust against installation paths with pattern matching characters.

pattern matching characters.
This commit is contained in:
Romain Failliot 2016-07-08 23:11:43 -04:00
parent 15e441f172
commit 2aecb941d7
1 changed files with 39 additions and 29 deletions

View File

@ -152,6 +152,12 @@ def logDebug(s):
# this is sorted based upon frequency to speed up code for stripping whitespace # this is sorted based upon frequency to speed up code for stripping whitespace
whitespace = ' \t\n\r\x0b\x0c' whitespace = ' \t\n\r\x0b\x0c'
# escape special glob characters
def globEscape(s):
print 'globEscape', repr(s)
m = dict([ (c, u'[%s]' % (c, )) for c in u'[]?*' ])
return u''.join([ m.get(c, c) for c in s ])
# associate our icon with all of our windows # associate our icon with all of our windows
if __name__ == '__main__': if __name__ == '__main__':
# this is not automatically set on some older version of PyGTK # this is not automatically set on some older version of PyGTK
@ -273,6 +279,9 @@ def splitlines(s):
def readlines(fd): def readlines(fd):
return strip_eols(splitlines(fd.read())) return strip_eols(splitlines(fd.read()))
def readconfiglines(fd):
return unicode(fd.read(), 'utf_8').replace(u'\r', u'').split(u'\n')
# This class to hold all customisable behaviour not exposed in the preferences # This class to hold all customisable behaviour not exposed in the preferences
# dialogue: hotkey assignment, colours, syntax highlighting, etc. # dialogue: hotkey assignment, colours, syntax highlighting, etc.
# Syntax highlighting is implemented in supporting '*.syntax' files normally # Syntax highlighting is implemented in supporting '*.syntax' files normally
@ -576,7 +585,7 @@ class Resources:
self.resource_files.add(file_name) self.resource_files.add(file_name)
f = open(file_name, 'r') f = open(file_name, 'r')
ss = readlines(f) ss = readconfiglines(f)
f.close() f.close()
# FIXME: improve validation # FIXME: improve validation
@ -588,10 +597,10 @@ class Resources:
try: try:
# eg. add Python syntax highlighting: # eg. add Python syntax highlighting:
# import /usr/share/diffuse/syntax/python.syntax # import /usr/share/diffuse/syntax/python.syntax
if args[0] == 'import' and len(args) == 2: if args[0] == u'import' and len(args) == 2:
path = os.path.expanduser(args[1]) path = os.path.expanduser(args[1])
# relative paths are relative to the parsed file # relative paths are relative to the parsed file
path = os.path.join(os.path.dirname(file_name), path) path = os.path.join(globEscape(os.path.dirname(file_name)), path)
paths = glob.glob(path) paths = glob.glob(path)
if len(paths) == 0: if len(paths) == 0:
paths = [ path ] paths = [ path ]
@ -602,28 +611,28 @@ class Resources:
self.parse(os.path.abspath(path)) self.parse(os.path.abspath(path))
# eg. make Ctrl+o trigger the open_file menu item # eg. make Ctrl+o trigger the open_file menu item
# keybinding menu open_file Ctrl+o # keybinding menu open_file Ctrl+o
elif args[0] == 'keybinding' and len(args) == 4: elif args[0] == u'keybinding' and len(args) == 4:
self.setKeyBinding(args[1], args[2], args[3]) self.setKeyBinding(args[1], args[2], args[3])
# eg. set the regular background colour to white # eg. set the regular background colour to white
# colour text_background 1.0 1.0 1.0 # colour text_background 1.0 1.0 1.0
elif args[0] in [ 'colour', 'color' ] and len(args) == 5: elif args[0] in [ u'colour', u'color' ] and len(args) == 5:
self.colours[args[1]] = Colour(float(args[2]), float(args[3]), float(args[4])) self.colours[args[1]] = Colour(float(args[2]), float(args[3]), float(args[4]))
# eg. set opacity of the line_selection colour # eg. set opacity of the line_selection colour
# float line_selection_opacity 0.4 # float line_selection_opacity 0.4
elif args[0] == 'float' and len(args) == 3: elif args[0] == u'float' and len(args) == 3:
self.floats[args[1]] = float(args[2]) self.floats[args[1]] = float(args[2])
# eg. set the help browser # eg. set the help browser
# string help_browser gnome-help # string help_browser gnome-help
elif args[0] == 'string' and len(args) == 3: elif args[0] == u'string' and len(args) == 3:
self.strings[args[1]] = args[2] self.strings[args[1]] = args[2]
if args[1] == 'difference_colours': if args[1] == u'difference_colours':
self.setDifferenceColours(args[2]) self.setDifferenceColours(args[2])
# eg. start a syntax specification for Python # eg. start a syntax specification for Python
# syntax Python normal text # syntax Python normal text
# where 'normal' is the name of the default state and # where 'normal' is the name of the default state and
# 'text' is the classification of all characters not # 'text' is the classification of all characters not
# explicitly matched by a syntax highlighting rule # explicitly matched by a syntax highlighting rule
elif args[0] == 'syntax' and (len(args) == 2 or len(args) == 4): elif args[0] == u'syntax' and (len(args) == 2 or len(args) == 4):
key = args[1] key = args[1]
if len(args) == 2: if len(args) == 2:
# remove file pattern for a syntax specification # remove file pattern for a syntax specification
@ -649,10 +658,10 @@ class Resources:
# the pattern '#' is matched and classify the matched # the pattern '#' is matched and classify the matched
# characters as 'python_comment' # characters as 'python_comment'
# syntax_pattern normal comment python_comment '#' # syntax_pattern normal comment python_comment '#'
elif args[0] == 'syntax_pattern' and self.current_syntax is not None and len(args) >= 5: elif args[0] == u'syntax_pattern' and self.current_syntax is not None and len(args) >= 5:
flags = 0 flags = 0
for arg in args[5:]: for arg in args[5:]:
if arg == 'ignorecase': if arg == u'ignorecase':
flags |= re.IGNORECASE flags |= re.IGNORECASE
else: else:
raise ValueError() raise ValueError()
@ -660,7 +669,7 @@ class Resources:
# eg. default to the Python syntax rules when viewing # eg. default to the Python syntax rules when viewing
# a file ending with '.py' or '.pyw' # a file ending with '.py' or '.pyw'
# syntax_files Python '\.pyw?$' # syntax_files Python '\.pyw?$'
elif args[0] == 'syntax_files' and (len(args) == 2 or len(args) == 3): elif args[0] == u'syntax_files' and (len(args) == 2 or len(args) == 3):
key = args[1] key = args[1]
if len(args) == 2: if len(args) == 2:
# remove file pattern for a syntax specification # remove file pattern for a syntax specification
@ -676,7 +685,7 @@ class Resources:
# eg. default to the Python syntax rules when viewing # eg. default to the Python syntax rules when viewing
# a files starting with patterns like #!/usr/bin/python # a files starting with patterns like #!/usr/bin/python
# syntax_magic Python '^#!/usr/bin/python$' # syntax_magic Python '^#!/usr/bin/python$'
elif args[0] == 'syntax_magic' and len(args) > 1: elif args[0] == u'syntax_magic' and len(args) > 1:
key = args[1] key = args[1]
if len(args) == 2: if len(args) == 2:
# remove magic pattern for a syntax specification # remove magic pattern for a syntax specification
@ -687,7 +696,7 @@ class Resources:
else: else:
flags = 0 flags = 0
for arg in args[3:]: for arg in args[3:]:
if arg == 'ignorecase': if arg == u'ignorecase':
flags |= re.IGNORECASE flags |= re.IGNORECASE
else: else:
raise ValueError() raise ValueError()
@ -914,7 +923,7 @@ class Preferences:
if os.path.isfile(self.path): if os.path.isfile(self.path):
try: try:
f = open(self.path, 'r') f = open(self.path, 'r')
ss = readlines(f) ss = readconfiglines(f)
f.close() f.close()
for j, s in enumerate(ss): for j, s in enumerate(ss):
try: try:
@ -2377,14 +2386,15 @@ class _Svn:
def getFileTemplate(self, prefs, name): def getFileTemplate(self, prefs, name):
# FIXME: verify this # FIXME: verify this
# merge conflict # merge conflict
left = glob.glob(name + '.merge-left.r*') escaped_name = globEscape(name)
right = glob.glob(name + '.merge-right.r*') left = glob.glob(escaped_name + u'.merge-left.r*')
right = glob.glob(escaped_name + u'.merge-right.r*')
if len(left) > 0 and len(right) > 0: if len(left) > 0 and len(right) > 0:
return [ (left[-1], None), (name, None), (right[-1], None) ] return [ (left[-1], None), (name, None), (right[-1], None) ]
# update conflict # update conflict
left = sorted(glob.glob(name + '.r*')) left = sorted(glob.glob(escaped_name + u'.r*'))
right = glob.glob(name + '.mine') right = glob.glob(escaped_name + u'.mine')
right.extend(glob.glob(name + '.working')) right.extend(glob.glob(escaped_name + u'.working'))
if len(left) > 0 and len(right) > 0: if len(left) > 0 and len(right) > 0:
return [ (left[-1], None), (name, None), (right[0], None) ] return [ (left[-1], None), (name, None), (right[0], None) ]
# default case # default case
@ -8341,16 +8351,16 @@ def make_subdirs(p, ss):
# process the command line arguments # process the command line arguments
if __name__ == '__main__': if __name__ == '__main__':
# find the config directory and create it if it didn't exist # find the config directory and create it if it didn't exist
rc_dir, subdirs = os.environ.get('XDG_CONFIG_HOME', None), ['diffuse'] rc_dir, subdirs = os.environ.get('XDG_CONFIG_HOME', None), [u'diffuse']
if rc_dir is None: if rc_dir is None:
rc_dir = os.path.expanduser('~') rc_dir = os.path.expanduser(u'~')
subdirs.insert(0, '.config') subdirs.insert(0, u'.config')
rc_dir = make_subdirs(rc_dir, subdirs) rc_dir = make_subdirs(rc_dir, subdirs)
# find the local data directory and create it if it didn't exist # find the local data directory and create it if it didn't exist
data_dir, subdirs = os.environ.get('XDG_DATA_HOME', None), ['diffuse'] data_dir, subdirs = os.environ.get('XDG_DATA_HOME', None), [u'diffuse']
if data_dir is None: if data_dir is None:
data_dir = os.path.expanduser('~') data_dir = os.path.expanduser(u'~')
subdirs[:0] = [ '.local', 'share' ] subdirs[:0] = [ u'.local', u'share' ]
data_dir = make_subdirs(data_dir, subdirs) data_dir = make_subdirs(data_dir, subdirs)
# load resource files # load resource files
i, rc_files = 1, [] i, rc_files = 1, []
@ -8363,10 +8373,10 @@ if __name__ == '__main__':
else: else:
# parse system wide then personal initialisation files # parse system wide then personal initialisation files
if isWindows(): if isWindows():
rc_file = os.path.join(bin_dir, 'diffuserc') rc_file = os.path.join(bin_dir, u'diffuserc')
else: else:
rc_file = os.path.join(bin_dir, '../../etc/diffuserc') rc_file = os.path.join(bin_dir, u'../../etc/diffuserc')
for rc_file in rc_file, os.path.join(rc_dir, 'diffuserc'): for rc_file in rc_file, os.path.join(rc_dir, u'diffuserc'):
if os.path.isfile(rc_file): if os.path.isfile(rc_file):
rc_files.append(rc_file) rc_files.append(rc_file)
for rc_file in rc_files: for rc_file in rc_files: