Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move a path being passed around as a byte string to being passed around as a text string. #17190

Merged
merged 1 commit into from
Aug 23, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
66 changes: 39 additions & 27 deletions lib/ansible/parsing/dataloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from ansible.parsing.yaml.objects import AnsibleBaseYAMLObject, AnsibleUnicode
from ansible.module_utils.basic import is_executable
from ansible.utils.path import unfrackpath
from ansible.utils.unicode import to_unicode, to_bytes
from ansible.utils.unicode import to_unicode, to_bytes, to_str

try:
from __main__ import display
Expand Down Expand Up @@ -279,45 +279,56 @@ def path_dwim_relative(self, path, dirname, source):
def path_dwim_relative_stack(self, paths, dirname, source):
'''
find one file in first path in stack taking roles into account and adding play basedir as fallback

:arg paths: A list of text strings which are the paths to look for the filename in.
:arg dirname: A text string representing a directory. The directory
is prepended to the source to form the path to search for.
:arg source: A text string which is the filename to search for
:rtype: A text string
:returns: An absolute path to the filename ``source``
'''
b_dirname = to_bytes(dirname)
b_source = to_bytes(source)

result = None
if not source:
display.warning('Invalid request to find a file that matches an empty string or "null" value')
elif source.startswith('~') or source.startswith(os.path.sep):
# path is absolute, no relative needed, check existence and return source
test_path = to_bytes(unfrackpath(source),errors='strict')
if os.path.exists(test_path):
test_path = unfrackpath(b_source)
if os.path.exists(to_bytes(test_path, errors='strict')):
result = test_path
else:
search = []
for path in paths:
upath = unfrackpath(path)
mydir = os.path.dirname(upath)
b_upath = to_bytes(upath, errors='strict')
b_mydir = os.path.dirname(b_upath)

# if path is in role and 'tasks' not there already, add it into the search
if upath.endswith('tasks') and os.path.exists(to_bytes(os.path.join(upath,'main.yml'), errors='strict')) \
or os.path.exists(to_bytes(os.path.join(upath,'tasks/main.yml'), errors='strict')) \
or os.path.exists(to_bytes(os.path.join(os.path.dirname(upath),'tasks/main.yml'), errors='strict')):
if mydir.endswith('tasks'):
search.append(os.path.join(os.path.dirname(mydir), dirname, source))
search.append(os.path.join(mydir, source))
if b_upath.endswith(b'tasks') and os.path.exists(os.path.join(b_upath, b'main.yml')) \
or os.path.exists(os.path.join(b_upath, b'tasks/main.yml')) \
or os.path.exists(os.path.join(b_mydir, b'tasks/main.yml')):
if b_mydir.endswith(b'tasks'):
search.append(os.path.join(os.path.dirname(b_mydir), b_dirname, b_source))
search.append(os.path.join(b_mydir, b_source))
else:
search.append(os.path.join(upath, dirname, source))
search.append(os.path.join(upath, 'tasks', source))
elif dirname not in source.split('/'):
search.append(os.path.join(b_upath, b_dirname, b_source))
search.append(os.path.join(b_upath, b'tasks', b_source))
elif b_dirname not in b_source.split(b'/'):
# don't add dirname if user already is using it in source
search.append(os.path.join(upath, dirname, source))
search.append(os.path.join(upath, source))
search.append(os.path.join(b_upath, b_dirname, b_source))
search.append(os.path.join(b_upath, b_source))

# always append basedir as last resort
search.append(os.path.join(self.get_basedir(), dirname, source))
search.append(os.path.join(self.get_basedir(), source))

display.debug('search_path:\n\t' + '\n\t'.join(search))
for candidate in search:
display.vvvvv('looking for "%s" at "%s"' % (source, candidate))
if os.path.exists(to_bytes(candidate, errors='strict')):
result = candidate
search.append(os.path.join(to_bytes(self.get_basedir()), b_dirname, b_source))
search.append(os.path.join(to_bytes(self.get_basedir()), b_source))

