Revert "Revert "Allow ini plugin to load file using other encoding than utf8." (#27407)"
This reverts commit 520696fb39
.
This commit is contained in:
parent
520696fb39
commit
51bd07204b
9 changed files with 78 additions and 35 deletions
|
@ -253,6 +253,7 @@ type ini Type of the file. Can be ini or properties (for java
|
||||||
file ansible.ini Name of the file to load
|
file ansible.ini Name of the file to load
|
||||||
section global Default section where to lookup for key.
|
section global Default section where to lookup for key.
|
||||||
re False The key is a regexp.
|
re False The key is a regexp.
|
||||||
|
encoding utf-8 Text encoding to use.
|
||||||
default empty string return value if the key is not in the ini file
|
default empty string return value if the key is not in the ini file
|
||||||
========== ============ =========================================================================================
|
========== ============ =========================================================================================
|
||||||
|
|
||||||
|
|
|
@ -179,7 +179,7 @@ class DataLoader:
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass # older versions of yaml don't have dispose function, ignore
|
pass # older versions of yaml don't have dispose function, ignore
|
||||||
|
|
||||||
def _get_file_contents(self, file_name):
|
def _get_file_contents(self, file_name, encoding='utf-8'):
|
||||||
'''
|
'''
|
||||||
Reads the file contents from the given file name, and will decrypt them
|
Reads the file contents from the given file name, and will decrypt them
|
||||||
if they are found to be vault-encrypted.
|
if they are found to be vault-encrypted.
|
||||||
|
@ -194,7 +194,7 @@ class DataLoader:
|
||||||
show_content = True
|
show_content = True
|
||||||
try:
|
try:
|
||||||
with open(b_file_name, 'rb') as f:
|
with open(b_file_name, 'rb') as f:
|
||||||
data = f.read()
|
data = to_text(f.read(), encoding=encoding)
|
||||||
if is_encrypted(data):
|
if is_encrypted(data):
|
||||||
data = self._vault.decrypt(data, filename=b_file_name)
|
data = self._vault.decrypt(data, filename=b_file_name)
|
||||||
show_content = False
|
show_content = False
|
||||||
|
|
|
@ -31,7 +31,7 @@ from ansible.plugins.lookup import LookupBase
|
||||||
def _parse_params(term):
|
def _parse_params(term):
|
||||||
'''Safely split parameter term to preserve spaces'''
|
'''Safely split parameter term to preserve spaces'''
|
||||||
|
|
||||||
keys = ['key', 'type', 'section', 'file', 're', 'default']
|
keys = ['key', 'type', 'section', 'file', 're', 'default', 'encoding']
|
||||||
params = {}
|
params = {}
|
||||||
for k in keys:
|
for k in keys:
|
||||||
params[k] = ''
|
params[k] = ''
|
||||||
|
@ -52,19 +52,6 @@ def _parse_params(term):
|
||||||
|
|
||||||
class LookupModule(LookupBase):
|
class LookupModule(LookupBase):
|
||||||
|
|
||||||
def read_properties(self, filename, key, dflt, is_regexp):
|
|
||||||
config = StringIO()
|
|
||||||
current_cfg_file = open(to_bytes(filename, errors='surrogate_or_strict'), 'rb')
|
|
||||||
|
|
||||||
config.write(u'[java_properties]\n' + to_text(current_cfg_file.read(), errors='surrogate_or_strict'))
|
|
||||||
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(to_bytes(filename, errors='surrogate_or_strict')))
|
|
||||||
return self.get_value(key, section, dflt, is_regexp)
|
|
||||||
|
|
||||||
def get_value(self, key, section, dflt, is_regexp):
|
def get_value(self, key, section, dflt, is_regexp):
|
||||||
# Retrieve all values from a section using a regexp
|
# Retrieve all values from a section using a regexp
|
||||||
if is_regexp:
|
if is_regexp:
|
||||||
|
@ -79,8 +66,6 @@ class LookupModule(LookupBase):
|
||||||
|
|
||||||
def run(self, terms, variables=None, **kwargs):
|
def run(self, terms, variables=None, **kwargs):
|
||||||
|
|
||||||
basedir = self.get_basedir(variables)
|
|
||||||
self.basedir = basedir
|
|
||||||
self.cp = configparser.ConfigParser()
|
self.cp = configparser.ConfigParser()
|
||||||
|
|
||||||
ret = []
|
ret = []
|
||||||
|
@ -94,6 +79,7 @@ class LookupModule(LookupBase):
|
||||||
'default': None,
|
'default': None,
|
||||||
'section': "global",
|
'section': "global",
|
||||||
'type': "ini",
|
'type': "ini",
|
||||||
|
'encoding': 'utf-8',
|
||||||
}
|
}
|
||||||
|
|
||||||
# parameters specified?
|
# parameters specified?
|
||||||
|
@ -105,11 +91,23 @@ class LookupModule(LookupBase):
|
||||||
except (ValueError, AssertionError) as e:
|
except (ValueError, AssertionError) as e:
|
||||||
raise AnsibleError(e)
|
raise AnsibleError(e)
|
||||||
|
|
||||||
|
# Retrieve file path
|
||||||
path = self.find_file_in_search_path(variables, 'files', paramvals['file'])
|
path = self.find_file_in_search_path(variables, 'files', paramvals['file'])
|
||||||
|
|
||||||
|
# Create StringIO later used to parse ini
|
||||||
|
config = StringIO()
|
||||||
|
# Special case for java properties
|
||||||
if paramvals['type'] == "properties":
|
if paramvals['type'] == "properties":
|
||||||
var = self.read_properties(path, key, paramvals['default'], paramvals['re'])
|
config.write(u'[java_properties]\n')
|
||||||
else:
|
paramvals['section'] = 'java_properties'
|
||||||
var = self.read_ini(path, key, paramvals['section'], paramvals['default'], paramvals['re'])
|
|
||||||
|
# Open file using encoding
|
||||||
|
contents, show_data = self._loader._get_file_contents(path, encoding=paramvals['encoding'])
|
||||||
|
config.write(contents)
|
||||||
|
config.seek(0, os.SEEK_SET)
|
||||||
|
|
||||||
|
self.cp.readfp(config)
|
||||||
|
var = self.get_value(key, paramvals['section'], paramvals['default'], paramvals['re'])
|
||||||
if var is not None:
|
if var is not None:
|
||||||
if isinstance(var, MutableSequence):
|
if isinstance(var, MutableSequence):
|
||||||
for v in var:
|
for v in var:
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
[global]
|
||||||
|
# A comment
|
||||||
|
value1=Text associated with value1 and global section
|
||||||
|
value2=Same for value2 and global section
|
||||||
|
value.dot=Properties with dot
|
||||||
|
field.with.space = another space
|
||||||
|
field_with_unicode=été indien où à château français ïîôû
|
|
@ -4,6 +4,7 @@ value1=Text associated with value1 and global section
|
||||||
value2=Same for value2 and global section
|
value2=Same for value2 and global section
|
||||||
value.dot=Properties with dot
|
value.dot=Properties with dot
|
||||||
field.with.space = another space
|
field.with.space = another space
|
||||||
|
unicode=été indien où à château français ïîôû
|
||||||
|
|
||||||
[section1]
|
[section1]
|
||||||
value1=section1/value1
|
value1=section1/value1
|
||||||
|
|
|
@ -3,3 +3,4 @@ value1=Text associated with value1
|
||||||
value2=Same for value2
|
value2=Same for value2
|
||||||
value.dot=Properties with dot
|
value.dot=Properties with dot
|
||||||
field.with.space = another space
|
field.with.space = another space
|
||||||
|
field.with.unicode = été indien où à château français ïîôû
|
||||||
|
|
|
@ -9,32 +9,63 @@
|
||||||
test2: "{{lookup('ini', 'value2 type=properties file=lookup.properties')}}"
|
test2: "{{lookup('ini', 'value2 type=properties file=lookup.properties')}}"
|
||||||
test_dot: "{{lookup('ini', 'value.dot type=properties file=lookup.properties')}}"
|
test_dot: "{{lookup('ini', 'value.dot type=properties file=lookup.properties')}}"
|
||||||
field_with_space: "{{lookup('ini', 'field.with.space type=properties file=lookup.properties')}}"
|
field_with_space: "{{lookup('ini', 'field.with.space type=properties file=lookup.properties')}}"
|
||||||
- debug: var={{item}}
|
- assert:
|
||||||
|
that: "{{item}} is defined"
|
||||||
with_items: [ 'test1', 'test2', 'test_dot', 'field_with_space' ]
|
with_items: [ 'test1', 'test2', 'test_dot', 'field_with_space' ]
|
||||||
- name: "read ini value"
|
- name: "read ini value"
|
||||||
set_fact:
|
set_fact:
|
||||||
value1_global: "{{lookup('ini', 'value1 section=global file=lookup.ini')}}"
|
value1_global: "{{lookup('ini', 'value1 section=global file=lookup.ini')}}"
|
||||||
value2_global: "{{lookup('ini', 'value2 section=global file=lookup.ini')}}"
|
value2_global: "{{lookup('ini', 'value2 section=global file=lookup.ini')}}"
|
||||||
value1_section1: "{{lookup('ini', 'value1 section=section1 file=lookup.ini')}}"
|
value1_section1: "{{lookup('ini', 'value1 section=section1 file=lookup.ini')}}"
|
||||||
|
field_with_unicode: "{{lookup('ini', 'unicode section=global file=lookup.ini')}}"
|
||||||
- debug: var={{item}}
|
- debug: var={{item}}
|
||||||
with_items: [ 'value1_global', 'value2_global', 'value1_section1' ]
|
with_items: [ 'value1_global', 'value2_global', 'value1_section1', 'field_with_unicode' ]
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "field_with_unicode == 'été indien où à château français ïîôû'"
|
||||||
|
- name: "read ini value from iso8859-15 file"
|
||||||
|
set_fact:
|
||||||
|
field_with_unicode: "{{lookup('ini', 'field_with_unicode section=global encoding=iso8859-1 file=lookup-8859-15.ini')}}"
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "field_with_unicode == 'été indien où à château français ïîôû'"
|
||||||
- name: "read ini value with section and regexp"
|
- name: "read ini value with section and regexp"
|
||||||
set_fact:
|
set_fact:
|
||||||
value_section: "{{lookup('ini', 'value[1-2] section=value_section file=lookup.ini re=true')}}"
|
value_section: "{{lookup('ini', 'value[1-2] section=value_section file=lookup.ini re=true')}}"
|
||||||
other_section: "{{lookup('ini', 'other[1-2] section=other_section file=lookup.ini re=true')}}"
|
other_section: "{{lookup('ini', 'other[1-2] section=other_section file=lookup.ini re=true')}}"
|
||||||
- debug: var={{item}}
|
- debug: var={{item}}
|
||||||
with_items: [ 'value_section', 'other_section' ]
|
with_items: [ 'value_section', 'other_section' ]
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "value_section == '1,2'"
|
||||||
|
- "other_section == '4,5'"
|
||||||
- name: "Reading unknown value"
|
- name: "Reading unknown value"
|
||||||
set_fact:
|
set_fact:
|
||||||
unknown: "{{lookup('ini', 'value2 default=unknown section=section1 file=lookup.ini')}}"
|
unknown: "{{lookup('ini', 'unknown default=unknown section=section1 file=lookup.ini')}}"
|
||||||
- debug: var=unknown
|
- debug: var=unknown
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- 'unknown == "unknown"'
|
||||||
- name: "Looping over section section1"
|
- name: "Looping over section section1"
|
||||||
debug: msg="{{item}}"
|
debug: msg="{{item}}"
|
||||||
with_ini: value[1-2] section=section1 file=lookup.ini re=true
|
with_ini: value[1-2] section=section1 file=lookup.ini re=true
|
||||||
|
register: _
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- '_.results.0.item == "section1/value1"'
|
||||||
|
- '_.results.1.item == "section1/value2"'
|
||||||
- name: "Looping over section value_section"
|
- name: "Looping over section value_section"
|
||||||
debug: msg="{{item}}"
|
debug: msg="{{item}}"
|
||||||
with_ini: value[1-2] section=value_section file=lookup.ini re=true
|
with_ini: value[1-2] section=value_section file=lookup.ini re=true
|
||||||
|
register: _
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- '_.results.0.item == "1"'
|
||||||
|
- '_.results.1.item == "2"'
|
||||||
- debug: msg="{{item}}"
|
- debug: msg="{{item}}"
|
||||||
with_ini: value[1-2] section=section1 file=lookup.ini re=true
|
with_ini: value[1-2] section=section1 file=lookup.ini re=true
|
||||||
register: _
|
register: _
|
||||||
- debug: var=_
|
- assert:
|
||||||
|
that:
|
||||||
|
- '_.results.0.item == "section1/value1"'
|
||||||
|
- '_.results.1.item == "section1/value2"'
|
||||||
|
|
|
@ -24,7 +24,7 @@ class Git(object):
|
||||||
:rtype: list[str]
|
:rtype: list[str]
|
||||||
"""
|
"""
|
||||||
cmd = ['diff'] + args
|
cmd = ['diff'] + args
|
||||||
return self.run_git_split(cmd, '\n')
|
return self.run_git_split(cmd, '\n', str_errors='replace')
|
||||||
|
|
||||||
def get_diff_names(self, args):
|
def get_diff_names(self, args):
|
||||||
"""
|
"""
|
||||||
|
@ -76,22 +76,24 @@ class Git(object):
|
||||||
except SubprocessError:
|
except SubprocessError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def run_git_split(self, cmd, separator=None):
|
def run_git_split(self, cmd, separator=None, str_errors='strict'):
|
||||||
"""
|
"""
|
||||||
:type cmd: list[str]
|
:type cmd: list[str]
|
||||||
:param separator: str | None
|
:param separator: str | None
|
||||||
|
:type str_errors: 'strict' | 'replace'
|
||||||
:rtype: list[str]
|
:rtype: list[str]
|
||||||
"""
|
"""
|
||||||
output = self.run_git(cmd).strip(separator)
|
output = self.run_git(cmd, str_errors=str_errors).strip(separator)
|
||||||
|
|
||||||
if not output:
|
if not output:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
return output.split(separator)
|
return output.split(separator)
|
||||||
|
|
||||||
def run_git(self, cmd):
|
def run_git(self, cmd, str_errors='strict'):
|
||||||
"""
|
"""
|
||||||
:type cmd: list[str]
|
:type cmd: list[str]
|
||||||
|
:type str_errors: 'strict' | 'replace'
|
||||||
:rtype: str
|
:rtype: str
|
||||||
"""
|
"""
|
||||||
return run_command(self.args, [self.git] + cmd, capture=True, always=True)[0]
|
return run_command(self.args, [self.git] + cmd, capture=True, always=True, str_errors=str_errors)[0]
|
||||||
|
|
|
@ -81,7 +81,7 @@ def find_executable(executable, cwd=None, path=None, required=True):
|
||||||
|
|
||||||
|
|
||||||
def run_command(args, cmd, capture=False, env=None, data=None, cwd=None, always=False, stdin=None, stdout=None,
|
def run_command(args, cmd, capture=False, env=None, data=None, cwd=None, always=False, stdin=None, stdout=None,
|
||||||
cmd_verbosity=1):
|
cmd_verbosity=1, str_errors='strict'):
|
||||||
"""
|
"""
|
||||||
:type args: CommonConfig
|
:type args: CommonConfig
|
||||||
:type cmd: collections.Iterable[str]
|
:type cmd: collections.Iterable[str]
|
||||||
|
@ -93,15 +93,16 @@ def run_command(args, cmd, capture=False, env=None, data=None, cwd=None, always=
|
||||||
:type stdin: file | None
|
:type stdin: file | None
|
||||||
:type stdout: file | None
|
:type stdout: file | None
|
||||||
:type cmd_verbosity: int
|
:type cmd_verbosity: int
|
||||||
|
:type str_errors: 'strict' | 'replace'
|
||||||
:rtype: str | None, str | None
|
:rtype: str | None, str | None
|
||||||
"""
|
"""
|
||||||
explain = args.explain and not always
|
explain = args.explain and not always
|
||||||
return raw_command(cmd, capture=capture, env=env, data=data, cwd=cwd, explain=explain, stdin=stdin, stdout=stdout,
|
return raw_command(cmd, capture=capture, env=env, data=data, cwd=cwd, explain=explain, stdin=stdin, stdout=stdout,
|
||||||
cmd_verbosity=cmd_verbosity)
|
cmd_verbosity=cmd_verbosity, str_errors=str_errors)
|
||||||
|
|
||||||
|
|
||||||
def raw_command(cmd, capture=False, env=None, data=None, cwd=None, explain=False, stdin=None, stdout=None,
|
def raw_command(cmd, capture=False, env=None, data=None, cwd=None, explain=False, stdin=None, stdout=None,
|
||||||
cmd_verbosity=1):
|
cmd_verbosity=1, str_errors='strict'):
|
||||||
"""
|
"""
|
||||||
:type cmd: collections.Iterable[str]
|
:type cmd: collections.Iterable[str]
|
||||||
:type capture: bool
|
:type capture: bool
|
||||||
|
@ -112,6 +113,7 @@ def raw_command(cmd, capture=False, env=None, data=None, cwd=None, explain=False
|
||||||
:type stdin: file | None
|
:type stdin: file | None
|
||||||
:type stdout: file | None
|
:type stdout: file | None
|
||||||
:type cmd_verbosity: int
|
:type cmd_verbosity: int
|
||||||
|
:type str_errors: 'strict' | 'replace'
|
||||||
:rtype: str | None, str | None
|
:rtype: str | None, str | None
|
||||||
"""
|
"""
|
||||||
if not cwd:
|
if not cwd:
|
||||||
|
@ -170,8 +172,8 @@ def raw_command(cmd, capture=False, env=None, data=None, cwd=None, explain=False
|
||||||
encoding = 'utf-8'
|
encoding = 'utf-8'
|
||||||
data_bytes = data.encode(encoding) if data else None
|
data_bytes = data.encode(encoding) if data else None
|
||||||
stdout_bytes, stderr_bytes = process.communicate(data_bytes)
|
stdout_bytes, stderr_bytes = process.communicate(data_bytes)
|
||||||
stdout_text = stdout_bytes.decode(encoding) if stdout_bytes else u''
|
stdout_text = stdout_bytes.decode(encoding, str_errors) if stdout_bytes else u''
|
||||||
stderr_text = stderr_bytes.decode(encoding) if stderr_bytes else u''
|
stderr_text = stderr_bytes.decode(encoding, str_errors) if stderr_bytes else u''
|
||||||
else:
|
else:
|
||||||
process.wait()
|
process.wait()
|
||||||
stdout_text, stderr_text = None, None
|
stdout_text, stderr_text = None, None
|
||||||
|
|
Loading…
Reference in a new issue