Repository: ansible/ansible-modules-core

Issue:
module ini_file fails when values are indented with tabs
##### Issue Type:

Bug Report
##### Ansible Version:

ansible 1.7.2
##### Environment:

Ubuntu 12.04
##### Summary:

When the `ini_file` encounters tabs in a file the task fails.
##### Steps To Reproduce:

Create a global `~/.gitconfig` file by calling `gitconfig --global user.name 'Test User'` and try to change the name using

```
ansible testhost -m ini_file -a "dest=~/.gitconfig section=user option=email value='test@example.com'"
```
##### Expected Results:

Task should run succesfully and final `~/.gitconfig` file should be something like this:

```
[user]
name = Test User
email = test@example.com
```
##### Actual Results:

Task fails and final `~/.gitconfig` file is:

```
[user]
    name = Test User
```

module ini_file fails when values are indented with tabs
##### Issue Type:

Bug Report
##### Ansible Version:

ansible 1.7.2
##### Environment:

Ubuntu 12.04
##### Summary:

When the `ini_file` encounters tabs in a file the task fails.
##### Steps To Reproduce:

Create a global `~/.gitconfig` file by calling `gitconfig --global user.name 'Test User'` and try to change the name using

```
ansible testhost -m ini_file -a "dest=~/.gitconfig section=user option=email value='test@example.com'"
```
##### Expected Results:

Task should run succesfully and final `~/.gitconfig` file should be something like this:

```
[user]
name = Test User
email = test@example.com
```
##### Actual Results:

Task fails and final `~/.gitconfig` file is:

```
[user]
    name = Test User
```



Discussion:
I just had another look at the problem and I guess this should probably also be reported upstream. On the [ConfigParser Documentation](https://docs.python.org/2/library/configparser.html) it is written that

>  Note that leading whitespace is removed from values.

This seems to be a common problem with ConfigParser, the people over at GitPython also seems to have stumbled over it in the past. A possible workaround for now would be something like [this](http://stackoverflow.com/questions/12821946/how-can-i-remove-the-white-characters-from-configuration-file), where they locally rewrite `readline` to work around the issue within ConfigParser.

**ANSIBLE VERSION** 2.0.2.0
**Environment:** Debian GNU/Linux 8 (jessie)
Problem of tabs is still present.
**ini_file.py** uses `re.match('%s *=' % option, line)` for searching option name and use only space as delimiter char.

could you replace `re.match('%s *=' % option, line)` by `re.match('%s( |\t)*=' % option, line)` or `re.match('%s\s*=' % option, line)`

@jimi-c I guess `re.match('%s( |\t)*=' % option, line)` would be preferred over `re.match('%s( |\t)*=' % option, line)`. If this would be the way to go I could do a pull request for it.

I just had another look at the problem and I guess this should probably also be reported upstream. On the [ConfigParser Documentation](https://docs.python.org/2/library/configparser.html) it is written that

>  Note that leading whitespace is removed from values.

This seems to be a common problem with ConfigParser, the people over at GitPython also seems to have stumbled over it in the past. A possible workaround for now would be something like [this](http://stackoverflow.com/questions/12821946/how-can-i-remove-the-white-characters-from-configuration-file), where they locally rewrite `readline` to work around the issue within ConfigParser.

**ANSIBLE VERSION** 2.0.2.0
**Environment:** Debian GNU/Linux 8 (jessie)
Problem of tabs is still present.
**ini_file.py** uses `re.match('%s *=' % option, line)` for searching option name and use only space as delimiter char.

could you replace `re.match('%s *=' % option, line)` by `re.match('%s( |\t)*=' % option, line)` or `re.match('%s\s*=' % option, line)`

@jimi-c I guess `re.match('%s( |\t)*=' % option, line)` would be preferred over `re.match('%s( |\t)*=' % option, line)`. If this would be the way to go I could do a pull request for it.


Resolving patch:
diff --git a/files/ini_file.py b/files/ini_file.py
--- a/files/ini_file.py
+++ b/files/ini_file.py
@@ -110,16 +110,16 @@
 
 def match_opt(option, line):
   option = re.escape(option)
-  return re.match('%s *=' % option, line) \
-    or re.match('# *%s *=' % option, line) \
-    or re.match('; *%s *=' % option, line)
+  return re.match('%s( |\t)*=' % option, line) \
+    or re.match('# *%s( |\t)*=' % option, line) \
+    or re.match('; *%s( |\t)*=' % option, line)
 
 # ==============================================================
 # match_active_opt
 
 def match_active_opt(option, line):
   option = re.escape(option)
-  return re.match('%s *=' % option, line)
+  return re.match('%s( |\t)*=' % option, line)
 
 # ==============================================================
 # do_ini


Test patch: