We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
subversion: export fails if dest directory exists
Using the following syntax, the task always fails if /tmp/foo already exists.

`- name: (testing) svn export of desired callflow.xml
      subversion: repo=http://repo.local/repos/target/ dest=/tmp/foo/ export=yes`

The error shown is:
`msg: ERROR: /tmp/foo/ folder already exists, but its not a subversion repository.`

This appears to be happening because the subversion module does not account for exporting if the target directory exists (but is not a working copy):

`if not os.path.exists(dest):`
...export and checkout both handled
`elif os.path.exists("%s/.svn" % (dest, )):`
...checkout handled. export presumably not handled because this is a working directory
`else:
        module.fail_json(msg="ERROR: %s folder already exists, but its not a subversion repository." % (dest, ))`

I think if we insert another case before the `else` of `elif os.path.exists(dest) and export:` and handle export to a preexisting directory there, it should work.


--- 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, 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     required: false
54     default: "yes"
55     choices: [ "yes", "no" ]
56   username:
57     description:
58       - --username parameter passed to svn.
59     required: false
60     default: null
61   password:
62     description:
63       - --password parameter passed to svn.
64     required: false
65     default: null
66   executable:
67     required: false
68     default: null
69     version_added: "1.4"
70     description:
71       - Path to svn executable to use. If not supplied,
72         the normal mechanism for resolving binary paths will be used.
73   export:
74     required: false
75     default: "no"
76     choices: [ "yes", "no" ]
77     version_added: "1.6"
78     description:
79       - If C(yes), do export instead of checkout/update.
80 '''
81 
82 EXAMPLES = '''
83 # Checkout subversion repository to specified folder.
84 - subversion: repo=svn+ssh://an.example.org/path/to/repo dest=/src/checkout
85 
86 # Export subversion directory to folder
87 - subversion: repo=svn+ssh://an.example.org/path/to/repo dest=/src/export export=True
88 '''
89 
90 import re
91 import tempfile
92 
93 
94 class Subversion(object):
95     def __init__(
96             self, module, dest, repo, revision, username, password, svn_path):
97         self.module = module
98         self.dest = dest
99         self.repo = repo
100         self.revision = revision
101         self.username = username
102         self.password = password
103         self.svn_path = svn_path
104 
105     def _exec(self, args):
106         bits = [
107             self.svn_path,
108             '--non-interactive',
109             '--trust-server-cert',
110             '--no-auth-cache',
111         ]
112         if self.username:
113             bits.extend(["--username", self.username])
114         if self.password:
115             bits.extend(["--password", self.password])
116         bits.extend(args)
117         rc, out, err = self.module.run_command(bits, check_rc=True)
118         return out.splitlines()
119 
120     def checkout(self):
121         '''Creates new svn working directory if it does not already exist.'''
122         self._exec(["checkout", "-r", self.revision, self.repo, self.dest])
123 		
124     def export(self, force=False):
125         '''Export svn repo to directory'''
126         self._exec(["export", "-r", self.revision, self.repo, self.dest])
127 
128     def switch(self):
129         '''Change working directory's repo.'''
130         # switch to ensure we are pointing at correct repo.
131         self._exec(["switch", self.repo, self.dest])
132 
133     def update(self):
134         '''Update existing svn working directory.'''
135         self._exec(["update", "-r", self.revision, self.dest])
136 
137     def revert(self):
138         '''Revert svn working directory.'''
139         self._exec(["revert", "-R", self.dest])
140 
141     def get_revision(self):
142         '''Revision and URL of subversion working directory.'''
143         text = '\n'.join(self._exec(["info", self.dest]))
144         rev = re.search(r'^Revision:.*$', text, re.MULTILINE).group(0)
145         url = re.search(r'^URL:.*$', text, re.MULTILINE).group(0)
146         return rev, url
147 
148     def has_local_mods(self):
149         '''True if revisioned files have been added or modified. Unrevisioned files are ignored.'''
150         lines = self._exec(["status", self.dest])
151         # Match only revisioned files, i.e. ignore status '?'.
152         regex = re.compile(r'^[^?]')
153         # Has local mods if more than 0 modifed revisioned files.
154         return len(filter(regex.match, lines)) > 0
155 
156     def needs_update(self):
157         curr, url = self.get_revision()
158         out2 = '\n'.join(self._exec(["info", "-r", "HEAD", self.dest]))
159         head = re.search(r'^Revision:.*$', out2, re.MULTILINE).group(0)
160         rev1 = int(curr.split(':')[1].strip())
161         rev2 = int(head.split(':')[1].strip())
162         change = False
163         if rev1 < rev2:
164             change = True
165         return change, curr, head
166 
167 
168 # ===========================================
169 
170 def main():
171     module = AnsibleModule(
172         argument_spec=dict(
173             dest=dict(required=True),
174             repo=dict(required=True, aliases=['name', 'repository']),
175             revision=dict(default='HEAD', aliases=['rev', 'version']),
176             force=dict(default='yes', type='bool'),
177             username=dict(required=False),
178             password=dict(required=False),
179             executable=dict(default=None),
180             export=dict(default=False, required=False, type='bool'),
181         ),
182         supports_check_mode=True
183     )
184 
185     dest = os.path.expanduser(module.params['dest'])
186     repo = module.params['repo']
187     revision = module.params['revision']
188     force = module.params['force']
189     username = module.params['username']
190     password = module.params['password']
191     svn_path = module.params['executable'] or module.get_bin_path('svn', True)
192     export = module.params['export']
193 
194     os.environ['LANG'] = 'C'
195     svn = Subversion(module, dest, repo, revision, username, password, svn_path)
196 
197     if not os.path.exists(dest):
198         before = None
199         local_mods = False
200         if module.check_mode:
201             module.exit_json(changed=True)
202         if not export:
203             svn.checkout()
204         else:
205             svn.export()
206     elif os.path.exists("%s/.svn" % (dest, )):
207         # Order matters. Need to get local mods before switch to avoid false
208         # positives. Need to switch before revert to ensure we are reverting to
209         # correct repo.
210         if module.check_mode:
211             check, before, after = svn.needs_update()
212             module.exit_json(changed=check, before=before, after=after)
213         before = svn.get_revision()
214         local_mods = svn.has_local_mods()
215         svn.switch()
216         if local_mods:
217             if force:
218                 svn.revert()
219             else:
220                 module.fail_json(msg="ERROR: modified files exist in the repository.")
221         svn.update()
222     else:
223         module.fail_json(msg="ERROR: %s folder already exists, but its not a subversion repository." % (dest, ))
224 
225     after = svn.get_revision()
226     changed = before != after or local_mods
227     module.exit_json(changed=changed, before=before, after=after)
228 
229 # import module snippets
230 from ansible.module_utils.basic import *
231 main()
232
```
--- 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
@@ -123,7 +123,12 @@
 		
     def export(self, force=False):
         '''Export svn repo to directory'''
-        self._exec(["export", "-r", self.revision, self.repo, self.dest])
+        cmd = ["export"]
+        if force:
+            cmd.append("--force")
+        cmd.extend(["-r", self.revision, self.repo, self.dest])
+
+        self._exec(cmd)
 
     def switch(self):
         '''Change working directory's repo.'''
@@ -173,7 +178,7 @@
             dest=dict(required=True),
             repo=dict(required=True, aliases=['name', 'repository']),
             revision=dict(default='HEAD', aliases=['rev', 'version']),
-            force=dict(default='yes', type='bool'),
+            force=dict(default='no', type='bool'),
             username=dict(required=False),
             password=dict(required=False),
             executable=dict(default=None),
@@ -194,7 +199,7 @@
     os.environ['LANG'] = 'C'
     svn = Subversion(module, dest, repo, revision, username, password, svn_path)
 
-    if not os.path.exists(dest):
+    if export or not os.path.exists(dest):
         before = None
         local_mods = False
         if module.check_mode:
@@ -202,7 +207,7 @@
         if not export:
             svn.checkout()
         else:
-            svn.export()
+            svn.export(force=force)
     elif os.path.exists("%s/.svn" % (dest, )):
         # Order matters. Need to get local mods before switch to avoid false
         # positives. Need to switch before revert to ensure we are reverting to
@@ -222,9 +227,12 @@
     else:
         module.fail_json(msg="ERROR: %s folder already exists, but its not a subversion repository." % (dest, ))
 
-    after = svn.get_revision()
-    changed = before != after or local_mods
-    module.exit_json(changed=changed, before=before, after=after)
+    if export:
+        module.exit_json(changed=True)
+    else:
+        after = svn.get_revision()
+        changed = before != after or local_mods
+        module.exit_json(changed=changed, before=before, after=after)
 
 # import module snippets
 from ansible.module_utils.basic import *

{"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@@ -123,7 +123,12 @@\n \t\t\n     def export(self, force=False):\n         '''Export svn repo to directory'''\n-        self._exec([\"export\", \"-r\", self.revision, self.repo, self.dest])\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@@ -173,7 +178,7 @@\n             dest=dict(required=True),\n             repo=dict(required=True, aliases=['name', 'repository']),\n             revision=dict(default='HEAD', aliases=['rev', 'version']),\n-            force=dict(default='yes', type='bool'),\n+            force=dict(default='no', type='bool'),\n             username=dict(required=False),\n             password=dict(required=False),\n             executable=dict(default=None),\n@@ -194,7 +199,7 @@\n     os.environ['LANG'] = 'C'\n     svn = Subversion(module, dest, repo, revision, username, password, svn_path)\n \n-    if not os.path.exists(dest):\n+    if export or not os.path.exists(dest):\n         before = None\n         local_mods = False\n         if module.check_mode:\n@@ -202,7 +207,7 @@\n         if not export:\n             svn.checkout()\n         else:\n-            svn.export()\n+            svn.export(force=force)\n     elif os.path.exists(\"%s/.svn\" % (dest, )):\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@@ -222,9 +227,12 @@\n     else:\n         module.fail_json(msg=\"ERROR: %s folder already exists, but its not a subversion repository.\" % (dest, ))\n \n-    after = svn.get_revision()\n-    changed = before != after or local_mods\n-    module.exit_json(changed=changed, before=before, after=after)\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\n from ansible.module_utils.basic import *\n", "issue": "subversion: export fails if dest directory exists\nUsing the following syntax, the task always fails if /tmp/foo already exists.\n\n`- name: (testing) svn export of desired callflow.xml\n      subversion: repo=http://repo.local/repos/target/ dest=/tmp/foo/ export=yes`\n\nThe error shown is:\n`msg: ERROR: /tmp/foo/ folder already exists, but its not a subversion repository.`\n\nThis appears to be happening because the subversion module does not account for exporting if the target directory exists (but is not a working copy):\n\n`if not os.path.exists(dest):`\n...export and checkout both handled\n`elif os.path.exists(\"%s/.svn\" % (dest, )):`\n...checkout handled. export presumably not handled because this is a working directory\n`else:\n        module.fail_json(msg=\"ERROR: %s folder already exists, but its not a subversion repository.\" % (dest, ))`\n\nI think if we insert another case before the `else` of `elif os.path.exists(dest) and export:` and handle export to a preexisting directory there, it should work.\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, 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    required: false\n    default: \"yes\"\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'''\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):\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=True)\n        return out.splitlines()\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\t\t\n    def export(self, force=False):\n        '''Export svn repo to directory'''\n        self._exec([\"export\", \"-r\", self.revision, self.repo, self.dest])\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\", self.dest])\n        # Match only revisioned files, i.e. ignore status '?'.\n        regex = re.compile(r'^[^?]')\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),\n            repo=dict(required=True, aliases=['name', 'repository']),\n            revision=dict(default='HEAD', aliases=['rev', 'version']),\n            force=dict(default='yes', type='bool'),\n            username=dict(required=False),\n            password=dict(required=False),\n            executable=dict(default=None),\n            export=dict(default=False, required=False, type='bool'),\n        ),\n        supports_check_mode=True\n    )\n\n    dest = os.path.expanduser(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\n    os.environ['LANG'] = 'C'\n    svn = Subversion(module, dest, repo, revision, username, password, svn_path)\n\n    if 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()\n    elif os.path.exists(\"%s/.svn\" % (dest, )):\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        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    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, 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    required: false\n    default: \"yes\"\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'''\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):\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=True)\n        return out.splitlines()\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\t\t\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\", self.dest])\n        # Match only revisioned files, i.e. ignore status '?'.\n        regex = re.compile(r'^[^?]')\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),\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),\n            export=dict(default=False, required=False, type='bool'),\n        ),\n        supports_check_mode=True\n    )\n\n    dest = os.path.expanduser(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\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 os.path.exists(\"%s/.svn\" % (dest, )):\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        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"}]}