from __future__ import absolute_import, division, print_function, unicode_literals

from echomesh.base import CommandFile
from echomesh.base import Yaml
from echomesh.base import Merge

def _add_exception_suffix(e, suffix):
  e.args = tuple(a + suffix for a in e.args)

def _merge_level_files():
  # Merge configuration files from the command directory hierarchy.
  config = None
  for f in reversed(CommandFile.expand('config.yml')):
    try:
      cfg = Yaml.read_one(f)
    except Exception as e:
      _add_exception_suffix(e, ' loading configuration file %s' % f)
      raise

    if config is None:
      assert cfg, "Unable to read default config file %s" % f
      config = cfg
    else:
      try:
        Merge.merge(config, cfg)
      except Exception as e:
        _add_exception_suffix(e, ' merging configuration file %s' % f)
        raise
  return config

def _merge_command_line_arguments(args, config):
  # Merge in command line arguments.
  for i, arg in enumerate(args):
    if arg.startswith('{'):
      try:
        cfgs = Yaml.decode_all(arg)
      except Exception as e:
        print('Error %s parsing command line argument %d: "%s"' %
              (str(e), i, arg))

      try:
        Merge.merge_all(config, *cfgs)
      except Exception as e:
        print('Error %s merging command line argument %d: "%s"' %
              (str(e), i, arg))

  return config

def merge(args):
  return _merge_command_line_arguments(args, _merge_level_files())

@@ -77,16 +77,34 @@
 terals%0A%0A
+import itertools%0A%0A
 from ech
@@ -230,16 +230,49 @@
 (e, 
+*
 suffix
+es):%0A  suffix = ' '.join(suffixes
 )
-:
 %0A  e
@@ -323,925 +323,688 @@
 ef _
-merge_level_files():%0A  # Merge configuration files from the command directory hierarchy.%0A  config = None%0A
+parse(items, parser, message):%0A  for item in items:%0A    try:%0A    
   for 
-f
+cfg
  in 
-reversed(CommandFile.expand('config.yml')):%0A    try:%0A      cfg = Yaml.read_one(f)%0A    except Exception as e:%0A      _add_exception_suffix(e, ' loading configuration file %25s' %25 f)%0A      raise%0A%0A    if config is None:%0A      assert cfg, %22Unable to read default config file %25s%22 %25 f%0A      config = cfg%0A    else:%0A      try:%0A        Merge.merge(config, cfg)%0A      except Exception as e:%0A        _add_exception_suffix(e, ' merging configuration file %25s' %25 f)%0A        raise%0A  return config%0A%0Adef _merge_command_line_arguments(args, config):%0A  # Merge in command line arguments.%0A  for i, arg in enumerate(args):%0A    if arg.startswith('%7B'):%0A      try:%0A        cfgs = Yaml.decode_all(arg)%0A      except Exception as e:%0A        print('Error %25s parsing command line argument %25d: %22
+parser(item):%0A        if cfg:%0A          yield cfg, item, message%0A    except Exception as e:%0A      _add_exception_suffix(e, message, 'parsing', item)%0A      raise%0A%0Adef merge(args):%0A  files = reversed(CommandFile.expand('config.yml'))%0A  file_iter = _parse(files, Yaml.read_all, 'config file')%0A  args = (a for a in args if a%5B0%5D in '%7B%5B')%0A  arg_iter = _parse(args, Yaml.decode_all, 'command line argument')%0A  config = None%0A%0A  for cfg, item, message in itertools.chain(file_iter, arg_iter):%0A    if config is None:%0A      assert cfg, %22Unable to read default %25s 
 %25s%22
-'
  %25
-%0A              (str(e), i, arg))%0A
+ (message, item)%0A      config = cfg%0A    else:
 %0A   
@@ -1030,20 +1030,16 @@
 ge.merge
-_all
 (config,
@@ -1043,13 +1043,11 @@
 ig, 
-*
 cfg
-s
 )%0A  
@@ -1085,196 +1085,71 @@
     
-print('Error %25s merging command line argument %25d: %22%25s%22' %25%0A              (str(e), i, arg))%0A%0A  return config%0A%0Adef merge(args):%0A  return _merge_command_line_arguments(args, _merge_level_files())
+_add_exception_suffix(e, message, 'merging', item)%0A  return config
 %0A

Simplify MergeConfig