Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve "changed" count flag #41

Merged
merged 11 commits into from
Jul 15, 2024
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication"
"License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication",
]

[tool.poetry.dependencies]
Expand Down
50 changes: 42 additions & 8 deletions stow
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,11 @@ from ansible.module_utils.basic import AnsibleModule


STOW_CONFLICTS_MESSAGE_REGEX_BY_VERSION = {
'2.3.1': r'^\* existing target is neither a link nor a directory: (?P<target_path>.+)$',
'2.3.1': r'^\* existing target is neither a link nor a directory: (?P<link_path>.+)$',
# pylint: disable-next=line-too-long
'2.4.0': r'^\* cannot stow (?P<link_path>.+) over existing target (?P<target_path>.+) since neither a link nor a directory and --adopt not specified$',
'2.4.0': r'^\* cannot stow (?P<package_path>.+) over existing target (?P<link_path>.+) since neither a link nor a directory and --adopt not specified$',
}


SUPPORTED_STOW_VERSIONS = list(STOW_CONFLICTS_MESSAGE_REGEX_BY_VERSION.keys())


Expand Down Expand Up @@ -171,14 +170,39 @@ def stow_has_conflicts(stow_version, module, package, cmd):
conflict_match = conflict_re.match(sel.strip())

if conflict_match:
conflicts.append(os.path.join(params['target'], conflict_match.group('target_path')))
conflicts.append(os.path.join(params['target'], conflict_match.group('link_path')))

conff = ', '.join(f'"{f}"' for f in conflicts)
msg = f'unable to stow package "{package}" to "{params["target"]}"; conflicted files: {conff}'

return {'recoverable': True, 'message': msg, 'files': conflicts}


def has_stow_changed_links(stow_output):
if stow_output.strip() == '':
return 0

n_linked = set()
link_re = re.compile(r'^LINK: (?P<link_path>.+) => (?P<package_path>.+)(?P<reverts> \(reverts previous action\))?$')

n_unlinked = set()
unlink_re = re.compile(r'^UNLINK: (?P<link_path>.+)$')

for sel in stow_output.split('\n'):
sel = sel.strip()

link_match = link_re.match(sel)
if link_match:
n_linked.add(link_match.group('link_path'))
continue

unlink_match = unlink_re.match(sel)
if unlink_match:
n_unlinked.add(unlink_match.group('link_path'))

return n_linked != n_unlinked


def stow(stow_version, module, package, state):
"""Perform stow on a package against the filesystem.

Expand Down Expand Up @@ -230,17 +254,27 @@ def stow(stow_version, module, package, state):
msg = f'execution of command "{cmd}" failed with error code {rc_}; output: "{se_}"'
return {'error': True, 'message': msg}

return {'error': False, 'changed': se_ != ''}
return {'error': False, 'changed': has_stow_changed_links(se_)}


def main():
'''The module main routine.'''

module = AnsibleModule(
argument_spec={
'dir': {'required': True, 'type': 'str'},
'package': {'required': True, 'type': 'list'},
'target': {'required': False, 'type': 'str', 'default': os.environ.get('HOME')},
'dir': {
'required': True,
'type': 'str',
},
'package': {
'required': True,
'type': 'list',
},
'target': {
'required': False,
'type': 'str',
'default': os.environ.get('HOME'),
},
'state': {
'required': True,
'type': 'str',
Expand Down
3 changes: 2 additions & 1 deletion tests/ansible.cfg
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[defaults]

interpreter_python=auto
interpreter_python = auto_silent
stdout_callback = debug
8 changes: 7 additions & 1 deletion tests/stow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,10 @@
stow:
state: '{{ state }}'
package: foo
dir: '$HOME/package'
dir: '$HOME/package'
register: stowt

- name: 'fail if "changed" is greater than 0 when nothing has changed'
fail:
msg: 'task should not have changed anything'
when: stowt is changed and fail_if_changed == 'yes'
8 changes: 5 additions & 3 deletions tests/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
set -e

run_playbook() {
ansible-playbook -i hosts stow.yml --extra-vars "state=$1" -v
ansible-playbook -i hosts stow.yml --extra-vars "state=$1 fail_if_changed=$2" -v
}

# create the library directory and copy the module
mkdir library
mkdir -p library
cp ../stow library

# move the package to the home directory
mv package ~
cp -r package ~

# run the playbook and stow the package
figlet "state: present"
Expand All @@ -34,6 +34,8 @@ test -h "$HOME/.config/foo" && exit 1
figlet "state: latest"
run_playbook "present"
run_playbook "latest"
run_playbook "latest" "yes"
run_playbook "latest" "yes"
run_playbook "absent"

# create a file that should conflict with the package
Expand Down
Loading