EntityManager: Split out PerformProbe

Continue breaking down the code so regular people can comprehend it.

Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Change-Id: Ic4458054df7426d579cb99dd21f3578d1265711d
diff --git a/src/EntityManager.cpp b/src/EntityManager.cpp
index 725f2bf..8bd97fd 100644
--- a/src/EntityManager.cpp
+++ b/src/EntityManager.cpp
@@ -109,222 +109,6 @@
     return ptr;
 }
 
-// probes dbus interface dictionary for a key with a value that matches a regex
-// When an interface passes a probe, also save its D-Bus path with it.
-bool probeDbus(const std::string& interface,
-               const std::map<std::string, nlohmann::json>& matches,
-               FoundDeviceT& devices, const std::shared_ptr<PerformScan>& scan,
-               bool& foundProbe)
-{
-    bool foundMatch = false;
-    foundProbe = false;
-
-    for (const auto& [path, interfaces] : scan->dbusProbeObjects)
-    {
-        auto it = interfaces.find(interface);
-        if (it == interfaces.end())
-        {
-            continue;
-        }
-
-        foundProbe = true;
-
-        bool deviceMatches = true;
-        const boost::container::flat_map<std::string, BasicVariantType>&
-            properties = it->second;
-
-        for (const auto& [matchProp, matchJSON] : matches)
-        {
-            auto deviceValue = properties.find(matchProp);
-            if (deviceValue != properties.end())
-            {
-                deviceMatches =
-                    deviceMatches && matchProbe(matchJSON, deviceValue->second);
-            }
-            else
-            {
-                // Move on to the next DBus path
-                deviceMatches = false;
-                break;
-            }
-        }
-        if (deviceMatches)
-        {
-            if constexpr (debug)
-            {
-                std::cerr << "probeDBus: Found probe match on " << path << " "
-                          << interface << "\n";
-            }
-            devices.emplace_back(properties, path);
-            foundMatch = true;
-        }
-    }
-    return foundMatch;
-}
-
-// default probe entry point, iterates a list looking for specific types to
-// call specific probe functions
-bool probe(const std::vector<std::string>& probeCommand,
-           const std::shared_ptr<PerformScan>& scan, FoundDeviceT& foundDevs)
-{
-    const static std::regex command(R"(\((.*)\))");
-    std::smatch match;
-    bool ret = false;
-    bool matchOne = false;
-    bool cur = true;
-    probe_type_codes lastCommand = probe_type_codes::FALSE_T;
-    bool first = true;
-
-    for (auto& probe : probeCommand)
-    {
-        bool foundProbe = false;
-        boost::container::flat_map<const char*, probe_type_codes,
-                                   CmpStr>::const_iterator probeType;
-
-        for (probeType = probeTypes.begin(); probeType != probeTypes.end();
-             ++probeType)
-        {
-            if (probe.find(probeType->first) != std::string::npos)
-            {
-                foundProbe = true;
-                break;
-            }
-        }
-        if (foundProbe)
-        {
-            switch (probeType->second)
-            {
-                case probe_type_codes::FALSE_T:
-                {
-                    cur = false;
-                    break;
-                }
-                case probe_type_codes::TRUE_T:
-                {
-                    cur = true;
-                    break;
-                }
-                case probe_type_codes::MATCH_ONE:
-                {
-                    // set current value to last, this probe type shouldn't
-                    // affect the outcome
-                    cur = ret;
-                    matchOne = true;
-                    break;
-                }
-                /*case probe_type_codes::AND:
-                  break;
-                case probe_type_codes::OR:
-                  break;
-                  // these are no-ops until the last command switch
-                  */
-                case probe_type_codes::FOUND:
-                {
-                    if (!std::regex_search(probe, match, command))
-                    {
-                        std::cerr << "found probe syntax error " << probe
-                                  << "\n";
-                        return false;
-                    }
-                    std::string commandStr = *(match.begin() + 1);
-                    boost::replace_all(commandStr, "'", "");
-                    cur = (std::find(scan->passedProbes.begin(),
-                                     scan->passedProbes.end(),
-                                     commandStr) != scan->passedProbes.end());
-                    break;
-                }
-                default:
-                {
-                    break;
-                }
-            }
-        }
-        // look on dbus for object
-        else
-        {
-            if (!std::regex_search(probe, match, command))
-            {
-                std::cerr << "dbus probe syntax error " << probe << "\n";
-                return false;
-            }
-            std::string commandStr = *(match.begin() + 1);
-            // convert single ticks and single slashes into legal json
-            boost::replace_all(commandStr, "'", "\"");
-            boost::replace_all(commandStr, R"(\)", R"(\\)");
-            auto json = nlohmann::json::parse(commandStr, nullptr, false);
-            if (json.is_discarded())
-            {
-                std::cerr << "dbus command syntax error " << commandStr << "\n";
-                return false;
-            }
-            // we can match any (string, variant) property. (string, string)
-            // does a regex
-            std::map<std::string, nlohmann::json> dbusProbeMap =
-                json.get<std::map<std::string, nlohmann::json>>();
-            auto findStart = probe.find('(');
-            if (findStart == std::string::npos)
-            {
-                return false;
-            }
-            std::string probeInterface = probe.substr(0, findStart);
-            cur = probeDbus(probeInterface, dbusProbeMap, foundDevs, scan,
-                            foundProbe);
-        }
-
-        // some functions like AND and OR only take affect after the
-        // fact
-        if (lastCommand == probe_type_codes::AND)
-        {
-            ret = cur && ret;
-        }
-        else if (lastCommand == probe_type_codes::OR)
-        {
-            ret = cur || ret;
-        }
-
-        if (first)
-        {
-            ret = cur;
-            first = false;
-        }
-        lastCommand = probeType != probeTypes.end() ? probeType->second
-                                                    : probe_type_codes::FALSE_T;
-    }
-
-    // probe passed, but empty device
-    if (ret && foundDevs.size() == 0)
-    {
-        foundDevs.emplace_back(
-            boost::container::flat_map<std::string, BasicVariantType>{},
-            std::string{});
-    }
-    if (matchOne && ret)
-    {
-        // match the last one
-        auto last = foundDevs.back();
-        foundDevs.clear();
-
-        foundDevs.emplace_back(std::move(last));
-    }
-    return ret;
-}
-
-PerformProbe::PerformProbe(
-    const std::vector<std::string>& probeCommand,
-    std::shared_ptr<PerformScan>& scanPtr,
-    std::function<void(FoundDeviceT&, const DBusProbeObjectT&)>&& callback) :
-    _probeCommand(probeCommand),
-    scan(scanPtr), _callback(std::move(callback))
-{}
-PerformProbe::~PerformProbe()
-{
-    FoundDeviceT foundDevs;
-    if (probe(_probeCommand, scan, foundDevs))
-    {
-        _callback(foundDevs, scan->dbusProbeObjects);
-    }
-}
-
 // writes output files to persist data
 bool writeJsonFiles(const nlohmann::json& systemConfiguration)
 {
diff --git a/src/PerformProbe.cpp b/src/PerformProbe.cpp
new file mode 100644
index 0000000..7024e47
--- /dev/null
+++ b/src/PerformProbe.cpp
@@ -0,0 +1,248 @@
+/*
+// Copyright (c) 2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+/// \file PerformProbe.cpp
+#include "EntityManager.hpp"
+
+#include <boost/algorithm/string/replace.hpp>
+
+#include <regex>
+
+constexpr const bool debug = false;
+
+/* Keep this in sync with EntityManager.cpp */
+static const boost::container::flat_map<const char*, probe_type_codes, CmpStr>
+    probeTypes{{{"FALSE", probe_type_codes::FALSE_T},
+                {"TRUE", probe_type_codes::TRUE_T},
+                {"AND", probe_type_codes::AND},
+                {"OR", probe_type_codes::OR},
+                {"FOUND", probe_type_codes::FOUND},
+                {"MATCH_ONE", probe_type_codes::MATCH_ONE}}};
+
+// probes dbus interface dictionary for a key with a value that matches a regex
+// When an interface passes a probe, also save its D-Bus path with it.
+bool probeDbus(const std::string& interface,
+               const std::map<std::string, nlohmann::json>& matches,
+               FoundDeviceT& devices, const std::shared_ptr<PerformScan>& scan,
+               bool& foundProbe)
+{
+    bool foundMatch = false;
+    foundProbe = false;
+
+    for (const auto& [path, interfaces] : scan->dbusProbeObjects)
+    {
+        auto it = interfaces.find(interface);
+        if (it == interfaces.end())
+        {
+            continue;
+        }
+
+        foundProbe = true;
+
+        bool deviceMatches = true;
+        const boost::container::flat_map<std::string, BasicVariantType>&
+            properties = it->second;
+
+        for (const auto& [matchProp, matchJSON] : matches)
+        {
+            auto deviceValue = properties.find(matchProp);
+            if (deviceValue != properties.end())
+            {
+                deviceMatches =
+                    deviceMatches && matchProbe(matchJSON, deviceValue->second);
+            }
+            else
+            {
+                // Move on to the next DBus path
+                deviceMatches = false;
+                break;
+            }
+        }
+        if (deviceMatches)
+        {
+            if constexpr (debug)
+            {
+                std::cerr << "probeDBus: Found probe match on " << path << " "
+                          << interface << "\n";
+            }
+            devices.emplace_back(properties, path);
+            foundMatch = true;
+        }
+    }
+    return foundMatch;
+}
+
+// default probe entry point, iterates a list looking for specific types to
+// call specific probe functions
+bool probe(const std::vector<std::string>& probeCommand,
+           const std::shared_ptr<PerformScan>& scan, FoundDeviceT& foundDevs)
+{
+    const static std::regex command(R"(\((.*)\))");
+    std::smatch match;
+    bool ret = false;
+    bool matchOne = false;
+    bool cur = true;
+    probe_type_codes lastCommand = probe_type_codes::FALSE_T;
+    bool first = true;
+
+    for (auto& probe : probeCommand)
+    {
+        bool foundProbe = false;
+        boost::container::flat_map<const char*, probe_type_codes,
+                                   CmpStr>::const_iterator probeType;
+
+        for (probeType = probeTypes.begin(); probeType != probeTypes.end();
+             ++probeType)
+        {
+            if (probe.find(probeType->first) != std::string::npos)
+            {
+                foundProbe = true;
+                break;
+            }
+        }
+        if (foundProbe)
+        {
+            switch (probeType->second)
+            {
+                case probe_type_codes::FALSE_T:
+                {
+                    cur = false;
+                    break;
+                }
+                case probe_type_codes::TRUE_T:
+                {
+                    cur = true;
+                    break;
+                }
+                case probe_type_codes::MATCH_ONE:
+                {
+                    // set current value to last, this probe type shouldn't
+                    // affect the outcome
+                    cur = ret;
+                    matchOne = true;
+                    break;
+                }
+                /*case probe_type_codes::AND:
+                  break;
+                case probe_type_codes::OR:
+                  break;
+                  // these are no-ops until the last command switch
+                  */
+                case probe_type_codes::FOUND:
+                {
+                    if (!std::regex_search(probe, match, command))
+                    {
+                        std::cerr << "found probe syntax error " << probe
+                                  << "\n";
+                        return false;
+                    }
+                    std::string commandStr = *(match.begin() + 1);
+                    boost::replace_all(commandStr, "'", "");
+                    cur = (std::find(scan->passedProbes.begin(),
+                                     scan->passedProbes.end(),
+                                     commandStr) != scan->passedProbes.end());
+                    break;
+                }
+                default:
+                {
+                    break;
+                }
+            }
+        }
+        // look on dbus for object
+        else
+        {
+            if (!std::regex_search(probe, match, command))
+            {
+                std::cerr << "dbus probe syntax error " << probe << "\n";
+                return false;
+            }
+            std::string commandStr = *(match.begin() + 1);
+            // convert single ticks and single slashes into legal json
+            boost::replace_all(commandStr, "'", "\"");
+            boost::replace_all(commandStr, R"(\)", R"(\\)");
+            auto json = nlohmann::json::parse(commandStr, nullptr, false);
+            if (json.is_discarded())
+            {
+                std::cerr << "dbus command syntax error " << commandStr << "\n";
+                return false;
+            }
+            // we can match any (string, variant) property. (string, string)
+            // does a regex
+            std::map<std::string, nlohmann::json> dbusProbeMap =
+                json.get<std::map<std::string, nlohmann::json>>();
+            auto findStart = probe.find('(');
+            if (findStart == std::string::npos)
+            {
+                return false;
+            }
+            std::string probeInterface = probe.substr(0, findStart);
+            cur = probeDbus(probeInterface, dbusProbeMap, foundDevs, scan,
+                            foundProbe);
+        }
+
+        // some functions like AND and OR only take affect after the
+        // fact
+        if (lastCommand == probe_type_codes::AND)
+        {
+            ret = cur && ret;
+        }
+        else if (lastCommand == probe_type_codes::OR)
+        {
+            ret = cur || ret;
+        }
+
+        if (first)
+        {
+            ret = cur;
+            first = false;
+        }
+        lastCommand = probeType != probeTypes.end() ? probeType->second
+                                                    : probe_type_codes::FALSE_T;
+    }
+
+    // probe passed, but empty device
+    if (ret && foundDevs.size() == 0)
+    {
+        foundDevs.emplace_back(
+            boost::container::flat_map<std::string, BasicVariantType>{},
+            std::string{});
+    }
+    if (matchOne && ret)
+    {
+        // match the last one
+        auto last = foundDevs.back();
+        foundDevs.clear();
+
+        foundDevs.emplace_back(std::move(last));
+    }
+    return ret;
+}
+
+PerformProbe::PerformProbe(
+    const std::vector<std::string>& probeCommand,
+    std::shared_ptr<PerformScan>& scanPtr,
+    std::function<void(FoundDeviceT&, const DBusProbeObjectT&)>&& callback) :
+    _probeCommand(probeCommand),
+    scan(scanPtr), _callback(std::move(callback))
+{}
+PerformProbe::~PerformProbe()
+{
+    FoundDeviceT foundDevs;
+    if (probe(_probeCommand, scan, foundDevs))
+    {
+        _callback(foundDevs, scan->dbusProbeObjects);
+    }
+}
diff --git a/src/meson.build b/src/meson.build
index bab416c..5add400 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -4,6 +4,7 @@
     'entity-manager',
     'EntityManager.cpp',
     'PerformScan.cpp',
+    'PerformProbe.cpp',
     'Overlay.cpp',
     'Utils.cpp',
     cpp_args: cpp_args + ['-DBOOST_ASIO_DISABLE_THREADS'],