Repository: conan-io/conan

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.




Discussion:

Resolving patch:
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 @@ def install(self, package_name):
         _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
 
 


Test patch:
diff --git a/conans/test/util/tools_test.py b/conans/test/util/tools_test.py
--- a/conans/test/util/tools_test.py
+++ b/conans/test/util/tools_test.py
@@ -109,7 +109,7 @@ def system_package_tool_test(self):
 
             runner.return_ok = True
             spt.install("a_package", force=False)
-            self.assertEquals(runner.command_called, "dpkg -s a_package")
+            self.assertEquals(runner.command_called, 'dpkg-query -W -f=\'${Status}\' a_package | grep -q "ok installed"')
 
             os_info.is_macos = True
             os_info.is_linux = False
@@ -224,7 +224,7 @@ def __call__(self, command, output):  # @UnusedVariable
 
         packages = ["a_package", "another_package", "yet_another_package"]
         with tools.environment_append({"CONAN_SYSREQUIRES_SUDO": "True"}):
-            runner = RunnerMultipleMock(["dpkg -s another_package"])
+            runner = RunnerMultipleMock(['dpkg-query -W -f=\'${Status}\' another_package | grep -q "ok installed"'])
             spt = SystemPackageTool(runner=runner, tool=AptTool())
             spt.install(packages)
             self.assertEquals(2, runner.calls)
@@ -501,7 +501,7 @@ def build(self):
 
     def test_global_tools_overrided(self):
         client = TestClient()
-
+ 
         conanfile = """
 from conans import ConanFile, tools