We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
homebrew_tap fails to tap caskroom/cask now.
<!---
Verify first that your issue/request is not already reported on GitHub.
THIS FORM WILL BE READ BY A MACHINE, COMPLETE ALL SECTIONS AS DESCRIBED.
Also test if the latest release, and devel branch are affected too.
ALWAYS add information AFTER (OUTSIDE) these html comments.
Otherwise it may end up being automatically closed by our bot. -->

##### SUMMARY
<!--- Explain the problem briefly -->
Running the task `homebrew_tap: name=caskroom/cask` fails due to the fact that caskroom/cask has migrated to homebrew/cask.  See https://github.com/Homebrew/brew/pull/4210
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
<!--- Insert, BELOW THIS COMMENT, the name of the module, plugin, task or feature.
Do not include extra details here, e.g. "vyos_command" not "the network module vyos_command" or the full path-->
homebrew_tap

##### ANSIBLE VERSION
<!--- Paste, BELOW THIS COMMENT, verbatim output from "ansible --version" between quotes below -->
```

```

##### CONFIGURATION
<!--- If using Ansible 2.4 or above, paste, BELOW THIS COMMENT, the results of "ansible-config dump --only-changed"
Otherwise, mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).-->
```
(14:49:33) C02W513SHTD8:tmp aso$ ansible-config dump --only-changed
(14:49:35) C02W513SHTD8:tmp aso$
```

##### OS / ENVIRONMENT
<!--- Mention, BELOW THIS COMMENT, the OS you are running Ansible from, and the OS you are
managing, or say "N/A" for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.-->
From macOS 10.13.4
To macOS 10.13.4

##### STEPS TO REPRODUCE
<!--- For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used. -->

<!--- Paste example playbooks or commands between quotes below -->
```yaml
- name: install homebrew cask
  homebrew_tap: name=caskroom/cask
```

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

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
The task should have succeeded and running `brew tap` should have resulted in caskroom/cask being listed.

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->
The task failed even though it successfully tapped a homebrew cask. Running `brew tap` results in homebrew/cask being listed.

