def recurse(name, source, clean=False, require=None, user=None, group=None, dir_mode=None, file_mode=None, sym_mode=None, template=None, context=None, defaults=None, include_empty=False, backup='', include_pat=None, exclude_pat=None, maxdepth=None, keep_symlinks=False, force_symlinks=False, **kwargs):
 if ('env' in kwargs):
  salt.utils.warn_until('Oxygen', "Parameter 'env' has been detected in the argument list.  This parameter is no longer used and has been replaced by 'saltenv' as of Salt 2016.11.0.  This warning will be removed in Salt Oxygen.")
  kwargs.pop('env')
 name = os.path.expanduser(sdecode(name))
 user = _test_owner(kwargs, user=user)
 if salt.utils.is_windows():
  if (group is not None):
   log.warning('The group argument for {0} has been ignored as this is a Windows system.'.format(name))
  group = user
 ret = {'name': name, 'changes': {}, 'pchanges': {}, 'result': True, 'comment': {}}
 if ('mode' in kwargs):
  ret['result'] = False
  ret['comment'] = "'mode' is not allowed in 'file.recurse'. Please use 'file_mode' and 'dir_mode'."
  return ret
 if (any([(x is not None) for x in (dir_mode, file_mode, sym_mode)]) and salt.utils.is_windows()):
  return _error(ret, 'mode management is not supported on Windows')
 dir_mode = salt.utils.normalize_mode(dir_mode)
 try:
  keep_mode = (file_mode.lower() == 'keep')
  if keep_mode:
   file_mode = None
 except AttributeError:
  keep_mode = False
 file_mode = salt.utils.normalize_mode(file_mode)
 u_check = _check_user(user, group)
 if u_check:
  return _error(ret, u_check)
 if (not os.path.isabs(name)):
  return _error(ret, 'Specified file {0} is not an absolute path'.format(name))
 source_list = _validate_str_list(source)
 for (idx, val) in enumerate(source_list):
  source_list[idx] = val.rstrip('/')
 for precheck in source_list:
  if (not precheck.startswith('salt://')):
   return _error(ret, "Invalid source '{0}' (must be a salt:// URI)".format(precheck))
 try:
  (source, source_hash) = __salt__['file.source_list'](source_list, '', __env__)
 except CommandExecutionError as exc:
  ret['result'] = False
  ret['comment'] = 'Recurse failed: {0}'.format(exc)
  return ret
 (srcpath, senv) = salt.utils.url.parse(source)
 if (senv is None):
  senv = __env__
 master_dirs = __salt__['cp.list_master_dirs'](saltenv=senv)
 if ((srcpath not in master_dirs) and (not any((x for x in master_dirs if x.startswith((srcpath + '/')))))):
  ret['result'] = False
  ret['comment'] = "The directory '{0}' does not exist on the salt fileserver in saltenv '{1}'".format(srcpath, senv)
  return ret
 if (not os.path.isdir(name)):
  if os.path.exists(name):
   return _error(ret, 'The path {0} exists and is not a directory'.format(name))
  if (not __opts__['test']):
   __salt__['file.makedirs_perms'](name, user, group, dir_mode)
 def add_comment(path, comment):
  comments = ret['comment'].setdefault(path, [])
  if isinstance(comment, six.string_types):
   comments.append(comment)
  else:
   comments.extend(comment)
 def merge_ret(path, _ret):
  if ((_ret['result'] is False) or (ret['result'] is True)):
   ret['result'] = _ret['result']
  if ((_ret['result'] is not True) and _ret['comment']):
   add_comment(path, _ret['comment'])
  if _ret['changes']:
   ret['changes'][path] = _ret['changes']
 def manage_file(path, source):
  if (clean and os.path.exists(path) and os.path.isdir(path)):
   _ret = {'name': name, 'changes': {}, 'result': True, 'comment': ''}
   if __opts__['test']:
    _ret['comment'] = 'Replacing directory {0} with a file'.format(path)
    _ret['result'] = None
    merge_ret(path, _ret)
    return
   else:
    __salt__['file.remove'](path)
    _ret['changes'] = {'diff': 'Replaced directory with a new file'}
    merge_ret(path, _ret)
  pass_kwargs = {}
  faults = ['mode', 'makedirs']
  for key in kwargs:
   if (key not in faults):
    pass_kwargs[key] = kwargs[key]
  _ret = managed(path, source=source, user=user, group=group, mode=('keep' if keep_mode else file_mode), template=template, makedirs=True, context=context, defaults=defaults, backup=backup, **pass_kwargs)
  merge_ret(path, _ret)
 def manage_directory(path):
  if (os.path.basename(path) == '..'):
   return
  if (clean and os.path.exists(path) and (not os.path.isdir(path))):
   _ret = {'name': name, 'changes': {}, 'result': True, 'comment': ''}
   if __opts__['test']:
    _ret['comment'] = 'Replacing {0} with a directory'.format(path)
    _ret['result'] = None
    merge_ret(path, _ret)
    return
   else:
    __salt__['file.remove'](path)
    _ret['changes'] = {'diff': 'Replaced file with a directory'}
    merge_ret(path, _ret)
  _ret = directory(path, user=user, group=group, recurse=[], dir_mode=dir_mode, file_mode=None, makedirs=True, clean=False, require=None)
  merge_ret(path, _ret)
 (mng_files, mng_dirs, mng_symlinks, keep) = _gen_recurse_managed_files(name, source, keep_symlinks, include_pat, exclude_pat, maxdepth, include_empty)
 for (srelpath, ltarget) in mng_symlinks:
  _ret = symlink(os.path.join(name, srelpath), ltarget, makedirs=True, force=force_symlinks, user=user, group=group, mode=sym_mode)
  if (not _ret):
   continue
  merge_ret(os.path.join(name, srelpath), _ret)
 for dirname in mng_dirs:
  manage_directory(dirname)
 for (dest, src) in mng_files:
  manage_file(dest, src)
 if clean:
  keep.update(_gen_keep_files(name, require))
  removed = _clean_dir(name, list(keep), exclude_pat)
  if removed:
   if __opts__['test']:
    if ret['result']:
     ret['result'] = None
    add_comment('removed', removed)
   else:
    ret['changes']['removed'] = removed
 ret['comment'] = '\n'.join((u'\n#### {0} ####\n{1}'.format(k, (v if isinstance(v, six.string_types) else '\n'.join(v))) for (k, v) in six.iteritems(ret['comment']))).strip()
 if (not ret['comment']):
  ret['comment'] = 'Recursively updated {0}'.format(name)
 if ((not ret['changes']) and ret['result']):
  ret['comment'] = 'The directory {0} is in the correct state'.format(name)
 return ret

