Browse Source

Initial commit

Sven Velt 8 years ago
commit
8aa8100dbf
2 changed files with 214 additions and 0 deletions
  1. 2 0
      .gitignore
  2. 212 0
      xbps.py

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+.*.sw?
+*~

+ 212 - 0
xbps.py

@@ -0,0 +1,212 @@
+#!/usr/bin/python2.7 -tt
+# -*- coding: utf-8 -*-
+
+def update_package_db(module, paths):
+	cmd = "%s -S" % paths['install']
+	rc, sout, serr = module.run_command(cmd, check_rc=False)
+
+	if rc == 0:
+		return True
+	else:
+		module.fail_json(msg="could not update package db", rc=rc, stdout=sout, stderr=serr)
+
+
+
+def query_package(module, paths, pkg):
+	'''
+	pkg: a package name
+	returns: (installed, available, latest) as booleans
+	'''
+	query_local = '%s -S %s | grep "^pkgver: "' % (paths['query'], pkg)
+	query_repo = '%s -RS %s | grep "^pkgver: "' % (paths['query'], pkg)
+
+	# query local installed packages
+	qlrc, qlsout, qlserr = module.run_command(query_local, use_unsafe_shell=True, check_rc=False)
+	if qlrc == 0:
+		# pkg installed
+		installed = True
+	else:
+		installed = False
+
+	# query repo conent
+	qrrc, qrsout, qrserr = module.run_command(query_repo, use_unsafe_shell=True, check_rc=False)
+	if qrrc == 0:
+		# pkg available
+		available = True
+	else:
+		available = False
+
+	if qlsout == qrsout:
+		# same pkgver
+		latest = True
+	else:
+		latest = False
+
+	#FIXME module.fail_json(msg='foo', ql=query_local, qlrc=qlrc, qlsout=qlsout, qlserr=qlserr, qr=query_repo, qrrc=qrrc, qrsout=qrsout, qrserr=qrserr)
+	return (installed, available, latest)
+
+
+
+def get_changed_packages(module, paths, pkgs, desired_state):
+	'''
+	pkgs: list of packages
+	desired_state: desired state (present, latest, absent)
+	returns: list of packages to be changed
+	'''
+	to_be_changed = []
+	for pkg in pkgs:
+		(installed, available, latest) = query_package(module, paths, pkg)
+		#FIXME module.fail_json(msg='foo', installed=installed, available=available, latest=latest)
+		if desired_state == 'latest' and not latest:
+			to_be_changed.append(pkg)
+		elif desired_state == 'present' and not installed:
+			to_be_changed.append(pkg)
+		elif desired_state == 'absent' and installed:
+			to_be_changed.append(pkg)
+
+	return to_be_changed
+
+
+
+def check_packages(module, paths, pkgs, desired_state):
+	'''
+	pkgs: list of packages
+	desired_state: desired state (present, latest, absent)
+	retuns: n/a, exit module
+	'''
+	to_be_changed = get_changed_packages(module, paths, pkgs, desired_state)
+
+	if to_be_changed:
+		module.exit_json(changed=True, msg="%s package(s) not in state %s" % (
+			len(to_be_changed), state))
+	else:
+		module.exit_json(changed=False, msg="package(s) already in state %s" % state)
+
+
+
+def upgrade(module, paths, check_mode):
+	'''
+	returns: (updates_available, updates_successful)
+	'''
+	# Check for updates
+	cmd = "%s -un" % paths['install']
+	rc, sout, serr = module.run_command(cmd, check_rc=False)
+
+	if sout:
+		# packages for upgrade available
+		if check_mode:
+			return (True, False)
+
+		# do upgrade
+		cmd = "%s -uy" % paths['install']
+		rc, sout, serr = module.run_command(cmd, check_rc=False)
+
+		if rc == 0:
+			return (True, True)
+		else:
+			module.fail_json(msg="could not upgrade packages", rc=rc, stdout=sout, stderr=serr)
+	else:
+		return (False, False)
+
+
+
+def ensure_packages_state(module, paths, pkgs, desired_state):
+	'''
+	pkgs: list of packages
+	desired_state: desired state (present, latest, absent)
+	returns: list of packages to be changed
+	'''
+
+	# which packages must change state
+	pkgs2do = get_changed_packages(module, paths, pkgs, desired_state)
+
+	if not pkgs2do:
+		module.exit_json(msg='All packages in desired state')
+
+	if desired_state in ['present', 'latest']:
+		cmdtype = 'install'
+	elif desired_state == 'absent':
+		cmdtype = 'remove'
+
+	cmd = '%s -y %s' % (paths[cmdtype], ' '.join(pkgs2do))
+	rc, sout, serr = module.run_command(cmd, check_rc=False)
+
+	if rc == 0:
+		msg = '%s package' % len(pkgs2do)
+		msg += '%s ' % len(pkgs2do) == 1 and '' or 's'
+		if cmdtype == 'install':
+			msg += 'installed'
+		elif cmdtype == 'remove':
+			msg += 'removed'
+		module.exit_json(msg=msg, rc=rc, stdout=sout, stderr=serr)
+	else:
+		module.fail_json(msg="could not install/remove package(s)", rc=rc, stdout=sout, stderr=serr)
+
+
+
+def main():
+	module = AnsibleModule(
+		argument_spec = dict(
+			name         = dict(aliases=['pkg', 'package'], type='list'),
+			state        = dict(default='present', choices=['present', 'installed', "latest", 'absent', 'removed']),
+			force        = dict(default=False, type='bool'),
+			upgrade      = dict(default=False, type='bool'),
+			update_cache = dict(default=False, aliases=['update-cache'], type='bool')
+		),
+		required_one_of = [['name', 'update_cache', 'upgrade']],
+		supports_check_mode = True)
+
+	paths = {}
+	paths['install'] = module.get_bin_path('xbps-install', True)
+	paths['remove'] = module.get_bin_path('xbps-remove', True)
+	paths['query']   = module.get_bin_path('xbps-query', True)
+
+	p = module.params
+
+	# normalize the state parameter
+	if p['state'] in ['present', 'installed']:
+		p['state'] = 'present'
+	elif p['state'] in ['absent', 'removed']:
+		p['state'] = 'absent'
+
+	# do update if package name is "*"
+	if p['name'] and p['name'][0] == '*' and p['state'] == 'latest':
+		p['update'] = True
+		p['name'] = []
+
+	# sync repo index
+	if p["update_cache"] and not module.check_mode:
+		update_package_db(module, paths) # FIXME
+		if not (p['name'] or p['upgrade']):
+			module.exit_json(changed=True, msg='Updated the package master lists')
+
+	if p['update_cache'] and module.check_mode and not (p['name'] or p['upgrade']):
+		module.exit_json(changed=True, msg='Would have updated the package cache')
+
+	# update/upgrade all installed packages
+	if p['upgrade']:
+		(upg_avail, upg_successful) = upgrade(module, paths, module.check_mode) 
+		if not p['name']: # upgrade is last action
+			if upg_avail:
+				if upg_successful:
+					module.exit_json(changed=True, msg="all packages upgraded")
+				else:
+					if module.check_mode:
+						module.exit_json(msg="no packages upgraded in check mode")
+					# should never happen, "upgrade" function should exit module
+					module.fail_json(msg="could not upgrade packages", rc=rc, stdout=sout, stderr=serr)
+			else:
+				module.exit_json(msg="all packages uptodate")
+
+	if p['name']:
+		if module.check_mode:
+			check_packages(module, paths, p['name'], p['state']) # FIXME
+
+		ensure_packages_state(module, paths, p['name'], p['state']) # FIXME
+
+# import module snippets
+from ansible.module_utils.basic import *
+
+if __name__ == "__main__":
+	main()
+