From 661a0687ec7837f983d75d02d50dfcb43ab8e3cb Mon Sep 17 00:00:00 2001 From: twangboy Date: Thu, 22 Feb 2018 18:37:57 -0700 Subject: [PATCH 1/7] Fix git utf-8 issues for Windows Adds the `output_encoding` option to all the functions Defaults to `utf-8` for Windows Fixes some utf-8 issues in the test --- salt/modules/git.py | 295 ++++++++++++++++++-------- tests/integration/modules/test_git.py | 9 +- 2 files changed, 208 insertions(+), 96 deletions(-) diff --git a/salt/modules/git.py b/salt/modules/git.py index 7ea4700d87..15d1d8db0d 100644 --- a/salt/modules/git.py +++ b/salt/modules/git.py @@ -67,6 +67,7 @@ def _config_getter(get_opt, user=None, password=None, ignore_retcode=False, + output_encoding=None, **kwargs): ''' Common code for config.get_* functions, builds and runs the git CLI command @@ -94,7 +95,8 @@ def _config_getter(get_opt, value_regex = None command = ['git', 'config'] - command.extend(_which_git_config(global_, cwd, user, password)) + command.extend(_which_git_config(global_, cwd, user, password, + output_encoding=output_encoding)) command.append(get_opt) command.append(key) if value_regex is not None: @@ -104,7 +106,8 @@ def _config_getter(get_opt, user=user, password=password, ignore_retcode=ignore_retcode, - failhard=False) + failhard=False, + output_encoding=output_encoding) def _expand_path(cwd, user): @@ -188,7 +191,7 @@ def _format_git_opts(opts): def _git_run(command, cwd=None, user=None, password=None, identity=None, ignore_retcode=False, failhard=True, redirect_stderr=False, - saltenv='base', **kwargs): + saltenv='base', output_encoding=None, **kwargs): ''' simple, throw an exception with the error message on an error return code. @@ -196,6 +199,9 @@ def _git_run(command, cwd=None, user=None, password=None, identity=None, 'cmd.run_all', and used as an alternative to 'cmd.run_all'. Some commands don't return proper retcodes, so this can't replace 'cmd.run_all'. ''' + if salt.utils.platform.is_windows() and output_encoding is None: + output_encoding = 'utf-8' + env = {} if identity: @@ -300,6 +306,7 @@ def _git_run(command, cwd=None, user=None, password=None, identity=None, log_callback=salt.utils.url.redact_http_basic_auth, ignore_retcode=ignore_retcode, redirect_stderr=redirect_stderr, + output_encoding=output_encoding **kwargs) finally: # Cleanup the temporary ssh wrapper file @@ -358,6 +365,7 @@ def _git_run(command, cwd=None, user=None, password=None, identity=None, log_callback=salt.utils.url.redact_http_basic_auth, ignore_retcode=ignore_retcode, redirect_stderr=redirect_stderr, + output_encoding=output_encoding, **kwargs) if result['retcode'] == 0: @@ -379,7 +387,7 @@ def _git_run(command, cwd=None, user=None, password=None, identity=None, return result -def _get_toplevel(path, user=None, password=None): +def _get_toplevel(path, user=None, password=None, output_encoding=None): ''' Use git rev-parse to return the top level of a repo ''' @@ -387,10 +395,11 @@ def _get_toplevel(path, user=None, password=None): ['git', 'rev-parse', '--show-toplevel'], cwd=path, user=user, - password=password)['stdout'] + password=password, + output_encoding=output_encoding)['stdout'] -def _git_config(cwd, user, password): +def _git_config(cwd, user, password, output_encoding=None): ''' Helper to retrieve git config options ''' @@ -400,7 +409,8 @@ def _git_config(cwd, user, password): opts=['--git-dir'], user=user, password=password, - ignore_retcode=True) + ignore_retcode=True, + output_encoding=output_encoding) if not os.path.isabs(git_dir): paths = (cwd, git_dir, 'config') else: @@ -409,7 +419,7 @@ def _git_config(cwd, user, password): return __context__[contextkey] -def _which_git_config(global_, cwd, user, password): +def _which_git_config(global_, cwd, user, password, output_encoding=None): ''' Based on whether global or local config is desired, return a list of CLI args to include in the git config command. @@ -422,7 +432,8 @@ def _which_git_config(global_, cwd, user, password): return ['--local'] else: # For earlier versions, need to specify the path to the git config file - return ['--file', _git_config(cwd, user, password)] + return ['--file', _git_config(cwd, user, password, + output_encoding=output_encoding)] def add(cwd, @@ -431,7 +442,8 @@ def add(cwd, git_opts='', user=None, password=None, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' .. versionchanged:: 2015.8.0 The ``--verbose`` command line argument is now implied @@ -499,7 +511,8 @@ def add(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode)['stdout'] + ignore_retcode=ignore_retcode, + output_encoding=output_encoding)['stdout'] def archive(cwd, @@ -510,6 +523,7 @@ def archive(cwd, user=None, password=None, ignore_retcode=False, + output_encoding=None, **kwargs): ''' .. versionchanged:: 2015.8.0 @@ -637,7 +651,8 @@ def archive(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode) + ignore_retcode=ignore_retcode, + output_encoding=output_encoding) # No output (unless --verbose is used, and we don't want all files listed # in the output in case there are thousands), so just return True. If there # was an error in the git command, it will have already raised an exception @@ -651,7 +666,8 @@ def branch(cwd, git_opts='', user=None, password=None, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' Interface to `git-branch(1)`_ @@ -728,7 +744,8 @@ def branch(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode) + ignore_retcode=ignore_retcode, + output_encoding=output_encoding) return True @@ -739,7 +756,8 @@ def checkout(cwd, git_opts='', user=None, password=None, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' Interface to `git-checkout(1)`_ @@ -827,7 +845,8 @@ def checkout(cwd, user=user, password=password, ignore_retcode=ignore_retcode, - redirect_stderr=True)['stdout'] + redirect_stderr=True, + output_encoding=output_encoding)['stdout'] def clone(cwd, @@ -841,7 +860,8 @@ def clone(cwd, https_user=None, https_pass=None, ignore_retcode=False, - saltenv='base'): + saltenv='base', + output_encoding=None): ''' Interface to `git-clone(1)`_ @@ -976,7 +996,8 @@ def clone(cwd, password=password, identity=identity, ignore_retcode=ignore_retcode, - saltenv=saltenv) + saltenv=saltenv, + output_encoding=output_encoding) return True @@ -987,7 +1008,8 @@ def commit(cwd, user=None, password=None, filename=None, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' Interface to `git-commit(1)`_ @@ -1068,7 +1090,8 @@ def commit(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode)['stdout'] + ignore_retcode=ignore_retcode, + output_encoding=output_encoding)['stdout'] def config_get(key, @@ -1076,6 +1099,7 @@ def config_get(key, user=None, password=None, ignore_retcode=False, + output_encoding=None, **kwargs): ''' Get the value of a key in the git configuration file @@ -1140,6 +1164,7 @@ def config_get(key, user=user, password=password, ignore_retcode=ignore_retcode, + output_encoding=output_encoding, **kwargs) # git config --get exits with retcode of 1 when key does not exist @@ -1162,6 +1187,7 @@ def config_get_regexp(key, user=None, password=None, ignore_retcode=False, + output_encoding=None, **kwargs): r''' .. versionadded:: 2015.8.0 @@ -1225,6 +1251,7 @@ def config_get_regexp(key, user=user, password=password, ignore_retcode=ignore_retcode, + output_encoding=output_encoding, **kwargs) # git config --get exits with retcode of 1 when key does not exist @@ -1249,6 +1276,7 @@ def config_set(key, user=None, password=None, ignore_retcode=False, + output_encoding=None, **kwargs): ''' .. versionchanged:: 2015.8.0 @@ -1362,7 +1390,8 @@ def config_set(key, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode) + ignore_retcode=ignore_retcode, + output_encoding=output_encoding) else: for idx, target in enumerate(multivar): command = copy.copy(command_prefix) @@ -1375,12 +1404,14 @@ def config_set(key, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode) + ignore_retcode=ignore_retcode, + output_encoding=output_encoding) return config_get(key, user=user, password=password, cwd=cwd, ignore_retcode=ignore_retcode, + output_encoding=output_encoding, **{'all': True, 'global': global_}) @@ -1390,6 +1421,7 @@ def config_unset(key, user=None, password=None, ignore_retcode=False, + output_encoding=None, **kwargs): ''' .. versionadded:: 2015.8.0 @@ -1456,7 +1488,8 @@ def config_unset(key, command.append('--unset-all') else: command.append('--unset') - command.extend(_which_git_config(global_, cwd, user, password)) + command.extend(_which_git_config(global_, cwd, user, password, + output_encoding=output_encoding)) command.append(key) if value_regex is not None: @@ -1466,7 +1499,8 @@ def config_unset(key, user=user, password=password, ignore_retcode=ignore_retcode, - failhard=False) + failhard=False, + output_encoding=output_encoding) retcode = ret['retcode'] if retcode == 0: return True @@ -1477,7 +1511,8 @@ def config_unset(key, key, user=user, password=password, - ignore_retcode=ignore_retcode) is None: + ignore_retcode=ignore_retcode, + output_encoding=output_encoding) is None: raise CommandExecutionError( 'Key \'{0}\' does not exist'.format(key) ) @@ -1501,7 +1536,8 @@ def config_unset(key, def current_branch(cwd, user=None, password=None, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' Returns the current branch name of a local checkout. If HEAD is detached, return the SHA1 of the revision which is currently checked out. @@ -1538,14 +1574,16 @@ def current_branch(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode)['stdout'] + ignore_retcode=ignore_retcode, + output_encoding=output_encoding)['stdout'] def describe(cwd, rev='HEAD', user=None, password=None, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' Returns the `git-describe(1)`_ string (or the SHA1 hash if there are no tags) for the given revision. @@ -1591,7 +1629,8 @@ def describe(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode)['stdout'] + ignore_retcode=ignore_retcode, + output_encoding=output_encoding)['stdout'] def diff(cwd, @@ -1603,7 +1642,8 @@ def diff(cwd, password=None, no_index=False, cached=False, - paths=None): + paths=None, + output_encoding=None): ''' .. versionadded:: 2015.8.12,2016.3.3,2016.11.0 @@ -1750,7 +1790,8 @@ def diff(cwd, password=password, ignore_retcode=ignore_retcode, failhard=failhard, - redirect_stderr=True)['stdout'] + redirect_stderr=True, + output_encoding=output_encoding)['stdout'] def fetch(cwd, @@ -1763,7 +1804,8 @@ def fetch(cwd, password=None, identity=None, ignore_retcode=False, - saltenv='base'): + saltenv='base', + output_encoding=None): ''' .. versionchanged:: 2015.8.2 Return data is now a dictionary containing information on branches and @@ -1888,7 +1930,8 @@ def fetch(cwd, identity=identity, ignore_retcode=ignore_retcode, redirect_stderr=True, - saltenv=saltenv)['stdout'] + saltenv=saltenv, + output_encoding=output_encoding)['stdout'] update_re = re.compile( r'[\s*]*(?:([0-9a-f]+)\.\.([0-9a-f]+)|' @@ -1926,7 +1969,8 @@ def init(cwd, git_opts='', user=None, password=None, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' Interface to `git-init(1)`_ @@ -2025,12 +2069,14 @@ def init(cwd, return _git_run(command, user=user, password=password, - ignore_retcode=ignore_retcode)['stdout'] + ignore_retcode=ignore_retcode, + output_encoding=output_encoding)['stdout'] def is_worktree(cwd, user=None, - password=None): + password=None, + output_encoding=None): ''' .. versionadded:: 2015.8.0 @@ -2060,7 +2106,8 @@ def is_worktree(cwd, ''' cwd = _expand_path(cwd, user) try: - toplevel = _get_toplevel(cwd, user=user, password=password) + toplevel = _get_toplevel(cwd, user=user, password=password, + output_encoding=output_encoding) except CommandExecutionError: return False gitdir = os.path.join(toplevel, '.git') @@ -2091,7 +2138,8 @@ def list_branches(cwd, remote=False, user=None, password=None, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' .. versionadded:: 2015.8.0 @@ -2141,13 +2189,15 @@ def list_branches(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode)['stdout'].splitlines() + ignore_retcode=ignore_retcode, + output_encoding=output_encoding)['stdout'].splitlines() def list_tags(cwd, user=None, password=None, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' .. versionadded:: 2015.8.0 @@ -2186,13 +2236,15 @@ def list_tags(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode)['stdout'].splitlines() + ignore_retcode=ignore_retcode, + output_encoding=output_encoding)['stdout'].splitlines() def list_worktrees(cwd, stale=False, user=None, password=None, + output_encoding=None, **kwargs): ''' .. versionadded:: 2015.8.0 @@ -2259,14 +2311,16 @@ def list_worktrees(cwd, '\'all\' and \'stale\' cannot both be set to True' ) - def _git_tag_points_at(cwd, rev, user=None, password=None): + def _git_tag_points_at(cwd, rev, user=None, password=None, + output_encoding=None): ''' Get any tags that point at a ''' return _git_run(['git', 'tag', '--points-at', rev], cwd=cwd, user=user, - password=password)['stdout'].splitlines() + password=password, + output_encoding=output_encoding)['stdout'].splitlines() def _desired(is_stale, all_, stale): ''' @@ -2303,7 +2357,8 @@ def list_worktrees(cwd, out = _git_run(['git', 'worktree', 'list', '--porcelain'], cwd=cwd, user=user, - password=password) + password=password, + output_encoding=output_encoding) if out['retcode'] != 0: msg = 'Failed to list worktrees' if out['stderr']: @@ -2373,7 +2428,8 @@ def list_worktrees(cwd, tags_found = _git_tag_points_at(cwd, wt_ptr['HEAD'], user=user, - password=password) + password=password, + output_encoding=output_encoding) if tags_found: wt_ptr['tags'] = tags_found else: @@ -2383,12 +2439,14 @@ def list_worktrees(cwd, return ret else: - toplevel = _get_toplevel(cwd, user=user, password=password) + toplevel = _get_toplevel(cwd, user=user, password=password, + output_encoding=output_encoding) try: worktree_root = rev_parse(cwd, opts=['--git-path', 'worktrees'], user=user, - password=password) + password=password, + output_encoding=output_encoding) except CommandExecutionError as exc: msg = 'Failed to find worktree location for ' + cwd log.error(msg, exc_info_on_loglevel=logging.DEBUG) @@ -2454,7 +2512,8 @@ def list_worktrees(cwd, wt_head = rev_parse(cwd, rev=head_ref, user=user, - password=password) + password=password, + output_encoding=output_encoding) wt_detached = False else: wt_branch = None @@ -2472,7 +2531,8 @@ def list_worktrees(cwd, tags_found = _git_tag_points_at(cwd, wt_head, user=user, - password=password) + password=password, + output_encoding=output_encoding) if tags_found: wt_ptr['tags'] = tags_found @@ -2490,6 +2550,7 @@ def ls_remote(cwd=None, https_user=None, https_pass=None, ignore_retcode=False, + output_encoding=None, saltenv='base'): ''' Interface to `git-ls-remote(1)`_. Returns the upstream hash for a remote @@ -2620,7 +2681,8 @@ def ls_remote(cwd=None, password=password, identity=identity, ignore_retcode=ignore_retcode, - saltenv=saltenv)['stdout'] + saltenv=saltenv, + output_encoding=output_encoding)['stdout'] ret = {} for line in output.splitlines(): try: @@ -2638,6 +2700,7 @@ def merge(cwd, user=None, password=None, ignore_retcode=False, + output_encoding=None, **kwargs): ''' Interface to `git-merge(1)`_ @@ -2713,7 +2776,8 @@ def merge(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode)['stdout'] + ignore_retcode=ignore_retcode, + output_encoding=output_encoding)['stdout'] def merge_base(cwd, @@ -2727,6 +2791,7 @@ def merge_base(cwd, user=None, password=None, ignore_retcode=False, + output_encoding=None, **kwargs): ''' .. versionadded:: 2015.8.0 @@ -2878,13 +2943,15 @@ def merge_base(cwd, opts=['--verify'], user=user, password=password, - ignore_retcode=ignore_retcode) + ignore_retcode=ignore_retcode, + output_encoding=output_encoding) return merge_base(cwd, refs=refs, is_ancestor=False, user=user, password=password, - ignore_retcode=ignore_retcode) == first_commit + ignore_retcode=ignore_retcode, + output_encoding=output_encoding) == first_commit command = ['git'] + _format_git_opts(git_opts) command.append('merge-base') @@ -2905,7 +2972,8 @@ def merge_base(cwd, user=user, password=password, ignore_retcode=ignore_retcode, - failhard=False if is_ancestor else True) + failhard=False if is_ancestor else True, + output_encoding=output_encoding) if is_ancestor: return result['retcode'] == 0 all_bases = result['stdout'].splitlines() @@ -2920,7 +2988,8 @@ def merge_tree(cwd, base=None, user=None, password=None, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' .. versionadded:: 2015.8.0 @@ -2969,7 +3038,8 @@ def merge_tree(cwd, command = ['git', 'merge-tree'] if base is None: try: - base = merge_base(cwd, refs=[ref1, ref2]) + base = merge_base(cwd, refs=[ref1, ref2], + output_encoding=output_encoding) except (SaltInvocationError, CommandExecutionError): raise CommandExecutionError( 'Unable to determine merge base for {0} and {1}' @@ -2980,7 +3050,8 @@ def merge_tree(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode)['stdout'] + ignore_retcode=ignore_retcode, + output_encoding=output_encoding)['stdout'] def pull(cwd, @@ -2990,7 +3061,8 @@ def pull(cwd, password=None, identity=None, ignore_retcode=False, - saltenv='base'): + saltenv='base', + output_encoding=None): ''' Interface to `git-pull(1)`_ @@ -3077,7 +3149,8 @@ def pull(cwd, password=password, identity=identity, ignore_retcode=ignore_retcode, - saltenv=saltenv)['stdout'] + saltenv=saltenv, + output_encoding=output_encoding)['stdout'] def push(cwd, @@ -3090,6 +3163,7 @@ def push(cwd, identity=None, ignore_retcode=False, saltenv='base', + output_encoding=None, **kwargs): ''' Interface to `git-push(1)`_ @@ -3200,7 +3274,8 @@ def push(cwd, password=password, identity=identity, ignore_retcode=ignore_retcode, - saltenv=saltenv)['stdout'] + saltenv=saltenv, + output_encoding=output_encoding)['stdout'] def rebase(cwd, @@ -3209,7 +3284,8 @@ def rebase(cwd, git_opts='', user=None, password=None, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' Interface to `git-rebase(1)`_ @@ -3278,7 +3354,8 @@ def rebase(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode)['stdout'] + ignore_retcode=ignore_retcode, + output_encoding=output_encoding)['stdout'] def remote_get(cwd, @@ -3286,7 +3363,8 @@ def remote_get(cwd, user=None, password=None, redact_auth=True, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' Get the fetch and push URL for a specific remote @@ -3337,7 +3415,8 @@ def remote_get(cwd, user=user, password=password, redact_auth=redact_auth, - ignore_retcode=ignore_retcode) + ignore_retcode=ignore_retcode, + output_encoding=output_encoding) if remote not in all_remotes: raise CommandExecutionError( 'Remote \'{0}\' not present in git checkout located at {1}' @@ -3355,6 +3434,7 @@ def remote_refs(url, https_user=None, https_pass=None, ignore_retcode=False, + output_encoding=None, saltenv='base'): ''' .. versionadded:: 2015.8.0 @@ -3441,7 +3521,8 @@ def remote_refs(url, password=password, identity=identity, ignore_retcode=ignore_retcode, - saltenv=saltenv)['stdout'] + saltenv=saltenv, + output_encoding=output_encoding)['stdout'] ret = {} for line in salt.utils.itertools.split(output, '\n'): try: @@ -3462,7 +3543,8 @@ def remote_set(cwd, push_url=None, push_https_user=None, push_https_pass=None, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' cwd The path to the git checkout @@ -3526,7 +3608,8 @@ def remote_set(cwd, salt myminion git.remote_set /path/to/repo https://github.com/user/repo.git remote=upstream push_url=git@github.com:user/repo.git ''' # Check if remote exists - if remote in remotes(cwd, user=user, password=password): + if remote in remotes(cwd, user=user, password=password, + output_encoding=output_encoding): log.debug( 'Remote \'%s\' already exists in git checkout located at %s, ' 'removing so it can be re-added', remote, cwd @@ -3536,7 +3619,8 @@ def remote_set(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode) + ignore_retcode=ignore_retcode, + output_encoding=output_encoding) # Add remote try: url = salt.utils.url.add_http_basic_auth(url, @@ -3550,7 +3634,8 @@ def remote_set(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode) + ignore_retcode=ignore_retcode, + output_encoding=output_encoding) if push_url: if not isinstance(push_url, six.string_types): push_url = six.text_type(push_url) @@ -3566,19 +3651,22 @@ def remote_set(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode) + ignore_retcode=ignore_retcode, + output_encoding=output_encoding) return remote_get(cwd=cwd, remote=remote, user=user, password=password, - ignore_retcode=ignore_retcode) + ignore_retcode=ignore_retcode, + output_encoding=output_encoding) def remotes(cwd, user=None, password=None, redact_auth=True, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' Get fetch and push URLs for each remote in a git checkout @@ -3628,7 +3716,8 @@ def remotes(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode)['stdout'] + ignore_retcode=ignore_retcode, + output_encoding=output_encoding)['stdout'] for remote_line in salt.utils.itertools.split(output, '\n'): try: remote, remote_info = remote_line.split(None, 1) @@ -3657,7 +3746,8 @@ def reset(cwd, git_opts='', user=None, password=None, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' Interface to `git-reset(1)`_, returns the stdout from the git command @@ -3718,7 +3808,8 @@ def reset(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode)['stdout'] + ignore_retcode=ignore_retcode, + output_encoding=output_encoding)['stdout'] def rev_parse(cwd, @@ -3727,7 +3818,8 @@ def rev_parse(cwd, git_opts='', user=None, password=None, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' .. versionadded:: 2015.8.0 @@ -3801,7 +3893,8 @@ def rev_parse(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode)['stdout'] + ignore_retcode=ignore_retcode, + output_encoding=output_encoding)['stdout'] def revision(cwd, @@ -3809,7 +3902,8 @@ def revision(cwd, short=False, user=None, password=None, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' Returns the SHA1 hash of a given identifier (hash, branch, tag, HEAD, etc.) @@ -3853,7 +3947,8 @@ def revision(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode)['stdout'] + ignore_retcode=ignore_retcode, + output_encoding=output_encoding)['stdout'] def rm_(cwd, @@ -3862,7 +3957,8 @@ def rm_(cwd, git_opts='', user=None, password=None, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' Interface to `git-rm(1)`_ @@ -3930,7 +4026,8 @@ def rm_(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode)['stdout'] + ignore_retcode=ignore_retcode, + output_encoding=output_encoding)['stdout'] def stash(cwd, @@ -3939,7 +4036,8 @@ def stash(cwd, git_opts='', user=None, password=None, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' Interface to `git-stash(1)`_, returns the stdout from the git command @@ -3999,13 +4097,15 @@ def stash(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode)['stdout'] + ignore_retcode=ignore_retcode, + output_encoding=output_encoding)['stdout'] def status(cwd, user=None, password=None, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' .. versionchanged:: 2015.8.0 Return data has changed from a list of lists to a dictionary @@ -4051,7 +4151,8 @@ def status(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode)['stdout'] + ignore_retcode=ignore_retcode, + output_encoding=output_encoding)['stdout'] for line in output.split('\0'): try: state, filename = line.split(None, 1) @@ -4070,6 +4171,7 @@ def submodule(cwd, identity=None, ignore_retcode=False, saltenv='base', + output_encoding=None, **kwargs): ''' .. versionchanged:: 2015.8.0 @@ -4202,7 +4304,8 @@ def submodule(cwd, password=password, identity=identity, ignore_retcode=ignore_retcode, - saltenv=saltenv)['stdout'] + saltenv=saltenv, + output_encoding=output_encoding)['stdout'] def symbolic_ref(cwd, @@ -4212,7 +4315,8 @@ def symbolic_ref(cwd, git_opts='', user=None, password=None, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' .. versionadded:: 2015.8.0 @@ -4293,7 +4397,8 @@ def symbolic_ref(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode)['stdout'] + ignore_retcode=ignore_retcode, + output_encoding=output_encoding)['stdout'] def version(versioninfo=False): @@ -4357,6 +4462,7 @@ def worktree_add(cwd, user=None, password=None, ignore_retcode=False, + output_encoding=None, **kwargs): ''' .. versionadded:: 2015.8.0 @@ -4480,7 +4586,8 @@ def worktree_add(cwd, user=user, password=password, ignore_retcode=ignore_retcode, - redirect_stderr=True)['stdout'] + redirect_stderr=True, + output_encoding=output_encoding)['stdout'] def worktree_prune(cwd, @@ -4491,7 +4598,8 @@ def worktree_prune(cwd, git_opts='', user=None, password=None, - ignore_retcode=False): + ignore_retcode=False, + output_encoding=None): ''' .. versionadded:: 2015.8.0 @@ -4581,10 +4689,11 @@ def worktree_prune(cwd, cwd=cwd, user=user, password=password, - ignore_retcode=ignore_retcode)['stdout'] + ignore_retcode=ignore_retcode, + output_encoding=output_encoding)['stdout'] -def worktree_rm(cwd, user=None): +def worktree_rm(cwd, user=None, output_encoding=None): ''' .. versionadded:: 2015.8.0 @@ -4620,7 +4729,7 @@ def worktree_rm(cwd, user=None): cwd = _expand_path(cwd, user) if not os.path.exists(cwd): raise CommandExecutionError(cwd + ' does not exist') - elif not is_worktree(cwd): + elif not is_worktree(cwd, output_encoding=output_encoding): raise CommandExecutionError(cwd + ' is not a git worktree') try: salt.utils.files.rm_rf(cwd) diff --git a/tests/integration/modules/test_git.py b/tests/integration/modules/test_git.py index 6ede0f96f1..1172e70332 100644 --- a/tests/integration/modules/test_git.py +++ b/tests/integration/modules/test_git.py @@ -147,7 +147,8 @@ class GitModuleTest(ModuleCase): TODO: maybe move this behavior to ModuleCase itself? ''' return salt.utils.data.decode( - super(GitModuleTest, self).run_function(*args, **kwargs) + super(GitModuleTest, self).run_function(*args, **kwargs), + encoding='utf-8' ) def tearDown(self): @@ -206,7 +207,8 @@ class GitModuleTest(ModuleCase): self.run_function('cmd.run', ['cp ' + tar_archive + ' /root/']) with closing(tarfile.open(tar_archive, 'r')) as tar_obj: self.assertEqual( - sorted(salt.utils.data.decode(tar_obj.getnames())), + sorted(salt.utils.data.decode(tar_obj.getnames(), + encoding='utf-8')), sorted([ 'foo', 'foo/bar', 'foo/baz', 'foo/foo', 'foo/питон', 'foo/qux', 'foo/qux/bar', 'foo/qux/baz', 'foo/qux/foo', @@ -236,7 +238,8 @@ class GitModuleTest(ModuleCase): self.assertTrue(tarfile.is_tarfile(tar_archive)) with closing(tarfile.open(tar_archive, 'r')) as tar_obj: self.assertEqual( - sorted(salt.utils.data.decode(tar_obj.getnames())), + sorted(salt.utils.data.decode(tar_obj.getnames(), + encoding='utf-8')), sorted(['foo', 'foo/bar', 'foo/baz', 'foo/foo', 'foo/питон']) ) finally: From 80e3a47dd4fc61b05bcfb659fee6794f38412f98 Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Fri, 23 Feb 2018 15:02:16 -0600 Subject: [PATCH 2/7] Add output_encoding argument to git state, and add docs --- salt/modules/git.py | 997 +++++++++++++++++++++++++++++++++++++++++++- salt/states/git.py | 390 +++++++++++++---- 2 files changed, 1276 insertions(+), 111 deletions(-) diff --git a/salt/modules/git.py b/salt/modules/git.py index 15d1d8db0d..f62d98ac62 100644 --- a/salt/modules/git.py +++ b/salt/modules/git.py @@ -306,7 +306,7 @@ def _git_run(command, cwd=None, user=None, password=None, identity=None, log_callback=salt.utils.url.redact_http_basic_auth, ignore_retcode=ignore_retcode, redirect_stderr=redirect_stderr, - output_encoding=output_encoding + output_encoding=output_encoding, **kwargs) finally: # Cleanup the temporary ssh wrapper file @@ -490,8 +490,31 @@ def add(cwd, .. versionadded:: 2015.8.0 - .. _`git-add(1)`: http://git-scm.com/docs/git-add + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + + .. _`git-add(1)`: http://git-scm.com/docs/git-add CLI Examples: @@ -615,8 +638,31 @@ def archive(cwd, .. versionadded:: 2015.8.0 - .. _`git-archive(1)`: http://git-scm.com/docs/git-archive + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + + .. _`git-archive(1)`: http://git-scm.com/docs/git-archive CLI Example: @@ -718,8 +764,31 @@ def branch(cwd, .. versionadded:: 2015.8.0 - .. _`git-branch(1)`: http://git-scm.com/docs/git-branch + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + + .. _`git-branch(1)`: http://git-scm.com/docs/git-branch CLI Examples: @@ -808,8 +877,31 @@ def checkout(cwd, .. versionadded:: 2015.8.0 - .. _`git-checkout(1)`: http://git-scm.com/docs/git-checkout + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + + .. _`git-checkout(1)`: http://git-scm.com/docs/git-checkout CLI Examples: @@ -951,6 +1043,30 @@ def clone(cwd, .. versionadded:: 2016.3.1 + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + .. _`git-clone(1)`: http://git-scm.com/docs/git-clone CLI Example: @@ -1068,8 +1184,31 @@ def commit(cwd, .. versionadded:: 2015.8.0 - .. _`git-commit(1)`: http://git-scm.com/docs/git-commit + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + + .. _`git-commit(1)`: http://git-scm.com/docs/git-commit CLI Examples: @@ -1144,6 +1283,29 @@ def config_get(key, .. versionadded:: 2015.8.0 + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 CLI Examples: @@ -1232,6 +1394,29 @@ def config_get_regexp(key, If ``True``, do not log an error to the minion log if the git command returns a nonzero exit status. + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 CLI Examples: @@ -1334,7 +1519,31 @@ def config_set(key, global : False If ``True``, set a global variable - CLI Example: + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + + CLI Examples: .. code-block:: bash @@ -1461,6 +1670,29 @@ def config_unset(key, If ``True``, do not log an error to the minion log if the git command returns a nonzero exit status. + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 CLI Example: @@ -1561,6 +1793,29 @@ def current_branch(cwd, .. versionadded:: 2015.8.0 + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 CLI Example: @@ -1610,8 +1865,31 @@ def describe(cwd, .. versionadded:: 2015.8.0 - .. _`git-describe(1)`: http://git-scm.com/docs/git-describe + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + + .. _`git-describe(1)`: http://git-scm.com/docs/git-describe CLI Examples: @@ -1711,8 +1989,31 @@ def diff(cwd, File paths to pass to the ``git diff`` command. Can be passed as a comma-separated list or a Python list. - .. _`git-diff(1)`: http://git-scm.com/docs/git-diff + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + + .. _`git-diff(1)`: http://git-scm.com/docs/git-diff CLI Example: @@ -1895,8 +2196,31 @@ def fetch(cwd, .. versionadded:: 2016.3.1 - .. _`git-fetch(1)`: http://git-scm.com/docs/git-fetch + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + + .. _`git-fetch(1)`: http://git-scm.com/docs/git-fetch CLI Example: @@ -2032,6 +2356,30 @@ def init(cwd, .. versionadded:: 2015.8.0 + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + .. _`git-init(1)`: http://git-scm.com/docs/git-init .. _`template directory`: http://git-scm.com/docs/git-init#_template_directory @@ -2097,6 +2445,29 @@ def is_worktree(cwd, .. versionadded:: 2016.3.4 + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 CLI Example: @@ -2174,6 +2545,29 @@ def list_branches(cwd, .. versionadded:: 2015.8.0 + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 CLI Examples: @@ -2222,6 +2616,29 @@ def list_tags(cwd, .. versionadded:: 2015.8.0 + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 CLI Examples: @@ -2287,8 +2704,31 @@ def list_worktrees(cwd, .. note:: Only one of ``all`` and ``stale`` can be set to ``True``. - .. _`git-worktree(1)`: http://git-scm.com/docs/git-worktree + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + + .. _`git-worktree(1)`: http://git-scm.com/docs/git-worktree CLI Examples: @@ -2650,8 +3090,31 @@ def ls_remote(cwd=None, .. versionadded:: 2016.3.1 - .. _`git-ls-remote(1)`: http://git-scm.com/docs/git-ls-remote + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + + .. _`git-ls-remote(1)`: http://git-scm.com/docs/git-ls-remote CLI Example: @@ -2748,8 +3211,31 @@ def merge(cwd, .. versionadded:: 2015.8.0 - .. _`git-merge(1)`: http://git-scm.com/docs/git-merge + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + + .. _`git-merge(1)`: http://git-scm.com/docs/git-merge CLI Example: @@ -2878,10 +3364,33 @@ def merge_base(cwd, if ``True``, do not log an error to the minion log if the git command returns a nonzero exit status. + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + .. _`git-merge-base(1)`: http://git-scm.com/docs/git-merge-base .. _here: http://git-scm.com/docs/git-merge-base#_discussion - CLI Examples: .. code-block:: bash @@ -3024,8 +3533,31 @@ def merge_tree(cwd, if ``True``, do not log an error to the minion log if the git command returns a nonzero exit status. - .. _`git-merge-tree(1)`: http://git-scm.com/docs/git-merge-tree + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + + .. _`git-merge-tree(1)`: http://git-scm.com/docs/git-merge-tree CLI Examples: @@ -3131,6 +3663,30 @@ def pull(cwd, .. versionadded:: 2016.3.1 + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + .. _`git-pull(1)`: http://git-scm.com/docs/git-pull CLI Example: @@ -3245,6 +3801,30 @@ def push(cwd, .. versionadded:: 2016.3.1 + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + .. _`git-push(1)`: http://git-scm.com/docs/git-push .. _refspec: http://git-scm.com/book/en/v2/Git-Internals-The-Refspec @@ -3329,6 +3909,30 @@ def rebase(cwd, .. versionadded:: 2015.8.0 + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + .. _`git-rebase(1)`: http://git-scm.com/docs/git-rebase @@ -3402,6 +4006,29 @@ def remote_get(cwd, .. versionadded:: 2015.8.0 + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 CLI Examples: @@ -3498,6 +4125,30 @@ def remote_refs(url, .. versionadded:: 2016.3.1 + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + CLI Example: .. code-block:: bash @@ -3598,6 +4249,29 @@ def remote_set(cwd, .. versionadded:: 2015.8.0 + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 CLI Examples: @@ -3702,6 +4376,29 @@ def remotes(cwd, .. versionadded:: 2015.8.0 + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 CLI Example: @@ -3788,8 +4485,31 @@ def reset(cwd, .. versionadded:: 2015.8.0 - .. _`git-reset(1)`: http://git-scm.com/docs/git-reset + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + + .. _`git-reset(1)`: http://git-scm.com/docs/git-reset CLI Examples: @@ -3863,11 +4583,34 @@ def rev_parse(cwd, If ``True``, do not log an error to the minion log if the git command returns a nonzero exit status. + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + .. _`git-rev-parse(1)`: http://git-scm.com/docs/git-rev-parse .. _`SPECIFYING REVISIONS`: http://git-scm.com/docs/git-rev-parse#_specifying_revisions .. _`Options for Files`: http://git-scm.com/docs/git-rev-parse#_options_for_files - CLI Examples: .. code-block:: bash @@ -3932,6 +4675,30 @@ def revision(cwd, .. versionadded:: 2015.8.0 + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + CLI Example: .. code-block:: bash @@ -4006,8 +4773,31 @@ def rm_(cwd, .. versionadded:: 2015.8.0 - .. _`git-rm(1)`: http://git-scm.com/docs/git-rm + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + + .. _`git-rm(1)`: http://git-scm.com/docs/git-rm CLI Examples: @@ -4077,8 +4867,31 @@ def stash(cwd, .. versionadded:: 2015.8.0 - .. _`git-stash(1)`: http://git-scm.com/docs/git-stash + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + + .. _`git-stash(1)`: http://git-scm.com/docs/git-stash CLI Examples: @@ -4131,6 +4944,29 @@ def status(cwd, .. versionadded:: 2015.8.0 + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 CLI Example: @@ -4263,6 +5099,30 @@ def submodule(cwd, .. versionadded:: 2016.3.1 + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + .. _`git-submodule(1)`: http://git-scm.com/docs/git-submodule CLI Example: @@ -4366,8 +5226,31 @@ def symbolic_ref(cwd, .. versionadded:: 2015.8.0 - .. _`git-symbolic-ref(1)`: http://git-scm.com/docs/git-symbolic-ref + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + + .. _`git-symbolic-ref(1)`: http://git-scm.com/docs/git-symbolic-ref CLI Examples: @@ -4411,7 +5294,6 @@ def version(versioninfo=False): If ``True``, return the version in a versioninfo list (e.g. ``[2, 5, 0]``) - CLI Example: .. code-block:: bash @@ -4539,8 +5421,31 @@ def worktree_add(cwd, .. versionadded:: 2015.8.0 - .. _`git-worktree(1)`: http://git-scm.com/docs/git-worktree + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + + .. _`git-worktree(1)`: http://git-scm.com/docs/git-worktree CLI Examples: @@ -4662,10 +5567,33 @@ def worktree_prune(cwd, .. versionadded:: 2015.8.0 + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + .. _`git-worktree(1)`: http://git-scm.com/docs/git-worktree .. _`git-config(1)`: http://git-scm.com/docs/git-config/2.5.1 - CLI Examples: .. code-block:: bash @@ -4718,6 +5646,29 @@ def worktree_rm(cwd, user=None, output_encoding=None): running. Setting this option will change the home directory from which path expansion is performed. + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 CLI Examples: diff --git a/salt/states/git.py b/salt/states/git.py index 72b1ce8e87..4bc49df299 100644 --- a/salt/states/git.py +++ b/salt/states/git.py @@ -110,26 +110,30 @@ def _get_branch_opts(branch, local_branch, all_local_branches, return ret -def _get_local_rev_and_branch(target, user, password): +def _get_local_rev_and_branch(target, user, password, output_encoding=None): ''' Return the local revision for before/after comparisons ''' log.info('Checking local revision for %s', target) try: - local_rev = __salt__['git.revision'](target, - user=user, - password=password, - ignore_retcode=True) + local_rev = __salt__['git.revision']( + target, + user=user, + password=password, + ignore_retcode=True, + output_encoding=output_encoding) except CommandExecutionError: log.info('No local revision for %s', target) local_rev = None log.info('Checking local branch for %s', target) try: - local_branch = __salt__['git.current_branch'](target, - user=user, - password=password, - ignore_retcode=True) + local_branch = __salt__['git.current_branch']( + target, + user=user, + password=password, + ignore_retcode=True, + output_encoding=output_encoding) except CommandExecutionError: log.info('No local branch for %s', target) local_branch = None @@ -260,6 +264,7 @@ def latest(name, unless=False, refspec_branch='*', refspec_tag='*', + output_encoding=None, **kwargs): ''' Make sure the repository is cloned to the given directory and is @@ -521,6 +526,30 @@ def latest(name, .. versionadded:: 2017.7.0 + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + .. _`git-fetch(1)`: http://git-scm.com/docs/git-fetch .. note:: @@ -698,7 +727,8 @@ def latest(name, https_user=https_user, https_pass=https_pass, ignore_retcode=False, - saltenv=__env__) + saltenv=__env__, + output_encoding=output_encoding) except CommandExecutionError as exc: return _fail( ret, @@ -808,18 +838,29 @@ def latest(name, check = 'refs' if bare else '.git' gitdir = os.path.join(target, check) comments = [] - if os.path.isdir(gitdir) or __salt__['git.is_worktree'](target, - user=user, - password=password): + if os.path.isdir(gitdir) \ + or __salt__['git.is_worktree']( + target, + user=user, + password=password, + output_encoding=output_encoding): # Target directory is a git repository or git worktree try: all_local_branches = __salt__['git.list_branches']( - target, user=user, password=password) - all_local_tags = __salt__['git.list_tags'](target, - user=user, - password=password) - local_rev, local_branch = \ - _get_local_rev_and_branch(target, user, password) + target, + user=user, + password=password, + output_encoding=output_encoding) + all_local_tags = __salt__['git.list_tags']( + target, + user=user, + password=password, + output_encoding=output_encoding) + local_rev, local_branch = _get_local_rev_and_branch( + target, + user, + password, + output_encoding) if not bare and remote_rev is None and local_rev is not None: return _fail( @@ -855,7 +896,8 @@ def latest(name, branch + '^{commit}', user=user, password=password, - ignore_retcode=True) + ignore_retcode=True, + output_encoding=output_encoding) except CommandExecutionError as exc: return _fail( ret, @@ -867,7 +909,8 @@ def latest(name, remotes = __salt__['git.remotes'](target, user=user, password=password, - redact_auth=False) + redact_auth=False, + output_encoding=output_encoding) revs_match = _revs_equal(local_rev, remote_rev, remote_rev_type) try: @@ -879,7 +922,8 @@ def latest(name, __salt__['git.diff'](target, 'HEAD', user=user, - password=password) + password=password, + output_encoding=output_encoding) ) except CommandExecutionError: # No need to capture the error and log it, the _git_run() @@ -933,7 +977,8 @@ def latest(name, remote_rev + '^{commit}', user=user, password=password, - ignore_retcode=True) + ignore_retcode=True, + output_encoding=output_encoding) except CommandExecutionError: # Local checkout doesn't have the remote_rev pass @@ -954,7 +999,8 @@ def latest(name, desired_upstream, user=user, password=password, - ignore_retcode=True) + ignore_retcode=True, + output_encoding=output_encoding) except CommandExecutionError: pass else: @@ -974,7 +1020,8 @@ def latest(name, rev + '^{commit}', user=user, password=password, - ignore_retcode=True) + ignore_retcode=True, + output_encoding=output_encoding) except CommandExecutionError: # Shouldn't happen if the tag exists # locally but account for this just in @@ -1044,7 +1091,8 @@ def latest(name, is_ancestor=True, user=user, password=password, - ignore_retcode=True) + ignore_retcode=True, + output_encoding=output_encoding) if fast_forward is False: if not force_reset: @@ -1075,7 +1123,8 @@ def latest(name, opts=['--abbrev-ref'], user=user, password=password, - ignore_retcode=True) + ignore_retcode=True, + output_encoding=output_encoding) except CommandExecutionError: # There is a local branch but the rev-parse command # failed, so that means there is no upstream tracking @@ -1144,7 +1193,8 @@ def latest(name, user=user, password=password, https_user=https_user, - https_pass=https_pass) + https_pass=https_pass, + output_encoding=output_encoding) if fetch_url is None: comments.append( 'Remote \'{0}\' set to {1}'.format( @@ -1318,7 +1368,7 @@ def latest(name, identity=identity, saltenv=__env__, ignore_retcode=True, - ).keys() if '^{}' not in x + output_encoding=output_encoding) if '^{}' not in x ]) if set(all_local_tags) != remote_tags: has_remote_rev = False @@ -1336,7 +1386,8 @@ def latest(name, user=user, password=password, identity=identity, - saltenv=__env__) + saltenv=__env__, + output_encoding=output_encoding) except CommandExecutionError as exc: return _failed_fetch(ret, exc, comments) else: @@ -1352,7 +1403,8 @@ def latest(name, remote_rev + '^{commit}', user=user, password=password, - ignore_retcode=True) + ignore_retcode=True, + output_encoding=output_encoding) except CommandExecutionError as exc: return _fail( ret, @@ -1384,7 +1436,8 @@ def latest(name, refs=[base_rev, remote_rev], is_ancestor=True, user=user, - password=password) + password=password, + output_encoding=output_encoding) if fast_forward is False and not force_reset: return _not_fast_forward( @@ -1427,7 +1480,8 @@ def latest(name, force=force_checkout, opts=checkout_opts, user=user, - password=password) + password=password, + output_encoding=output_encoding) if '-b' in checkout_opts: comments.append( 'New branch \'{0}\' was checked out, with {1} ' @@ -1450,7 +1504,7 @@ def latest(name, opts=['--hard', remote_rev], user=user, password=password, - ) + output_encoding=output_encoding) ret['changes']['forced update'] = True comments.append( 'Repository was hard-reset to {0}'.format(remote_loc) @@ -1461,7 +1515,8 @@ def latest(name, target, opts=branch_opts, user=user, - password=password) + password=password, + output_encoding=output_encoding) comments.append(upstream_action) # Fast-forward to the desired revision @@ -1474,12 +1529,14 @@ def latest(name, # trying to merge changes. (The call to # git.symbolic_ref will only return output if HEAD # points to a branch.) - if __salt__['git.symbolic_ref'](target, - 'HEAD', - opts=['--quiet'], - user=user, - password=password, - ignore_retcode=True): + if __salt__['git.symbolic_ref']( + target, + 'HEAD', + opts=['--quiet'], + user=user, + password=password, + ignore_retcode=True, + output_encoding=output_encoding): if git_ver >= _LooseVersion('1.8.1.6'): # --ff-only added in version 1.8.1.6. It's not @@ -1499,7 +1556,8 @@ def latest(name, rev=remote_rev, opts=merge_opts, user=user, - password=password) + password=password, + output_encoding=output_encoding) comments.append( 'Repository was fast-forwarded to {0}' .format(remote_loc) @@ -1518,7 +1576,8 @@ def latest(name, opts=['--hard', remote_rev if rev == 'HEAD' else rev], user=user, - password=password) + password=password, + output_encoding=output_encoding) comments.append( 'Repository was reset to {0} (fast-forward)' .format(rev) @@ -1535,7 +1594,8 @@ def latest(name, user=user, password=password, identity=identity, - saltenv=__env__) + saltenv=__env__, + output_encoding=output_encoding) except CommandExecutionError as exc: return _failed_submodule_update(ret, exc, comments) elif bare: @@ -1557,7 +1617,8 @@ def latest(name, user=user, password=password, identity=identity, - saltenv=__env__) + saltenv=__env__, + output_encoding=output_encoding) except CommandExecutionError as exc: return _failed_fetch(ret, exc, comments) else: @@ -1574,7 +1635,8 @@ def latest(name, cwd=target, user=user, password=password, - ignore_retcode=True) + ignore_retcode=True, + output_encoding=output_encoding) except CommandExecutionError: new_rev = None @@ -1682,7 +1744,8 @@ def latest(name, identity=identity, https_user=https_user, https_pass=https_pass, - saltenv=__env__) + saltenv=__env__, + output_encoding=output_encoding) except CommandExecutionError as exc: msg = 'Clone failed: {0}'.format(_strip_exc(exc)) return _fail(ret, msg, comments) @@ -1715,7 +1778,10 @@ def latest(name, else: if remote_rev_type == 'tag' \ and rev not in __salt__['git.list_tags']( - target, user=user, password=password): + target, + user=user, + password=password, + output_encoding=output_encoding): return _fail( ret, 'Revision \'{0}\' does not exist in clone' @@ -1728,18 +1794,21 @@ def latest(name, __salt__['git.list_branches']( target, user=user, - password=password): + password=password, + output_encoding=output_encoding): if rev == 'HEAD': checkout_rev = remote_rev else: checkout_rev = desired_upstream \ if desired_upstream \ else rev - __salt__['git.checkout'](target, - checkout_rev, - opts=['-b', branch], - user=user, - password=password) + __salt__['git.checkout']( + target, + checkout_rev, + opts=['-b', branch], + user=user, + password=password, + output_encoding=output_encoding) comments.append( 'Branch \'{0}\' checked out, with {1} ' 'as a starting point'.format( @@ -1748,8 +1817,11 @@ def latest(name, ) ) - local_rev, local_branch = \ - _get_local_rev_and_branch(target, user, password) + local_rev, local_branch = _get_local_rev_and_branch( + target, + user, + password, + output_encoding=output_encoding) if local_branch is None \ and remote_rev is not None \ @@ -1771,7 +1843,8 @@ def latest(name, target, opts=['--hard', remote_rev], user=user, - password=password) + password=password, + output_encoding=output_encoding) comments.append( 'Repository was reset to {0}'.format(remote_loc) ) @@ -1783,7 +1856,8 @@ def latest(name, opts=['--abbrev-ref'], user=user, password=password, - ignore_retcode=True) + ignore_retcode=True, + output_encoding=output_encoding) except CommandExecutionError: upstream = False @@ -1796,9 +1870,11 @@ def latest(name, branch_opts = _get_branch_opts( branch, local_branch, - __salt__['git.list_branches'](target, - user=user, - password=password), + __salt__['git.list_branches']( + target, + user=user, + password=password, + output_encoding=output_encoding), desired_upstream, git_ver) elif upstream and desired_upstream is False: @@ -1821,9 +1897,11 @@ def latest(name, branch_opts = _get_branch_opts( branch, local_branch, - __salt__['git.list_branches'](target, - user=user, - password=password), + __salt__['git.list_branches']( + target, + user=user, + password=password, + output_encoding=output_encoding), desired_upstream, git_ver) else: @@ -1834,17 +1912,20 @@ def latest(name, target, opts=branch_opts, user=user, - password=password) + password=password, + output_encoding=output_encoding) comments.append(upstream_action) if submodules and remote_rev: try: - __salt__['git.submodule'](target, - 'update', - opts=['--init', '--recursive'], - user=user, - password=password, - identity=identity) + __salt__['git.submodule']( + target, + 'update', + opts=['--init', '--recursive'], + user=user, + password=password, + identity=identity, + output_encoding=output_encoding) except CommandExecutionError as exc: return _failed_submodule_update(ret, exc, comments) @@ -1853,7 +1934,8 @@ def latest(name, cwd=target, user=user, password=password, - ignore_retcode=True) + ignore_retcode=True, + output_encoding=output_encoding) except CommandExecutionError: new_rev = None @@ -1883,7 +1965,8 @@ def present(name, separate_git_dir=None, shared=None, user=None, - password=None): + password=None, + output_encoding=None): ''' Ensure that a repository exists in the given directory @@ -1943,6 +2026,30 @@ def present(name, .. versionadded:: 2016.3.4 + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + .. _`git-init(1)`: http://git-scm.com/docs/git-init .. _`worktree`: http://git-scm.com/docs/git-worktree ''' @@ -1954,7 +2061,10 @@ def present(name, return ret elif not bare and \ (os.path.isdir(os.path.join(name, '.git')) or - __salt__['git.is_worktree'](name, user=user, password=password)): + __salt__['git.is_worktree'](name, + user=user, + password=password, + output_encoding=output_encoding)): return ret # Directory exists and is not a git repo, if force is set destroy the # directory and recreate, otherwise throw an error @@ -2013,7 +2123,8 @@ def present(name, separate_git_dir=separate_git_dir, shared=shared, user=user, - password=password) + password=password, + output_encoding=output_encoding) actions = [ 'Initialized {0}repository in {1}'.format( @@ -2050,6 +2161,7 @@ def detached(name, https_pass=None, onlyif=False, unless=False, + output_encoding=None, **kwargs): ''' .. versionadded:: 2016.3.0 @@ -2132,6 +2244,29 @@ def detached(name, A command to run as a check, only run the named command if the command passed to the ``unless`` option returns false + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 ''' ret = {'name': name, 'result': True, 'comment': '', 'changes': {}} @@ -2252,10 +2387,17 @@ def detached(name, gitdir = os.path.join(target, '.git') if os.path.isdir(gitdir) \ - or __salt__['git.is_worktree'](target, user=user, password=password): + or __salt__['git.is_worktree'](target, + user=user, + password=password, + output_encoding=output_encoding): # Target directory is a git repository or git worktree - local_commit_id = _get_local_rev_and_branch(target, user, password)[0] + local_commit_id = _get_local_rev_and_branch( + target, + user, + password, + output_encoding=output_encoding)[0] if remote_rev_type is 'hash': try: @@ -2263,7 +2405,8 @@ def detached(name, rev, user=user, password=password, - ignore_retcode=True) + ignore_retcode=True, + output_encoding=output_encoding) except CommandExecutionError: hash_exists_locally = False else: @@ -2274,7 +2417,8 @@ def detached(name, remotes = __salt__['git.remotes'](target, user=user, password=password, - redact_auth=False) + redact_auth=False, + output_encoding=output_encoding) if remote in remotes and name in remotes[remote]['fetch']: pass @@ -2300,7 +2444,8 @@ def detached(name, user=user, password=password, https_user=https_user, - https_pass=https_pass) + https_pass=https_pass, + output_encoding=output_encoding) comments.append( 'Remote {0} updated from \'{1}\' to \'{2}\''.format( remote, @@ -2380,7 +2525,8 @@ def detached(name, identity=identity, https_user=https_user, https_pass=https_pass, - saltenv=__env__) + saltenv=__env__, + output_encoding=output_encoding) comments.append('{0} cloned to {1}'.format(name, target)) except Exception as exc: @@ -2417,7 +2563,8 @@ def detached(name, user=user, password=password, identity=identity, - saltenv=__env__) + saltenv=__env__, + output_encoding=output_encoding) except CommandExecutionError as exc: msg = 'Fetch failed' msg += ':\n\n' + six.text_type(exc) @@ -2432,7 +2579,12 @@ def detached(name, #get refs and checkout checkout_commit_id = '' if remote_rev_type is 'hash': - if __salt__['git.describe'](target, rev, user=user, password=password): + if __salt__['git.describe']( + target, + rev, + user=user, + password=password, + output_encoding=output_encoding): checkout_commit_id = rev else: return _fail( @@ -2448,7 +2600,8 @@ def detached(name, identity=identity, https_user=https_user, https_pass=https_pass, - ignore_retcode=False) + ignore_retcode=False, + output_encoding=output_encoding) if 'refs/remotes/'+remote+'/'+rev in all_remote_refs: checkout_commit_id = all_remote_refs['refs/remotes/' + remote + '/' + rev] @@ -2476,7 +2629,8 @@ def detached(name, target, opts=['--hard', 'HEAD'], user=user, - password=password) + password=password, + output_encoding=output_encoding) comments.append( 'Repository was reset to HEAD before checking out revision' ) @@ -2499,7 +2653,8 @@ def detached(name, checkout_commit_id, force=force_checkout, user=user, - password=password) + password=password, + output_encoding=output_encoding) comments.append( 'Commit ID {0} was checked out at {1}'.format( checkout_commit_id, @@ -2512,7 +2667,8 @@ def detached(name, cwd=target, user=user, password=password, - ignore_retcode=True) + ignore_retcode=True, + output_encoding=output_encoding) except CommandExecutionError: new_rev = None @@ -2522,7 +2678,8 @@ def detached(name, opts=['--init', '--recursive'], user=user, password=password, - identity=identity) + identity=identity, + output_encoding=output_encoding) comments.append( 'Submodules were updated' ) @@ -2544,6 +2701,7 @@ def config_unset(name, repo=None, user=None, password=None, + output_encoding=None, **kwargs): r''' .. versionadded:: 2015.8.0 @@ -2586,6 +2744,30 @@ def config_unset(name, global : False If ``True``, this will set a global git config option + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + **Examples:** @@ -2658,6 +2840,7 @@ def config_unset(name, user=user, password=password, ignore_retcode=True, + output_encoding=output_encoding, **{'global': global_} ) @@ -2707,6 +2890,7 @@ def config_unset(name, user=user, password=password, ignore_retcode=True, + output_encoding=output_encoding, **{'global': global_} ) @@ -2722,6 +2906,7 @@ def config_unset(name, all=all_, user=user, password=password, + output_encoding=output_encoding, **{'global': global_} ) except CommandExecutionError as exc: @@ -2746,6 +2931,7 @@ def config_unset(name, user=user, password=password, ignore_retcode=True, + output_encoding=output_encoding, **{'global': global_} ) @@ -2766,6 +2952,7 @@ def config_unset(name, user=user, password=password, ignore_retcode=True, + output_encoding=output_encoding, **{'global': global_} ) @@ -2787,6 +2974,7 @@ def config_set(name, repo=None, user=None, password=None, + output_encoding=None, **kwargs): ''' .. versionadded:: 2014.7.0 @@ -2829,6 +3017,30 @@ def config_set(name, global : False If ``True``, this will set a global git config option + output_encoding + Use this option to specify which encoding to use to decode the output + from any git commands which are run. This should not be needed in most + cases. + + .. note:: + + On Windows, this option works slightly differently in the git state + and execution module than it does in the :mod:`"cmd" execution + module `. The filenames in most git + repositories are created using a UTF-8 locale, and the system + encoding on Windows (CP1252) will successfully (but incorrectly) + decode many UTF-8 characters. This makes interacting with + repositories containing UTF-8 filenames on Windows unreliable. + Therefore, Windows will default to decoding the output from git + commands using UTF-8 unless this option is explicitly used to + specify the encoding. + + On non-Windows platforms, the default output decoding behavior will + be observed (i.e. the encoding specified by the locale will be + tried first, and if that fails, UTF-8 will be used as a fallback). + + .. versionadded:: 2018.3.1 + **Local Config Example:** .. code-block:: yaml @@ -2922,6 +3134,7 @@ def config_set(name, user=user, password=password, ignore_retcode=True, + output_encoding=output_encoding, **{'all': True, 'global': global_} ) @@ -2952,6 +3165,7 @@ def config_set(name, multivar=multivar, user=user, password=password, + output_encoding=output_encoding, **{'global': global_} ) except CommandExecutionError as exc: From b5e508f33939c2e5ca23fa026938c20be4a5fd04 Mon Sep 17 00:00:00 2001 From: Mihai Dinca Date: Fri, 2 Mar 2018 17:17:58 +0100 Subject: [PATCH 3/7] Fix openscap push --- salt/modules/openscap.py | 4 +--- tests/unit/modules/test_openscap.py | 10 +++++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/salt/modules/openscap.py b/salt/modules/openscap.py index c5b51a1846..e3190e1e11 100644 --- a/salt/modules/openscap.py +++ b/salt/modules/openscap.py @@ -13,7 +13,6 @@ from subprocess import Popen, PIPE # Import Salt libs from salt.ext import six -from salt.client import Caller ArgumentParser = object @@ -105,8 +104,7 @@ def xccdf(params): success = _OSCAP_EXIT_CODES_MAP[proc.returncode] returncode = proc.returncode if success: - caller = Caller() - caller.cmd('cp.push_dir', tempdir) + __salt__['cp.push_dir'](tempdir) shutil.rmtree(tempdir, ignore_errors=True) upload_dir = tempdir diff --git a/tests/unit/modules/test_openscap.py b/tests/unit/modules/test_openscap.py index eb8ad1225b..6e17148de1 100644 --- a/tests/unit/modules/test_openscap.py +++ b/tests/unit/modules/test_openscap.py @@ -28,8 +28,10 @@ class OpenscapTestCase(TestCase): policy_file = '/usr/share/openscap/policy-file-xccdf.xml' def setUp(self): + import salt.modules.openscap + salt.modules.openscap.__salt__ = MagicMock() patchers = [ - patch('salt.modules.openscap.Caller', MagicMock()), + patch('salt.modules.openscap.__salt__', MagicMock()), patch('salt.modules.openscap.shutil.rmtree', Mock()), patch( 'salt.modules.openscap.tempfile.mkdtemp', @@ -68,8 +70,7 @@ class OpenscapTestCase(TestCase): cwd=openscap.tempfile.mkdtemp.return_value, stderr=PIPE, stdout=PIPE) - openscap.Caller().cmd.assert_called_once_with( - 'cp.push_dir', self.random_temp_dir) + openscap.__salt__['cp.push_dir'].assert_called_once_with(self.random_temp_dir) self.assertEqual(openscap.shutil.rmtree.call_count, 1) self.assertEqual( response, @@ -106,8 +107,7 @@ class OpenscapTestCase(TestCase): cwd=openscap.tempfile.mkdtemp.return_value, stderr=PIPE, stdout=PIPE) - openscap.Caller().cmd.assert_called_once_with( - 'cp.push_dir', self.random_temp_dir) + openscap.__salt__['cp.push_dir'].assert_called_once_with(self.random_temp_dir) self.assertEqual(openscap.shutil.rmtree.call_count, 1) self.assertEqual( response, From 3d6f6583097a1a4c0c2f3dd6b5105222d028ca58 Mon Sep 17 00:00:00 2001 From: Benjamin Drung Date: Wed, 7 Mar 2018 15:28:33 +0100 Subject: [PATCH 4/7] Skip SSHPasswordTests if ssh binary is not found If the ssh binary is not found in path, SSHPasswordTests will fail: ERROR: test_password_failure (unit.ssh.test_ssh.SSHPasswordTests) [CPU:0.0%|MEM:54.9%] ---------------------------------------------------------------------- Traceback (most recent call last): File "tests/unit/ssh/test_ssh.py", line 42, in test_password_failure client = ssh.SSH(opts) File "salt/client/ssh/__init__.py", line 226, in __init__ raise salt.exceptions.SaltSystemExit('No ssh binary found in path -- ssh must be ' salt.exceptions.SaltSystemExit: None Either SSHPasswordTests needs to be converted into a real unit test (i.e. mocking the salt call) or this tests needs to be skipped if ssh is not available. Signed-off-by: Benjamin Drung --- tests/unit/ssh/test_ssh.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit/ssh/test_ssh.py b/tests/unit/ssh/test_ssh.py index 265a96f2a2..b80483b0b7 100644 --- a/tests/unit/ssh/test_ssh.py +++ b/tests/unit/ssh/test_ssh.py @@ -14,10 +14,12 @@ from tests.support.mock import NO_MOCK, NO_MOCK_REASON, patch, MagicMock # Import Salt libs import salt.config +import salt.utils.path from salt.client import ssh @skipIf(NO_MOCK, NO_MOCK_REASON) +@skipIf(not salt.utils.path.which('ssh'), "No ssh binary found in path") class SSHPasswordTests(ShellCase): def test_password_failure(self): ''' From 479818703504a838a1f42c9b766abf1695231133 Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Wed, 7 Mar 2018 15:45:38 -0600 Subject: [PATCH 5/7] Improve reliability/idempotence of file.blockreplace state (2018.3 branch) This makes the following changes: - The `append_newline` argument to the `file.blockreplace` remote-execution function has been modified so that if its value is `None`, it only appends a newline when the content block does not end in one. - A couple of fixes were made to newline handling. The existing code normalized the newlines in the content block, replacing them with os.linesep. However, when the file contains newlines that don't match the OS (i.e. POSIX newlines in a file on a Windows box, or Windows newlines on a Linux/Mac/BSD/etc. box), then we would still end up with mixed newlines. The line separator is now detected when we read in the original file, and the detected line separator is used when writing the content block. Additionally, the same newline mismatch was possible when appending/prepending the content block. This has been fixed by using a common function for appending, prepending, and replacing the content block. - Support for the `append_newline` argument has been added to the `file.blockreplace` state. The default value for the state is `None`. A `versionchanged` has been added to the remote execution function to let users know that the Fluorine release will change the default value of that variable. - 20 new integration tests have been written to test the `file.blockreplace` state. --- salt/modules/file.py | 209 +++-- salt/states/file.py | 98 +- tests/integration/states/test_file.py | 1216 ++++++++++++++++++++++++- tests/support/helpers.py | 21 +- tests/unit/modules/test_file.py | 89 +- 5 files changed, 1473 insertions(+), 160 deletions(-) diff --git a/salt/modules/file.py b/salt/modules/file.py index 994410743c..755fb1ed87 100644 --- a/salt/modules/file.py +++ b/salt/modules/file.py @@ -2433,8 +2433,7 @@ def blockreplace(path, backup='.bak', dry_run=False, show_changes=True, - append_newline=False, - ): + append_newline=False): ''' .. versionadded:: 2014.1.0 @@ -2481,18 +2480,30 @@ def blockreplace(path, The file extension to use for a backup of the file if any edit is made. Set to ``False`` to skip making a backup. - dry_run - Don't make any edits to the file. + dry_run : False + If ``True``, do not make any edits to the file and simply return the + changes that *would* be made. - show_changes - Output a unified diff of the old file and the new file. If ``False``, - return a boolean if any changes were made. + show_changes : True + Controls how changes are presented. If ``True``, this function will + return a unified diff of the changes made. If False, then it will + return a boolean (``True`` if any changes were made, otherwise + ``False``). - append_newline: - Append a newline to the content block. For more information see: - https://github.com/saltstack/salt/issues/33686 + append_newline : False + Controls whether or not a newline is appended to the content block. If + the value of this argument is ``True`` then a newline will be added to + the content block. If it is ``False``, then a newline will *not* be + added to the content block. If it is ``None`` then a newline will only + be added to the content block if it does not already end in a newline. .. versionadded:: 2016.3.4 + .. versionchanged:: 2017.7.5,2018.3.1 + New behavior added when value is ``None``. + .. versionchanged:: Fluorine + The default value of this argument will change to ``None`` to match + the behavior of the :py:func:`file.blockreplace state + ` CLI Example: @@ -2502,87 +2513,137 @@ def blockreplace(path, '#-- end managed zone foobar --' $'10.0.1.1 foo.foobar\\n10.0.1.2 bar.foobar' True ''' - path = os.path.expanduser(path) - - if not os.path.exists(path): - raise SaltInvocationError('File not found: {0}'.format(path)) - if append_if_not_found and prepend_if_not_found: raise SaltInvocationError( 'Only one of append and prepend_if_not_found is permitted' ) + path = os.path.expanduser(path) + + if not os.path.exists(path): + raise SaltInvocationError('File not found: {0}'.format(path)) + if not __utils__['files.is_text'](path): raise SaltInvocationError( 'Cannot perform string replacements on a binary file: {0}' .format(path) ) - # Search the file; track if any changes have been made for the return val + if append_newline is None and not content.endswith((os.linesep, '\n')): + append_newline = True + + # Split the content into a list of lines, removing newline characters. To + # ensure that we handle both Windows and POSIX newlines, first split on + # Windows newlines, and then split on POSIX newlines. + split_content = [] + for win_line in content.split('\r\n'): + for content_line in win_line.split('\n'): + split_content.append(content_line) + + line_count = len(split_content) + has_changes = False orig_file = [] new_file = [] in_block = False - old_content = '' - done = False - # we do not use in_place editing to avoid file attrs modifications when + block_found = False + linesep = None + + def _add_content(linesep, lines=None, include_marker_start=True, + end_line=None): + if lines is None: + lines = [] + include_marker_start = True + + if end_line is None: + end_line = marker_end + end_line = end_line.rstrip('\r\n') + linesep + + if include_marker_start: + lines.append(marker_start + linesep) + + if split_content: + for index, content_line in enumerate(split_content, 1): + if index != line_count: + lines.append(content_line + linesep) + else: + # We're on the last line of the content block + if append_newline: + lines.append(content_line + linesep) + lines.append(end_line) + else: + lines.append(content_line + end_line) + else: + lines.append(end_line) + + return lines + + # We do not use in-place editing to avoid file attrs modifications when # no changes are required and to avoid any file access on a partially # written file. - # we could also use salt.utils.filebuffer.BufferedReader + # + # We could also use salt.utils.filebuffer.BufferedReader try: - fi_file = fileinput.input(path, - inplace=False, backup=False, - bufsize=1, mode='rb') - for line in fi_file: + fi_file = fileinput.input( + path, + inplace=False, + backup=False, + bufsize=1, + mode='rb') + for line in fi_file: line = salt.utils.stringutils.to_unicode(line) - result = line + write_line_to_new_file = True + + if linesep is None: + # Auto-detect line separator + if line.endswith('\r\n'): + linesep = '\r\n' + elif line.endswith('\n'): + linesep = '\n' + else: + # No newline(s) in file, fall back to system's linesep + linesep = os.linesep if marker_start in line: - # managed block start found, start recording + # We've entered the content block in_block = True - else: if in_block: - if marker_end in line: - # end of block detected + # We're not going to write the lines from the old file to + # the new file until we have exited the block. + write_line_to_new_file = False + + marker_end_pos = line.find(marker_end) + if marker_end_pos != -1: + # End of block detected in_block = False + # We've found and exited the block + block_found = True - # Handle situations where there may be multiple types - # of line endings in the same file. Separate the content - # into lines. Account for Windows-style line endings - # using os.linesep, then by linux-style line endings - # using '\n' - split_content = [] - for linesep_line in content.split(os.linesep): - for content_line in linesep_line.split('\n'): - split_content.append(content_line) - - # Trim any trailing new lines to avoid unwanted - # additional new lines - while not split_content[-1]: - split_content.pop() - - # push new block content in file - for content_line in split_content: - new_file.append(content_line + os.linesep) - - done = True - - else: - # remove old content, but keep a trace - old_content += line - result = None - # else: we are not in the marked block, keep saving things + _add_content(linesep, lines=new_file, + include_marker_start=False, + end_line=line[marker_end_pos:]) + # Save the line from the original file orig_file.append(line) - if result is not None: - new_file.append(result) - # end for. If we are here without block management we maybe have some problems, - # or we need to initialise the marked block + if write_line_to_new_file: + new_file.append(line) + except (IOError, OSError) as exc: + raise CommandExecutionError( + 'Failed to read from {0}: {1}'.format(path, exc) + ) finally: - fi_file.close() + if linesep is None: + # If the file was empty, we will not have set linesep yet. Assume + # the system's line separator. This is needed for when we + # prepend/append later on. + linesep = os.linesep + try: + fi_file.close() + except Exception: + pass if in_block: # unterminated block => bad, always fail @@ -2590,35 +2651,27 @@ def blockreplace(path, 'Unterminated marked block. End of file reached before marker_end.' ) - if not done: + if not block_found: if prepend_if_not_found: # add the markers and content at the beginning of file - new_file.insert(0, marker_end + os.linesep) - if append_newline is True: - new_file.insert(0, content + os.linesep) - else: - new_file.insert(0, content) - new_file.insert(0, marker_start + os.linesep) - done = True + prepended_content = _add_content(linesep) + prepended_content.extend(new_file) + new_file = prepended_content + block_found = True elif append_if_not_found: # Make sure we have a newline at the end of the file if 0 != len(new_file): - if not new_file[-1].endswith(os.linesep): - new_file[-1] += os.linesep + if not new_file[-1].endswith(linesep): + new_file[-1] += linesep # add the markers and content at the end of file - new_file.append(marker_start + os.linesep) - if append_newline is True: - new_file.append(content + os.linesep) - else: - new_file.append(content) - new_file.append(marker_end + os.linesep) - done = True + _add_content(linesep, lines=new_file) + block_found = True else: raise CommandExecutionError( 'Cannot edit marked block. Markers were not found in file.' ) - if done: + if block_found: diff = ''.join(difflib.unified_diff(orig_file, new_file)) has_changes = diff is not '' if has_changes and not dry_run: diff --git a/salt/states/file.py b/salt/states/file.py index 3fabe17480..8e1a167864 100644 --- a/salt/states/file.py +++ b/salt/states/file.py @@ -4143,11 +4143,20 @@ def blockreplace( append_if_not_found=False, prepend_if_not_found=False, backup='.bak', - show_changes=True): + show_changes=True, + append_newline=None): ''' Maintain an edit in a file in a zone delimited by two line markers .. versionadded:: 2014.1.0 + .. versionchanged:: 2017.7.5,2018.3.1 + ``append_newline`` argument added. Additionally, to improve + idempotence, if the string represented by ``marker_end`` is found in + the middle of the line, the content preceding the marker will be + removed when the block is replaced. This allows one to remove + ``append_newline: False`` from the SLS and have the block properly + replaced if the end of the content block is immediately followed by the + ``marker_end`` (i.e. no newline before the marker). A block of content delimited by comments can help you manage several lines entries without worrying about old entries removal. This can help you @@ -4232,41 +4241,54 @@ def blockreplace( See the ``source_hash`` parameter description for :mod:`file.managed ` function for more details and examples. - template - The named templating engine will be used to render the downloaded file. - Defaults to ``jinja``. The following templates are supported: + template : jinja + Templating engine to be used to render the downloaded file. The + following engines are supported: - - :mod:`cheetah` - - :mod:`genshi` - - :mod:`jinja` - - :mod:`mako` - - :mod:`py` - - :mod:`wempy` + - :mod:`cheetah ` + - :mod:`genshi ` + - :mod:`jinja ` + - :mod:`mako ` + - :mod:`py ` + - :mod:`wempy ` context - Overrides default context variables passed to the template. + Overrides default context variables passed to the template defaults - Default context passed to the template. + Default context passed to the template - append_if_not_found - If markers are not found and set to True then the markers and content - will be appended to the file. Default is ``False`` + append_if_not_found : False + If markers are not found and this option is set to ``True``, the + content block will be appended to the file. - prepend_if_not_found - If markers are not found and set to True then the markers and content - will be prepended to the file. Default is ``False`` + prepend_if_not_found : False + If markers are not found and this option is set to ``True``, the + content block will be prepended to the file. backup The file extension to use for a backup of the file if any edit is made. Set this to ``False`` to skip making a backup. - dry_run - Don't make any edits to the file + dry_run : False + If ``True``, do not make any edits to the file and simply return the + changes that *would* be made. - show_changes - Output a unified diff of the old file and the new file. If ``False`` - return a boolean if any changes were made + show_changes : True + Controls how changes are presented. If ``True``, the ``Changes`` + section of the state return will contain a unified diff of the changes + made. If False, then it will contain a boolean (``True`` if any changes + were made, otherwise ``False``). + + append_newline + Controls whether or not a newline is appended to the content block. If + the value of this argument is ``True`` then a newline will be added to + the content block. If it is ``False``, then a newline will *not* be + added to the content block. If it is unspecified, then a newline will + only be added to the content block if it does not already end in a + newline. + + .. versionadded:: 2017.7.5,2018.3.1 Example of usage with an accumulator and with a variable: @@ -4368,17 +4390,25 @@ def blockreplace( for index, item in enumerate(text): content += six.text_type(item) - changes = __salt__['file.blockreplace']( - name, - marker_start, - marker_end, - content=content, - append_if_not_found=append_if_not_found, - prepend_if_not_found=prepend_if_not_found, - backup=backup, - dry_run=__opts__['test'], - show_changes=show_changes - ) + try: + changes = __salt__['file.blockreplace']( + name, + marker_start, + marker_end, + content=content, + append_if_not_found=append_if_not_found, + prepend_if_not_found=prepend_if_not_found, + backup=backup, + dry_run=__opts__['test'], + show_changes=show_changes, + append_newline=append_newline) + except Exception as exc: + log.exception('Encountered error managing block') + ret['comment'] = ( + 'Encountered error managing block: {0}. ' + 'See the log for details.'.format(exc) + ) + return ret if changes: ret['pchanges'] = {'diff': changes} diff --git a/tests/integration/states/test_file.py b/tests/integration/states/test_file.py index 4da68f194a..0a3c5778c1 100644 --- a/tests/integration/states/test_file.py +++ b/tests/integration/states/test_file.py @@ -27,6 +27,7 @@ from tests.support.paths import FILES, TMP, TMP_STATE_TREE from tests.support.helpers import ( skip_if_not_root, with_system_user_and_group, + with_tempfile, Webserver, ) from tests.support.mixins import SaltReturnAssertsMixin @@ -134,6 +135,16 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin): ''' Validate the file state ''' + def tearDown(self): + ''' + remove files created in previous tests + ''' + for path in (FILEPILLAR, FILEPILLARDEF, FILEPILLARGIT): + try: + os.remove(path) + except OSError as exc: + if exc.errno != os.errno.ENOENT: + log.error('Failed to remove %s: %s', path, exc) def test_symlink(self): ''' @@ -2491,15 +2502,1206 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin): ret = self.run_function('state.sls', mods=state_file) self.assertSaltTrueReturn(ret) - def tearDown(self): + +class BlockreplaceTest(ModuleCase, SaltReturnAssertsMixin): + marker_start = '# start' + marker_end = '# end' + content = textwrap.dedent('''\ + Line 1 of block + Line 2 of block + ''') + without_block = textwrap.dedent('''\ + Hello world! + + # comment here + ''') + with_non_matching_block = textwrap.dedent('''\ + Hello world! + + # start + No match here + # end + # comment here + ''') + with_non_matching_block_and_marker_end_not_after_newline = textwrap.dedent('''\ + Hello world! + + # start + No match here# end + # comment here + ''') + with_matching_block = textwrap.dedent('''\ + Hello world! + + # start + Line 1 of block + Line 2 of block + # end + # comment here + ''') + with_matching_block_and_extra_newline = textwrap.dedent('''\ + Hello world! + + # start + Line 1 of block + Line 2 of block + + # end + # comment here + ''') + with_matching_block_and_marker_end_not_after_newline = textwrap.dedent('''\ + Hello world! + + # start + Line 1 of block + Line 2 of block# end + # comment here + ''') + content_explicit_posix_newlines = ('Line 1 of block\n' + 'Line 2 of block\n') + content_explicit_windows_newlines = ('Line 1 of block\r\n' + 'Line 2 of block\r\n') + without_block_explicit_posix_newlines = ('Hello world!\n\n' + '# comment here\n') + without_block_explicit_windows_newlines = ('Hello world!\r\n\r\n' + '# comment here\r\n') + with_block_prepended_explicit_posix_newlines = ('# start\n' + 'Line 1 of block\n' + 'Line 2 of block\n' + '# end\n' + 'Hello world!\n\n' + '# comment here\n') + with_block_prepended_explicit_windows_newlines = ('# start\r\n' + 'Line 1 of block\r\n' + 'Line 2 of block\r\n' + '# end\r\n' + 'Hello world!\r\n\r\n' + '# comment here\r\n') + with_block_appended_explicit_posix_newlines = ('Hello world!\n\n' + '# comment here\n' + '# start\n' + 'Line 1 of block\n' + 'Line 2 of block\n' + '# end\n') + with_block_appended_explicit_windows_newlines = ('Hello world!\r\n\r\n' + '# comment here\r\n' + '# start\r\n' + 'Line 1 of block\r\n' + 'Line 2 of block\r\n' + '# end\r\n') + + @staticmethod + def _write(dest, content): + with salt.utils.fopen(dest, 'wb') as fp_: + fp_.write(salt.utils.to_bytes(content)) + + @staticmethod + def _read(src): + with salt.utils.fopen(src, 'rb') as fp_: + return salt.utils.to_unicode(fp_.read()) + + @with_tempfile + def test_prepend(self, name): ''' - remove files created in previous tests + Test blockreplace when prepend_if_not_found=True and block doesn't + exist in file. ''' - all_files = [FILEPILLAR, FILEPILLARDEF, FILEPILLARGIT] - for file in all_files: - check_file = self.run_function('file.file_exists', [file]) - if check_file: - self.run_function('file.remove', [file]) + expected = self.marker_start + os.linesep + self.content + \ + self.marker_end + os.linesep + self.without_block + + # Pass 1: content ends in newline + self._write(name, self.without_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + prepend_if_not_found=True) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + # Pass 1a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + prepend_if_not_found=True) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + + # Pass 2: content does not end in newline + self._write(name, self.without_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + prepend_if_not_found=True) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + # Pass 2a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + prepend_if_not_found=True) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + + @with_tempfile + def test_prepend_append_newline(self, name): + ''' + Test blockreplace when prepend_if_not_found=True and block doesn't + exist in file. Test with append_newline explicitly set to True. + ''' + # Pass 1: content ends in newline + expected = self.marker_start + os.linesep + self.content + \ + os.linesep + self.marker_end + os.linesep + self.without_block + self._write(name, self.without_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + prepend_if_not_found=True, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + # Pass 1a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + prepend_if_not_found=True, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + + # Pass 2: content does not end in newline + expected = self.marker_start + os.linesep + self.content + \ + self.marker_end + os.linesep + self.without_block + self._write(name, self.without_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + prepend_if_not_found=True, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + # Pass 2a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + prepend_if_not_found=True, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + + @with_tempfile + def test_prepend_no_append_newline(self, name): + ''' + Test blockreplace when prepend_if_not_found=True and block doesn't + exist in file. Test with append_newline explicitly set to False. + ''' + # Pass 1: content ends in newline + expected = self.marker_start + os.linesep + self.content + \ + self.marker_end + os.linesep + self.without_block + self._write(name, self.without_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + prepend_if_not_found=True, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + # Pass 1a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + prepend_if_not_found=True, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + + # Pass 2: content does not end in newline + expected = self.marker_start + os.linesep + \ + self.content.rstrip('\r\n') + self.marker_end + os.linesep + \ + self.without_block + self._write(name, self.without_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + prepend_if_not_found=True, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + # Pass 2a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + prepend_if_not_found=True, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + + @with_tempfile + def test_append(self, name): + ''' + Test blockreplace when append_if_not_found=True and block doesn't + exist in file. + ''' + expected = self.without_block + self.marker_start + os.linesep + \ + self.content + self.marker_end + os.linesep + + # Pass 1: content ends in newline + self._write(name, self.without_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_if_not_found=True) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + # Pass 1a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_if_not_found=True) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + + # Pass 2: content does not end in newline + self._write(name, self.without_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_if_not_found=True) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + # Pass 2a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_if_not_found=True) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + + @with_tempfile + def test_append_append_newline(self, name): + ''' + Test blockreplace when append_if_not_found=True and block doesn't + exist in file. Test with append_newline explicitly set to True. + ''' + # Pass 1: content ends in newline + expected = self.without_block + self.marker_start + os.linesep + \ + self.content + os.linesep + self.marker_end + os.linesep + self._write(name, self.without_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_if_not_found=True, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + # Pass 1a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_if_not_found=True, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + + # Pass 2: content does not end in newline + expected = self.without_block + self.marker_start + os.linesep + \ + self.content + self.marker_end + os.linesep + self._write(name, self.without_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_if_not_found=True, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + # Pass 2a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_if_not_found=True, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + + @with_tempfile + def test_append_no_append_newline(self, name): + ''' + Test blockreplace when append_if_not_found=True and block doesn't + exist in file. Test with append_newline explicitly set to False. + ''' + # Pass 1: content ends in newline + expected = self.without_block + self.marker_start + os.linesep + \ + self.content + self.marker_end + os.linesep + self._write(name, self.without_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_if_not_found=True, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + # Pass 1a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_if_not_found=True, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + + # Pass 2: content does not end in newline + expected = self.without_block + self.marker_start + os.linesep + \ + self.content.rstrip('\r\n') + self.marker_end + os.linesep + self._write(name, self.without_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_if_not_found=True, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + # Pass 2a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_if_not_found=True, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), expected) + + @with_tempfile + def test_prepend_auto_line_separator(self, name): + ''' + This tests the line separator auto-detection when prepending the block + ''' + # POSIX newlines to Windows newlines + self._write(name, self.without_block_explicit_windows_newlines) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content_explicit_posix_newlines, + marker_start=self.marker_start, + marker_end=self.marker_end, + prepend_if_not_found=True) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_block_prepended_explicit_windows_newlines) + # Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content_explicit_posix_newlines, + marker_start=self.marker_start, + marker_end=self.marker_end, + prepend_if_not_found=True) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_block_prepended_explicit_windows_newlines) + + # Windows newlines to POSIX newlines + self._write(name, self.without_block_explicit_posix_newlines) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content_explicit_windows_newlines, + marker_start=self.marker_start, + marker_end=self.marker_end, + prepend_if_not_found=True) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_block_prepended_explicit_posix_newlines) + # Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content_explicit_windows_newlines, + marker_start=self.marker_start, + marker_end=self.marker_end, + prepend_if_not_found=True) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_block_prepended_explicit_posix_newlines) + + @with_tempfile + def test_append_auto_line_separator(self, name): + ''' + This tests the line separator auto-detection when appending the block + ''' + # POSIX newlines to Windows newlines + self._write(name, self.without_block_explicit_windows_newlines) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content_explicit_posix_newlines, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_if_not_found=True) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_block_appended_explicit_windows_newlines) + # Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content_explicit_posix_newlines, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_if_not_found=True) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_block_appended_explicit_windows_newlines) + + # Windows newlines to POSIX newlines + self._write(name, self.without_block_explicit_posix_newlines) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content_explicit_windows_newlines, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_if_not_found=True) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_block_appended_explicit_posix_newlines) + # Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content_explicit_windows_newlines, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_if_not_found=True) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_block_appended_explicit_posix_newlines) + + @with_tempfile + def test_non_matching_block(self, name): + ''' + Test blockreplace when block exists but its contents are not a + match. + ''' + # Pass 1: content ends in newline + self._write(name, self.with_non_matching_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + # Pass 1a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + + # Pass 2: content does not end in newline + self._write(name, self.with_non_matching_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + # Pass 2a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + + @with_tempfile + def test_non_matching_block_append_newline(self, name): + ''' + Test blockreplace when block exists but its contents are not a + match. Test with append_newline explicitly set to True. + ''' + # Pass 1: content ends in newline + self._write(name, self.with_non_matching_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_matching_block_and_extra_newline) + # Pass 1a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_matching_block_and_extra_newline) + + # Pass 2: content does not end in newline + self._write(name, self.with_non_matching_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + # Pass 2a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + + @with_tempfile + def test_non_matching_block_no_append_newline(self, name): + ''' + Test blockreplace when block exists but its contents are not a + match. Test with append_newline explicitly set to False. + ''' + # Pass 1: content ends in newline + self._write(name, self.with_non_matching_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + # Pass 1a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + + # Pass 2: content does not end in newline + self._write(name, self.with_non_matching_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_matching_block_and_marker_end_not_after_newline) + # Pass 2a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_matching_block_and_marker_end_not_after_newline) + + @with_tempfile + def test_non_matching_block_and_marker_not_after_newline(self, name): + ''' + Test blockreplace when block exists but its contents are not a + match, and the marker_end is not directly preceded by a newline. + ''' + # Pass 1: content ends in newline + self._write( + name, + self.with_non_matching_block_and_marker_end_not_after_newline) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + # Pass 1a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + + # Pass 2: content does not end in newline + self._write( + name, + self.with_non_matching_block_and_marker_end_not_after_newline) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + # Pass 2a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + + @with_tempfile + def test_non_matching_block_and_marker_not_after_newline_append_newline(self, name): + ''' + Test blockreplace when block exists but its contents are not a match, + and the marker_end is not directly preceded by a newline. Test with + append_newline explicitly set to True. + ''' + # Pass 1: content ends in newline + self._write( + name, + self.with_non_matching_block_and_marker_end_not_after_newline) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_matching_block_and_extra_newline) + # Pass 1a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_matching_block_and_extra_newline) + + # Pass 2: content does not end in newline + self._write( + name, + self.with_non_matching_block_and_marker_end_not_after_newline) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + # Pass 2a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + + @with_tempfile + def test_non_matching_block_and_marker_not_after_newline_no_append_newline(self, name): + ''' + Test blockreplace when block exists but its contents are not a match, + and the marker_end is not directly preceded by a newline. Test with + append_newline explicitly set to False. + ''' + # Pass 1: content ends in newline + self._write( + name, + self.with_non_matching_block_and_marker_end_not_after_newline) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + # Pass 1a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + + # Pass 2: content does not end in newline + self._write( + name, + self.with_non_matching_block_and_marker_end_not_after_newline) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_matching_block_and_marker_end_not_after_newline) + # Pass 2a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_matching_block_and_marker_end_not_after_newline) + + @with_tempfile + def test_matching_block(self, name): + ''' + Test blockreplace when block exists and its contents are a match. No + changes should be made. + ''' + # Pass 1: content ends in newline + self._write(name, self.with_matching_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + # Pass 1a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + + # Pass 2: content does not end in newline + self._write(name, self.with_matching_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + # Pass 2a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + + @with_tempfile + def test_matching_block_append_newline(self, name): + ''' + Test blockreplace when block exists and its contents are a match. Test + with append_newline explicitly set to True. This will result in an + extra newline when the content ends in a newline, and will not when the + content does not end in a newline. + ''' + # Pass 1: content ends in newline + self._write(name, self.with_matching_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_matching_block_and_extra_newline) + # Pass 1a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_matching_block_and_extra_newline) + + # Pass 2: content does not end in newline + self._write(name, self.with_matching_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + # Pass 2a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + + @with_tempfile + def test_matching_block_no_append_newline(self, name): + ''' + Test blockreplace when block exists and its contents are a match. Test + with append_newline explicitly set to False. This will result in the + marker_end not being directly preceded by a newline when the content + does not end in a newline. + ''' + # Pass 1: content ends in newline + self._write(name, self.with_matching_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + # Pass 1a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + + # Pass 2: content does not end in newline + self._write(name, self.with_matching_block) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_matching_block_and_marker_end_not_after_newline) + # Pass 2a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_matching_block_and_marker_end_not_after_newline) + + @with_tempfile + def test_matching_block_and_marker_not_after_newline(self, name): + ''' + Test blockreplace when block exists and its contents are a match, but + the marker_end is not directly preceded by a newline. + ''' + # Pass 1: content ends in newline + self._write( + name, + self.with_matching_block_and_marker_end_not_after_newline) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + # Pass 1a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + + # Pass 2: content does not end in newline + self._write( + name, + self.with_matching_block_and_marker_end_not_after_newline) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + # Pass 2a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + + @with_tempfile + def test_matching_block_and_marker_not_after_newline_append_newline(self, name): + ''' + Test blockreplace when block exists and its contents are a match, but + the marker_end is not directly preceded by a newline. Test with + append_newline explicitly set to True. This will result in an extra + newline when the content ends in a newline, and will not when the + content does not end in a newline. + ''' + # Pass 1: content ends in newline + self._write( + name, + self.with_matching_block_and_marker_end_not_after_newline) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_matching_block_and_extra_newline) + # Pass 1a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_matching_block_and_extra_newline) + + # Pass 2: content does not end in newline + self._write( + name, + self.with_matching_block_and_marker_end_not_after_newline) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + # Pass 2a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=True) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + + @with_tempfile + def test_matching_block_and_marker_not_after_newline_no_append_newline(self, name): + ''' + Test blockreplace when block exists and its contents are a match, but + the marker_end is not directly preceded by a newline. Test with + append_newline explicitly set to False. + ''' + # Pass 1: content ends in newline + self._write( + name, + self.with_matching_block_and_marker_end_not_after_newline) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertTrue(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + # Pass 1a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content, + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual(self._read(name), self.with_matching_block) + + # Pass 2: content does not end in newline + self._write( + name, + self.with_matching_block_and_marker_end_not_after_newline) + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_matching_block_and_marker_end_not_after_newline) + # Pass 2a: Re-run state, no changes should be made + ret = self.run_state('file.blockreplace', + name=name, + content=self.content.rstrip('\r\n'), + marker_start=self.marker_start, + marker_end=self.marker_end, + append_newline=False) + self.assertSaltTrueReturn(ret) + self.assertFalse(ret[next(iter(ret))]['changes']) + self.assertEqual( + self._read(name), + self.with_matching_block_and_marker_end_not_after_newline) class RemoteFileTest(ModuleCase, SaltReturnAssertsMixin): diff --git a/tests/support/helpers.py b/tests/support/helpers.py index 05989848b7..5864c83b14 100644 --- a/tests/support/helpers.py +++ b/tests/support/helpers.py @@ -24,6 +24,7 @@ import signal import socket import string import sys +import tempfile import threading import time import tornado.ioloop @@ -50,7 +51,7 @@ except ImportError: # Import Salt Tests Support libs from tests.support.unit import skip, _id from tests.support.mock import patch -from tests.support.paths import FILES +from tests.support.paths import FILES, TMP log = logging.getLogger(__name__) @@ -954,6 +955,24 @@ def with_system_user_and_group(username, group, return decorator +def with_tempfile(func): + ''' + Generates a tempfile and cleans it up when test completes. + ''' + @functools.wraps(func) + def wrapper(self, *args, **kwargs): + fd_, name = tempfile.mkstemp(prefix='__salt.test.', dir=TMP) + os.close(fd_) + del fd_ + ret = func(self, name, *args, **kwargs) + try: + os.remove(name) + except Exception: + pass + return ret + return wrapper + + def requires_system_grains(func): ''' Function decorator which loads and passes the system's grains to the test diff --git a/tests/unit/modules/test_file.py b/tests/unit/modules/test_file.py index c7ec9eff86..309330fe92 100644 --- a/tests/unit/modules/test_file.py +++ b/tests/unit/modules/test_file.py @@ -285,10 +285,11 @@ class FileBlockReplaceTestCase(TestCase, LoaderModuleMockMixin): "We shall say 'Ni' again to you, if you do not appease us." ]) filemod.blockreplace(self.tfile.name, - '#-- START BLOCK 1', - '#-- END BLOCK 1', - new_multiline_content, - backup=False) + marker_start='#-- START BLOCK 1', + marker_end='#-- END BLOCK 1', + content=new_multiline_content, + backup=False, + append_newline=None) with salt.utils.files.fopen(self.tfile.name, 'rb') as fp: filecontent = fp.read() @@ -306,9 +307,9 @@ class FileBlockReplaceTestCase(TestCase, LoaderModuleMockMixin): CommandExecutionError, filemod.blockreplace, self.tfile.name, - '#-- START BLOCK 2', - '#-- END BLOCK 2', - new_content, + marker_start='#-- START BLOCK 2', + marker_end='#-- END BLOCK 2', + content=new_content, append_if_not_found=False, backup=False ) @@ -319,9 +320,9 @@ class FileBlockReplaceTestCase(TestCase, LoaderModuleMockMixin): ) filemod.blockreplace(self.tfile.name, - '#-- START BLOCK 2', - '#-- END BLOCK 2', - new_content, + marker_start='#-- START BLOCK 2', + marker_end='#-- END BLOCK 2', + content=new_content, backup=False, append_if_not_found=True) @@ -382,9 +383,9 @@ class FileBlockReplaceTestCase(TestCase, LoaderModuleMockMixin): CommandExecutionError, filemod.blockreplace, self.tfile.name, - '#-- START BLOCK 2', - '#-- END BLOCK 2', - new_content, + marker_start='#-- START BLOCK 2', + marker_end='#-- END BLOCK 2', + content=new_content, prepend_if_not_found=False, backup=False ) @@ -396,8 +397,9 @@ class FileBlockReplaceTestCase(TestCase, LoaderModuleMockMixin): fp.read()) filemod.blockreplace(self.tfile.name, - '#-- START BLOCK 2', '#-- END BLOCK 2', - new_content, + marker_start='#-- START BLOCK 2', + marker_end='#-- END BLOCK 2', + content=new_content, backup=False, prepend_if_not_found=True) @@ -410,9 +412,9 @@ class FileBlockReplaceTestCase(TestCase, LoaderModuleMockMixin): def test_replace_partial_marked_lines(self): filemod.blockreplace(self.tfile.name, - '// START BLOCK', - '// END BLOCK', - 'new content 1', + marker_start='// START BLOCK', + marker_end='// END BLOCK', + content='new content 1', backup=False) with salt.utils.files.fopen(self.tfile.name, 'r') as fp: @@ -420,7 +422,7 @@ class FileBlockReplaceTestCase(TestCase, LoaderModuleMockMixin): self.assertIn('new content 1', filecontent) self.assertNotIn('to be removed', filecontent) self.assertIn('first part of start line', filecontent) - self.assertIn('first part of end line', filecontent) + self.assertNotIn('first part of end line', filecontent) self.assertIn('part of start line not removed', filecontent) self.assertIn('part of end line not removed', filecontent) @@ -430,7 +432,9 @@ class FileBlockReplaceTestCase(TestCase, LoaderModuleMockMixin): filemod.blockreplace( self.tfile.name, - '// START BLOCK', '// END BLOCK', 'new content 2', + marker_start='// START BLOCK', + marker_end='// END BLOCK', + content='new content 2', backup=fext) self.assertTrue(os.path.exists(bak_file)) @@ -441,22 +445,27 @@ class FileBlockReplaceTestCase(TestCase, LoaderModuleMockMixin): bak_file = '{0}{1}'.format(self.tfile.name, fext) filemod.blockreplace(self.tfile.name, - '// START BLOCK', '// END BLOCK', 'new content 3', + marker_start='// START BLOCK', + marker_end='// END BLOCK', + content='new content 3', backup=False) self.assertFalse(os.path.exists(bak_file)) def test_no_modifications(self): filemod.blockreplace(self.tfile.name, - '// START BLOCK', '// END BLOCK', - 'new content 4', - backup=False) + marker_start='#-- START BLOCK 1', + marker_end='#-- END BLOCK 1', + content='new content 4', + backup=False, + append_newline=None) before_ctime = os.stat(self.tfile.name).st_mtime filemod.blockreplace(self.tfile.name, - '// START BLOCK', - '// END BLOCK', - 'new content 4', - backup=False) + marker_start='#-- START BLOCK 1', + marker_end='#-- END BLOCK 1', + content='new content 4', + backup=False, + append_newline=None) after_ctime = os.stat(self.tfile.name).st_mtime self.assertEqual(before_ctime, after_ctime) @@ -464,9 +473,9 @@ class FileBlockReplaceTestCase(TestCase, LoaderModuleMockMixin): def test_dry_run(self): before_ctime = os.stat(self.tfile.name).st_mtime filemod.blockreplace(self.tfile.name, - '// START BLOCK', - '// END BLOCK', - 'new content 5', + marker_start='// START BLOCK', + marker_end='// END BLOCK', + content='new content 5', dry_run=True) after_ctime = os.stat(self.tfile.name).st_mtime @@ -474,18 +483,18 @@ class FileBlockReplaceTestCase(TestCase, LoaderModuleMockMixin): def test_show_changes(self): ret = filemod.blockreplace(self.tfile.name, - '// START BLOCK', - '// END BLOCK', - 'new content 6', + marker_start='// START BLOCK', + marker_end='// END BLOCK', + content='new content 6', backup=False, show_changes=True) self.assertTrue(ret.startswith('---')) # looks like a diff ret = filemod.blockreplace(self.tfile.name, - '// START BLOCK', - '// END BLOCK', - 'new content 7', + marker_start='// START BLOCK', + marker_end='// END BLOCK', + content='new content 7', backup=False, show_changes=False) @@ -496,9 +505,9 @@ class FileBlockReplaceTestCase(TestCase, LoaderModuleMockMixin): CommandExecutionError, filemod.blockreplace, self.tfile.name, - '#-- START BLOCK UNFINISHED', - '#-- END BLOCK UNFINISHED', - 'foobar', + marker_start='#-- START BLOCK UNFINISHED', + marker_end='#-- END BLOCK UNFINISHED', + content='foobar', backup=False ) From 3d37eca847044226a745dc3c22b96b16528a62cd Mon Sep 17 00:00:00 2001 From: Benjamin Drung Date: Thu, 8 Mar 2018 19:11:13 +0100 Subject: [PATCH 6/7] Fix various spelling mistakes lintian found various spelling mistakes. Signed-off-by: Benjamin Drung --- doc/ref/configuration/master.rst | 4 ++-- doc/ref/configuration/minion.rst | 2 +- doc/topics/cloud/config.rst | 2 +- doc/topics/cloud/saltify.rst | 2 +- doc/topics/jinja/index.rst | 4 ++-- doc/topics/orchestrate/orchestrate_runner.rst | 4 ++-- doc/topics/releases/2016.3.4.rst | 2 +- doc/topics/releases/2018.3.0.rst | 8 ++++---- doc/topics/slots/index.rst | 2 +- doc/topics/tutorials/salt_bootstrap.rst | 4 ++-- pkg/suse/salt.changes | 2 +- salt/cloud/clouds/proxmox.py | 2 +- salt/cloud/deploy/bootstrap-salt.sh | 2 +- salt/config/__init__.py | 4 ++-- salt/engines/ircbot.py | 2 +- salt/engines/slack.py | 6 +++--- salt/modules/aptpkg.py | 2 +- salt/modules/cmdmod.py | 14 +++++++------- salt/modules/highstate_doc.py | 2 +- salt/modules/infoblox.py | 6 +++--- salt/modules/kernelpkg_linux_apt.py | 2 +- salt/modules/kernelpkg_linux_yum.py | 2 +- salt/modules/libcloud_compute.py | 2 +- salt/modules/logadm.py | 2 +- salt/modules/reg.py | 2 +- salt/modules/state.py | 4 ++-- salt/modules/vsphere.py | 16 ++++++++-------- salt/modules/win_file.py | 2 +- salt/modules/zypper.py | 2 +- salt/pillar/http_json.py | 2 +- salt/pillar/http_yaml.py | 2 +- salt/states/esxi.py | 4 ++-- salt/states/etcd_mod.py | 2 +- salt/states/infoblox_host_record.py | 2 +- salt/states/kernelpkg.py | 2 +- salt/states/pkg.py | 8 ++++---- salt/states/rabbitmq_policy.py | 2 +- salt/states/vagrant.py | 2 +- salt/thorium/check.py | 2 +- salt/utils/gitfs.py | 2 +- salt/utils/napalm.py | 2 +- .../saltclass/examples/classes/roles/app.yml | 2 +- tests/unit/states/test_docker_image.py | 2 +- tests/unit/utils/test_state.py | 2 +- 44 files changed, 74 insertions(+), 74 deletions(-) diff --git a/doc/ref/configuration/master.rst b/doc/ref/configuration/master.rst index 708d5a84bc..4f9df91e4e 100644 --- a/doc/ref/configuration/master.rst +++ b/doc/ref/configuration/master.rst @@ -1404,7 +1404,7 @@ This should still be considered a less than secure option, due to the fact that trust is based on just the requesting minion. Please see the :ref:`Autoaccept Minions from Grains ` -documentation for more infomation. +documentation for more information. .. code-block:: yaml @@ -2178,7 +2178,7 @@ This allows the following more convenient syntax to be used: # (this comment remains in the rendered template) ## ensure all the formula services are running % for service in formula_services: - enable_service_{{ serivce }}: + enable_service_{{ service }}: service.running: name: {{ service }} % endfor diff --git a/doc/ref/configuration/minion.rst b/doc/ref/configuration/minion.rst index 88a57d1b41..49a905a668 100644 --- a/doc/ref/configuration/minion.rst +++ b/doc/ref/configuration/minion.rst @@ -2463,7 +2463,7 @@ The grains that should be sent to the master on authentication to decide if the minion's key should be accepted automatically. Please see the :ref:`Autoaccept Minions from Grains ` -documentation for more infomation. +documentation for more information. .. code-block:: yaml diff --git a/doc/topics/cloud/config.rst b/doc/topics/cloud/config.rst index df456e72da..a8bb1684ef 100644 --- a/doc/topics/cloud/config.rst +++ b/doc/topics/cloud/config.rst @@ -71,7 +71,7 @@ The generated grain information will appear similar to: provider: my_ec2:ec2 profile: ec2-web -The generation of the salt-cloud grain can be surpressed by the +The generation of the salt-cloud grain can be suppressed by the option ``enable_cloud_grains: 'False'`` in the cloud configuration file. Cloud Configuration Syntax diff --git a/doc/topics/cloud/saltify.rst b/doc/topics/cloud/saltify.rst index ac89e374c7..aed77baec8 100644 --- a/doc/topics/cloud/saltify.rst +++ b/doc/topics/cloud/saltify.rst @@ -125,7 +125,7 @@ to start that machine running. The "magic packet" must be sent by an existing salt minion which is on the same network segment as the target machine. (Or your router must be set up especially to route WoL packets.) Your target machine -must be set up to listen for WoL and to respond appropriatly. +must be set up to listen for WoL and to respond appropriately. You must provide the Salt node id of the machine which will send the WoL packet \(parameter ``wol_sender_node``\), and diff --git a/doc/topics/jinja/index.rst b/doc/topics/jinja/index.rst index caa7da9d13..a049d0694d 100644 --- a/doc/topics/jinja/index.rst +++ b/doc/topics/jinja/index.rst @@ -153,7 +153,7 @@ starts at the root of the state tree or pillar. Errors ====== -Saltstack allows to raise custom errors using the ``raise`` jinja function. +Saltstack allows raising custom errors using the ``raise`` jinja function. .. code-block:: jinja @@ -1122,7 +1122,7 @@ Returns: 'body': '{ "userId": 1, "id": 1, - "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", + "title": "sunt aut facere repellat provident occaecati excepturi option reprehenderit", "body": "quia et suscipit\\nsuscipit recusandae consequuntur expedita et cum\\nreprehenderit molestiae ut ut quas totam\\nnostrum rerum est autem sunt rem eveniet architecto" }' } diff --git a/doc/topics/orchestrate/orchestrate_runner.rst b/doc/topics/orchestrate/orchestrate_runner.rst index 4771ff1d47..1a735f5e9e 100644 --- a/doc/topics/orchestrate/orchestrate_runner.rst +++ b/doc/topics/orchestrate/orchestrate_runner.rst @@ -338,8 +338,8 @@ Given the above setup, the orchestration will be carried out as follows: .. _orchestrate-runner-parsing-results-programatically: -Parsing Results Programatically -------------------------------- +Parsing Results Programmatically +-------------------------------- Orchestration jobs return output in a specific data structure. That data structure is represented differently depending on the outputter used. With the diff --git a/doc/topics/releases/2016.3.4.rst b/doc/topics/releases/2016.3.4.rst index 4cd6e5a7b3..b6b27e52e1 100644 --- a/doc/topics/releases/2016.3.4.rst +++ b/doc/topics/releases/2016.3.4.rst @@ -146,7 +146,7 @@ Changes: - **PR** `#36690`_: (*rallytime*) [2016.3] Merge forward from 2015.8 to 2016.3 - **PR** `#36680`_: (*rallytime*) [2016.3] Merge forward from 2015.8 to 2016.3 - **PR** `#36659`_: (*terminalmage*) Support dynamic env in new-style git_pillar -- **PR** `#36538`_: (*clinta*) daemon-reload on call to service.avaliable +- **PR** `#36538`_: (*clinta*) daemon-reload on call to service.available - **PR** `#36616`_: (*cro*) Zypper fix test - **PR** `#36621`_: (*terminalmage*) Fix shadowed builtins - **PR** `#36636`_: (*rallytime*) Back-port `#36618`_ to 2016.3 diff --git a/doc/topics/releases/2018.3.0.rst b/doc/topics/releases/2018.3.0.rst index 9ef219621d..fb55f3e680 100644 --- a/doc/topics/releases/2018.3.0.rst +++ b/doc/topics/releases/2018.3.0.rst @@ -503,7 +503,7 @@ setting a ``port`` option under the Master's ``discovery`` configuration: .. note:: When using a port number other than the default, the Minion's ``discovery`` - configuraton must *also* have a port specified, otherwise the Minion will + configuration must *also* have a port specified, otherwise the Minion will still attempt to contact the Master on port ``4520``. **Minion configuration** @@ -528,7 +528,7 @@ Connection to a type instead of DNS By now each Minion was connecting to a Master by DNS or IP address. From now on it is possible also to connect to a _type_ of a Master. For example, in a network there are three different Masters, each corresponds for a particular niche or environment or specific role etc. The Minion -is supposed to connect only to one of those Masters that is described approriately. +is supposed to connect only to one of those Masters that is described appropriately. To achieve such an effect, each `/etc/salt/master` configuration should have a `discovery` option, which should have a `mapping` element with arbitrary key/value pairs. The same configuration should @@ -701,7 +701,7 @@ The generated grain information will appear similar to: provider: my_ec2:ec2 profile: ec2-web -The generation of salt-cloud grains can be surpressed by the +The generation of salt-cloud grains can be suppressed by the option ``enable_cloud_grains: 'False'`` in the cloud configuration file. Upgraded Saltify Driver @@ -766,7 +766,7 @@ Terms usable in yaml files Description ========================== =========== classes A list of classes that will be processed in order states A list of states that will be returned by master_tops function -pillars A yaml dictionnary that will be returned by the ext_pillar function +pillars A yaml dictionary that will be returned by the ext_pillar function environment Node saltenv that will be used by master_tops ========================== =========== diff --git a/doc/topics/slots/index.rst b/doc/topics/slots/index.rst index ebb0dc1f46..42a77cf1bd 100644 --- a/doc/topics/slots/index.rst +++ b/doc/topics/slots/index.rst @@ -10,7 +10,7 @@ Slots future releases Many times it is useful to store the results of a command during the course of -an execution. Salt Slots are designed to allow to store this information and +an execution. Salt Slots are designed to allow you to store this information and use it later during the :ref:`highstate ` or other job execution. diff --git a/doc/topics/tutorials/salt_bootstrap.rst b/doc/topics/tutorials/salt_bootstrap.rst index 4b11ee91da..605dc66634 100644 --- a/doc/topics/tutorials/salt_bootstrap.rst +++ b/doc/topics/tutorials/salt_bootstrap.rst @@ -327,14 +327,14 @@ Here's a summary of the command line options: -U If set, fully upgrade the system prior to bootstrapping Salt -I If set, allow insecure connections while downloading any files. For example, pass '--no-check-certificate' to 'wget' or '--insecure' to - 'curl'. On Debian and Ubuntu, using this option with -U allows to obtain + 'curl'. On Debian and Ubuntu, using this option with -U allows one to obtain GnuPG archive keys insecurely if distro has changed release signatures. -F Allow copied files to overwrite existing (config, init.d, etc) -K If set, keep the temporary files in the temporary directories specified with -c and -k -C Only run the configuration function. Implies -F (forced overwrite). To overwrite Master or Syndic configs, -M or -S, respectively, must - also be specified. Salt installation will be ommitted, but some of the + also be specified. Salt installation will be omitted, but some of the dependencies could be installed to write configuration with -j or -J. -A Pass the salt-master DNS name or IP. This will be stored under ${BS_SALT_ETC_DIR}/minion.d/99-master-address.conf diff --git a/pkg/suse/salt.changes b/pkg/suse/salt.changes index 7e6ac7ee29..d806880d6d 100644 --- a/pkg/suse/salt.changes +++ b/pkg/suse/salt.changes @@ -70,7 +70,7 @@ Mon Oct 12 08:48:25 UTC 2015 - dmacvicar@suse.de ------------------------------------------------------------------- Mon Oct 12 08:19:45 UTC 2015 - dmacvicar@suse.de -- allow to disable docs in preparation for building +- allow one to disable docs in preparation for building on other platforms without all dependencies. ------------------------------------------------------------------- diff --git a/salt/cloud/clouds/proxmox.py b/salt/cloud/clouds/proxmox.py index 765217fed6..4246aa409a 100644 --- a/salt/cloud/clouds/proxmox.py +++ b/salt/cloud/clouds/proxmox.py @@ -648,7 +648,7 @@ def _get_properties(path="", method="GET", forced_params=None): # Browse all path elements but last for elem in path_levels[:-1]: search_path += '/' + elem - # Lookup for a dictionnary with path = "requested path" in list" and return its children + # Lookup for a dictionary with path = "requested path" in list" and return its children sub = (item for item in sub if item["path"] == search_path).next()['children'] # Get leaf element in path search_path += '/' + path_levels[-1] diff --git a/salt/cloud/deploy/bootstrap-salt.sh b/salt/cloud/deploy/bootstrap-salt.sh index a9baf0680b..519d795a0a 100755 --- a/salt/cloud/deploy/bootstrap-salt.sh +++ b/salt/cloud/deploy/bootstrap-salt.sh @@ -345,7 +345,7 @@ __usage() { with -c and -k -C Only run the configuration function. Implies -F (forced overwrite). To overwrite Master or Syndic configs, -M or -S, respectively, must - also be specified. Salt installation will be ommitted, but some of the + also be specified. Salt installation will be omitted, but some of the dependencies could be installed to write configuration with -j or -J. -A Pass the salt-master DNS name or IP. This will be stored under \${BS_SALT_ETC_DIR}/minion.d/99-master-address.conf diff --git a/salt/config/__init__.py b/salt/config/__init__.py index df0e1388b7..04b35ef1c5 100644 --- a/salt/config/__init__.py +++ b/salt/config/__init__.py @@ -252,7 +252,7 @@ VALID_OPTS = { # Force the minion into a single environment when it fetches files from the master 'saltenv': (type(None), six.string_types), - # Prevent saltenv from being overriden on the command line + # Prevent saltenv from being overridden on the command line 'lock_saltenv': bool, # Force the minion into a single pillar root when it fetches pillar data from the master @@ -2310,7 +2310,7 @@ def prepend_root_dir(opts, path_options): # drive is not prefixed on a config option pass elif os.path.isabs(path): - # Absolute path (not default or overriden root_dir) + # Absolute path (not default or overridden root_dir) # No prepending required continue # Prepending the root dir diff --git a/salt/engines/ircbot.py b/salt/engines/ircbot.py index e3b8778cd2..7c75037703 100644 --- a/salt/engines/ircbot.py +++ b/salt/engines/ircbot.py @@ -46,7 +46,7 @@ Example of usage 08:33:57 gtmanbot > gtmanfred: pong 08:34:02 @gtmanfred > !echo ping 08:34:02 gtmanbot > ping - 08:34:17 @gtmanfred > !event test/tag/ircbot irc is usefull + 08:34:17 @gtmanfred > !event test/tag/ircbot irc is useful 08:34:17 gtmanbot > gtmanfred: TaDa! .. code-block:: text diff --git a/salt/engines/slack.py b/salt/engines/slack.py index 4189f0e2b8..2fccda66be 100644 --- a/salt/engines/slack.py +++ b/salt/engines/slack.py @@ -267,7 +267,7 @@ class SlackClient(object): def can_user_run(self, user, command, groups): ''' - Break out the permissions into the folowing: + Break out the permissions into the following: Check whether a user is in any group, including whether a group has the '*' membership @@ -282,7 +282,7 @@ class SlackClient(object): :rtype: tuple :returns: On a successful permitting match, returns 2-element tuple that contains - the name of the group that successfuly matched, and a dictionary containing + the name of the group that successfully matched, and a dictionary containing the configuration of the group so it can be referenced. On failure it returns an empty tuple @@ -400,7 +400,7 @@ class SlackClient(object): When encountering an error (e.g. invalid message), yields {}, the caller can proceed to the next message When the websocket being read from has given up all its messages, yields {'done': True} to - indicate that the caller has read all of the relevent data for now, and should continue + indicate that the caller has read all of the relevant data for now, and should continue its own processing and check back for more data later. This relies on the caller sleeping between checks, otherwise this could flood diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py index cef5b179b1..dd1ffd3b36 100644 --- a/salt/modules/aptpkg.py +++ b/salt/modules/aptpkg.py @@ -1084,7 +1084,7 @@ def upgrade(refresh=True, dist_upgrade=False, **kwargs): seconds download_only - Only donwload the packages, don't unpack or install them + Only download the packages, don't unpack or install them .. versionadded:: 2018.3.0 diff --git a/salt/modules/cmdmod.py b/salt/modules/cmdmod.py index 3717155e0e..80fda445b6 100644 --- a/salt/modules/cmdmod.py +++ b/salt/modules/cmdmod.py @@ -3226,10 +3226,10 @@ def powershell_all(cmd, empty Powershell output (which would result in an exception). Instead we treat this as a special case and one of two things will happen: - - If the value of the ``force_list`` paramater is ``True``, then the + - If the value of the ``force_list`` parameter is ``True``, then the ``result`` field of the return dictionary will be an empty list. - - If the value of the ``force_list`` paramater is ``False``, then the + - If the value of the ``force_list`` parameter is ``False``, then the return dictionary **will not have a result key added to it**. We aren't setting ``result`` to ``None`` in this case, because ``None`` is the Python representation of "null" in JSON. (We likewise can't use ``False`` @@ -3242,20 +3242,20 @@ def powershell_all(cmd, content, and the type of the resulting Python object is other than ``list`` then one of two things will happen: - - If the value of the ``force_list`` paramater is ``True``, then the + - If the value of the ``force_list`` parameter is ``True``, then the ``result`` field will be a singleton list with the Python object as its sole member. - - If the value of the ``force_list`` paramater is ``False``, then the value + - If the value of the ``force_list`` parameter is ``False``, then the value of ``result`` will be the unmodified Python object. If Powershell's output is not an empty string, Python is able to parse its content, and the type of the resulting Python object is ``list``, then the value of ``result`` will be the unmodified Python object. The - ``force_list`` paramater has no effect in this case. + ``force_list`` parameter has no effect in this case. .. note:: - An example of why the ``force_list`` paramater is useful is as + An example of why the ``force_list`` parameter is useful is as follows: The Powershell command ``dir x | Convert-ToJson`` results in - no output when x is an empty directory. @@ -3403,7 +3403,7 @@ def powershell_all(cmd, where characters may be dropped or incorrectly converted when executed. Default is False. - :param bool force_list: The purpose of this paramater is described in the + :param bool force_list: The purpose of this parameter is described in the preamble of this function's documentation. Default value is False. :return: A dictionary with the following entries: diff --git a/salt/modules/highstate_doc.py b/salt/modules/highstate_doc.py index d551d760f1..77a1d37848 100644 --- a/salt/modules/highstate_doc.py +++ b/salt/modules/highstate_doc.py @@ -178,7 +178,7 @@ If you wish to customize the document format: - mode: '0640' -Some `replace_text_regex` values that might be helpfull. +Some `replace_text_regex` values that might be helpful. ## CERTS '-----BEGIN RSA PRIVATE KEY-----[\r\n\t\f\S]{0,2200}': 'XXXXXXX' diff --git a/salt/modules/infoblox.py b/salt/modules/infoblox.py index f44b45b272..511512d284 100644 --- a/salt/modules/infoblox.py +++ b/salt/modules/infoblox.py @@ -367,7 +367,7 @@ def get_host_mac(name=None, allow_array=False, **api_opts): ''' Get mac address from host record. - Use `allow_array` to return possible mutiple values. + Use `allow_array` to return possible multiple values. CLI Example: @@ -390,7 +390,7 @@ def get_host_ipv4(name=None, mac=None, allow_array=False, **api_opts): ''' Get ipv4 address from host record. - Use `allow_array` to return possible mutiple values. + Use `allow_array` to return possible multiple values. CLI Example: @@ -446,7 +446,7 @@ def get_host_ipv6addr_info(ipv6addr=None, mac=None, def get_network(ipv4addr=None, network=None, return_fields=None, **api_opts): ''' Get list of all networks. - This is helpfull when looking up subnets to + This is helpful when looking up subnets to use with func:nextavailableip This call is offen slow and not cached! diff --git a/salt/modules/kernelpkg_linux_apt.py b/salt/modules/kernelpkg_linux_apt.py index f807a89f3f..d08388f7e1 100644 --- a/salt/modules/kernelpkg_linux_apt.py +++ b/salt/modules/kernelpkg_linux_apt.py @@ -189,7 +189,7 @@ def upgrade(reboot=False, at_time=None): def upgrade_available(): ''' Detect if a new kernel version is available in the repositories. - Returns True if a new kernel is avaliable, False otherwise. + Returns True if a new kernel is available, False otherwise. CLI Example: diff --git a/salt/modules/kernelpkg_linux_yum.py b/salt/modules/kernelpkg_linux_yum.py index 3cd90a922f..c9da824523 100644 --- a/salt/modules/kernelpkg_linux_yum.py +++ b/salt/modules/kernelpkg_linux_yum.py @@ -182,7 +182,7 @@ def upgrade(reboot=False, at_time=None): def upgrade_available(): ''' Detect if a new kernel version is available in the repositories. - Returns True if a new kernel is avaliable, False otherwise. + Returns True if a new kernel is available, False otherwise. CLI Example: diff --git a/salt/modules/libcloud_compute.py b/salt/modules/libcloud_compute.py index 47725f5668..f1191dea59 100644 --- a/salt/modules/libcloud_compute.py +++ b/salt/modules/libcloud_compute.py @@ -206,7 +206,7 @@ def destroy_node(node_id, profile, **libcloud_kwargs): ''' Destroy a node in the cloud - :param node_id: Unique ID of the node to destory + :param node_id: Unique ID of the node to destroy :type node_id: ``str`` :param profile: The profile key diff --git a/salt/modules/logadm.py b/salt/modules/logadm.py index 98ba62b5c4..869e5b7987 100644 --- a/salt/modules/logadm.py +++ b/salt/modules/logadm.py @@ -256,7 +256,7 @@ def rotate(name, pattern=None, conf_file=default_conf, **kwargs): ``name`` and ``pattern`` were kept for backwards compatibility reasons. ``name`` is an alias for the ``entryname`` argument, ``pattern`` is an alias - for ``log_file``. These aliasses wil only be used if the ``entryname`` and + for ``log_file``. These aliases will only be used if the ``entryname`` and ``log_file`` arguments are not passed. For a full list of arguments see ```logadm.show_args```. diff --git a/salt/modules/reg.py b/salt/modules/reg.py index 3e79bf9991..929a63121d 100644 --- a/salt/modules/reg.py +++ b/salt/modules/reg.py @@ -728,7 +728,7 @@ def import_file(source, use_32bit_registry=False): can be either a local file path or a URL type supported by salt (e.g. ``salt://salt_master_path``). - :param bool use_32bit_registry: If the value of this paramater is ``True`` + :param bool use_32bit_registry: If the value of this parameter is ``True`` then the ``REG`` file will be imported into the Windows 32 bit registry. Otherwise the Windows 64 bit registry will be used. diff --git a/salt/modules/state.py b/salt/modules/state.py index 9f6b832d49..01e70b7b47 100644 --- a/salt/modules/state.py +++ b/salt/modules/state.py @@ -230,7 +230,7 @@ def soft_kill(jid, state_id=None): this instructs a running state to safely exit at a given state id. This needs to pass in the jid of the running state. If a state_id is not passed then the jid referenced will be safely exited - at the begining of the next state run. + at the beginning of the next state run. The given state id is the id got a given state execution, so given a state that looks like this: @@ -263,7 +263,7 @@ def pause(jid, state_id=None, duration=None): Set up a state id pause, this instructs a running state to pause at a given state id. This needs to pass in the jid of the running state and can optionally pass in a duration in seconds. If a state_id is not passed then - the jid referenced will be paused at the begining of the next state run. + the jid referenced will be paused at the beginning of the next state run. The given state id is the id got a given state execution, so given a state that looks like this: diff --git a/salt/modules/vsphere.py b/salt/modules/vsphere.py index 37f7d6f0fd..7fc971a621 100644 --- a/salt/modules/vsphere.py +++ b/salt/modules/vsphere.py @@ -3944,7 +3944,7 @@ def create_dvs(dvs_dict, dvs_name, service_instance=None): Note: The ``dvs_name`` param will override any name set in ``dvs_dict``. dvs_dict - Dict representation of the new DVS (exmaple in salt.states.dvs) + Dict representation of the new DVS (example in salt.states.dvs) dvs_name Name of the DVS to be created. @@ -4019,7 +4019,7 @@ def update_dvs(dvs_dict, dvs, service_instance=None): dvs_dict Dictionary with the values the DVS should be update with - (exmaple in salt.states.dvs) + (example in salt.states.dvs) dvs Name of the DVS to be updated. @@ -4479,7 +4479,7 @@ def create_dvportgroup(portgroup_dict, portgroup_name, dvs, portgroup_dict Dictionary with the config values the portgroup should be created with - (exmaple in salt.states.dvs). + (example in salt.states.dvs). portgroup_name Name of the portgroup to be created. @@ -4526,7 +4526,7 @@ def update_dvportgroup(portgroup_dict, portgroup, dvs, service_instance=True): portgroup_dict Dictionary with the values the portgroup should be update with - (exmaple in salt.states.dvs). + (example in salt.states.dvs). portgroup Name of the portgroup to be updated. @@ -4813,7 +4813,7 @@ def create_storage_policy(policy_name, policy_dict, service_instance=None): policy_dict Dictionary containing the changes to apply to the policy. - (exmaple in salt.states.pbm) + (example in salt.states.pbm) service_instance Service instance (vim.ServiceInstance) of the vCenter. @@ -4853,7 +4853,7 @@ def update_storage_policy(policy, policy_dict, service_instance=None): policy_dict Dictionary containing the changes to apply to the policy. - (exmaple in salt.states.pbm) + (example in salt.states.pbm) service_instance Service instance (vim.ServiceInstance) of the vCenter. @@ -6472,7 +6472,7 @@ def configure_host_cache(enabled, datastore=None, swap_size_MiB=None, swap_size_MiB Swap size in Mibibytes. Needs to be set if enabled is ``true``. Must be - smaller thant the datastore size. + smaller than the datastore size. service_instance Service instance (vim.ServiceInstance) of the vCenter/ESXi host. @@ -7595,7 +7595,7 @@ def _apply_hard_disk(unit_number, key, operation, disk_label=None, size=None, Action which should be done on the device add or edit disk_label - Label of the new disk, can be overriden + Label of the new disk, can be overridden size Size of the disk diff --git a/salt/modules/win_file.py b/salt/modules/win_file.py index 8eb8ddd60c..d321bd538e 100644 --- a/salt/modules/win_file.py +++ b/salt/modules/win_file.py @@ -1605,7 +1605,7 @@ def check_perms(path, ``True``. reset (bool): - ``True`` wil show what permisisons will be removed by resetting the + ``True`` will show what permisisons will be removed by resetting the DACL. ``False`` will do nothing. Default is ``False``. Returns: diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py index b84d8abcc9..f0d7aaafab 100644 --- a/salt/modules/zypper.py +++ b/salt/modules/zypper.py @@ -1058,7 +1058,7 @@ def install(name=None, This parameter is ignored if ``pkgs`` or ``sources`` is passed. resolve_capabilities - If this option is set to True zypper will take capabilites into + If this option is set to True zypper will take capabilities into account. In this case names which are just provided by a package will get installed. Default is False. diff --git a/salt/pillar/http_json.py b/salt/pillar/http_json.py index e24b80a2f4..5f0fd9a7fa 100644 --- a/salt/pillar/http_json.py +++ b/salt/pillar/http_json.py @@ -29,7 +29,7 @@ in <> brackets) in the url in order to populate pillar data based on the grain v .. versionchanged:: 2018.3.0 - If %s is present in the url, it will be automaticaly replaced by the minion_id: + If %s is present in the url, it will be automatically replaced by the minion_id: .. code-block:: yaml diff --git a/salt/pillar/http_yaml.py b/salt/pillar/http_yaml.py index e3523ad044..7ba64aef65 100644 --- a/salt/pillar/http_yaml.py +++ b/salt/pillar/http_yaml.py @@ -29,7 +29,7 @@ in <> brackets) in the url in order to populate pillar data based on the grain v .. versionchanged:: 2018.3.0 - If %s is present in the url, it will be automaticaly replaced by the minion_id: + If %s is present in the url, it will be automatically replaced by the minion_id: .. code-block:: yaml diff --git a/salt/states/esxi.py b/salt/states/esxi.py index f179840182..f44533c1be 100644 --- a/salt/states/esxi.py +++ b/salt/states/esxi.py @@ -1061,7 +1061,7 @@ def diskgroups_configured(name, diskgroups, erase_disks=False): erase_disks Specifies whether to erase all partitions on all disks member of the - disk group before the disk group is created. Default vaule is False. + disk group before the disk group is created. Default value is False. ''' proxy_details = __salt__['esxi.get_details']() hostname = proxy_details['host'] if not proxy_details.get('vcenter') \ @@ -1371,7 +1371,7 @@ def host_cache_configured(name, enabled, datastore, swap_size='100%', erase_backing_disk Specifies whether to erase all partitions on the backing disk before - the datastore is created. Default vaule is False. + the datastore is created. Default value is False. ''' log.trace('enabled = %s', enabled) log.trace('datastore = %s', datastore) diff --git a/salt/states/etcd_mod.py b/salt/states/etcd_mod.py index cef4a915ec..da112d7e76 100644 --- a/salt/states/etcd_mod.py +++ b/salt/states/etcd_mod.py @@ -41,7 +41,7 @@ or clusters are available. as this makes all master configuration settings available in all minion's pillars. -Etcd profile configuration can be overriden using following arguments: ``host``, +Etcd profile configuration can be overridden using following arguments: ``host``, ``port``, ``username``, ``password``, ``ca``, ``client_key`` and ``client_cert``. .. code-block:: yaml diff --git a/salt/states/infoblox_host_record.py b/salt/states/infoblox_host_record.py index ff02bd8698..f61ba499e3 100644 --- a/salt/states/infoblox_host_record.py +++ b/salt/states/infoblox_host_record.py @@ -104,7 +104,7 @@ def present(name=None, data=None, ensure_data=True, **api_opts): addr['ipv4addr'] = ip found_matches += 1 if found_matches > 1: - ret['comment'] = 'infoblox record cant updated because ipaddress {0} matches mutiple func:nextavailableip'.format(ip) + ret['comment'] = 'infoblox record cant updated because ipaddress {0} matches multiple func:nextavailableip'.format(ip) ret['result'] = False return ret diff --git a/salt/states/kernelpkg.py b/salt/states/kernelpkg.py index 83b2eea097..6d4fd56357 100644 --- a/salt/states/kernelpkg.py +++ b/salt/states/kernelpkg.py @@ -31,7 +31,7 @@ Example state chaining the install and reboot operations: - onchanges: - kernel: install-latest-kernel -Chaining can also be acheived using wait/listen requisites: +Chaining can also be achieved using wait/listen requisites: .. code-block:: yaml diff --git a/salt/states/pkg.py b/salt/states/pkg.py index 4c406aa04e..5bd6c3a688 100644 --- a/salt/states/pkg.py +++ b/salt/states/pkg.py @@ -1133,7 +1133,7 @@ def installed( .. versionadded:: 2014.1.1 :param bool resolve_capabilities: - Turn on resolving capabilities. This allow to name "provides" or alias names for packages. + Turn on resolving capabilities. This allow one to name "provides" or alias names for packages. .. versionadded:: 2018.3.0 @@ -1967,7 +1967,7 @@ def downloaded(name, - salt-minion: 2015.8.5-1.el6 :param bool resolve_capabilities: - Turn on resolving capabilities. This allow to name "provides" or alias names for packages. + Turn on resolving capabilities. This allow one to name "provides" or alias names for packages. .. versionadded:: 2018.3.0 @@ -2259,7 +2259,7 @@ def latest( has no effect on the rest. :param bool resolve_capabilities: - Turn on resolving capabilities. This allow to name "provides" or alias names for packages. + Turn on resolving capabilities. This allow one to name "provides" or alias names for packages. .. versionadded:: 2018.3.0 @@ -2886,7 +2886,7 @@ def uptodate(name, refresh=False, pkgs=None, **kwargs): have no effect on the rest. :param bool resolve_capabilities: - Turn on resolving capabilities. This allow to name "provides" or alias names for packages. + Turn on resolving capabilities. This allow one to name "provides" or alias names for packages. .. versionadded:: 2018.3.0 diff --git a/salt/states/rabbitmq_policy.py b/salt/states/rabbitmq_policy.py index 002a4a0fb6..a533c1195d 100644 --- a/salt/states/rabbitmq_policy.py +++ b/salt/states/rabbitmq_policy.py @@ -54,7 +54,7 @@ def present(name, priority Priority (defaults to 0) apply_to - Apply policy to 'queues', 'exchanges' or 'all' (defailt to 'all') + Apply policy to 'queues', 'exchanges' or 'all' (default to 'all') vhost Virtual host to apply to (defaults to '/') runas diff --git a/salt/states/vagrant.py b/salt/states/vagrant.py index 86e2f13797..6b63616b6a 100644 --- a/salt/states/vagrant.py +++ b/salt/states/vagrant.py @@ -319,7 +319,7 @@ def powered_off(name): def destroyed(name): ''' - Stops a VM (or VMs) and removes all refences to it (them). (Runs ``vagrant destroy``.) + Stops a VM (or VMs) and removes all references to it (them). (Runs ``vagrant destroy``.) Subsequent re-use of the same machine will requere another operation of ``vagrant.running`` or a call to the ``vagrant.init`` execution module. diff --git a/salt/thorium/check.py b/salt/thorium/check.py index ea4e99c12d..41b47d9397 100644 --- a/salt/thorium/check.py +++ b/salt/thorium/check.py @@ -373,7 +373,7 @@ def len_gte(name, value): def len_lt(name, value): ''' - Only succeed if the lenght of the given register location is less than + Only succeed if the length of the given register location is less than the given value. USAGE: diff --git a/salt/utils/gitfs.py b/salt/utils/gitfs.py index d483192951..526b9aa8fb 100644 --- a/salt/utils/gitfs.py +++ b/salt/utils/gitfs.py @@ -492,7 +492,7 @@ class GitProvider(object): @classmethod def add_conf_overlay(cls, name): ''' - Programatically determine config value based on the desired saltenv + Programmatically determine config value based on the desired saltenv ''' def _getconf(self, tgt_env='base'): strip_sep = lambda x: x.rstrip(os.sep) \ diff --git a/salt/utils/napalm.py b/salt/utils/napalm.py index b551c63e09..9fafd124f7 100644 --- a/salt/utils/napalm.py +++ b/salt/utils/napalm.py @@ -259,7 +259,7 @@ def get_device_opts(opts, salt_obj=None): if opts.get('proxy') or opts.get('napalm'): opts['multiprocessing'] = device_dict.get('multiprocessing', False) # Most NAPALM drivers are SSH-based, so multiprocessing should default to False. - # But the user can be allows to have a different value for the multiprocessing, which will + # But the user can be allows one to have a different value for the multiprocessing, which will # override the opts. if salt_obj and not device_dict: # get the connection details from the opts diff --git a/tests/integration/files/saltclass/examples/classes/roles/app.yml b/tests/integration/files/saltclass/examples/classes/roles/app.yml index af244e402c..dc8b9864f1 100644 --- a/tests/integration/files/saltclass/examples/classes/roles/app.yml +++ b/tests/integration/files/saltclass/examples/classes/roles/app.yml @@ -17,5 +17,5 @@ pillars: - app-backend # Safe minion_id matching {% if minion_id == 'zrh.node3' %} - safe_pillar: '_only_ zrh.node3 will see this pillar and this cannot be overriden like grains' + safe_pillar: '_only_ zrh.node3 will see this pillar and this cannot be overridden like grains' {% endif %} diff --git a/tests/unit/states/test_docker_image.py b/tests/unit/states/test_docker_image.py index 72c5af76cc..df77541a56 100644 --- a/tests/unit/states/test_docker_image.py +++ b/tests/unit/states/test_docker_image.py @@ -84,7 +84,7 @@ class DockerImageTestCase(TestCase, LoaderModuleMockMixin): - force: true if ``image:latest`` is not downloaded and force is true - should pull a new image successfuly. + should pull a new image successfully. ''' docker_inspect_image = MagicMock(return_value={'Id': '1234567890ab'}) docker_pull = MagicMock( diff --git a/tests/unit/utils/test_state.py b/tests/unit/utils/test_state.py index 695def80b8..d076e7d004 100644 --- a/tests/unit/utils/test_state.py +++ b/tests/unit/utils/test_state.py @@ -482,7 +482,7 @@ class UtilStateMergeSubreturnTestcase(TestCase): res = salt.utils.state.merge_subreturn(m, s) self.assertFalse(res['result']) - # False result cannot be overriden + # False result cannot be overridden for any_result in [True, None, False]: m = copy.deepcopy(self.main_ret) m['result'] = False From ddd1f39578cf8d0236e4ca14912461f1149606c4 Mon Sep 17 00:00:00 2001 From: rallytime Date: Mon, 12 Mar 2018 13:03:04 -0400 Subject: [PATCH 7/7] Update old utils paths to new utils paths --- salt/cloud/clouds/azurearm.py | 6 +++--- salt/modules/openbsdpkg.py | 7 ++++--- salt/states/azurearm_resource.py | 8 ++++---- salt/utils/docker/__init__.py | 2 +- tests/integration/states/test_file.py | 9 +++++---- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/salt/cloud/clouds/azurearm.py b/salt/cloud/clouds/azurearm.py index 190d980f24..6d7454577c 100644 --- a/salt/cloud/clouds/azurearm.py +++ b/salt/cloud/clouds/azurearm.py @@ -103,8 +103,8 @@ import time import salt.cache import salt.config as config import salt.loader -import salt.utils import salt.utils.cloud +import salt.utils.files import salt.utils.yaml import salt.ext.six as six import salt.version @@ -1003,7 +1003,7 @@ def request_instance(vm_): ) if ssh_publickeyfile is not None: try: - with salt.utils.fopen(ssh_publickeyfile, 'r') as spkc_: + with salt.utils.files.fopen(ssh_publickeyfile, 'r') as spkc_: ssh_publickeyfile_contents = spkc_.read() except Exception as exc: raise SaltCloudConfigError( @@ -1219,7 +1219,7 @@ def request_instance(vm_): if userdata_file: if os.path.exists(userdata_file): - with salt.utils.fopen(userdata_file, 'r') as fh_: + with salt.utils.files.fopen(userdata_file, 'r') as fh_: userdata = fh_.read() if userdata and userdata_template: diff --git a/salt/modules/openbsdpkg.py b/salt/modules/openbsdpkg.py index add6f1bbd3..decceee1fc 100644 --- a/salt/modules/openbsdpkg.py +++ b/salt/modules/openbsdpkg.py @@ -153,9 +153,10 @@ def latest_version(*names, **kwargs): continue cur = pkgs.get(pkgname, '') - if not cur or salt.utils.compare_versions(ver1=cur, - oper='<', - ver2=pkgver): + if not cur or salt.utils.versions.compare( + ver1=cur, + oper='<', + ver2=pkgver): ret[pkgname] = pkgver # Return a string if only one package name passed diff --git a/salt/states/azurearm_resource.py b/salt/states/azurearm_resource.py index d0c555c90d..79f124b5da 100644 --- a/salt/states/azurearm_resource.py +++ b/salt/states/azurearm_resource.py @@ -81,13 +81,13 @@ parameters are sensitive, it's recommended to pass them to the states via pillar ''' -# Python libs +# Import Python libs from __future__ import absolute_import import json import logging -# Salt libs -import salt.utils +# Import Salt libs +import salt.utils.files __virtualname__ = 'azurearm_resource' @@ -424,7 +424,7 @@ def policy_definition_present(name, policy_rule=None, policy_type=None, mode=Non return ret try: - with salt.utils.fopen(sfn, 'r') as prf: + with salt.utils.files.fopen(sfn, 'r') as prf: temp_rule = json.load(prf) except Exception as exc: ret['comment'] = 'Unable to load policy rule file "{0}"! ({1})'.format(policy_rule_file, exc) diff --git a/salt/utils/docker/__init__.py b/salt/utils/docker/__init__.py index adbb97ed56..4edaca7860 100644 --- a/salt/utils/docker/__init__.py +++ b/salt/utils/docker/__init__.py @@ -184,7 +184,7 @@ def translate_input(translator, of that tuple will have their translation skipped. Optionally, skip_translate can be set to True to skip *all* translation. ''' - kwargs = copy.deepcopy(salt.utils.clean_kwargs(**kwargs)) + kwargs = copy.deepcopy(salt.utils.args.clean_kwargs(**kwargs)) invalid = {} collisions = [] diff --git a/tests/integration/states/test_file.py b/tests/integration/states/test_file.py index 2de06f68e7..d0c0c06cd4 100644 --- a/tests/integration/states/test_file.py +++ b/tests/integration/states/test_file.py @@ -36,6 +36,7 @@ from tests.support.mixins import SaltReturnAssertsMixin import salt.utils.files import salt.utils.path import salt.utils.platform +import salt.utils.stringutils HAS_PWD = True try: @@ -2632,13 +2633,13 @@ class BlockreplaceTest(ModuleCase, SaltReturnAssertsMixin): @staticmethod def _write(dest, content): - with salt.utils.fopen(dest, 'wb') as fp_: - fp_.write(salt.utils.to_bytes(content)) + with salt.utils.files.fopen(dest, 'wb') as fp_: + fp_.write(salt.utils.stringutils.to_bytes(content)) @staticmethod def _read(src): - with salt.utils.fopen(src, 'rb') as fp_: - return salt.utils.to_unicode(fp_.read()) + with salt.utils.files.fopen(src, 'rb') as fp_: + return salt.utils.stringutils.to_unicode(fp_.read()) @with_tempfile def test_prepend(self, name):