display.debug(u'search_path:\n\t%s' % to_unicode(b'\n\t'.join(search), errors='replace'))
for b_candidate in search:
display.vvvvv(u'looking for "%s" at "%s"' % (source, to_unicode(b_candidate)))
if os.path.exists(b_candidate):
result = to_unicode(b_candidate)
break

return result
Expand Down Expand Up @@ -370,10 +381,11 @@ def get_real_file(self, file_path):
"""

if not file_path or not isinstance(file_path, string_types):
raise AnsibleParserError("Invalid filename: '%s'" % str(file_path))
raise AnsibleParserError("Invalid filename: '%s'" % to_str(file_path))

if not self.path_exists(file_path) or not self.is_file(file_path):
raise AnsibleFileNotFound("the file_name '%s' does not exist, or is not readable" % file_path)
b_file_path = to_bytes(file_path, errors='strict')
if not self.path_exists(b_file_path) or not self.is_file(b_file_path):
raise AnsibleFileNotFound("the file_name '%s' does not exist, or is not readable" % to_str(file_path))

if not self._vault:
self._vault = VaultLib(password="")
Expand All @@ -398,7 +410,7 @@ def get_real_file(self, file_path):
return real_path

except (IOError, OSError) as e:
raise AnsibleParserError("an error occurred while trying to read the file '%s': %s" % (real_path, str(e)))
raise AnsibleParserError("an error occurred while trying to read the file '%s': %s" % (to_str(real_path), to_str(e)))

def cleanup_tmp_file(self, file_path):
"""
Expand Down
4 changes: 2 additions & 2 deletions lib/ansible/plugins/action/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
from ansible.executor.module_common import modify_module
from ansible.release import __version__
from ansible.parsing.utils.jsonify import jsonify
from ansible.utils.unicode import to_bytes, to_unicode
from ansible.utils.unicode import to_bytes, to_str, to_unicode

try:
from __main__ import display
Expand Down Expand Up @@ -844,7 +844,7 @@ def _find_needle(self, dirname, needle):
result = self._loader.path_dwim_relative_stack(path_stack, dirname, needle)

if result is None:
raise AnsibleError("Unable to find '%s' in expected paths." % needle)
raise AnsibleError("Unable to find '%s' in expected paths." % to_str(needle))

return result

8 changes: 4 additions & 4 deletions lib/ansible/plugins/action/assemble.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from ansible.plugins.action import ActionBase
from ansible.utils.boolean import boolean
from ansible.utils.hashing import checksum_s
from ansible.utils.unicode import to_str
from ansible.utils.unicode import to_str, to_unicode


