|
|
|
@ -42,7 +42,7 @@ options:
|
|
|
|
|
state:
|
|
|
|
|
description:
|
|
|
|
|
- state of the cask
|
|
|
|
|
choices: [ 'present', 'absent' ]
|
|
|
|
|
choices: [ 'present', 'absent', 'upgraded' ]
|
|
|
|
|
required: false
|
|
|
|
|
default: present
|
|
|
|
|
update_homebrew:
|
|
|
|
@ -61,6 +61,24 @@ options:
|
|
|
|
|
default: null
|
|
|
|
|
aliases: ['options']
|
|
|
|
|
version_added: "2.2"
|
|
|
|
|
accept_external_apps:
|
|
|
|
|
description:
|
|
|
|
|
- allow external apps
|
|
|
|
|
required: false
|
|
|
|
|
default: False
|
|
|
|
|
version_added: "2.5.0"
|
|
|
|
|
upgrade_all:
|
|
|
|
|
description:
|
|
|
|
|
- upgrade all casks (mutually exclusive with `upgrade`)
|
|
|
|
|
required: False
|
|
|
|
|
default: False
|
|
|
|
|
version_added: "2.5.0"
|
|
|
|
|
upgrade:
|
|
|
|
|
description:
|
|
|
|
|
- upgrade all casks (mutually exclusive with `upgrade_all`)
|
|
|
|
|
required: False
|
|
|
|
|
default: False
|
|
|
|
|
version_added: "2.5.0"
|
|
|
|
|
'''
|
|
|
|
|
EXAMPLES = '''
|
|
|
|
|
- homebrew_cask:
|
|
|
|
@ -81,10 +99,24 @@ EXAMPLES = '''
|
|
|
|
|
state: present
|
|
|
|
|
install_options: 'debug,appdir=/Applications'
|
|
|
|
|
|
|
|
|
|
- homebrew_cask:
|
|
|
|
|
name: alfred
|
|
|
|
|
state: present
|
|
|
|
|
allow_external_apps: True
|
|
|
|
|
|
|
|
|
|
- homebrew_cask:
|
|
|
|
|
name: alfred
|
|
|
|
|
state: absent
|
|
|
|
|
install_options: force
|
|
|
|
|
|
|
|
|
|
- homebrew_cask:
|
|
|
|
|
upgrade_all: true
|
|
|
|
|
|
|
|
|
|
- homebrew_cask:
|
|
|
|
|
name: alfred
|
|
|
|
|
state: upgraded
|
|
|
|
|
install_options: force
|
|
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
import os.path
|
|
|
|
@ -225,7 +257,6 @@ class HomebrewCask(object):
|
|
|
|
|
'''A valid module is an instance of AnsibleModule.'''
|
|
|
|
|
|
|
|
|
|
return isinstance(module, AnsibleModule)
|
|
|
|
|
|
|
|
|
|
# /class validations ------------------------------------------- }}}
|
|
|
|
|
|
|
|
|
|
# class properties --------------------------------------------- {{{
|
|
|
|
@ -308,13 +339,16 @@ class HomebrewCask(object):
|
|
|
|
|
# /class properties -------------------------------------------- }}}
|
|
|
|
|
|
|
|
|
|
def __init__(self, module, path=path, casks=None, state=None,
|
|
|
|
|
update_homebrew=False, install_options=None):
|
|
|
|
|
update_homebrew=False, install_options=None,
|
|
|
|
|
accept_external_apps=False, upgrade_all=False):
|
|
|
|
|
if not install_options:
|
|
|
|
|
install_options = list()
|
|
|
|
|
self._setup_status_vars()
|
|
|
|
|
self._setup_instance_vars(module=module, path=path, casks=casks,
|
|
|
|
|
state=state, update_homebrew=update_homebrew,
|
|
|
|
|
install_options=install_options,)
|
|
|
|
|
install_options=install_options,
|
|
|
|
|
accept_external_apps=accept_external_apps,
|
|
|
|
|
upgrade_all=upgrade_all, )
|
|
|
|
|
|
|
|
|
|
self._prep()
|
|
|
|
|
|
|
|
|
@ -373,6 +407,19 @@ class HomebrewCask(object):
|
|
|
|
|
return (failed, changed, message)
|
|
|
|
|
|
|
|
|
|
# checks ------------------------------------------------------- {{{
|
|
|
|
|
def _current_cask_is_outdated(self):
|
|
|
|
|
if not self.valid_cask(self.current_cask):
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
rc, out, err = self.module.run_command([
|
|
|
|
|
self.brew_path,
|
|
|
|
|
'cask',
|
|
|
|
|
'outdated',
|
|
|
|
|
self.current_cask,
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
return out != ""
|
|
|
|
|
|
|
|
|
|
def _current_cask_is_installed(self):
|
|
|
|
|
if not self.valid_cask(self.current_cask):
|
|
|
|
|
self.failed = True
|
|
|
|
@ -382,33 +429,33 @@ class HomebrewCask(object):
|
|
|
|
|
cmd = [
|
|
|
|
|
"{brew_path}".format(brew_path=self.brew_path),
|
|
|
|
|
"cask",
|
|
|
|
|
"list"
|
|
|
|
|
"list",
|
|
|
|
|
self.current_cask
|
|
|
|
|
]
|
|
|
|
|
rc, out, err = self.module.run_command(cmd)
|
|
|
|
|
|
|
|
|
|
if 'nothing to list' in err:
|
|
|
|
|
if re.search(r'Error: Cask .* is not installed.', err):
|
|
|
|
|
return False
|
|
|
|
|
elif rc == 0:
|
|
|
|
|
casks = [cask_.strip() for cask_ in out.split('\n') if cask_.strip()]
|
|
|
|
|
return self.current_cask in casks
|
|
|
|
|
else:
|
|
|
|
|
self.failed = True
|
|
|
|
|
self.message = err.strip()
|
|
|
|
|
raise HomebrewCaskException(self.message)
|
|
|
|
|
return True
|
|
|
|
|
# /checks ------------------------------------------------------ }}}
|
|
|
|
|
|
|
|
|
|
# commands ----------------------------------------------------- {{{
|
|
|
|
|
def _run(self):
|
|
|
|
|
if self.update_homebrew:
|
|
|
|
|
self._update_homebrew()
|
|
|
|
|
if self.upgrade_all:
|
|
|
|
|
return self._upgrade_all()
|
|
|
|
|
|
|
|
|
|
if self.state == 'installed':
|
|
|
|
|
return self._install_casks()
|
|
|
|
|
elif self.state == 'absent':
|
|
|
|
|
return self._uninstall_casks()
|
|
|
|
|
if self.casks:
|
|
|
|
|
if self.state == 'installed':
|
|
|
|
|
return self._install_casks()
|
|
|
|
|
elif self.state == 'upgraded':
|
|
|
|
|
return self._upgrade_casks()
|
|
|
|
|
elif self.state == 'absent':
|
|
|
|
|
return self._uninstall_casks()
|
|
|
|
|
|
|
|
|
|
if self.command:
|
|
|
|
|
return self._command()
|
|
|
|
|
self.failed = True
|
|
|
|
|
self.message = "You must select a cask to install."
|
|
|
|
|
raise HomebrewCaskException(self.message)
|
|
|
|
|
|
|
|
|
|
# updated -------------------------------- {{{
|
|
|
|
|
def _update_homebrew(self):
|
|
|
|
@ -436,6 +483,33 @@ class HomebrewCask(object):
|
|
|
|
|
raise HomebrewCaskException(self.message)
|
|
|
|
|
# /updated ------------------------------- }}}
|
|
|
|
|
|
|
|
|
|
# _upgrade_all --------------------------- {{{
|
|
|
|
|
def _upgrade_all(self):
|
|
|
|
|
if self.module.check_mode:
|
|
|
|
|
self.changed = True
|
|
|
|
|
self.message = 'Casks would be upgraded.'
|
|
|
|
|
raise HomebrewCaskException(self.message)
|
|
|
|
|
|
|
|
|
|
rc, out, err = self.module.run_command([
|
|
|
|
|
self.brew_path,
|
|
|
|
|
'cask',
|
|
|
|
|
'upgrade',
|
|
|
|
|
])
|
|
|
|
|
if rc == 0:
|
|
|
|
|
if re.search(r'==> No Casks to upgrade', out.strip(), re.IGNORECASE):
|
|
|
|
|
self.message = 'Homebrew casks already upgraded.'
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
self.changed = True
|
|
|
|
|
self.message = 'Homebrew casks upgraded.'
|
|
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
self.failed = True
|
|
|
|
|
self.message = err.strip()
|
|
|
|
|
raise HomebrewCaskException(self.message)
|
|
|
|
|
# /_upgrade_all -------------------------- }}}
|
|
|
|
|
|
|
|
|
|
# installed ------------------------------ {{{
|
|
|
|
|
def _install_current_cask(self):
|
|
|
|
|
if not self.valid_cask(self.current_cask):
|
|
|
|
@ -470,6 +544,12 @@ class HomebrewCask(object):
|
|
|
|
|
self.changed = True
|
|
|
|
|
self.message = 'Cask installed: {0}'.format(self.current_cask)
|
|
|
|
|
return True
|
|
|
|
|
elif self.accept_external_apps and re.search(r"Error: It seems there is already an App at", err):
|
|
|
|
|
self.unchanged_count += 1
|
|
|
|
|
self.message = 'Cask already installed: {0}'.format(
|
|
|
|
|
self.current_cask,
|
|
|
|
|
)
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
self.failed = True
|
|
|
|
|
self.message = err.strip()
|
|
|
|
@ -483,6 +563,58 @@ class HomebrewCask(object):
|
|
|
|
|
return True
|
|
|
|
|
# /installed ----------------------------- }}}
|
|
|
|
|
|
|
|
|
|
# upgraded ------------------------------- {{{
|
|
|
|
|
def _upgrade_current_cask(self):
|
|
|
|
|
command = 'upgrade'
|
|
|
|
|
|
|
|
|
|
if not self.valid_cask(self.current_cask):
|
|
|
|
|
self.failed = True
|
|
|
|
|
self.message = 'Invalid cask: {0}.'.format(self.current_cask)
|
|
|
|
|
raise HomebrewCaskException(self.message)
|
|
|
|
|
|
|
|
|
|
if not self._current_cask_is_installed():
|
|
|
|
|
command = 'install'
|
|
|
|
|
|
|
|
|
|
if self._current_cask_is_installed() and not self._current_cask_is_outdated():
|
|
|
|
|
self.message = 'Cask is already upgraded: {0}'.format(
|
|
|
|
|
self.current_cask,
|
|
|
|
|
)
|
|
|
|
|
self.unchanged_count += 1
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
if self.module.check_mode:
|
|
|
|
|
self.changed = True
|
|
|
|
|
self.message = 'Cask would be upgraded: {0}'.format(
|
|
|
|
|
self.current_cask
|
|
|
|
|
)
|
|
|
|
|
raise HomebrewCaskException(self.message)
|
|
|
|
|
|
|
|
|
|
opts = (
|
|
|
|
|
[self.brew_path, 'cask', command]
|
|
|
|
|
+ self.install_options
|
|
|
|
|
+ [self.current_cask]
|
|
|
|
|
)
|
|
|
|
|
cmd = [opt for opt in opts if opt]
|
|
|
|
|
rc, out, err = self.module.run_command(cmd)
|
|
|
|
|
|
|
|
|
|
if self._current_cask_is_installed() and not self._current_cask_is_outdated():
|
|
|
|
|
self.changed_count += 1
|
|
|
|
|
self.changed = True
|
|
|
|
|
self.message = 'Cask upgraded: {0}'.format(self.current_cask)
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
self.failed = True
|
|
|
|
|
self.message = err.strip()
|
|
|
|
|
raise HomebrewCaskException(self.message)
|
|
|
|
|
|
|
|
|
|
def _upgrade_casks(self):
|
|
|
|
|
for cask in self.casks:
|
|
|
|
|
self.current_cask = cask
|
|
|
|
|
self._upgrade_current_cask()
|
|
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
# /upgraded ------------------------------ }}}
|
|
|
|
|
|
|
|
|
|
# uninstalled ---------------------------- {{{
|
|
|
|
|
def _uninstall_current_cask(self):
|
|
|
|
|
if not self.valid_cask(self.current_cask):
|
|
|
|
@ -526,7 +658,7 @@ class HomebrewCask(object):
|
|
|
|
|
self._uninstall_current_cask()
|
|
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
# /uninstalled ----------------------------- }}}
|
|
|
|
|
# /uninstalled --------------------------- }}}
|
|
|
|
|
# /commands ---------------------------------------------------- }}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -547,6 +679,7 @@ def main():
|
|
|
|
|
default="present",
|
|
|
|
|
choices=[
|
|
|
|
|
"present", "installed",
|
|
|
|
|
"latest", "upgraded",
|
|
|
|
|
"absent", "removed", "uninstalled",
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
@ -559,7 +692,16 @@ def main():
|
|
|
|
|
default=None,
|
|
|
|
|
aliases=['options'],
|
|
|
|
|
type='list',
|
|
|
|
|
)
|
|
|
|
|
),
|
|
|
|
|
accept_external_apps=dict(
|
|
|
|
|
default=False,
|
|
|
|
|
type='bool',
|
|
|
|
|
),
|
|
|
|
|
upgrade_all=dict(
|
|
|
|
|
default=False,
|
|
|
|
|
aliases=["upgrade"],
|
|
|
|
|
type='bool',
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
supports_check_mode=True,
|
|
|
|
|
)
|
|
|
|
@ -580,17 +722,25 @@ def main():
|
|
|
|
|
state = p['state']
|
|
|
|
|
if state in ('present', 'installed'):
|
|
|
|
|
state = 'installed'
|
|
|
|
|
if state in ('latest', 'upgraded'):
|
|
|
|
|
state = 'upgraded'
|
|
|
|
|
if state in ('absent', 'removed', 'uninstalled'):
|
|
|
|
|
state = 'absent'
|
|
|
|
|
|
|
|
|
|
update_homebrew = p['update_homebrew']
|
|
|
|
|
upgrade_all = p['upgrade_all']
|
|
|
|
|
p['install_options'] = p['install_options'] or []
|
|
|
|
|
install_options = ['--{0}'.format(install_option)
|
|
|
|
|
for install_option in p['install_options']]
|
|
|
|
|
|
|
|
|
|
accept_external_apps = p['accept_external_apps']
|
|
|
|
|
|
|
|
|
|
brew_cask = HomebrewCask(module=module, path=path, casks=casks,
|
|
|
|
|
state=state, update_homebrew=update_homebrew,
|
|
|
|
|
install_options=install_options)
|
|
|
|
|
install_options=install_options,
|
|
|
|
|
accept_external_apps=accept_external_apps,
|
|
|
|
|
upgrade_all=upgrade_all,
|
|
|
|
|
)
|
|
|
|
|
(failed, changed, message) = brew_cask.run()
|
|
|
|
|
if failed:
|
|
|
|
|
module.fail_json(msg=message)
|
|
|
|
|