We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[bug] SystemPackageTool doesn't correctly detect when apt packages are installed
**Summary**
`SystemPackageTool` uses `dpkg -s <package_name>` to detect whether a package is installed via apt. This is not a sufficient check, and fails to detect that a package has been uninstalled.

Line where the issue is:
https://github.com/conan-io/conan/blob/d508c44031542c95051d6036047ce156b935e8bc/conans/client/tools/system_pm.py#L134

**Reproduction**
On a fresh Ubuntu 16.04 box without the `libudev-dev` package installed, `dpkg -s` gives this behaviour:
```bash
vagrant@ubuntu-xenial:~$ dpkg -s libudev-dev
dpkg-query: package 'libudev-dev' is not installed and no information is available
Use dpkg --info (= dpkg-deb --info) to examine archive files,
and dpkg --contents (= dpkg-deb --contents) to list their contents.

vagrant@ubuntu-xenial:~$ echo $?
1
```
The return value is `1`, so `SystemPackageTool` correctly detects that the package is not installed.

If the package is installed with `sudo apt-get install libudev-dev` then `dpkg -s` gives this behaviour:
```bash
vagrant@ubuntu-xenial:~$ dpkg -s libudev-dev
Package: libudev-dev
Status: install ok installed
Priority: optional
Section: libdevel
Installed-Size: 527
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Architecture: amd64
Multi-Arch: same
Source: systemd
Version: 229-4ubuntu21.2
Depends: libacl1 (>= 2.2.51-8), libblkid1 (>= 2.19.1), libc6 (>= 2.17), libkmod2 (>= 5~), libselinux1 (>= 2.0.65), libudev1 (= 229-4ubuntu21.2)
Pre-Depends: dpkg (>= 1.17.14)
Description: libudev development files
 This package contains the files needed for developing applications that
 use libudev.
Homepage: http://www.freedesktop.org/wiki/Software/systemd
Original-Maintainer: Debian systemd Maintainers <pkg-systemd-maintainers@lists.alioth.debian.org>

vagrant@ubuntu-xenial:~$ echo $?
0
```
Note the return code is `0`, so `SystemPackageTool` works correctly here, too.

However, if the package is uninstalled with `sudo apt-get remove libudev-dev` then `dpkg -s` still returns an exit code of 0:
```bash
vagrant@ubuntu-xenial:~$ dpkg -s libudev-dev
Package: libudev-dev
Status: deinstall ok config-files
Priority: optional
Section: libdevel
Installed-Size: 527
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Architecture: amd64
Multi-Arch: same
Source: systemd
Version: 229-4ubuntu21.2
Config-Version: 229-4ubuntu21.2
Depends: libacl1 (>= 2.2.51-8), libblkid1 (>= 2.19.1), libc6 (>= 2.17), libkmod2 (>= 5~), libselinux1 (>= 2.0.65), libudev1 (= 229-4ubuntu21.2)
Pre-Depends: dpkg (>= 1.17.14)
Description: libudev development files
 This package contains the files needed for developing applications that
 use libudev.
Homepage: http://www.freedesktop.org/wiki/Software/systemd
Original-Maintainer: Debian systemd Maintainers <pkg-systemd-maintainers@lists.alioth.debian.org>

vagrant@ubuntu-xenial:~$ echo $?
0
```

Note the different values for the `Status` line.

**Suggested Fix**
There are discussions of the best ways to script a check for package installation here:
https://stackoverflow.com/questions/1298066/check-if-a-package-is-installed-and-then-install-it-if-its-not
https://askubuntu.com/questions/319307/reliably-check-if-a-package-is-installed-or-not?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa

Those discussions indicate that the preferred way of checking is to use:
```bash
dpkg-query -W -f='${Status}' <package_name> | grep -q "ok installed"
```
This will return `0` only if the package is installed.

I will raise a PR containing the suggested fix.

**Environment**
Conan 1.4.1
Ubuntu 16.04