class ActionModule(ActionBase):
Expand All @@ -42,10 +42,10 @@ def _assemble_from_fragments(self, src_path, delimiter=None, compiled_regexp=Non
delimit_me = False
add_newline = False

for f in sorted(os.listdir(src_path)):
for f in (to_unicode(p, errors='strict') for p in sorted(os.listdir(src_path))):
if compiled_regexp and not compiled_regexp.search(f):
continue
fragment = "%s/%s" % (src_path, f)
fragment = u"%s/%s" % (src_path, f)
if not os.path.isfile(fragment) or (ignore_hidden and os.path.basename(fragment).startswith('.')):
continue

Expand Down Expand Up @@ -119,7 +119,7 @@ def run(self, tmp=None, task_vars=None):

if not os.path.isdir(src):
result['failed'] = True
result['msg'] = "Source (%s) is not a directory" % src
result['msg'] = u"Source (%s) is not a directory" % src
return result

_re = None
Expand Down
2 changes: 2 additions & 0 deletions lib/ansible/plugins/action/async.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
__metaclass__ = type

import json
import pipes
import random

from ansible import constants as C
from ansible.plugins.action import ActionBase
from ansible.compat.six import iteritems
from ansible.utils.unicode import to_unicode

class ActionModule(ActionBase):
Expand Down
6 changes: 3 additions & 3 deletions lib/ansible/plugins/action/copy.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from ansible.plugins.action import ActionBase
from ansible.utils.boolean import boolean
from ansible.utils.hashing import checksum
from ansible.utils.unicode import to_bytes, to_str
from ansible.utils.unicode import to_bytes, to_str, to_unicode


class ActionModule(ActionBase):
Expand Down Expand Up @@ -96,7 +96,7 @@ def run(self, tmp=None, task_vars=None):
source = self._find_needle('files', source)
except AnsibleError as e:
result['failed'] = True
result['msg'] = to_str(e)
result['msg'] = to_unicode(e)
return result

# A list of source file tuples (full_path, relative_path) which will try to copy to the destination
Expand All @@ -111,7 +111,7 @@ def run(self, tmp=None, task_vars=None):
sz = len(source.rsplit('/', 1)[0]) + 1

# Walk the directory and append the file tuples to source_files.
for base_path, sub_folders, files in os.walk(source):
for base_path, sub_folders, files in os.walk(to_bytes(source)):
for file in files:
full_path = os.path.join(base_path, file)
rel_path = full_path[sz:]
Expand Down
11 changes: 6 additions & 5 deletions lib/ansible/plugins/action/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,20 @@ def run(self, tmp=None, task_vars=None):
dest = os.path.join(dest, base)

# template the source data locally & get ready to transfer
b_source = to_bytes(source)
try:
with open(source, 'r') as f:
with open(b_source, 'r') as f:
template_data = to_unicode(f.read())

try:
template_uid = pwd.getpwuid(os.stat(source).st_uid).pw_name
template_uid = pwd.getpwuid(os.stat(b_source).st_uid).pw_name
except:
template_uid = os.stat(source).st_uid
template_uid = os.stat(b_source).st_uid

temp_vars = task_vars.copy()
temp_vars['template_host'] = os.uname()[1]
temp_vars['template_path'] = source
temp_vars['template_mtime'] = datetime.datetime.fromtimestamp(os.path.getmtime(source))
temp_vars['template_mtime'] = datetime.datetime.fromtimestamp(os.path.getmtime(b_source))
temp_vars['template_uid'] = template_uid
temp_vars['template_fullpath'] = os.path.abspath(source)
temp_vars['template_run_date'] = datetime.datetime.now()
Expand All @@ -118,7 +119,7 @@ def run(self, tmp=None, task_vars=None):
)
temp_vars['ansible_managed'] = time.strftime(
managed_str,
time.localtime(os.path.getmtime(source))
time.localtime(os.path.getmtime(b_source))
)

# Create a new searchpath list to assign to the templar environment's file
Expand Down
2 changes: 1 addition & 1 deletion lib/ansible/plugins/lookup/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def run(self, terms, variables=None, **kwargs):

# Find the file in the expected search path
lookupfile = self.find_file_in_search_path(variables, 'files', term)
display.vvvv("File lookup using %s as file" % lookupfile)
display.vvvv(u"File lookup using %s as file" % lookupfile)
try:
if lookupfile:
contents, show_data = self._loader._get_file_contents(lookupfile)
Expand Down
5 changes: 3 additions & 2 deletions lib/ansible/plugins/lookup/fileglob.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

from ansible.plugins.lookup import LookupBase
from ansible.errors import AnsibleFileNotFound
from ansible.module_utils.unicode import to_bytes

class LookupModule(LookupBase):

Expand All @@ -35,6 +36,6 @@ def run(self, terms, variables=None, **kwargs):
except AnsibleFileNotFound:
dwimmed_path = None
if dwimmed_path:
globbed = glob.glob(os.path.join(dwimmed_path, term_file))
ret.extend(g for g in globbed if os.path.isfile(g))
globbed = glob.glob(to_bytes(os.path.join(dwimmed_path, term_file), errors='strict'))
ret.extend(to_unicode(g, errors='strict') for g in globbed if os.path.isfile(g))
return ret
4 changes: 2 additions & 2 deletions lib/ansible/plugins/lookup/ini.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,13 @@ class LookupModule(LookupBase):

def read_properties(self, filename, key, dflt, is_regexp):
config = StringIO()
config.write(u'[java_properties]\n' + open(filename).read())
config.write(u'[java_properties]\n' + open(to_bytes(filename, errors='strict')).read())
config.seek(0, os.SEEK_SET)
self.cp.readfp(config)
return self.get_value(key, 'java_properties', dflt, is_regexp)