def recurse ( name , source , clean = False , require = None , user = None , group = None , dir_mode = None , file_mode = None , sym_mode = None , template = None , context = None , defaults = None , include_empty = False , backup = '' , include_pat = None , exclude_pat = None , maxdepth = None , keep_symlinks = False , force_symlinks = False , ** kwargs ) : if ( 'env' in kwargs ) : salt . utils . warn_until ( 'Oxygen' , "Parameter 'env' has been detected in the argument list.  This parameter is no longer used and has been replaced by 'saltenv' as of Salt 2016.11.0.  This warning will be removed in Salt Oxygen." ) kwargs . pop ( 'env' ) name = os . path . expanduser ( sdecode ( name ) ) user = _test_owner ( kwargs , user = user ) if salt . utils . is_windows ( ) : if ( group is not None ) : log . warning ( 'The group argument for {0} has been ignored as this is a Windows system.' . format ( name ) ) group = user ret = { 'name' : name , 'changes' : { } , 'pchanges' : { } , 'result' : True , 'comment' : { } } if ( 'mode' in kwargs ) : ret [ 'result' ] = False ret [ 'comment' ] = "'mode' is not allowed in 'file.recurse'. Please use 'file_mode' and 'dir_mode'." return ret if ( any ( [ ( x is not None ) for x in ( dir_mode , file_mode , sym_mode ) ] ) and salt . utils . is_windows ( ) ) : return _error ( ret , 'mode management is not supported on Windows' ) dir_mode = salt . utils . normalize_mode ( dir_mode ) try : keep_mode = ( file_mode . lower ( ) == 'keep' ) if keep_mode : file_mode = None except AttributeError : keep_mode = False file_mode = salt . utils . normalize_mode ( file_mode ) u_check = _check_user ( user , group ) if u_check : return _error ( ret , u_check ) if ( not os . path . isabs ( name ) ) : return _error ( ret , 'Specified file {0} is not an absolute path' . format ( name ) ) source_list = _validate_str_list ( source ) for ( idx , val ) in enumerate ( source_list ) : source_list [ idx ] = val . rstrip ( '/' ) for precheck in source_list : if ( not precheck . startswith ( 'salt://' ) ) : return _error ( ret , "Invalid source '{0}' (must be a salt:// URI)" . format ( precheck ) ) try : ( source , source_hash ) = __salt__ [ 'file.source_list' ] ( source_list , '' , __env__ ) except CommandExecutionError as exc : ret [ 'result' ] = False ret [ 'comment' ] = 'Recurse failed: {0}' . format ( exc ) return ret ( srcpath , senv ) = salt . utils . url . parse ( source ) if ( senv is None ) : senv = __env__ master_dirs = __salt__ [ 'cp.list_master_dirs' ] ( saltenv = senv ) if ( ( srcpath not in master_dirs ) and ( not any ( ( x for x in master_dirs if x . startswith ( ( srcpath + '/' ) ) ) ) ) ) : ret [ 'result' ] = False ret [ 'comment' ] = "The directory '{0}' does not exist on the salt fileserver in saltenv '{1}'" . format ( srcpath , senv ) return ret if ( not os . path . isdir ( name ) ) : if os . path . exists ( name ) : return _error ( ret , 'The path {0} exists and is not a directory' . format ( name ) ) if ( not __opts__ [ 'test' ] ) : __salt__ [ 'file.makedirs_perms' ] ( name , user , group , dir_mode ) def add_comment ( path , comment ) : comments = ret [ 'comment' ] . setdefault ( path , [ ] ) if isinstance ( comment , six . string_types ) : comments . append ( comment ) else : comments . extend ( comment ) def merge_ret ( path , _ret ) : if ( ( _ret [ 'result' ] is False ) or ( ret [ 'result' ] is True ) ) : ret [ 'result' ] = _ret [ 'result' ] if ( ( _ret [ 'result' ] is not True ) and _ret [ 'comment' ] ) : add_comment ( path , _ret [ 'comment' ] ) if _ret [ 'changes' ] : ret [ 'changes' ] [ path ] = _ret [ 'changes' ] def manage_file ( path , source ) : if ( clean and os . path . exists ( path ) and os . path . isdir ( path ) ) : _ret = { 'name' : name , 'changes' : { } , 'result' : True , 'comment' : '' } if __opts__ [ 'test' ] : _ret [ 'comment' ] = 'Replacing directory {0} with a file' . format ( path ) _ret [ 'result' ] = None merge_ret ( path , _ret ) return else : __salt__ [ 'file.remove' ] ( path ) _ret [ 'changes' ] = { 'diff' : 'Replaced directory with a new file' } merge_ret ( path , _ret ) pass_kwargs = { } faults = [ 'mode' , 'makedirs' ] for key in kwargs : if ( key not in faults ) : pass_kwargs [ key ] = kwargs [ key ] _ret = managed ( path , source = source , user = user , group = group , mode = ( 'keep' if keep_mode else file_mode ) , template = template , makedirs = True , context = context , defaults = defaults , backup = backup , ** pass_kwargs ) merge_ret ( path , _ret ) def manage_directory ( path ) : if ( os . path . basename ( path ) == '..' ) : return if ( clean and os . path . exists ( path ) and ( not os . path . isdir ( path ) ) ) : _ret = { 'name' : name , 'changes' : { } , 'result' : True , 'comment' : '' } if __opts__ [ 'test' ] : _ret [ 'comment' ] = 'Replacing {0} with a directory' . format ( path ) _ret [ 'result' ] = None merge_ret ( path , _ret ) return else : __salt__ [ 'file.remove' ] ( path ) _ret [ 'changes' ] = { 'diff' : 'Replaced file with a directory' } merge_ret ( path , _ret ) _ret = directory ( path , user = user , group = group , recurse = [ ] , dir_mode = dir_mode , file_mode = None , makedirs = True , clean = False , require = None ) merge_ret ( path , _ret ) ( mng_files , mng_dirs , mng_symlinks , keep ) = _gen_recurse_managed_files ( name , source , keep_symlinks , include_pat , exclude_pat , maxdepth , include_empty ) for ( srelpath , ltarget ) in mng_symlinks : _ret = symlink ( os . path . join ( name , srelpath ) , ltarget , makedirs = True , force = force_symlinks , user = user , group = group , mode = sym_mode ) if ( not _ret ) : continue merge_ret ( os . path . join ( name , srelpath ) , _ret ) for dirname in mng_dirs : manage_directory ( dirname ) for ( dest , src ) in mng_files : manage_file ( dest , src ) if clean : keep . update ( _gen_keep_files ( name , require ) ) removed = _clean_dir ( name , list ( keep ) , exclude_pat ) if removed : if __opts__ [ 'test' ] : if ret [ 'result' ] : ret [ 'result' ] = None add_comment ( 'removed' , removed ) else : ret [ 'changes' ] [ 'removed' ] = removed ret [ 'comment' ] = '\n' . join ( ( u'\n#### {0} ####\n{1}' . format ( k , ( v if isinstance ( v , six . string_types ) else '\n' . join ( v ) ) ) for ( k , v ) in six . iteritems ( ret [ 'comment' ] ) ) ) . strip ( ) if ( not ret [ 'comment' ] ) : ret [ 'comment' ] = 'Recursively updated {0}' . format ( name ) if ( ( not ret [ 'changes' ] ) and ret [ 'result' ] ) : ret [ 'comment' ] = 'The directory {0} is in the correct state' . format ( name ) return ret
function decorator to help with recursion .