Repository: ansible-collections/community.general

Issue:
launchd plugin module broken on user-level services
##### SUMMARY
`community.general.launchd` module looks for user's LaunchAgents, but fails to expand ~ when opening their plist files.


##### ISSUE TYPE
- Bug Report

##### COMPONENT NAME
launchd

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes -->
```
ansible 2.9.6
  config file = /home/user/X/ansible/ansible.cfg
  configured module search path = ['/home/user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/user/.local/pipx/venvs/ansible/lib/python3.6/site-packages/ansible
  executable location = /home/user/.local/bin/ansible
  python version = 3.6.9 (default, Jul 17 2020, 12:50:27) [GCC 8.4.0]
```

##### CONFIGURATION
```paste below
ANSIBLE_PIPELINING(/home/user/X/ansible/ansible.cfg) = True
CACHE_PLUGIN(/home/user/X/ansible/ansible.cfg) = jsonfile
CACHE_PLUGIN_CONNECTION(/home/user/X/ansible/ansible.cfg) = .fact_cache
DEFAULT_FORCE_HANDLERS(/home/user/X/ansible/ansible.cfg) = True
DEFAULT_GATHERING(/home/user/X/ansible/ansible.cfg) = smart
DEFAULT_HOST_LIST(/home/user/X/ansible/ansible.cfg) = ['/home/user/X/ansible/hosts']
DEFAULT_REMOTE_USER(/home/user/X/ansible/ansible.cfg) = root
DEFAULT_ROLES_PATH(/home/user/X/ansible/ansible.cfg) = ['/home/user/X/ansible/.galaxy_roles']
DIFF_ALWAYS(/home/user/X/ansible/ansible.cfg) = True
RETRY_FILES_ENABLED(/home/user/X/ansible/ansible.cfg) = False
```

##### OS / ENVIRONMENT
MacOS


##### STEPS TO REPRODUCE
```
$ ansible mac-machine -m'community.general.launchd' -a "name=com.company.myservice state=restarted" -u myuser --become-user myuser
```


##### EXPECTED RESULTS
The service is restarted.


##### ACTUAL RESULTS
An error is thrown:
```paste below
File \"/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plistlib.py\", line 75, in readPlist
    pathOrFile = open(pathOrFile)
IOError: [Errno 2] No such file or directory: '~/Library/LaunchAgents/com.company.myservice.plist'
```


Discussion:
Files identified in the description:
None

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
It's enough to expand the user-level path before finding matching plist files:
```diff
--- /tmp/launchd.py	2020-09-16 17:20:17.298359891 +0200
+++ /home/user/.ansible/collections/ansible_collections/community/general/plugins/modules/system/launchd.py	2020-09-16 17:20:24.550332655 +0200
@@ -153,18 +153,18 @@
     def __find_service_plist(self, service_name):
         """Finds the plist file associated with a service"""
 
         launchd_paths = [
-            '~/Library/LaunchAgents',
+            os.path.expanduser('~/Library/LaunchAgents'),
             '/Library/LaunchAgents',
             '/Library/LaunchDaemons',
             '/System/Library/LaunchAgents',
             '/System/Library/LaunchDaemons'
         ]
 
         for path in launchd_paths:
             try:
-                files = os.listdir(os.path.expanduser(path))
+                files = os.listdir(path)
             except OSError:
                 continue
 
             filename = '%s.plist' % service_name
```
Result:
```
mac-machine | CHANGED => {
    "changed": true,
    "name": "com.company.myservice",
    "status": {
        "current_pid": "4141",
        "current_state": "started",
        "error": "",
        "previous_pid": "1161",
        "previous_state": "started",
        "status_code": "0"
    }
}
```
Please stop prefixing the module name under `COMPONENTS`. That confuses the bot (please see https://github.com/ansible-collections/community.general/issues/896#issuecomment-693494622).
Files identified in the description:
* [`plugins/modules/system/launchd.py`](https://github.com/ansible-collections/community.general/blob/master/plugins/modules/system/launchd.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @MorrisA @bcoca @d-little @flynn1973 @gforster @kairoaraujo @martinm82 @marvin-sinister @mator @molekuul @ramooncamacho @wtcross
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
@tomaszn since you identified the problem, would you mind creating a PR to fix this (including a [changelog fragment](https://docs.ansible.com/ansible/devel/community/development_process.html#changelogs-how-to))? Thanks!
@tomaszn have you tried this patch: https://github.com/ansible/ansible/pull/45541#issuecomment-583784873
@martinm82 that link does not seem to point anywhere.
Now it should work 
Yes, it does. That patch is equivalent to https://github.com/ansible-collections/community.general/issues/896#issuecomment-693495097

Resolving patch:
diff --git a/plugins/modules/system/launchd.py b/plugins/modules/system/launchd.py
--- a/plugins/modules/system/launchd.py
+++ b/plugins/modules/system/launchd.py
@@ -154,7 +154,7 @@ def __find_service_plist(self, service_name):
         """Finds the plist file associated with a service"""
 
         launchd_paths = [
-            '~/Library/LaunchAgents',
+            os.path.expanduser('~/Library/LaunchAgents'),
             '/Library/LaunchAgents',
             '/Library/LaunchDaemons',
             '/System/Library/LaunchAgents',
@@ -163,7 +163,7 @@ def __find_service_plist(self, service_name):
 
         for path in launchd_paths:
             try:
-                files = os.listdir(os.path.expanduser(path))
+                files = os.listdir(path)
             except OSError:
                 continue
 


Test patch: