From 9d87733f9843ecdfdf30ab18d1cc40a5543b5905 Mon Sep 17 00:00:00 2001
From: willthames <will@thames.id.au>
Date: Mon, 8 Apr 2013 14:47:43 +1000
Subject: [PATCH] Test case and fix for shlex.split unicode bug

When operating on a unicode string in python 2.6, shlex.split returns
a result that does not work with the file constructor.

To reproduce this requires a task include that is templated (this is
because the templated string is a unicode result, whereas a non-
templated string is a non-unicode string)

    [will@centos6.3] $ python
    Python 2.6.6 (r266:84292, Sep 11 2012, 08:34:23)
    [GCC 4.4.6 20120305 (Red Hat 4.4.6-4)] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import shlex
    >>> shlex.split(u'abc')
    ['a\x00\x00\x00b\x00\x00\x00c\x00\x00\x00']

    [will@fedora17] $ python
    Python 2.7.3 (default, Jul 24 2012, 10:05:38)
    [GCC 4.7.0 20120507 (Red Hat 4.7.0-5)] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import shlex
    >>> shlex.split(u'abc')
    ['abc']

The proposed fix (coercing the include parameters to string before the
shlex.split) may not be ideal but it does fix the bug for my test case.
---
 lib/ansible/playbook/play.py |  2 +-
 test/TestPlayBook.py         | 21 +++++++++++++++++++++
 test/task-included.yml       |  2 ++
 test/task-includer.yml       |  9 +++++++++
 4 files changed, 33 insertions(+), 1 deletion(-)
 create mode 100644 test/task-included.yml
 create mode 100644 test/task-includer.yml

diff --git a/lib/ansible/playbook/play.py b/lib/ansible/playbook/play.py
index 8646bcd..dcb67bd 100644
--- a/lib/ansible/playbook/play.py
+++ b/lib/ansible/playbook/play.py
@@ -194,7 +194,7 @@ class Play(object):
                 task_vars['_original_file'] = original_file
 
             if 'include' in x:
-                tokens = shlex.split(x['include'])
+                tokens = shlex.split(str(x['include']))
                 items = ['']
                 included_additional_conditions = list(additional_conditions)
                 for k in x:
diff --git a/test/TestPlayBook.py b/test/TestPlayBook.py
index 0445158..e2dfcd8 100644
--- a/test/TestPlayBook.py
+++ b/test/TestPlayBook.py
@@ -211,6 +211,27 @@ class TestPlaybook(unittest.TestCase):
 
        assert utils.jsonify(expected, format=True) == utils.jsonify(actual,format=True)
 
+   def test_task_includes(self):
+       pb = os.path.join(self.test_dir, 'task-includer.yml')
+       actual = self._run(pb)
+
+       # if different, this will output to screen
+       print "**ACTUAL**"
+       print utils.jsonify(actual, format=True)
+       expected =  {
+           "localhost": {
+               "changed": 0,
+               "failures": 0,
+               "ok": 1,
+               "skipped": 0,
+               "unreachable": 0
+           }
+       }
+       print "**EXPECTED**"
+       print utils.jsonify(expected, format=True)
+
+       assert utils.jsonify(expected, format=True) == utils.jsonify(actual,format=True)
+
    def test_playbook_vars(self):
        test_callbacks = TestCallbacks()
        playbook = ansible.playbook.PlayBook(
diff --git a/test/task-included.yml b/test/task-included.yml
new file mode 100644
index 0000000..0c68a12
--- /dev/null
+++ b/test/task-included.yml
@@ -0,0 +1,2 @@
+---
+- action: debug msg="$internal"
diff --git a/test/task-includer.yml b/test/task-includer.yml
new file mode 100644
index 0000000..b728827
--- /dev/null
+++ b/test/task-includer.yml
@@ -0,0 +1,9 @@
+---
+- hosts: all
+  connection: local
+  gather_facts: no
+  vars:
+  - internal: xyz
+
+  tasks:
+  - include: task-included.yml internal=$internal
--
libgit2 0.26.0