]> TLD Linux GIT Repositories - packages/ansible.git/blob - poldek.py
- updated to 2.9.12
[packages/ansible.git] / poldek.py
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3
4 # Copyright: (c) 2019, Marcin Krol <hawk@tld-linux.org>
5 # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
6
7 from __future__ import absolute_import, division, print_function
8 __metaclass__ = type
9
10 ANSIBLE_METADATA = {'metadata_version': '1.0',
11                     'status': ['preview'],
12                     'supported_by': 'community'}
13
14 DOCUMENTATION = '''
15 ---
16 module: poldek
17 short_description: Manage packages with I(poldek)
18 description:
19     - Manage packages with the I(poldek) package manager, which is used by TLD Linux and PLD Linux
20 version_added: "1.0"
21 author:
22     - Marcin Krol <hawk@tld-linux.org>
23 options:
24     name:
25         description:
26             - Name or list of names of the package(s) or file(s) to install, upgrade, or remove.
27               Can't be used in combination with C(upgrade).
28         aliases: [ package, pkg ]
29
30     state:
31         description:
32             - Desired state of the package.
33         default: present
34         choices: [ absent, latest, present ]
35
36     extra_args:
37         description:
38             - Additional option to pass to poldek when enforcing C(state).
39         default:
40
41     update_cache:
42         description:
43             - Whether or not to refresh the master package lists.
44             - This can be run as part of a package installation or as a separate step.
45         default: no
46         type: bool
47         aliases: [ update-cache ]
48
49     update_cache_extra_args:
50         description:
51             - Additional option to pass to poldek when enforcing C(update_cache).
52         default:
53
54     upgrade:
55         description:
56             - Whether or not to upgrade the whole system.
57               Can't be used in combination with C(name).
58         default: no
59         type: bool
60
61     upgrade_extra_args:
62         description:
63             - Additional option to pass to poldek when enforcing C(upgrade).
64         default:
65 '''
66
67 RETURN = '''
68 packages:
69     description: a list of packages that have been changed
70     returned: when upgrade is set to yes
71     type: list
72     sample: [ package, other-package ]
73 '''
74
75 EXAMPLES = '''
76 - name: Install packages foo and bar
77   poldek:
78     name:
79       - foo
80       - bar
81     state: present
82
83 - name: Update package cache and upgrade package foo
84   poldek:
85     name: foo
86     state: latest
87     update_cache: yes
88
89 - name: Remove packages foo and bar
90   poldek:
91     name:
92       - foo
93       - bar
94     state: absent
95
96 - name: Update package cache only
97   poldek:
98     update_cache: yes
99
100 - name: Update package cache and upgrade all packages
101   poldek:
102     upgrade: yes
103     update_cache: yes
104 '''
105
106 import re
107
108 from ansible.module_utils.basic import AnsibleModule
109
110
111 def query_package(module, poldek_path, name):
112     """Query the package status in both the local system and the repository. Returns a boolean to indicate if the package is installed, a second
113     boolean to indicate if the package is up-to-date. Note: indexes must be up to date to ensure that poldek knows latest version of package.
114     """
115     lcmd = "%s -q --shcmd='ls -n --installed %s'" % (poldek_path, name)
116     lrc, lstdout, lstderr = module.run_command(lcmd, check_rc=False)
117     rcmd = "%s -q --shcmd='ls -n --installed --upgradeable %s'" % (poldek_path, name)
118     rrc, rstdout, rstderr = module.run_command(rcmd, check_rc=False)
119     if lrc != 0 or rrc != 0:
120         return False, False
121
122     pkg_latest = False
123     if rstdout == "":
124         return True, True
125     else:
126         return True, False
127
128
129 def update_package_db(module, poldek_path):
130     if module.params['force']:
131         module.params["update_cache_extra_args"] += " --upa"
132
133     cmd = "%s --noask --up %s" % (poldek_path, module.params["update_cache_extra_args"])
134     rc, stdout, stderr = module.run_command(cmd, check_rc=False)
135
136     if rc == 0:
137         return True
138     else:
139         module.fail_json(msg="error updating package database")
140
141
142 def upgrade(module, poldek_path):
143     cmdupgrade = "%s -v --noask --upgrade-dist %s" % (poldek_path, module.params["upgrade_extra_args"])
144     cmdupgradeable = "%s -q --shcmd='ls --upgradeable --qf=\"%%{NAME}-%%{VERSION}-%%{RELEASE}\n\"' %s" % (poldek_path, module.params["upgrade_extra_args"])
145     rc, stdout, stderr = module.run_command(cmdupgradeable, check_rc=False)
146
147     packages = stdout.split('\n')[:-1]
148     if stdout == "":
149         module.exit_json(changed=False, msg='Nothing to upgrade', packages=packages, stdout=stdout, stderr=stderr, rc=rc)
150     else:
151         if module.check_mode:
152             module.exit_json(changed=True, msg="%s package(s) would be upgraded" % (len(packages)), packages=packages, stdout=stdout, stderr=stderr, rc=rc)
153         rc, stdout, stderr = module.run_command(cmdupgrade, check_rc=False)
154         if rc == 0:
155             module.exit_json(changed=True, msg="%s package(s) upgraded" % (len(packages)), packages=packages, stdout=stdout, stderr=stderr, rc=rc)
156         else:
157             module.fail_json(msg="Error while upgrading packages", stdout=stdout, stderr=stderr, rc=rc)
158
159
160 def remove_packages(module, poldek_path, packages):
161     if module.params["force"]:
162         module.params["extra_args"] += " --force --nodeps"
163
164     remove_c = 0
165     out = ""
166     err = ""
167
168     for package in packages:
169         installed, updated = query_package(module, poldek_path, package)
170         if not installed:
171             continue
172
173         cmd = "%s -v --noask --erase %s %s" % (poldek_path, module.params["extra_args"], package)
174         rc, stdout, stderr = module.run_command(cmd, check_rc=False)
175
176         out = out + stdout
177         err = err + stderr
178
179         if rc != 0:
180             module.fail_json(msg="failed to remove %s" % (package), stdout=out, stderr=err, rc=rc)
181
182         remove_c += 1
183
184     if remove_c > 0:
185         module.exit_json(changed=True, msg="removed %s package(s)" % (remove_c), packages=packages, stdout=out, stderr=err, rc=0)
186
187     module.exit_json(changed=False, msg="package(s) already absent", packages=packages, stdout=out, stderr=err, rc=0)
188
189
190 def install_packages(module, poldek_path, state, packages):
191     if module.params["force"]:
192         module.params["extra_args"] += " --force --nodeps"
193
194     install_c = 0
195     out = ""
196     err = ""
197
198     for package in packages:
199         installed, updated = query_package(module, poldek_path, package)
200         if installed and (state == 'present' or (state == 'latest' and updated)):
201             continue
202
203         cmd = "%s -v --noask --upgrade %s %s" % (poldek_path, module.params["extra_args"], package)
204         rc, stdout, stderr = module.run_command(cmd, check_rc=False)
205
206         out = out + stdout
207         err = err + stderr
208
209         if rc != 0:
210             module.fail_json(msg="failed to install %s" % (package), stdout=out, stderr=err, rc=rc)
211
212         install_c += 1
213
214     if install_c > 0:
215         module.exit_json(changed=True, msg="installed %s package(s)" % (install_c), packages=packages, stdout=out, stderr=err, rc=0)
216
217     module.exit_json(changed=False, msg="package(s) already installed", packages=packages, stdout=out, stderr=err, rc=0)
218
219
220 def check_packages(module, poldek_path, packages, state):
221     would_be_changed = []
222
223     for package in packages:
224         installed, updated = query_package(module, poldek_path, package)
225         if ((state in ["present", "latest"] and not installed) or
226                 (state == "absent" and installed) or
227                 (state == "latest" and not updated)):
228             would_be_changed.append(package)
229
230     if state == "absent":
231         state = "removed"
232     if state == "present" or state == "latest":
233         state = "installed"
234
235     if would_be_changed:
236         module.exit_json(changed=True, msg="%s package(s) would be %s" % (
237             len(would_be_changed), state))
238     else:
239         module.exit_json(changed=False, msg="package(s) already %s" % state)
240
241
242 def main():
243     module = AnsibleModule(
244         argument_spec=dict(
245             name=dict(type='list', aliases=['pkg', 'package']),
246             state=dict(type='str', default='present', choices=['present', 'installed', 'latest', 'absent', 'removed']),
247             extra_args=dict(type='str', default=''),
248             upgrade=dict(type='bool', default=False),
249             upgrade_extra_args=dict(type='str', default=''),
250             update_cache=dict(type='bool', default=False, aliases=['update-cache']),
251             update_cache_extra_args=dict(type='str', default=''),
252             force=dict(type='bool', default=False),
253         ),
254         required_one_of=[['name', 'update_cache', 'upgrade']],
255         mutually_exclusive=[['name', 'upgrade']],
256         supports_check_mode=True,
257     )
258
259     poldek_path = module.get_bin_path('poldek', True)
260
261     p = module.params
262
263     if p['state'] in ['present', 'installed']:
264         p['state'] = 'present'
265     elif p['state'] in ['absent', 'removed']:
266         p['state'] = 'absent'
267
268     if p["update_cache"] and not module.check_mode:
269         update_package_db(module, poldek_path)
270         if not (p['name'] or p['upgrade']):
271             module.exit_json(changed=True, msg='Updated package database')
272
273     if p['update_cache'] and module.check_mode and not (p['name'] or p['upgrade']):
274         module.exit_json(changed=True, msg='Would have updated package database')
275
276     if p['upgrade']:
277         upgrade(module, poldek_path)
278
279     if p['name']:
280         pkgs = p['name']
281
282         if module.check_mode:
283             check_packages(module, poldek_path, pkgs, p['state'])
284
285         if p['state'] in ['present', 'latest']:
286             install_packages(module, poldek_path, p['state'], pkgs)
287         elif p['state'] == 'absent':
288             remove_packages(module, poldek_path, pkgs)
289     else:
290         module.exit_json(changed=False, msg="No package specified to work on")
291
292
293 if __name__ == "__main__":
294     main()