- [x] I've read the [CONTRIBUTING guide](https://raw.githubusercontent.com/conan-io/conan/develop/.github/CONTRIBUTING.md).
- [x] I've specified the Conan version, operating system version and any tool that can be relevant.
- [x] I've explained the steps to reproduce the error or the motivation/use case of the question/suggestion.



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `conans/client/tools/system_pm.py`
Content:
```
1 import os
2 from conans.client.runner import ConanRunner
3 from conans.client.tools.oss import OSInfo
4 from conans.errors import ConanException
5 from conans.util.env_reader import get_env
6 
7 _global_output = None
8 
9 
10 class SystemPackageTool(object):
11 
12     def __init__(self, runner=None, os_info=None, tool=None, recommends=False):
13         os_info = os_info or OSInfo()
14         self._is_up_to_date = False
15         self._tool = tool or self._create_tool(os_info)
16         self._tool._sudo_str = "sudo " if self._is_sudo_enabled() else ""
17         self._tool._runner = runner or ConanRunner()
18         self._tool._recommends = recommends
19 
20     @staticmethod
21     def _is_sudo_enabled():
22         if "CONAN_SYSREQUIRES_SUDO" not in os.environ:
23             if os.name == 'posix' and os.geteuid() == 0:
24                 return False
25             if os.name == 'nt':
26                 return False
27         return get_env("CONAN_SYSREQUIRES_SUDO", True)
28 
29     @staticmethod
30     def _get_sysrequire_mode():
31         allowed_modes = ("enabled", "verify", "disabled")
32         mode = get_env("CONAN_SYSREQUIRES_MODE", "enabled")
33         mode_lower = mode.lower()
34         if mode_lower not in allowed_modes:
35             raise ConanException("CONAN_SYSREQUIRES_MODE=%s is not allowed, allowed modes=%r" % (mode, allowed_modes))
36         return mode_lower
37 
38     @staticmethod
39     def _create_tool(os_info):
40         if os_info.with_apt:
41             return AptTool()
42         elif os_info.with_yum:
43             return YumTool()
44         elif os_info.with_pacman:
45             return PacManTool()
46         elif os_info.is_macos:
47             return BrewTool()
48         elif os_info.is_freebsd:
49             return PkgTool()
50         elif os_info.is_solaris:
51             return PkgUtilTool()
52         elif os_info.with_zypper:
53             return ZypperTool()
54         else:
55             return NullTool()
56 
57     def update(self):
58         """
59             Get the system package tool update command
60         """
61         mode = self._get_sysrequire_mode()
62         if mode in ("disabled", "verify"):
63             _global_output.info("Not updating system_requirements. CONAN_SYSREQUIRES_MODE=%s" % mode)
64             return
65         self._is_up_to_date = True
66         self._tool.update()
67 
68     def install(self, packages, update=True, force=False):
69         """
70             Get the system package tool install command.
71         '"""
72         packages = [packages] if isinstance(packages, str) else list(packages)
73 
74         mode = self._get_sysrequire_mode()
75 
76         if mode in ("verify", "disabled"):
77             # Report to output packages need to be installed
78             if mode == "disabled":
79                 _global_output.info("The following packages need to be installed:\n %s" % "\n".join(packages))
80                 return
81 
82             if mode == "verify" and not self._installed(packages):
83                 _global_output.error("The following packages need to be installed:\n %s" % "\n".join(packages))
84                 raise ConanException(
85                     "Aborted due to CONAN_SYSREQUIRES_MODE=%s. Some system packages need to be installed" % mode
86                 )
87 
88         if not force and self._installed(packages):
89             return
90 
91         # From here system packages can be updated/modified
92         if update and not self._is_up_to_date:
93             self.update()
94         self._install_any(packages)
95 
96     def _installed(self, packages):
97         if not packages:
98             return True
99 
100         for pkg in packages:
101             if self._tool.installed(pkg):
102                 _global_output.info("Package already installed: %s" % pkg)
103                 return True
104         return False
105 
106     def _install_any(self, packages):
107         if len(packages) == 1:
108             return self._tool.install(packages[0])
109         for pkg in packages:
110             try:
111                 return self._tool.install(pkg)
112             except ConanException:
113                 pass
114         raise ConanException("Could not install any of %s" % packages)
115 
116 
117 class NullTool(object):
118     def update(self):
119         pass
120 
121     def install(self, package_name):
122         _global_output.warn("Only available for linux with apt-get, yum, or pacman or OSX with brew or "
123                             "FreeBSD with pkg or Solaris with pkgutil")
124 
125     def installed(self, package_name):
126         return False
127 
128 
129 class AptTool(object):
130     def update(self):
131         _run(self._runner, "%sapt-get update" % self._sudo_str)
132 
133     def install(self, package_name):
134         recommends_str = '' if self._recommends else '--no-install-recommends '
135         _run(self._runner, "%sapt-get install -y %s%s" % (self._sudo_str, recommends_str, package_name))
136 
137     def installed(self, package_name):
138         exit_code = self._runner("dpkg -s %s" % package_name, None)
139         return exit_code == 0
140 
141 
142 class YumTool(object):
143     def update(self):
144         _run(self._runner, "%syum update" % self._sudo_str, accepted_returns=[0, 100])
145 
146     def install(self, package_name):
147         _run(self._runner, "%syum install -y %s" % (self._sudo_str, package_name))
148 
149     def installed(self, package_name):
150         exit_code = self._runner("rpm -q %s" % package_name, None)
151         return exit_code == 0
152 
153 
154 class BrewTool(object):
155     def update(self):
156         _run(self._runner, "brew update")
157 
158     def install(self, package_name):
159         _run(self._runner, "brew install %s" % package_name)
160 
161     def installed(self, package_name):
162         exit_code = self._runner('test -n "$(brew ls --versions %s)"' % package_name, None)
163         return exit_code == 0
164 
165 
166 class PkgTool(object):
167     def update(self):
168         _run(self._runner, "%spkg update" % self._sudo_str)
169 
170     def install(self, package_name):
171         _run(self._runner, "%spkg install -y %s" % (self._sudo_str, package_name))
172 
173     def installed(self, package_name):
174         exit_code = self._runner("pkg info %s" % package_name, None)
175         return exit_code == 0
176 
177 
178 class PkgUtilTool(object):
179     def update(self):
180         _run(self._runner, "%spkgutil --catalog" % self._sudo_str)
181 
182     def install(self, package_name):
183         _run(self._runner, "%spkgutil --install --yes %s" % (self._sudo_str, package_name))
184 
185     def installed(self, package_name):
186         exit_code = self._runner('test -n "`pkgutil --list %s`"' % package_name, None)
187         return exit_code == 0
188 
189 
190 class ChocolateyTool(object):
191     def update(self):
192         _run(self._runner, "choco outdated")
193 
194     def install(self, package_name):
195         _run(self._runner, "choco install --yes %s" % package_name)
196 
197     def installed(self, package_name):
198         exit_code = self._runner('choco search --local-only --exact %s | '
199                                  'findstr /c:"1 packages installed."' % package_name, None)
200         return exit_code == 0
201 
202 
203 class PacManTool(object):
204     def update(self):
205         _run(self._runner, "%spacman -Syyu --noconfirm" % self._sudo_str)
206 
207     def install(self, package_name):
208         _run(self._runner, "%spacman -S --noconfirm %s" % (self._sudo_str, package_name))
209 
210     def installed(self, package_name):
211         exit_code = self._runner("pacman -Qi %s" % package_name, None)
212         return exit_code == 0
213 
214 
215 class ZypperTool(object):
216     def update(self):
217         _run(self._runner, "%szypper --non-interactive ref" % self._sudo_str)
218 
219     def install(self, package_name):
220         _run(self._runner, "%szypper --non-interactive in %s" % (self._sudo_str, package_name))
221 
222     def installed(self, package_name):
223         exit_code = self._runner("rpm -q %s" % package_name, None)
224         return exit_code == 0
225 
226 
227 def _run(runner, command, accepted_returns=None):
228     accepted_returns = accepted_returns or [0, ]
229     _global_output.info("Running: %s" % command)
230     if runner(command, True) not in accepted_returns:
231         raise ConanException("Command '%s' failed" % command)
232
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/conans/client/tools/system_pm.py b/conans/client/tools/system_pm.py
--- a/conans/client/tools/system_pm.py
+++ b/conans/client/tools/system_pm.py
@@ -135,7 +135,7 @@
         _run(self._runner, "%sapt-get install -y %s%s" % (self._sudo_str, recommends_str, package_name))
 
     def installed(self, package_name):
-        exit_code = self._runner("dpkg -s %s" % package_name, None)
+        exit_code = self._runner("dpkg-query -W -f='${Status}' %s | grep -q \"ok installed\"" % package_name, None)
         return exit_code == 0

{"golden_diff": "diff --git a/conans/client/tools/system_pm.py b/conans/client/tools/system_pm.py\n--- a/conans/client/tools/system_pm.py\n+++ b/conans/client/tools/system_pm.py\n@@ -135,7 +135,7 @@\n         _run(self._runner, \"%sapt-get install -y %s%s\" % (self._sudo_str, recommends_str, package_name))\n \n     def installed(self, package_name):\n-        exit_code = self._runner(\"dpkg -s %s\" % package_name, None)\n+        exit_code = self._runner(\"dpkg-query -W -f='${Status}' %s | grep -q \\\"ok installed\\\"\" % package_name, None)\n         return exit_code == 0\n", "issue": "[bug] SystemPackageTool doesn't correctly detect when apt packages are installed\n**Summary**\r\n`SystemPackageTool` uses `dpkg -s <package_name>` to detect whether a package is installed via apt. This is not a sufficient check, and fails to detect that a package has been uninstalled.\r\n\r\nLine where the issue is:\r\nhttps://github.com/conan-io/conan/blob/d508c44031542c95051d6036047ce156b935e8bc/conans/client/tools/system_pm.py#L134\r\n\r\n**Reproduction**\r\nOn a fresh Ubuntu 16.04 box without the `libudev-dev` package installed, `dpkg -s` gives this behaviour:\r\n```bash\r\nvagrant@ubuntu-xenial:~$ dpkg -s libudev-dev\r\ndpkg-query: package 'libudev-dev' is not installed and no information is available\r\nUse dpkg --info (= dpkg-deb --info) to examine archive files,\r\nand dpkg --contents (= dpkg-deb --contents) to list their contents.\r\n\r\nvagrant@ubuntu-xenial:~$ echo $?\r\n1\r\n```\r\nThe return value is `1`, so `SystemPackageTool` correctly detects that the package is not installed.\r\n\r\nIf the package is installed with `sudo apt-get install libudev-dev` then `dpkg -s` gives this behaviour:\r\n```bash\r\nvagrant@ubuntu-xenial:~$ dpkg -s libudev-dev\r\nPackage: libudev-dev\r\nStatus: install ok installed\r\nPriority: optional\r\nSection: libdevel\r\nInstalled-Size: 527\r\nMaintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>\r\nArchitecture: amd64\r\nMulti-Arch: same\r\nSource: systemd\r\nVersion: 229-4ubuntu21.2\r\nDepends: libacl1 (>= 2.2.51-8), libblkid1 (>= 2.19.1), libc6 (>= 2.17), libkmod2 (>= 5~), libselinux1 (>= 2.0.65), libudev1 (= 229-4ubuntu21.2)\r\nPre-Depends: dpkg (>= 1.17.14)\r\nDescription: libudev development files\r\n This package contains the files needed for developing applications that\r\n use libudev.\r\nHomepage: http://www.freedesktop.org/wiki/Software/systemd\r\nOriginal-Maintainer: Debian systemd Maintainers <pkg-systemd-maintainers@lists.alioth.debian.org>\r\n\r\nvagrant@ubuntu-xenial:~$ echo $?\r\n0\r\n```\r\nNote the return code is `0`, so `SystemPackageTool` works correctly here, too.\r\n\r\nHowever, if the package is uninstalled with `sudo apt-get remove libudev-dev` then `dpkg -s` still returns an exit code of 0:\r\n```bash\r\nvagrant@ubuntu-xenial:~$ dpkg -s libudev-dev\r\nPackage: libudev-dev\r\nStatus: deinstall ok config-files\r\nPriority: optional\r\nSection: libdevel\r\nInstalled-Size: 527\r\nMaintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>\r\nArchitecture: amd64\r\nMulti-Arch: same\r\nSource: systemd\r\nVersion: 229-4ubuntu21.2\r\nConfig-Version: 229-4ubuntu21.2\r\nDepends: libacl1 (>= 2.2.51-8), libblkid1 (>= 2.19.1), libc6 (>= 2.17), libkmod2 (>= 5~), libselinux1 (>= 2.0.65), libudev1 (= 229-4ubuntu21.2)\r\nPre-Depends: dpkg (>= 1.17.14)\r\nDescription: libudev development files\r\n This package contains the files needed for developing applications that\r\n use libudev.\r\nHomepage: http://www.freedesktop.org/wiki/Software/systemd\r\nOriginal-Maintainer: Debian systemd Maintainers <pkg-systemd-maintainers@lists.alioth.debian.org>\r\n\r\nvagrant@ubuntu-xenial:~$ echo $?\r\n0\r\n```\r\n\r\nNote the different values for the `Status` line.\r\n\r\n**Suggested Fix**\r\nThere are discussions of the best ways to script a check for package installation here:\r\nhttps://stackoverflow.com/questions/1298066/check-if-a-package-is-installed-and-then-install-it-if-its-not\r\nhttps://askubuntu.com/questions/319307/reliably-check-if-a-package-is-installed-or-not?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa\r\n\r\nThose discussions indicate that the preferred way of checking is to use:\r\n```bash\r\ndpkg-query -W -f='${Status}' <package_name> | grep -q \"ok installed\"\r\n```\r\nThis will return `0` only if the package is installed.\r\n\r\nI will raise a PR containing the suggested fix.\r\n\r\n**Environment**\r\nConan 1.4.1\r\nUbuntu 16.04\r\n\r\n- [x] I've read the [CONTRIBUTING guide](https://raw.githubusercontent.com/conan-io/conan/develop/.github/CONTRIBUTING.md).\r\n- [x] I've specified the Conan version, operating system version and any tool that can be relevant.\r\n- [x] I've explained the steps to reproduce the error or the motivation/use case of the question/suggestion.\r\n\r\n\n", "before_files": [{"content": "import os\nfrom conans.client.runner import ConanRunner\nfrom conans.client.tools.oss import OSInfo\nfrom conans.errors import ConanException\nfrom conans.util.env_reader import get_env\n\n_global_output = None\n\n\nclass SystemPackageTool(object):\n\n    def __init__(self, runner=None, os_info=None, tool=None, recommends=False):\n        os_info = os_info or OSInfo()\n        self._is_up_to_date = False\n        self._tool = tool or self._create_tool(os_info)\n        self._tool._sudo_str = \"sudo \" if self._is_sudo_enabled() else \"\"\n        self._tool._runner = runner or ConanRunner()\n        self._tool._recommends = recommends\n\n    @staticmethod\n    def _is_sudo_enabled():\n        if \"CONAN_SYSREQUIRES_SUDO\" not in os.environ:\n            if os.name == 'posix' and os.geteuid() == 0:\n                return False\n            if os.name == 'nt':\n                return False\n        return get_env(\"CONAN_SYSREQUIRES_SUDO\", True)\n\n    @staticmethod\n    def _get_sysrequire_mode():\n        allowed_modes = (\"enabled\", \"verify\", \"disabled\")\n        mode = get_env(\"CONAN_SYSREQUIRES_MODE\", \"enabled\")\n        mode_lower = mode.lower()\n        if mode_lower not in allowed_modes:\n            raise ConanException(\"CONAN_SYSREQUIRES_MODE=%s is not allowed, allowed modes=%r\" % (mode, allowed_modes))\n        return mode_lower\n\n    @staticmethod\n    def _create_tool(os_info):\n        if os_info.with_apt:\n            return AptTool()\n        elif os_info.with_yum:\n            return YumTool()\n        elif os_info.with_pacman:\n            return PacManTool()\n        elif os_info.is_macos:\n            return BrewTool()\n        elif os_info.is_freebsd:\n            return PkgTool()\n        elif os_info.is_solaris:\n            return PkgUtilTool()\n        elif os_info.with_zypper:\n            return ZypperTool()\n        else:\n            return NullTool()\n\n    def update(self):\n        \"\"\"\n            Get the system package tool update command\n        \"\"\"\n        mode = self._get_sysrequire_mode()\n        if mode in (\"disabled\", \"verify\"):\n            _global_output.info(\"Not updating system_requirements. CONAN_SYSREQUIRES_MODE=%s\" % mode)\n            return\n        self._is_up_to_date = True\n        self._tool.update()\n\n    def install(self, packages, update=True, force=False):\n        \"\"\"\n            Get the system package tool install command.\n        '\"\"\"\n        packages = [packages] if isinstance(packages, str) else list(packages)\n\n        mode = self._get_sysrequire_mode()\n\n        if mode in (\"verify\", \"disabled\"):\n            # Report to output packages need to be installed\n            if mode == \"disabled\":\n                _global_output.info(\"The following packages need to be installed:\\n %s\" % \"\\n\".join(packages))\n                return\n\n            if mode == \"verify\" and not self._installed(packages):\n                _global_output.error(\"The following packages need to be installed:\\n %s\" % \"\\n\".join(packages))\n                raise ConanException(\n                    \"Aborted due to CONAN_SYSREQUIRES_MODE=%s. Some system packages need to be installed\" % mode\n                )\n\n        if not force and self._installed(packages):\n            return\n\n        # From here system packages can be updated/modified\n        if update and not self._is_up_to_date:\n            self.update()\n        self._install_any(packages)\n\n    def _installed(self, packages):\n        if not packages:\n            return True\n\n        for pkg in packages:\n            if self._tool.installed(pkg):\n                _global_output.info(\"Package already installed: %s\" % pkg)\n                return True\n        return False\n\n    def _install_any(self, packages):\n        if len(packages) == 1:\n            return self._tool.install(packages[0])\n        for pkg in packages:\n            try:\n                return self._tool.install(pkg)\n            except ConanException:\n                pass\n        raise ConanException(\"Could not install any of %s\" % packages)\n\n\nclass NullTool(object):\n    def update(self):\n        pass\n\n    def install(self, package_name):\n        _global_output.warn(\"Only available for linux with apt-get, yum, or pacman or OSX with brew or \"\n                            \"FreeBSD with pkg or Solaris with pkgutil\")\n\n    def installed(self, package_name):\n        return False\n\n\nclass AptTool(object):\n    def update(self):\n        _run(self._runner, \"%sapt-get update\" % self._sudo_str)\n\n    def install(self, package_name):\n        recommends_str = '' if self._recommends else '--no-install-recommends '\n        _run(self._runner, \"%sapt-get install -y %s%s\" % (self._sudo_str, recommends_str, package_name))\n\n    def installed(self, package_name):\n        exit_code = self._runner(\"dpkg -s %s\" % package_name, None)\n        return exit_code == 0\n\n\nclass YumTool(object):\n    def update(self):\n        _run(self._runner, \"%syum update\" % self._sudo_str, accepted_returns=[0, 100])\n\n    def install(self, package_name):\n        _run(self._runner, \"%syum install -y %s\" % (self._sudo_str, package_name))\n\n    def installed(self, package_name):\n        exit_code = self._runner(\"rpm -q %s\" % package_name, None)\n        return exit_code == 0\n\n\nclass BrewTool(object):\n    def update(self):\n        _run(self._runner, \"brew update\")\n\n    def install(self, package_name):\n        _run(self._runner, \"brew install %s\" % package_name)\n\n    def installed(self, package_name):\n        exit_code = self._runner('test -n \"$(brew ls --versions %s)\"' % package_name, None)\n        return exit_code == 0\n\n\nclass PkgTool(object):\n    def update(self):\n        _run(self._runner, \"%spkg update\" % self._sudo_str)\n\n    def install(self, package_name):\n        _run(self._runner, \"%spkg install -y %s\" % (self._sudo_str, package_name))\n\n    def installed(self, package_name):\n        exit_code = self._runner(\"pkg info %s\" % package_name, None)\n        return exit_code == 0\n\n\nclass PkgUtilTool(object):\n    def update(self):\n        _run(self._runner, \"%spkgutil --catalog\" % self._sudo_str)\n\n    def install(self, package_name):\n        _run(self._runner, \"%spkgutil --install --yes %s\" % (self._sudo_str, package_name))\n\n    def installed(self, package_name):\n        exit_code = self._runner('test -n \"`pkgutil --list %s`\"' % package_name, None)\n        return exit_code == 0\n\n\nclass ChocolateyTool(object):\n    def update(self):\n        _run(self._runner, \"choco outdated\")\n\n    def install(self, package_name):\n        _run(self._runner, \"choco install --yes %s\" % package_name)\n\n    def installed(self, package_name):\n        exit_code = self._runner('choco search --local-only --exact %s | '\n                                 'findstr /c:\"1 packages installed.\"' % package_name, None)\n        return exit_code == 0\n\n\nclass PacManTool(object):\n    def update(self):\n        _run(self._runner, \"%spacman -Syyu --noconfirm\" % self._sudo_str)\n\n    def install(self, package_name):\n        _run(self._runner, \"%spacman -S --noconfirm %s\" % (self._sudo_str, package_name))\n\n    def installed(self, package_name):\n        exit_code = self._runner(\"pacman -Qi %s\" % package_name, None)\n        return exit_code == 0\n\n\nclass ZypperTool(object):\n    def update(self):\n        _run(self._runner, \"%szypper --non-interactive ref\" % self._sudo_str)\n\n    def install(self, package_name):\n        _run(self._runner, \"%szypper --non-interactive in %s\" % (self._sudo_str, package_name))\n\n    def installed(self, package_name):\n        exit_code = self._runner(\"rpm -q %s\" % package_name, None)\n        return exit_code == 0\n\n\ndef _run(runner, command, accepted_returns=None):\n    accepted_returns = accepted_returns or [0, ]\n    _global_output.info(\"Running: %s\" % command)\n    if runner(command, True) not in accepted_returns:\n        raise ConanException(\"Command '%s' failed\" % command)\n", "path": "conans/client/tools/system_pm.py"}], "after_files": [{"content": "import os\nfrom conans.client.runner import ConanRunner\nfrom conans.client.tools.oss import OSInfo\nfrom conans.errors import ConanException\nfrom conans.util.env_reader import get_env\n\n_global_output = None\n\n\nclass SystemPackageTool(object):\n\n    def __init__(self, runner=None, os_info=None, tool=None, recommends=False):\n        os_info = os_info or OSInfo()\n        self._is_up_to_date = False\n        self._tool = tool or self._create_tool(os_info)\n        self._tool._sudo_str = \"sudo \" if self._is_sudo_enabled() else \"\"\n        self._tool._runner = runner or ConanRunner()\n        self._tool._recommends = recommends\n\n    @staticmethod\n    def _is_sudo_enabled():\n        if \"CONAN_SYSREQUIRES_SUDO\" not in os.environ:\n            if os.name == 'posix' and os.geteuid() == 0:\n                return False\n            if os.name == 'nt':\n                return False\n        return get_env(\"CONAN_SYSREQUIRES_SUDO\", True)\n\n    @staticmethod\n    def _get_sysrequire_mode():\n        allowed_modes = (\"enabled\", \"verify\", \"disabled\")\n        mode = get_env(\"CONAN_SYSREQUIRES_MODE\", \"enabled\")\n        mode_lower = mode.lower()\n        if mode_lower not in allowed_modes:\n            raise ConanException(\"CONAN_SYSREQUIRES_MODE=%s is not allowed, allowed modes=%r\" % (mode, allowed_modes))\n        return mode_lower\n\n    @staticmethod\n    def _create_tool(os_info):\n        if os_info.with_apt:\n            return AptTool()\n        elif os_info.with_yum:\n            return YumTool()\n        elif os_info.with_pacman:\n            return PacManTool()\n        elif os_info.is_macos:\n            return BrewTool()\n        elif os_info.is_freebsd:\n            return PkgTool()\n        elif os_info.is_solaris:\n            return PkgUtilTool()\n        elif os_info.with_zypper:\n            return ZypperTool()\n        else:\n            return NullTool()\n\n    def update(self):\n        \"\"\"\n            Get the system package tool update command\n        \"\"\"\n        mode = self._get_sysrequire_mode()\n        if mode in (\"disabled\", \"verify\"):\n            _global_output.info(\"Not updating system_requirements. CONAN_SYSREQUIRES_MODE=%s\" % mode)\n            return\n        self._is_up_to_date = True\n        self._tool.update()\n\n    def install(self, packages, update=True, force=False):\n        \"\"\"\n            Get the system package tool install command.\n        '\"\"\"\n        packages = [packages] if isinstance(packages, str) else list(packages)\n\n        mode = self._get_sysrequire_mode()\n\n        if mode in (\"verify\", \"disabled\"):\n            # Report to output packages need to be installed\n            if mode == \"disabled\":\n                _global_output.info(\"The following packages need to be installed:\\n %s\" % \"\\n\".join(packages))\n                return\n\n            if mode == \"verify\" and not self._installed(packages):\n                _global_output.error(\"The following packages need to be installed:\\n %s\" % \"\\n\".join(packages))\n                raise ConanException(\n                    \"Aborted due to CONAN_SYSREQUIRES_MODE=%s. Some system packages need to be installed\" % mode\n                )\n\n        if not force and self._installed(packages):\n            return\n\n        # From here system packages can be updated/modified\n        if update and not self._is_up_to_date:\n            self.update()\n        self._install_any(packages)\n\n    def _installed(self, packages):\n        if not packages:\n            return True\n\n        for pkg in packages:\n            if self._tool.installed(pkg):\n                _global_output.info(\"Package already installed: %s\" % pkg)\n                return True\n        return False\n\n    def _install_any(self, packages):\n        if len(packages) == 1:\n            return self._tool.install(packages[0])\n        for pkg in packages:\n            try:\n                return self._tool.install(pkg)\n            except ConanException:\n                pass\n        raise ConanException(\"Could not install any of %s\" % packages)\n\n\nclass NullTool(object):\n    def update(self):\n        pass\n\n    def install(self, package_name):\n        _global_output.warn(\"Only available for linux with apt-get, yum, or pacman or OSX with brew or \"\n                            \"FreeBSD with pkg or Solaris with pkgutil\")\n\n    def installed(self, package_name):\n        return False\n\n\nclass AptTool(object):\n    def update(self):\n        _run(self._runner, \"%sapt-get update\" % self._sudo_str)\n\n    def install(self, package_name):\n        recommends_str = '' if self._recommends else '--no-install-recommends '\n        _run(self._runner, \"%sapt-get install -y %s%s\" % (self._sudo_str, recommends_str, package_name))\n\n    def installed(self, package_name):\n        exit_code = self._runner(\"dpkg-query -W -f='${Status}' %s | grep -q \\\"ok installed\\\"\" % package_name, None)\n        return exit_code == 0\n\n\nclass YumTool(object):\n    def update(self):\n        _run(self._runner, \"%syum update\" % self._sudo_str, accepted_returns=[0, 100])\n\n    def install(self, package_name):\n        _run(self._runner, \"%syum install -y %s\" % (self._sudo_str, package_name))\n\n    def installed(self, package_name):\n        exit_code = self._runner(\"rpm -q %s\" % package_name, None)\n        return exit_code == 0\n\n\nclass BrewTool(object):\n    def update(self):\n        _run(self._runner, \"brew update\")\n\n    def install(self, package_name):\n        _run(self._runner, \"brew install %s\" % package_name)\n\n    def installed(self, package_name):\n        exit_code = self._runner('test -n \"$(brew ls --versions %s)\"' % package_name, None)\n        return exit_code == 0\n\n\nclass PkgTool(object):\n    def update(self):\n        _run(self._runner, \"%spkg update\" % self._sudo_str)\n\n    def install(self, package_name):\n        _run(self._runner, \"%spkg install -y %s\" % (self._sudo_str, package_name))\n\n    def installed(self, package_name):\n        exit_code = self._runner(\"pkg info %s\" % package_name, None)\n        return exit_code == 0\n\n\nclass PkgUtilTool(object):\n    def update(self):\n        _run(self._runner, \"%spkgutil --catalog\" % self._sudo_str)\n\n    def install(self, package_name):\n        _run(self._runner, \"%spkgutil --install --yes %s\" % (self._sudo_str, package_name))\n\n    def installed(self, package_name):\n        exit_code = self._runner('test -n \"`pkgutil --list %s`\"' % package_name, None)\n        return exit_code == 0\n\n\nclass ChocolateyTool(object):\n    def update(self):\n        _run(self._runner, \"choco outdated\")\n\n    def install(self, package_name):\n        _run(self._runner, \"choco install --yes %s\" % package_name)\n\n    def installed(self, package_name):\n        exit_code = self._runner('choco search --local-only --exact %s | '\n                                 'findstr /c:\"1 packages installed.\"' % package_name, None)\n        return exit_code == 0\n\n\nclass PacManTool(object):\n    def update(self):\n        _run(self._runner, \"%spacman -Syyu --noconfirm\" % self._sudo_str)\n\n    def install(self, package_name):\n        _run(self._runner, \"%spacman -S --noconfirm %s\" % (self._sudo_str, package_name))\n\n    def installed(self, package_name):\n        exit_code = self._runner(\"pacman -Qi %s\" % package_name, None)\n        return exit_code == 0\n\n\nclass ZypperTool(object):\n    def update(self):\n        _run(self._runner, \"%szypper --non-interactive ref\" % self._sudo_str)\n\n    def install(self, package_name):\n        _run(self._runner, \"%szypper --non-interactive in %s\" % (self._sudo_str, package_name))\n\n    def installed(self, package_name):\n        exit_code = self._runner(\"rpm -q %s\" % package_name, None)\n        return exit_code == 0\n\n\ndef _run(runner, command, accepted_returns=None):\n    accepted_returns = accepted_returns or [0, ]\n    _global_output.info(\"Running: %s\" % command)\n    if runner(command, True) not in accepted_returns:\n        raise ConanException(\"Command '%s' failed\" % command)\n", "path": "conans/client/tools/system_pm.py"}]}