<!--- Paste verbatim command output between quotes below -->
```
Alberts-Mac:bin bambooagent$ brew tap
homebrew/cask
homebrew/core
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `lib/ansible/modules/packaging/os/homebrew_tap.py`
Content:
```
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3 
4 # (c) 2013, Daniel Jaouen <dcj24@cornell.edu>
5 # (c) 2016, Indrajit Raychaudhuri <irc+code@indrajit.com>
6 #
7 # Based on homebrew (Andrew Dunham <andrew@du.nham.ca>)
8 #
9 # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
10 
11 from __future__ import absolute_import, division, print_function
12 __metaclass__ = type
13 
14 
15 ANSIBLE_METADATA = {'metadata_version': '1.1',
16                     'status': ['preview'],
17                     'supported_by': 'community'}
18 
19 
20 DOCUMENTATION = '''
21 ---
22 module: homebrew_tap
23 author:
24     - "Indrajit Raychaudhuri (@indrajitr)"
25     - "Daniel Jaouen (@danieljaouen)"
26 short_description: Tap a Homebrew repository.
27 description:
28     - Tap external Homebrew repositories.
29 version_added: "1.6"
30 options:
31     name:
32         description:
33             - The GitHub user/organization repository to tap.
34         required: true
35         aliases: ['tap']
36     url:
37         description:
38             - The optional git URL of the repository to tap. The URL is not
39               assumed to be on GitHub, and the protocol doesn't have to be HTTP.
40               Any location and protocol that git can handle is fine.
41             - I(name) option may not be a list of multiple taps (but a single
42               tap instead) when this option is provided.
43         required: false
44         version_added: "2.2"
45     state:
46         description:
47             - state of the repository.
48         choices: [ 'present', 'absent' ]
49         required: false
50         default: 'present'
51 requirements: [ homebrew ]
52 '''
53 
54 EXAMPLES = '''
55 - homebrew_tap:
56     name: homebrew/dupes
57 
58 - homebrew_tap:
59     name: homebrew/dupes
60     state: absent
61 
62 - homebrew_tap:
63     name: homebrew/dupes,homebrew/science
64     state: present
65 
66 - homebrew_tap:
67     name: telemachus/brew
68     url: 'https://bitbucket.org/telemachus/brew'
69 '''
70 
71 import re
72 
73 from ansible.module_utils.basic import AnsibleModule
74 
75 
76 def a_valid_tap(tap):
77     '''Returns True if the tap is valid.'''
78     regex = re.compile(r'^([\w-]+)/(homebrew-)?([\w-]+)$')
79     return regex.match(tap)
80 
81 
82 def already_tapped(module, brew_path, tap):
83     '''Returns True if already tapped.'''
84 
85     rc, out, err = module.run_command([
86         brew_path,
87         'tap',
88     ])
89 
90     taps = [tap_.strip().lower() for tap_ in out.split('\n') if tap_]
91     tap_name = re.sub('homebrew-', '', tap.lower())
92 
93     return tap_name in taps
94 
95 
96 def add_tap(module, brew_path, tap, url=None):
97     '''Adds a single tap.'''
98     failed, changed, msg = False, False, ''
99 
100     if not a_valid_tap(tap):
101         failed = True
102         msg = 'not a valid tap: %s' % tap
103 
104     elif not already_tapped(module, brew_path, tap):
105         if module.check_mode:
106             module.exit_json(changed=True)
107 
108         rc, out, err = module.run_command([
109             brew_path,
110             'tap',
111             tap,
112             url,
113         ])
114         if already_tapped(module, brew_path, tap):
115             changed = True
116             msg = 'successfully tapped: %s' % tap
117         else:
118             failed = True
119             msg = 'failed to tap: %s' % tap
120 
121     else:
122         msg = 'already tapped: %s' % tap
123 
124     return (failed, changed, msg)
125 
126 
127 def add_taps(module, brew_path, taps):
128     '''Adds one or more taps.'''
129     failed, unchanged, added, msg = False, 0, 0, ''
130 
131     for tap in taps:
132         (failed, changed, msg) = add_tap(module, brew_path, tap)
133         if failed:
134             break
135         if changed:
136             added += 1
137         else:
138             unchanged += 1
139 
140     if failed:
141         msg = 'added: %d, unchanged: %d, error: ' + msg
142         msg = msg % (added, unchanged)
143     elif added:
144         changed = True
145         msg = 'added: %d, unchanged: %d' % (added, unchanged)
146     else:
147         msg = 'added: %d, unchanged: %d' % (added, unchanged)
148 
149     return (failed, changed, msg)
150 
151 
152 def remove_tap(module, brew_path, tap):
153     '''Removes a single tap.'''
154     failed, changed, msg = False, False, ''
155 
156     if not a_valid_tap(tap):
157         failed = True
158         msg = 'not a valid tap: %s' % tap
159 
160     elif already_tapped(module, brew_path, tap):
161         if module.check_mode:
162             module.exit_json(changed=True)
163 
164         rc, out, err = module.run_command([
165             brew_path,
166             'untap',
167             tap,
168         ])
169         if not already_tapped(module, brew_path, tap):
170             changed = True
171             msg = 'successfully untapped: %s' % tap
172         else:
173             failed = True
174             msg = 'failed to untap: %s' % tap
175 
176     else:
177         msg = 'already untapped: %s' % tap
178 
179     return (failed, changed, msg)
180 
181 
182 def remove_taps(module, brew_path, taps):
183     '''Removes one or more taps.'''
184     failed, unchanged, removed, msg = False, 0, 0, ''
185 
186     for tap in taps:
187         (failed, changed, msg) = remove_tap(module, brew_path, tap)
188         if failed:
189             break
190         if changed:
191             removed += 1
192         else:
193             unchanged += 1
194 
195     if failed:
196         msg = 'removed: %d, unchanged: %d, error: ' + msg
197         msg = msg % (removed, unchanged)
198     elif removed:
199         changed = True
200         msg = 'removed: %d, unchanged: %d' % (removed, unchanged)
201     else:
202         msg = 'removed: %d, unchanged: %d' % (removed, unchanged)
203 
204     return (failed, changed, msg)
205 
206 
207 def main():
208     module = AnsibleModule(
209         argument_spec=dict(
210             name=dict(aliases=['tap'], type='list', required=True),
211             url=dict(default=None, required=False),
212             state=dict(default='present', choices=['present', 'absent']),
213         ),
214         supports_check_mode=True,
215     )
216 
217     brew_path = module.get_bin_path(
218         'brew',
219         required=True,
220         opt_dirs=['/usr/local/bin']
221     )
222 
223     taps = module.params['name']
224     url = module.params['url']
225 
226     if module.params['state'] == 'present':
227         if url is None:
228             # No tap URL provided explicitly, continue with bulk addition
229             # of all the taps.
230             failed, changed, msg = add_taps(module, brew_path, taps)
231         else:
232             # When an tap URL is provided explicitly, we allow adding
233             # *single* tap only. Validate and proceed to add single tap.
234             if len(taps) > 1:
235                 msg = "List of multiple taps may not be provided with 'url' option."
236                 module.fail_json(msg=msg)
237             else:
238                 failed, changed, msg = add_tap(module, brew_path, taps[0], url)
239 
240         if failed:
241             module.fail_json(msg=msg)
242         else:
243             module.exit_json(changed=changed, msg=msg)
244 
245     elif module.params['state'] == 'absent':
246         failed, changed, msg = remove_taps(module, brew_path, taps)
247 
248         if failed:
249             module.fail_json(msg=msg)
250         else:
251             module.exit_json(changed=changed, msg=msg)
252 
253 
254 if __name__ == '__main__':
255     main()
256
```
--- 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/lib/ansible/modules/packaging/os/homebrew_tap.py b/lib/ansible/modules/packaging/os/homebrew_tap.py
--- a/lib/ansible/modules/packaging/os/homebrew_tap.py
+++ b/lib/ansible/modules/packaging/os/homebrew_tap.py
@@ -111,7 +111,7 @@
             tap,
             url,
         ])
-        if already_tapped(module, brew_path, tap):
+        if rc == 0:
             changed = True
             msg = 'successfully tapped: %s' % tap
         else:

{"golden_diff": "diff --git a/lib/ansible/modules/packaging/os/homebrew_tap.py b/lib/ansible/modules/packaging/os/homebrew_tap.py\n--- a/lib/ansible/modules/packaging/os/homebrew_tap.py\n+++ b/lib/ansible/modules/packaging/os/homebrew_tap.py\n@@ -111,7 +111,7 @@\n             tap,\n             url,\n         ])\n-        if already_tapped(module, brew_path, tap):\n+        if rc == 0:\n             changed = True\n             msg = 'successfully tapped: %s' % tap\n         else:\n", "issue": "homebrew_tap fails to tap caskroom/cask now.\n<!---\r\nVerify first that your issue/request is not already reported on GitHub.\r\nTHIS FORM WILL BE READ BY A MACHINE, COMPLETE ALL SECTIONS AS DESCRIBED.\r\nAlso test if the latest release, and devel branch are affected too.\r\nALWAYS add information AFTER (OUTSIDE) these html comments.\r\nOtherwise it may end up being automatically closed by our bot. -->\r\n\r\n##### SUMMARY\r\n<!--- Explain the problem briefly -->\r\nRunning the task `homebrew_tap: name=caskroom/cask` fails due to the fact that caskroom/cask has migrated to homebrew/cask.  See https://github.com/Homebrew/brew/pull/4210\r\n##### ISSUE TYPE\r\n - Bug Report\r\n\r\n##### COMPONENT NAME\r\n<!--- Insert, BELOW THIS COMMENT, the name of the module, plugin, task or feature.\r\nDo not include extra details here, e.g. \"vyos_command\" not \"the network module vyos_command\" or the full path-->\r\nhomebrew_tap\r\n\r\n##### ANSIBLE VERSION\r\n<!--- Paste, BELOW THIS COMMENT, verbatim output from \"ansible --version\" between quotes below -->\r\n```\r\n\r\n```\r\n\r\n##### CONFIGURATION\r\n<!--- If using Ansible 2.4 or above, paste, BELOW THIS COMMENT, the results of \"ansible-config dump --only-changed\"\r\nOtherwise, mention any settings you have changed/added/removed in ansible.cfg\r\n(or using the ANSIBLE_* environment variables).-->\r\n```\r\n(14:49:33) C02W513SHTD8:tmp aso$ ansible-config dump --only-changed\r\n(14:49:35) C02W513SHTD8:tmp aso$\r\n```\r\n\r\n##### OS / ENVIRONMENT\r\n<!--- Mention, BELOW THIS COMMENT, the OS you are running Ansible from, and the OS you are\r\nmanaging, or say \"N/A\" for anything that is not platform-specific.\r\nAlso mention the specific version of what you are trying to control,\r\ne.g. if this is a network bug the version of firmware on the network device.-->\r\nFrom macOS 10.13.4\r\nTo macOS 10.13.4\r\n\r\n##### STEPS TO REPRODUCE\r\n<!--- For bugs, show exactly how to reproduce the problem, using a minimal test-case.\r\nFor new features, show how the feature would be used. -->\r\n\r\n<!--- Paste example playbooks or commands between quotes below -->\r\n```yaml\r\n- name: install homebrew cask\r\n  homebrew_tap: name=caskroom/cask\r\n```\r\n\r\n<!--- You can also paste gist.github.com links for larger files -->\r\n\r\n##### EXPECTED RESULTS\r\n<!--- What did you expect to happen when running the steps above? -->\r\nThe task should have succeeded and running `brew tap` should have resulted in caskroom/cask being listed.\r\n\r\n##### ACTUAL RESULTS\r\n<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->\r\nThe task failed even though it successfully tapped a homebrew cask. Running `brew tap` results in homebrew/cask being listed.\r\n\r\n<!--- Paste verbatim command output between quotes below -->\r\n```\r\nAlberts-Mac:bin bambooagent$ brew tap\r\nhomebrew/cask\r\nhomebrew/core\r\n```\r\n\n", "before_files": [{"content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n\n# (c) 2013, Daniel Jaouen <dcj24@cornell.edu>\n# (c) 2016, Indrajit Raychaudhuri <irc+code@indrajit.com>\n#\n# Based on homebrew (Andrew Dunham <andrew@du.nham.ca>)\n#\n# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: homebrew_tap\nauthor:\n    - \"Indrajit Raychaudhuri (@indrajitr)\"\n    - \"Daniel Jaouen (@danieljaouen)\"\nshort_description: Tap a Homebrew repository.\ndescription:\n    - Tap external Homebrew repositories.\nversion_added: \"1.6\"\noptions:\n    name:\n        description:\n            - The GitHub user/organization repository to tap.\n        required: true\n        aliases: ['tap']\n    url:\n        description:\n            - The optional git URL of the repository to tap. The URL is not\n              assumed to be on GitHub, and the protocol doesn't have to be HTTP.\n              Any location and protocol that git can handle is fine.\n            - I(name) option may not be a list of multiple taps (but a single\n              tap instead) when this option is provided.\n        required: false\n        version_added: \"2.2\"\n    state:\n        description:\n            - state of the repository.\n        choices: [ 'present', 'absent' ]\n        required: false\n        default: 'present'\nrequirements: [ homebrew ]\n'''\n\nEXAMPLES = '''\n- homebrew_tap:\n    name: homebrew/dupes\n\n- homebrew_tap:\n    name: homebrew/dupes\n    state: absent\n\n- homebrew_tap:\n    name: homebrew/dupes,homebrew/science\n    state: present\n\n- homebrew_tap:\n    name: telemachus/brew\n    url: 'https://bitbucket.org/telemachus/brew'\n'''\n\nimport re\n\nfrom ansible.module_utils.basic import AnsibleModule\n\n\ndef a_valid_tap(tap):\n    '''Returns True if the tap is valid.'''\n    regex = re.compile(r'^([\\w-]+)/(homebrew-)?([\\w-]+)$')\n    return regex.match(tap)\n\n\ndef already_tapped(module, brew_path, tap):\n    '''Returns True if already tapped.'''\n\n    rc, out, err = module.run_command([\n        brew_path,\n        'tap',\n    ])\n\n    taps = [tap_.strip().lower() for tap_ in out.split('\\n') if tap_]\n    tap_name = re.sub('homebrew-', '', tap.lower())\n\n    return tap_name in taps\n\n\ndef add_tap(module, brew_path, tap, url=None):\n    '''Adds a single tap.'''\n    failed, changed, msg = False, False, ''\n\n    if not a_valid_tap(tap):\n        failed = True\n        msg = 'not a valid tap: %s' % tap\n\n    elif not already_tapped(module, brew_path, tap):\n        if module.check_mode:\n            module.exit_json(changed=True)\n\n        rc, out, err = module.run_command([\n            brew_path,\n            'tap',\n            tap,\n            url,\n        ])\n        if already_tapped(module, brew_path, tap):\n            changed = True\n            msg = 'successfully tapped: %s' % tap\n        else:\n            failed = True\n            msg = 'failed to tap: %s' % tap\n\n    else:\n        msg = 'already tapped: %s' % tap\n\n    return (failed, changed, msg)\n\n\ndef add_taps(module, brew_path, taps):\n    '''Adds one or more taps.'''\n    failed, unchanged, added, msg = False, 0, 0, ''\n\n    for tap in taps:\n        (failed, changed, msg) = add_tap(module, brew_path, tap)\n        if failed:\n            break\n        if changed:\n            added += 1\n        else:\n            unchanged += 1\n\n    if failed:\n        msg = 'added: %d, unchanged: %d, error: ' + msg\n        msg = msg % (added, unchanged)\n    elif added:\n        changed = True\n        msg = 'added: %d, unchanged: %d' % (added, unchanged)\n    else:\n        msg = 'added: %d, unchanged: %d' % (added, unchanged)\n\n    return (failed, changed, msg)\n\n\ndef remove_tap(module, brew_path, tap):\n    '''Removes a single tap.'''\n    failed, changed, msg = False, False, ''\n\n    if not a_valid_tap(tap):\n        failed = True\n        msg = 'not a valid tap: %s' % tap\n\n    elif already_tapped(module, brew_path, tap):\n        if module.check_mode:\n            module.exit_json(changed=True)\n\n        rc, out, err = module.run_command([\n            brew_path,\n            'untap',\n            tap,\n        ])\n        if not already_tapped(module, brew_path, tap):\n            changed = True\n            msg = 'successfully untapped: %s' % tap\n        else:\n            failed = True\n            msg = 'failed to untap: %s' % tap\n\n    else:\n        msg = 'already untapped: %s' % tap\n\n    return (failed, changed, msg)\n\n\ndef remove_taps(module, brew_path, taps):\n    '''Removes one or more taps.'''\n    failed, unchanged, removed, msg = False, 0, 0, ''\n\n    for tap in taps:\n        (failed, changed, msg) = remove_tap(module, brew_path, tap)\n        if failed:\n            break\n        if changed:\n            removed += 1\n        else:\n            unchanged += 1\n\n    if failed:\n        msg = 'removed: %d, unchanged: %d, error: ' + msg\n        msg = msg % (removed, unchanged)\n    elif removed:\n        changed = True\n        msg = 'removed: %d, unchanged: %d' % (removed, unchanged)\n    else:\n        msg = 'removed: %d, unchanged: %d' % (removed, unchanged)\n\n    return (failed, changed, msg)\n\n\ndef main():\n    module = AnsibleModule(\n        argument_spec=dict(\n            name=dict(aliases=['tap'], type='list', required=True),\n            url=dict(default=None, required=False),\n            state=dict(default='present', choices=['present', 'absent']),\n        ),\n        supports_check_mode=True,\n    )\n\n    brew_path = module.get_bin_path(\n        'brew',\n        required=True,\n        opt_dirs=['/usr/local/bin']\n    )\n\n    taps = module.params['name']\n    url = module.params['url']\n\n    if module.params['state'] == 'present':\n        if url is None:\n            # No tap URL provided explicitly, continue with bulk addition\n            # of all the taps.\n            failed, changed, msg = add_taps(module, brew_path, taps)\n        else:\n            # When an tap URL is provided explicitly, we allow adding\n            # *single* tap only. Validate and proceed to add single tap.\n            if len(taps) > 1:\n                msg = \"List of multiple taps may not be provided with 'url' option.\"\n                module.fail_json(msg=msg)\n            else:\n                failed, changed, msg = add_tap(module, brew_path, taps[0], url)\n\n        if failed:\n            module.fail_json(msg=msg)\n        else:\n            module.exit_json(changed=changed, msg=msg)\n\n    elif module.params['state'] == 'absent':\n        failed, changed, msg = remove_taps(module, brew_path, taps)\n\n        if failed:\n            module.fail_json(msg=msg)\n        else:\n            module.exit_json(changed=changed, msg=msg)\n\n\nif __name__ == '__main__':\n    main()\n", "path": "lib/ansible/modules/packaging/os/homebrew_tap.py"}], "after_files": [{"content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n\n# (c) 2013, Daniel Jaouen <dcj24@cornell.edu>\n# (c) 2016, Indrajit Raychaudhuri <irc+code@indrajit.com>\n#\n# Based on homebrew (Andrew Dunham <andrew@du.nham.ca>)\n#\n# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: homebrew_tap\nauthor:\n    - \"Indrajit Raychaudhuri (@indrajitr)\"\n    - \"Daniel Jaouen (@danieljaouen)\"\nshort_description: Tap a Homebrew repository.\ndescription:\n    - Tap external Homebrew repositories.\nversion_added: \"1.6\"\noptions:\n    name:\n        description:\n            - The GitHub user/organization repository to tap.\n        required: true\n        aliases: ['tap']\n    url:\n        description:\n            - The optional git URL of the repository to tap. The URL is not\n              assumed to be on GitHub, and the protocol doesn't have to be HTTP.\n              Any location and protocol that git can handle is fine.\n            - I(name) option may not be a list of multiple taps (but a single\n              tap instead) when this option is provided.\n        required: false\n        version_added: \"2.2\"\n    state:\n        description:\n            - state of the repository.\n        choices: [ 'present', 'absent' ]\n        required: false\n        default: 'present'\nrequirements: [ homebrew ]\n'''\n\nEXAMPLES = '''\n- homebrew_tap:\n    name: homebrew/dupes\n\n- homebrew_tap:\n    name: homebrew/dupes\n    state: absent\n\n- homebrew_tap:\n    name: homebrew/dupes,homebrew/science\n    state: present\n\n- homebrew_tap:\n    name: telemachus/brew\n    url: 'https://bitbucket.org/telemachus/brew'\n'''\n\nimport re\n\nfrom ansible.module_utils.basic import AnsibleModule\n\n\ndef a_valid_tap(tap):\n    '''Returns True if the tap is valid.'''\n    regex = re.compile(r'^([\\w-]+)/(homebrew-)?([\\w-]+)$')\n    return regex.match(tap)\n\n\ndef already_tapped(module, brew_path, tap):\n    '''Returns True if already tapped.'''\n\n    rc, out, err = module.run_command([\n        brew_path,\n        'tap',\n    ])\n\n    taps = [tap_.strip().lower() for tap_ in out.split('\\n') if tap_]\n    tap_name = re.sub('homebrew-', '', tap.lower())\n\n    return tap_name in taps\n\n\ndef add_tap(module, brew_path, tap, url=None):\n    '''Adds a single tap.'''\n    failed, changed, msg = False, False, ''\n\n    if not a_valid_tap(tap):\n        failed = True\n        msg = 'not a valid tap: %s' % tap\n\n    elif not already_tapped(module, brew_path, tap):\n        if module.check_mode:\n            module.exit_json(changed=True)\n\n        rc, out, err = module.run_command([\n            brew_path,\n            'tap',\n            tap,\n            url,\n        ])\n        if rc == 0:\n            changed = True\n            msg = 'successfully tapped: %s' % tap\n        else:\n            failed = True\n            msg = 'failed to tap: %s' % tap\n\n    else:\n        msg = 'already tapped: %s' % tap\n\n    return (failed, changed, msg)\n\n\ndef add_taps(module, brew_path, taps):\n    '''Adds one or more taps.'''\n    failed, unchanged, added, msg = False, 0, 0, ''\n\n    for tap in taps:\n        (failed, changed, msg) = add_tap(module, brew_path, tap)\n        if failed:\n            break\n        if changed:\n            added += 1\n        else:\n            unchanged += 1\n\n    if failed:\n        msg = 'added: %d, unchanged: %d, error: ' + msg\n        msg = msg % (added, unchanged)\n    elif added:\n        changed = True\n        msg = 'added: %d, unchanged: %d' % (added, unchanged)\n    else:\n        msg = 'added: %d, unchanged: %d' % (added, unchanged)\n\n    return (failed, changed, msg)\n\n\ndef remove_tap(module, brew_path, tap):\n    '''Removes a single tap.'''\n    failed, changed, msg = False, False, ''\n\n    if not a_valid_tap(tap):\n        failed = True\n        msg = 'not a valid tap: %s' % tap\n\n    elif already_tapped(module, brew_path, tap):\n        if module.check_mode:\n            module.exit_json(changed=True)\n\n        rc, out, err = module.run_command([\n            brew_path,\n            'untap',\n            tap,\n        ])\n        if not already_tapped(module, brew_path, tap):\n            changed = True\n            msg = 'successfully untapped: %s' % tap\n        else:\n            failed = True\n            msg = 'failed to untap: %s' % tap\n\n    else:\n        msg = 'already untapped: %s' % tap\n\n    return (failed, changed, msg)\n\n\ndef remove_taps(module, brew_path, taps):\n    '''Removes one or more taps.'''\n    failed, unchanged, removed, msg = False, 0, 0, ''\n\n    for tap in taps:\n        (failed, changed, msg) = remove_tap(module, brew_path, tap)\n        if failed:\n            break\n        if changed:\n            removed += 1\n        else:\n            unchanged += 1\n\n    if failed:\n        msg = 'removed: %d, unchanged: %d, error: ' + msg\n        msg = msg % (removed, unchanged)\n    elif removed:\n        changed = True\n        msg = 'removed: %d, unchanged: %d' % (removed, unchanged)\n    else:\n        msg = 'removed: %d, unchanged: %d' % (removed, unchanged)\n\n    return (failed, changed, msg)\n\n\ndef main():\n    module = AnsibleModule(\n        argument_spec=dict(\n            name=dict(aliases=['tap'], type='list', required=True),\n            url=dict(default=None, required=False),\n            state=dict(default='present', choices=['present', 'absent']),\n        ),\n        supports_check_mode=True,\n    )\n\n    brew_path = module.get_bin_path(\n        'brew',\n        required=True,\n        opt_dirs=['/usr/local/bin']\n    )\n\n    taps = module.params['name']\n    url = module.params['url']\n\n    if module.params['state'] == 'present':\n        if url is None:\n            # No tap URL provided explicitly, continue with bulk addition\n            # of all the taps.\n            failed, changed, msg = add_taps(module, brew_path, taps)\n        else:\n            # When an tap URL is provided explicitly, we allow adding\n            # *single* tap only. Validate and proceed to add single tap.\n            if len(taps) > 1:\n                msg = \"List of multiple taps may not be provided with 'url' option.\"\n                module.fail_json(msg=msg)\n            else:\n                failed, changed, msg = add_tap(module, brew_path, taps[0], url)\n\n        if failed:\n            module.fail_json(msg=msg)\n        else:\n            module.exit_json(changed=changed, msg=msg)\n\n    elif module.params['state'] == 'absent':\n        failed, changed, msg = remove_taps(module, brew_path, taps)\n\n        if failed:\n            module.fail_json(msg=msg)\n        else:\n            module.exit_json(changed=changed, msg=msg)\n\n\nif __name__ == '__main__':\n    main()\n", "path": "lib/ansible/modules/packaging/os/homebrew_tap.py"}]}