We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
source_control/subversion.py needs to reset LC_MESSAGES
##### Issue Type:

<!-- Please pick one and delete the rest: -->
- Bug Report
##### Plugin Name:

<!-- Name of the plugin/module/task -->

subversion
##### Ansible Version:

```
ansible-playbook 2.1.0 (devel 86080fbaa9) last updated 2016/03/15 19:12:05 (GMT +200)
  lib/ansible/modules/core: (detached HEAD a8841e6834) last updated 2016/03/15 19:40:46 (GMT +200)
  lib/ansible/modules/extras: (detached HEAD 45bba8ec64) last updated 2016/03/15 19:40:46 (GMT +200)
  config file = /var/tmp/subversion.bug/ansible.cfg
  configured module search path = Default w/o overrides
```
##### Ansible Configuration:

<!-- Please mention any settings you've changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables). -->

Default
##### Environment:

<!-- Please mention the OS you are running Ansible from, and the OS you are managing,
or say “N/A” for anything that isn't platform-specific. -->

Debian GNU Linux 8.3
##### Summary:

<!-- Please explain the problem briefly.  -->

Subversion module needs to reset LC_MESSAGES, not just LANG, since it screenscrapes the output of the svn(1) client. #2462 was the same issue for git.
##### Steps To Reproduce:

<!-- For bugs, please show exactly how to reproduce the problem.
For new features, show how the feature would be used.  -->

```
- hosts: all
  tasks:
    - shell: rm -fr {{ playbook_dir }}/repo {{ playbook_dir }}/working && svnadmin create {{ playbook_dir }}/repo
    - subversion: repo=file://{{ playbook_dir }}/repo dest={{ playbook_dir }}/working
EOF
```

<!-- You can also paste gist.github.com links for larger files.  -->
##### Expected Results:

<!-- What did you expect to happen when running the steps above?  -->

Success
##### Actual Results:

<!-- What actually happened? If possible run with high verbosity (-vvvv) -->

```
$ LANG=fr_FR.utf8 ansible-playbook -i localhost, svn_co.yml 

PLAY [all] *********************************************************************

TASK [setup] *******************************************************************
ok: [localhost]

TASK [command] *****************************************************************
changed: [localhost]
 [WARNING]: Consider using file module with state=absent rather than running rm


TASK [subversion] **************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "failed": true, "module_stderr": "", "module_stdout": "Traceback (most recent call last):\r\n  File \"/home/quinot/.ansible/tmp/ansible-tmp-1458067626.47-249928368830364/subversion\", line 2323, in <module>\r\n    main()\r\n  File \"/home/quinot/.ansible/tmp/ansible-tmp-1458067626.47-249928368830364/subversion\", line 259, in main\r\n    after = svn.get_revision()\r\n  File \"/home/quinot/.ansible/tmp/ansible-tmp-1458067626.47-249928368830364/subversion\", line 167, in get_revision\r\n    rev = re.search(r'^Revision:.*$', text, re.MULTILINE).group(0)\r\nAttributeError: 'NoneType' object has no attribute 'group'\r\n", "msg": "MODULE FAILURE", "parsed": false}

NO MORE HOSTS LEFT *************************************************************
    to retry, use: --limit @svn_co.retry

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=1
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `source_control/subversion.py`
Content:
```
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3 
4 # (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
5 #
6 # This file is part of Ansible
7 #
8 # Ansible is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # Ansible is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
20 
21 DOCUMENTATION = '''
22 ---
23 module: subversion
24 short_description: Deploys a subversion repository.
25 description:
26    - Deploy given repository URL / revision to dest. If dest exists, update to the specified revision, otherwise perform a checkout.
27 version_added: "0.7"
28 author: "Dane Summers (@dsummersl) <njharman@gmail.com>"
29 notes:
30    - Requires I(svn) to be installed on the client.
31 requirements: []
32 options:
33   repo:
34     description:
35       - The subversion URL to the repository.
36     required: true
37     aliases: [ name, repository ]
38     default: null
39   dest:
40     description:
41       - Absolute path where the repository should be deployed.
42     required: true
43     default: null
44   revision:
45     description:
46       - Specific revision to checkout.
47     required: false
48     default: HEAD
49     aliases: [ version ]
50   force:
51     description:
52       - If C(yes), modified files will be discarded. If C(no), module will fail if it encounters modified files.
53         Prior to 1.9 the default was `yes`.
54     required: false
55     default: "no"
56     choices: [ "yes", "no" ]
57   username:
58     description:
59       - --username parameter passed to svn.
60     required: false
61     default: null
62   password:
63     description:
64       - --password parameter passed to svn.
65     required: false
66     default: null
67   executable:
68     required: false
69     default: null
70     version_added: "1.4"
71     description:
72       - Path to svn executable to use. If not supplied,
73         the normal mechanism for resolving binary paths will be used.
74   export:
75     required: false
76     default: "no"
77     choices: [ "yes", "no" ]
78     version_added: "1.6"
79     description:
80       - If C(yes), do export instead of checkout/update.
81   switch:
82     required: false
83     default: "yes"
84     choices: [ "yes", "no" ]
85     version_added: "2.0"
86     description:
87       - If C(no), do not call svn switch before update.
88 '''
89 
90 EXAMPLES = '''
91 # Checkout subversion repository to specified folder.
92 - subversion: repo=svn+ssh://an.example.org/path/to/repo dest=/src/checkout
93 
94 # Export subversion directory to folder
95 - subversion: repo=svn+ssh://an.example.org/path/to/repo dest=/src/export export=True
96 '''
97 
98 import re
99 import tempfile
100 
101 
102 class Subversion(object):
103     def __init__(
104             self, module, dest, repo, revision, username, password, svn_path):
105         self.module = module
106         self.dest = dest
107         self.repo = repo
108         self.revision = revision
109         self.username = username
110         self.password = password
111         self.svn_path = svn_path
112 
113     def _exec(self, args, check_rc=True):
114         '''Execute a subversion command, and return output. If check_rc is False, returns the return code instead of the output.'''
115         bits = [
116             self.svn_path,
117             '--non-interactive',
118             '--trust-server-cert',
119             '--no-auth-cache',
120         ]
121         if self.username:
122             bits.extend(["--username", self.username])
123         if self.password:
124             bits.extend(["--password", self.password])
125         bits.extend(args)
126         rc, out, err = self.module.run_command(bits, check_rc)
127         if check_rc:
128             return out.splitlines()
129         else:
130             return rc
131 
132     def is_svn_repo(self):
133         '''Checks if path is a SVN Repo.'''
134         rc = self._exec(["info", self.dest], check_rc=False)
135         return rc == 0
136 
137     def checkout(self):
138         '''Creates new svn working directory if it does not already exist.'''
139         self._exec(["checkout", "-r", self.revision, self.repo, self.dest])
140 
141     def export(self, force=False):
142         '''Export svn repo to directory'''
143         cmd = ["export"]
144         if force:
145             cmd.append("--force")
146         cmd.extend(["-r", self.revision, self.repo, self.dest])
147 
148         self._exec(cmd)
149 
150     def switch(self):
151         '''Change working directory's repo.'''
152         # switch to ensure we are pointing at correct repo.
153         self._exec(["switch", self.repo, self.dest])
154 
155     def update(self):
156         '''Update existing svn working directory.'''
157         self._exec(["update", "-r", self.revision, self.dest])
158 
159     def revert(self):
160         '''Revert svn working directory.'''
161         self._exec(["revert", "-R", self.dest])
162 
163     def get_revision(self):
164         '''Revision and URL of subversion working directory.'''
165         text = '\n'.join(self._exec(["info", self.dest]))
166         rev = re.search(r'^Revision:.*$', text, re.MULTILINE).group(0)
167         url = re.search(r'^URL:.*$', text, re.MULTILINE).group(0)
168         return rev, url
169 
170     def has_local_mods(self):
171         '''True if revisioned files have been added or modified. Unrevisioned files are ignored.'''
172         lines = self._exec(["status", "--quiet", "--ignore-externals",  self.dest])
173         # The --quiet option will return only modified files.
174         # Match only revisioned files, i.e. ignore status '?'.
175         regex = re.compile(r'^[^?X]')
176         # Has local mods if more than 0 modifed revisioned files.
177         return len(filter(regex.match, lines)) > 0
178 
179     def needs_update(self):
180         curr, url = self.get_revision()
181         out2 = '\n'.join(self._exec(["info", "-r", "HEAD", self.dest]))
182         head = re.search(r'^Revision:.*$', out2, re.MULTILINE).group(0)
183         rev1 = int(curr.split(':')[1].strip())
184         rev2 = int(head.split(':')[1].strip())
185         change = False
186         if rev1 < rev2:
187             change = True
188         return change, curr, head
189 
190 
191 # ===========================================
192 
193 def main():
194     module = AnsibleModule(
195         argument_spec=dict(
196             dest=dict(required=True, type='path'),
197             repo=dict(required=True, aliases=['name', 'repository']),
198             revision=dict(default='HEAD', aliases=['rev', 'version']),
199             force=dict(default='no', type='bool'),
200             username=dict(required=False),
201             password=dict(required=False),
202             executable=dict(default=None, type='path'),
203             export=dict(default=False, required=False, type='bool'),
204             switch=dict(default=True, required=False, type='bool'),
205         ),
206         supports_check_mode=True
207     )
208 
209     dest = module.params['dest']
210     repo = module.params['repo']
211     revision = module.params['revision']
212     force = module.params['force']
213     username = module.params['username']
214     password = module.params['password']
215     svn_path = module.params['executable'] or module.get_bin_path('svn', True)
216     export = module.params['export']
217     switch = module.params['switch']
218 
219     os.environ['LANG'] = 'C'
220     svn = Subversion(module, dest, repo, revision, username, password, svn_path)
221 
222     if export or not os.path.exists(dest):
223         before = None
224         local_mods = False
225         if module.check_mode:
226             module.exit_json(changed=True)
227         if not export:
228             svn.checkout()
229         else:
230             svn.export(force=force)
231     elif svn.is_svn_repo():
232         # Order matters. Need to get local mods before switch to avoid false
233         # positives. Need to switch before revert to ensure we are reverting to
234         # correct repo.
235         if module.check_mode:
236             check, before, after = svn.needs_update()
237             module.exit_json(changed=check, before=before, after=after)
238         before = svn.get_revision()
239         local_mods = svn.has_local_mods()
240         if switch:
241             svn.switch()
242         if local_mods:
243             if force:
244                 svn.revert()
245             else:
246                 module.fail_json(msg="ERROR: modified files exist in the repository.")
247         svn.update()
248     else:
249         module.fail_json(msg="ERROR: %s folder already exists, but its not a subversion repository." % (dest, ))
250 
251     if export:
252         module.exit_json(changed=True)
253     else:
254         after = svn.get_revision()
255         changed = before != after or local_mods
256         module.exit_json(changed=changed, before=before, after=after)
257 
258 # import module snippets
259 from ansible.module_utils.basic import *
260 main()
261
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/source_control/subversion.py b/source_control/subversion.py
--- a/source_control/subversion.py
+++ b/source_control/subversion.py
@@ -216,7 +216,10 @@
     export = module.params['export']
     switch = module.params['switch']
 