def read_ini(self, filename, key, section, dflt, is_regexp):
self.cp.readfp(open(filename))
self.cp.readfp(open(to_bytes(filename, errors='strict')))
return self.get_value(key, section, dflt, is_regexp)

def get_value(self, key, section, dflt, is_regexp):
Expand Down
5 changes: 3 additions & 2 deletions lib/ansible/plugins/lookup/shelvefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

from ansible.errors import AnsibleError
from ansible.plugins.lookup import LookupBase
from ansible.utils.unicode import to_bytes, to_unicode

class LookupModule(LookupBase):

Expand All @@ -29,7 +30,7 @@ def read_shelve(self, shelve_filename, key):
"""
Read the value of "key" from a shelve file
"""
d = shelve.open(shelve_filename)
d = shelve.open(to_bytes(shelve_filename))
res = d.get(key, None)
d.close()
return res
Expand Down Expand Up @@ -65,7 +66,7 @@ def run(self, terms, variables=None, **kwargs):
if res is None:
raise AnsibleError("Key %s not found in shelve file %s" % (key, file))
# Convert the value read to string
ret.append(str(res))
ret.append(to_unicode(res))
break
else:
raise AnsibleError("Could not locate shelve file in lookup: %s" % file)
Expand Down
2 changes: 1 addition & 1 deletion lib/ansible/plugins/lookup/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def run(self, terms, variables, **kwargs):
lookupfile = self.find_file_in_search_path(variables, 'templates', term)
display.vvvv("File lookup using %s as file" % lookupfile)
if lookupfile:
with open(lookupfile, 'r') as f:
with open(to_bytes(lookupfile, errors='strict'), 'r') as f:
template_data = to_unicode(f.read())

# set jinja2 internal search path for includes
Expand Down
39 changes: 29 additions & 10 deletions lib/ansible/utils/path.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,48 @@
import os
from errno import EEXIST
from ansible.errors import AnsibleError
from ansible.utils.unicode import to_bytes, to_str
from ansible.utils.unicode import to_bytes, to_str, to_unicode
from ansible.compat.six import PY2

__all__ = ['unfrackpath', 'makedirs_safe']

def unfrackpath(path):
'''
returns a path that is free of symlinks, environment
Returns a path that is free of symlinks, environment
variables, relative path traversals and symbols (~)
example:
'$HOME/../../var/mail' becomes '/var/spool/mail'

:arg path: A byte or text string representing a path to be canonicalized
:raises UnicodeDecodeError: If the canonicalized version of the path
contains non-utf8 byte sequences.
:rtype: A text string (unicode on pyyhon2, str on python3).
:returns: An absolute path with symlinks, environment variables, and tilde
expanded. Note that this does not check whether a path exists.

example::
'$HOME/../../var/mail' becomes '/var/spool/mail'
'''
return os.path.normpath(os.path.realpath(os.path.expanduser(os.path.expandvars(to_bytes(path, errors='strict')))))
canonical_path = os.path.normpath(os.path.realpath(os.path.expanduser(os.path.expandvars(to_bytes(path, errors='strict')))))
if PY2:
return to_unicode(canonical_path, errors='strict')
return to_unicode(canonical_path, errors='surrogateescape')

def makedirs_safe(path, mode=None):
'''Safe way to create dirs in muliprocess/thread environments'''
'''Safe way to create dirs in muliprocess/thread environments.

:arg path: A byte or text string representing a directory to be created
:kwarg mode: If given, the mode to set the directory to
:raises AnsibleError: If the directory cannot be created and does not already exists.
:raises UnicodeDecodeError: if the path is not decodable in the utf-8 encoding.
'''

rpath = unfrackpath(path)
if not os.path.exists(rpath):
b_rpath = to_bytes(rpath)
if not os.path.exists(b_rpath):
try:
if mode:
os.makedirs(rpath, mode)
os.makedirs(b_rpath, mode)
else:
os.makedirs(rpath)
os.makedirs(b_rpath)
except OSError as e:
if e.errno != EEXIST:
raise AnsibleError("Unable to create local directories(%s): %s" % (rpath, to_str(e)))
raise AnsibleError("Unable to create local directories(%s): %s" % (to_str(rpath), to_str(e)))