xbps.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. #!/usr/bin/python2.7 -tt
  2. # -*- coding: utf-8 -*-
  3. def update_package_db(module, paths):
  4. cmd = "%s -S" % paths['install']
  5. rc, sout, serr = module.run_command(cmd, check_rc=False)
  6. if rc == 0:
  7. return True
  8. else:
  9. module.fail_json(msg="could not update package db", rc=rc, stdout=sout, stderr=serr)
  10. def query_package(module, paths, pkg):
  11. '''
  12. pkg: a package name
  13. returns: (installed, available, latest) as booleans
  14. '''
  15. query_local = '%s -S %s | grep "^pkgver: "' % (paths['query'], pkg)
  16. query_repo = '%s -RS %s | grep "^pkgver: "' % (paths['query'], pkg)
  17. # query local installed packages
  18. qlrc, qlsout, qlserr = module.run_command(query_local, use_unsafe_shell=True, check_rc=False)
  19. if qlrc == 0:
  20. # pkg installed
  21. installed = True
  22. else:
  23. installed = False
  24. # query repo conent
  25. qrrc, qrsout, qrserr = module.run_command(query_repo, use_unsafe_shell=True, check_rc=False)
  26. if qrrc == 0:
  27. # pkg available
  28. available = True
  29. else:
  30. available = False
  31. if qlsout == qrsout:
  32. # same pkgver
  33. latest = True
  34. else:
  35. latest = False
  36. #FIXME module.fail_json(msg='foo', ql=query_local, qlrc=qlrc, qlsout=qlsout, qlserr=qlserr, qr=query_repo, qrrc=qrrc, qrsout=qrsout, qrserr=qrserr)
  37. return (installed, available, latest)
  38. def get_changed_packages(module, paths, pkgs, desired_state):
  39. '''
  40. pkgs: list of packages
  41. desired_state: desired state (present, latest, absent)
  42. returns: list of packages to be changed
  43. '''
  44. to_be_changed = []
  45. for pkg in pkgs:
  46. (installed, available, latest) = query_package(module, paths, pkg)
  47. #FIXME module.fail_json(msg='foo', installed=installed, available=available, latest=latest)
  48. if desired_state == 'latest' and not latest:
  49. to_be_changed.append(pkg)
  50. elif desired_state == 'present' and not installed:
  51. to_be_changed.append(pkg)
  52. elif desired_state == 'absent' and installed:
  53. to_be_changed.append(pkg)
  54. return to_be_changed
  55. def check_packages(module, paths, pkgs, desired_state):
  56. '''
  57. pkgs: list of packages
  58. desired_state: desired state (present, latest, absent)
  59. retuns: n/a, exit module
  60. '''
  61. to_be_changed = get_changed_packages(module, paths, pkgs, desired_state)
  62. if to_be_changed:
  63. module.exit_json(changed=True, msg="%s package(s) not in state %s" % (
  64. len(to_be_changed), state))
  65. else:
  66. module.exit_json(changed=False, msg="package(s) already in state %s" % state)
  67. def upgrade(module, paths, check_mode):
  68. '''
  69. returns: (updates_available, updates_successful)
  70. '''
  71. # Check for updates
  72. cmd = "%s -un" % paths['install']
  73. rc, sout, serr = module.run_command(cmd, check_rc=False)
  74. if sout:
  75. # packages for upgrade available
  76. if check_mode:
  77. return (True, False)
  78. # do upgrade
  79. cmd = "%s -uy" % paths['install']
  80. rc, sout, serr = module.run_command(cmd, check_rc=False)
  81. if rc == 0:
  82. return (True, True)
  83. else:
  84. module.fail_json(msg="could not upgrade packages", rc=rc, stdout=sout, stderr=serr)
  85. else:
  86. return (False, False)
  87. def ensure_packages_state(module, paths, pkgs, desired_state):
  88. '''
  89. pkgs: list of packages
  90. desired_state: desired state (present, latest, absent)
  91. returns: list of packages to be changed
  92. '''
  93. # which packages must change state
  94. pkgs2do = get_changed_packages(module, paths, pkgs, desired_state)
  95. if not pkgs2do:
  96. module.exit_json(msg='All packages in desired state')
  97. if desired_state in ['present', 'latest']:
  98. cmdtype = 'install'
  99. elif desired_state == 'absent':
  100. cmdtype = 'remove'
  101. cmd = '%s -y %s' % (paths[cmdtype], ' '.join(pkgs2do))
  102. rc, sout, serr = module.run_command(cmd, check_rc=False)
  103. if rc == 0:
  104. msg = '%s package' % len(pkgs2do)
  105. msg += '%s ' % len(pkgs2do) == 1 and '' or 's'
  106. if cmdtype == 'install':
  107. msg += 'installed'
  108. elif cmdtype == 'remove':
  109. msg += 'removed'
  110. module.exit_json(msg=msg, rc=rc, stdout=sout, stderr=serr)
  111. else:
  112. module.fail_json(msg="could not install/remove package(s)", rc=rc, stdout=sout, stderr=serr)
  113. def main():
  114. module = AnsibleModule(
  115. argument_spec = dict(
  116. name = dict(aliases=['pkg', 'package'], type='list'),
  117. state = dict(default='present', choices=['present', 'installed', "latest", 'absent', 'removed']),
  118. force = dict(default=False, type='bool'),
  119. upgrade = dict(default=False, type='bool'),
  120. update_cache = dict(default=False, aliases=['update-cache'], type='bool')
  121. ),
  122. required_one_of = [['name', 'update_cache', 'upgrade']],
  123. supports_check_mode = True)
  124. paths = {}
  125. paths['install'] = module.get_bin_path('xbps-install', True)
  126. paths['remove'] = module.get_bin_path('xbps-remove', True)
  127. paths['query'] = module.get_bin_path('xbps-query', True)
  128. p = module.params
  129. # normalize the state parameter
  130. if p['state'] in ['present', 'installed']:
  131. p['state'] = 'present'
  132. elif p['state'] in ['absent', 'removed']:
  133. p['state'] = 'absent'
  134. # do update if package name is "*"
  135. if p['name'] and p['name'][0] == '*' and p['state'] == 'latest':
  136. p['update'] = True
  137. p['name'] = []
  138. # sync repo index
  139. if p["update_cache"] and not module.check_mode:
  140. update_package_db(module, paths) # FIXME
  141. if not (p['name'] or p['upgrade']):
  142. module.exit_json(changed=True, msg='Updated the package master lists')
  143. if p['update_cache'] and module.check_mode and not (p['name'] or p['upgrade']):
  144. module.exit_json(changed=True, msg='Would have updated the package cache')
  145. # update/upgrade all installed packages
  146. if p['upgrade']:
  147. (upg_avail, upg_successful) = upgrade(module, paths, module.check_mode)
  148. if not p['name']: # upgrade is last action
  149. if upg_avail:
  150. if upg_successful:
  151. module.exit_json(changed=True, msg="all packages upgraded")
  152. else:
  153. if module.check_mode:
  154. module.exit_json(msg="no packages upgraded in check mode")
  155. # should never happen, "upgrade" function should exit module
  156. module.fail_json(msg="could not upgrade packages", rc=rc, stdout=sout, stderr=serr)
  157. else:
  158. module.exit_json(msg="all packages uptodate")
  159. if p['name']:
  160. if module.check_mode:
  161. check_packages(module, paths, p['name'], p['state']) # FIXME
  162. ensure_packages_state(module, paths, p['name'], p['state']) # FIXME
  163. # import module snippets
  164. from ansible.module_utils.basic import *
  165. if __name__ == "__main__":
  166. main()