-    os.environ['LANG'] = 'C'
+    # We screenscrape a huge amount of svn commands so use C locale anytime we
+    # call run_command()
+    module.run_command_environ_update = dict(LANG='C', LC_ALL='C', LC_MESSAGES='C', LC_CTYPE='C')
+
     svn = Subversion(module, dest, repo, revision, username, password, svn_path)
 
     if export or not os.path.exists(dest):

{"golden_diff": "diff --git a/source_control/subversion.py b/source_control/subversion.py\n--- a/source_control/subversion.py\n+++ b/source_control/subversion.py\n@@ -216,7 +216,10 @@\n     export = module.params['export']\n     switch = module.params['switch']\n \n-    os.environ['LANG'] = 'C'\n+    # We screenscrape a huge amount of svn commands so use C locale anytime we\n+    # call run_command()\n+    module.run_command_environ_update = dict(LANG='C', LC_ALL='C', LC_MESSAGES='C', LC_CTYPE='C')\n+\n     svn = Subversion(module, dest, repo, revision, username, password, svn_path)\n \n     if export or not os.path.exists(dest):\n", "issue": "source_control/subversion.py needs to reset LC_MESSAGES\n##### Issue Type:\n\n<!-- Please pick one and delete the rest: -->\n- Bug Report\n##### Plugin Name:\n\n<!-- Name of the plugin/module/task -->\n\nsubversion\n##### Ansible Version:\n\n```\nansible-playbook 2.1.0 (devel 86080fbaa9) last updated 2016/03/15 19:12:05 (GMT +200)\n  lib/ansible/modules/core: (detached HEAD a8841e6834) last updated 2016/03/15 19:40:46 (GMT +200)\n  lib/ansible/modules/extras: (detached HEAD 45bba8ec64) last updated 2016/03/15 19:40:46 (GMT +200)\n  config file = /var/tmp/subversion.bug/ansible.cfg\n  configured module search path = Default w/o overrides\n```\n##### Ansible Configuration:\n\n<!-- Please mention any settings you've changed/added/removed in ansible.cfg\n(or using the ANSIBLE_* environment variables). -->\n\nDefault\n##### Environment:\n\n<!-- Please mention the OS you are running Ansible from, and the OS you are managing,\nor say \u201cN/A\u201d for anything that isn't platform-specific. -->\n\nDebian GNU Linux 8.3\n##### Summary:\n\n<!-- Please explain the problem briefly.  -->\n\nSubversion module needs to reset LC_MESSAGES, not just LANG, since it screenscrapes the output of the svn(1) client. #2462 was the same issue for git.\n##### Steps To Reproduce:\n\n<!-- For bugs, please show exactly how to reproduce the problem.\nFor new features, show how the feature would be used.  -->\n\n```\n- hosts: all\n  tasks:\n    - shell: rm -fr {{ playbook_dir }}/repo {{ playbook_dir }}/working && svnadmin create {{ playbook_dir }}/repo\n    - subversion: repo=file://{{ playbook_dir }}/repo dest={{ playbook_dir }}/working\nEOF\n```\n\n<!-- You can also paste gist.github.com links for larger files.  -->\n##### Expected Results:\n\n<!-- What did you expect to happen when running the steps above?  -->\n\nSuccess\n##### Actual Results:\n\n<!-- What actually happened? If possible run with high verbosity (-vvvv) -->\n\n```\n$ LANG=fr_FR.utf8 ansible-playbook -i localhost, svn_co.yml \n\nPLAY [all] *********************************************************************\n\nTASK [setup] *******************************************************************\nok: [localhost]\n\nTASK [command] *****************************************************************\nchanged: [localhost]\n [WARNING]: Consider using file module with state=absent rather than running rm\n\n\nTASK [subversion] **************************************************************\nfatal: [localhost]: FAILED! => {\"changed\": false, \"failed\": true, \"module_stderr\": \"\", \"module_stdout\": \"Traceback (most recent call last):\\r\\n  File \\\"/home/quinot/.ansible/tmp/ansible-tmp-1458067626.47-249928368830364/subversion\\\", line 2323, in <module>\\r\\n    main()\\r\\n  File \\\"/home/quinot/.ansible/tmp/ansible-tmp-1458067626.47-249928368830364/subversion\\\", line 259, in main\\r\\n    after = svn.get_revision()\\r\\n  File \\\"/home/quinot/.ansible/tmp/ansible-tmp-1458067626.47-249928368830364/subversion\\\", line 167, in get_revision\\r\\n    rev = re.search(r'^Revision:.*$', text, re.MULTILINE).group(0)\\r\\nAttributeError: 'NoneType' object has no attribute 'group'\\r\\n\", \"msg\": \"MODULE FAILURE\", \"parsed\": false}\n\nNO MORE HOSTS LEFT *************************************************************\n    to retry, use: --limit @svn_co.retry\n\nPLAY RECAP *********************************************************************\nlocalhost                  : ok=2    changed=1    unreachable=0    failed=1\n```\n\n", "before_files": [{"content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n\n# (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>\n#\n# This file is part of Ansible\n#\n# Ansible is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# Ansible is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.\n\nDOCUMENTATION = '''\n---\nmodule: subversion\nshort_description: Deploys a subversion repository.\ndescription:\n   - Deploy given repository URL / revision to dest. If dest exists, update to the specified revision, otherwise perform a checkout.\nversion_added: \"0.7\"\nauthor: \"Dane Summers (@dsummersl) <njharman@gmail.com>\"\nnotes:\n   - Requires I(svn) to be installed on the client.\nrequirements: []\noptions:\n  repo:\n    description:\n      - The subversion URL to the repository.\n    required: true\n    aliases: [ name, repository ]\n    default: null\n  dest:\n    description:\n      - Absolute path where the repository should be deployed.\n    required: true\n    default: null\n  revision:\n    description:\n      - Specific revision to checkout.\n    required: false\n    default: HEAD\n    aliases: [ version ]\n  force:\n    description:\n      - If C(yes), modified files will be discarded. If C(no), module will fail if it encounters modified files.\n        Prior to 1.9 the default was `yes`.\n    required: false\n    default: \"no\"\n    choices: [ \"yes\", \"no\" ]\n  username:\n    description:\n      - --username parameter passed to svn.\n    required: false\n    default: null\n  password:\n    description:\n      - --password parameter passed to svn.\n    required: false\n    default: null\n  executable:\n    required: false\n    default: null\n    version_added: \"1.4\"\n    description:\n      - Path to svn executable to use. If not supplied,\n        the normal mechanism for resolving binary paths will be used.\n  export:\n    required: false\n    default: \"no\"\n    choices: [ \"yes\", \"no\" ]\n    version_added: \"1.6\"\n    description:\n      - If C(yes), do export instead of checkout/update.\n  switch:\n    required: false\n    default: \"yes\"\n    choices: [ \"yes\", \"no\" ]\n    version_added: \"2.0\"\n    description:\n      - If C(no), do not call svn switch before update.\n'''\n\nEXAMPLES = '''\n# Checkout subversion repository to specified folder.\n- subversion: repo=svn+ssh://an.example.org/path/to/repo dest=/src/checkout\n\n# Export subversion directory to folder\n- subversion: repo=svn+ssh://an.example.org/path/to/repo dest=/src/export export=True\n'''\n\nimport re\nimport tempfile\n\n\nclass Subversion(object):\n    def __init__(\n            self, module, dest, repo, revision, username, password, svn_path):\n        self.module = module\n        self.dest = dest\n        self.repo = repo\n        self.revision = revision\n        self.username = username\n        self.password = password\n        self.svn_path = svn_path\n\n    def _exec(self, args, check_rc=True):\n        '''Execute a subversion command, and return output. If check_rc is False, returns the return code instead of the output.'''\n        bits = [\n            self.svn_path,\n            '--non-interactive',\n            '--trust-server-cert',\n            '--no-auth-cache',\n        ]\n        if self.username:\n            bits.extend([\"--username\", self.username])\n        if self.password:\n            bits.extend([\"--password\", self.password])\n        bits.extend(args)\n        rc, out, err = self.module.run_command(bits, check_rc)\n        if check_rc:\n            return out.splitlines()\n        else:\n            return rc\n\n    def is_svn_repo(self):\n        '''Checks if path is a SVN Repo.'''\n        rc = self._exec([\"info\", self.dest], check_rc=False)\n        return rc == 0\n\n    def checkout(self):\n        '''Creates new svn working directory if it does not already exist.'''\n        self._exec([\"checkout\", \"-r\", self.revision, self.repo, self.dest])\n\n    def export(self, force=False):\n        '''Export svn repo to directory'''\n        cmd = [\"export\"]\n        if force:\n            cmd.append(\"--force\")\n        cmd.extend([\"-r\", self.revision, self.repo, self.dest])\n\n        self._exec(cmd)\n\n    def switch(self):\n        '''Change working directory's repo.'''\n        # switch to ensure we are pointing at correct repo.\n        self._exec([\"switch\", self.repo, self.dest])\n\n    def update(self):\n        '''Update existing svn working directory.'''\n        self._exec([\"update\", \"-r\", self.revision, self.dest])\n\n    def revert(self):\n        '''Revert svn working directory.'''\n        self._exec([\"revert\", \"-R\", self.dest])\n\n    def get_revision(self):\n        '''Revision and URL of subversion working directory.'''\n        text = '\\n'.join(self._exec([\"info\", self.dest]))\n        rev = re.search(r'^Revision:.*$', text, re.MULTILINE).group(0)\n        url = re.search(r'^URL:.*$', text, re.MULTILINE).group(0)\n        return rev, url\n\n    def has_local_mods(self):\n        '''True if revisioned files have been added or modified. Unrevisioned files are ignored.'''\n        lines = self._exec([\"status\", \"--quiet\", \"--ignore-externals\",  self.dest])\n        # The --quiet option will return only modified files.\n        # Match only revisioned files, i.e. ignore status '?'.\n        regex = re.compile(r'^[^?X]')\n        # Has local mods if more than 0 modifed revisioned files.\n        return len(filter(regex.match, lines)) > 0\n\n    def needs_update(self):\n        curr, url = self.get_revision()\n        out2 = '\\n'.join(self._exec([\"info\", \"-r\", \"HEAD\", self.dest]))\n        head = re.search(r'^Revision:.*$', out2, re.MULTILINE).group(0)\n        rev1 = int(curr.split(':')[1].strip())\n        rev2 = int(head.split(':')[1].strip())\n        change = False\n        if rev1 < rev2:\n            change = True\n        return change, curr, head\n\n\n# ===========================================\n\ndef main():\n    module = AnsibleModule(\n        argument_spec=dict(\n            dest=dict(required=True, type='path'),\n            repo=dict(required=True, aliases=['name', 'repository']),\n            revision=dict(default='HEAD', aliases=['rev', 'version']),\n            force=dict(default='no', type='bool'),\n            username=dict(required=False),\n            password=dict(required=False),\n            executable=dict(default=None, type='path'),\n            export=dict(default=False, required=False, type='bool'),\n            switch=dict(default=True, required=False, type='bool'),\n        ),\n        supports_check_mode=True\n    )\n\n    dest = module.params['dest']\n    repo = module.params['repo']\n    revision = module.params['revision']\n    force = module.params['force']\n    username = module.params['username']\n    password = module.params['password']\n    svn_path = module.params['executable'] or module.get_bin_path('svn', True)\n    export = module.params['export']\n    switch = module.params['switch']\n\n    os.environ['LANG'] = 'C'\n    svn = Subversion(module, dest, repo, revision, username, password, svn_path)\n\n    if export or not os.path.exists(dest):\n        before = None\n        local_mods = False\n        if module.check_mode:\n            module.exit_json(changed=True)\n        if not export:\n            svn.checkout()\n        else:\n            svn.export(force=force)\n    elif svn.is_svn_repo():\n        # Order matters. Need to get local mods before switch to avoid false\n        # positives. Need to switch before revert to ensure we are reverting to\n        # correct repo.\n        if module.check_mode:\n            check, before, after = svn.needs_update()\n            module.exit_json(changed=check, before=before, after=after)\n        before = svn.get_revision()\n        local_mods = svn.has_local_mods()\n        if switch:\n            svn.switch()\n        if local_mods:\n            if force:\n                svn.revert()\n            else:\n                module.fail_json(msg=\"ERROR: modified files exist in the repository.\")\n        svn.update()\n    else:\n        module.fail_json(msg=\"ERROR: %s folder already exists, but its not a subversion repository.\" % (dest, ))\n\n    if export:\n        module.exit_json(changed=True)\n    else:\n        after = svn.get_revision()\n        changed = before != after or local_mods\n        module.exit_json(changed=changed, before=before, after=after)\n\n# import module snippets\nfrom ansible.module_utils.basic import *\nmain()\n", "path": "source_control/subversion.py"}], "after_files": [{"content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n\n# (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>\n#\n# This file is part of Ansible\n#\n# Ansible is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# Ansible is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.\n\nDOCUMENTATION = '''\n---\nmodule: subversion\nshort_description: Deploys a subversion repository.\ndescription:\n   - Deploy given repository URL / revision to dest. If dest exists, update to the specified revision, otherwise perform a checkout.\nversion_added: \"0.7\"\nauthor: \"Dane Summers (@dsummersl) <njharman@gmail.com>\"\nnotes:\n   - Requires I(svn) to be installed on the client.\nrequirements: []\noptions:\n  repo:\n    description:\n      - The subversion URL to the repository.\n    required: true\n    aliases: [ name, repository ]\n    default: null\n  dest:\n    description:\n      - Absolute path where the repository should be deployed.\n    required: true\n    default: null\n  revision:\n    description:\n      - Specific revision to checkout.\n    required: false\n    default: HEAD\n    aliases: [ version ]\n  force:\n    description:\n      - If C(yes), modified files will be discarded. If C(no), module will fail if it encounters modified files.\n        Prior to 1.9 the default was `yes`.\n    required: false\n    default: \"no\"\n    choices: [ \"yes\", \"no\" ]\n  username:\n    description:\n      - --username parameter passed to svn.\n    required: false\n    default: null\n  password:\n    description:\n      - --password parameter passed to svn.\n    required: false\n    default: null\n  executable:\n    required: false\n    default: null\n    version_added: \"1.4\"\n    description:\n      - Path to svn executable to use. If not supplied,\n        the normal mechanism for resolving binary paths will be used.\n  export:\n    required: false\n    default: \"no\"\n    choices: [ \"yes\", \"no\" ]\n    version_added: \"1.6\"\n    description:\n      - If C(yes), do export instead of checkout/update.\n  switch:\n    required: false\n    default: \"yes\"\n    choices: [ \"yes\", \"no\" ]\n    version_added: \"2.0\"\n    description:\n      - If C(no), do not call svn switch before update.\n'''\n\nEXAMPLES = '''\n# Checkout subversion repository to specified folder.\n- subversion: repo=svn+ssh://an.example.org/path/to/repo dest=/src/checkout\n\n# Export subversion directory to folder\n- subversion: repo=svn+ssh://an.example.org/path/to/repo dest=/src/export export=True\n'''\n\nimport re\nimport tempfile\n\n\nclass Subversion(object):\n    def __init__(\n            self, module, dest, repo, revision, username, password, svn_path):\n        self.module = module\n        self.dest = dest\n        self.repo = repo\n        self.revision = revision\n        self.username = username\n        self.password = password\n        self.svn_path = svn_path\n\n    def _exec(self, args, check_rc=True):\n        '''Execute a subversion command, and return output. If check_rc is False, returns the return code instead of the output.'''\n        bits = [\n            self.svn_path,\n            '--non-interactive',\n            '--trust-server-cert',\n            '--no-auth-cache',\n        ]\n        if self.username:\n            bits.extend([\"--username\", self.username])\n        if self.password:\n            bits.extend([\"--password\", self.password])\n        bits.extend(args)\n        rc, out, err = self.module.run_command(bits, check_rc)\n        if check_rc:\n            return out.splitlines()\n        else:\n            return rc\n\n    def is_svn_repo(self):\n        '''Checks if path is a SVN Repo.'''\n        rc = self._exec([\"info\", self.dest], check_rc=False)\n        return rc == 0\n\n    def checkout(self):\n        '''Creates new svn working directory if it does not already exist.'''\n        self._exec([\"checkout\", \"-r\", self.revision, self.repo, self.dest])\n\n    def export(self, force=False):\n        '''Export svn repo to directory'''\n        cmd = [\"export\"]\n        if force:\n            cmd.append(\"--force\")\n        cmd.extend([\"-r\", self.revision, self.repo, self.dest])\n\n        self._exec(cmd)\n\n    def switch(self):\n        '''Change working directory's repo.'''\n        # switch to ensure we are pointing at correct repo.\n        self._exec([\"switch\", self.repo, self.dest])\n\n    def update(self):\n        '''Update existing svn working directory.'''\n        self._exec([\"update\", \"-r\", self.revision, self.dest])\n\n    def revert(self):\n        '''Revert svn working directory.'''\n        self._exec([\"revert\", \"-R\", self.dest])\n\n    def get_revision(self):\n        '''Revision and URL of subversion working directory.'''\n        text = '\\n'.join(self._exec([\"info\", self.dest]))\n        rev = re.search(r'^Revision:.*$', text, re.MULTILINE).group(0)\n        url = re.search(r'^URL:.*$', text, re.MULTILINE).group(0)\n        return rev, url\n\n    def has_local_mods(self):\n        '''True if revisioned files have been added or modified. Unrevisioned files are ignored.'''\n        lines = self._exec([\"status\", \"--quiet\", \"--ignore-externals\",  self.dest])\n        # The --quiet option will return only modified files.\n        # Match only revisioned files, i.e. ignore status '?'.\n        regex = re.compile(r'^[^?X]')\n        # Has local mods if more than 0 modifed revisioned files.\n        return len(filter(regex.match, lines)) > 0\n\n    def needs_update(self):\n        curr, url = self.get_revision()\n        out2 = '\\n'.join(self._exec([\"info\", \"-r\", \"HEAD\", self.dest]))\n        head = re.search(r'^Revision:.*$', out2, re.MULTILINE).group(0)\n        rev1 = int(curr.split(':')[1].strip())\n        rev2 = int(head.split(':')[1].strip())\n        change = False\n        if rev1 < rev2:\n            change = True\n        return change, curr, head\n\n\n# ===========================================\n\ndef main():\n    module = AnsibleModule(\n        argument_spec=dict(\n            dest=dict(required=True, type='path'),\n            repo=dict(required=True, aliases=['name', 'repository']),\n            revision=dict(default='HEAD', aliases=['rev', 'version']),\n            force=dict(default='no', type='bool'),\n            username=dict(required=False),\n            password=dict(required=False),\n            executable=dict(default=None, type='path'),\n            export=dict(default=False, required=False, type='bool'),\n            switch=dict(default=True, required=False, type='bool'),\n        ),\n        supports_check_mode=True\n    )\n\n    dest = module.params['dest']\n    repo = module.params['repo']\n    revision = module.params['revision']\n    force = module.params['force']\n    username = module.params['username']\n    password = module.params['password']\n    svn_path = module.params['executable'] or module.get_bin_path('svn', True)\n    export = module.params['export']\n    switch = module.params['switch']\n\n    # We screenscrape a huge amount of svn commands so use C locale anytime we\n    # call run_command()\n    module.run_command_environ_update = dict(LANG='C', LC_ALL='C', LC_MESSAGES='C', LC_CTYPE='C')\n\n    svn = Subversion(module, dest, repo, revision, username, password, svn_path)\n\n    if export or not os.path.exists(dest):\n        before = None\n        local_mods = False\n        if module.check_mode:\n            module.exit_json(changed=True)\n        if not export:\n            svn.checkout()\n        else:\n            svn.export(force=force)\n    elif svn.is_svn_repo():\n        # Order matters. Need to get local mods before switch to avoid false\n        # positives. Need to switch before revert to ensure we are reverting to\n        # correct repo.\n        if module.check_mode:\n            check, before, after = svn.needs_update()\n            module.exit_json(changed=check, before=before, after=after)\n        before = svn.get_revision()\n        local_mods = svn.has_local_mods()\n        if switch:\n            svn.switch()\n        if local_mods:\n            if force:\n                svn.revert()\n            else:\n                module.fail_json(msg=\"ERROR: modified files exist in the repository.\")\n        svn.update()\n    else:\n        module.fail_json(msg=\"ERROR: %s folder already exists, but its not a subversion repository.\" % (dest, ))\n\n    if export:\n        module.exit_json(changed=True)\n    else:\n        after = svn.get_revision()\n        changed = before != after or local_mods\n        module.exit_json(changed=changed, before=before, after=after)\n\n# import module snippets\nfrom ansible.module_utils.basic import *\nmain()\n", "path": "source_control/subversion.py"}]}