propertywatch: Add ignore_start_callback config

Add an optional `ignore_start_callback` config to indicate if the
callback shall be ignored on start.

By default the callbacks in property watch are called on start.
There are cases where we do not want such behavior and only expect
callbacks on property changes.

Add the `ignore_start_callback` so that we could config a watch to not
trigger the start callback.

Tested: Verify the callback is not called if the watch config has
        `ignore_start_callback: true`

Signed-off-by: Lei YU <yulei.sh@bytedance.com>
Change-Id: I7e5887cc8b0d0775d9b3d689f1511250667aaa5b
diff --git a/src/example/example.yaml b/src/example/example.yaml
index c613d1e..68b54c1 100644
--- a/src/example/example.yaml
+++ b/src/example/example.yaml
@@ -56,7 +56,12 @@
     affect on any optional callback that may be triggered.
 
     An optional callback can be triggered when property values change and
-    those values pass all filters that may be defined.'
+    those values pass all filters that may be defined.
+
+    By default the callback is called when the monitor starts.
+    An optional `ignore_start_callback` can be set to true so that the
+    callback will not be called when the monitor starts.'
+
   class: watch
   watch: property
   paths: example path group
@@ -67,6 +72,7 @@
       bound: 0
     - op: '<='
       bound: 100
+  ignore_start_callback: true
 
 - name: example journal callback
   description: >
diff --git a/src/pdmgen.py b/src/pdmgen.py
index 0f9a13b..925dd21 100755
--- a/src/pdmgen.py
+++ b/src/pdmgen.py
@@ -676,6 +676,8 @@
         # Pop optional filters for the properties being watched
         self.filters = kw.pop('filters', None)
         self.callback = kw.pop('callback', None)
+        self.ignore_start_callback = kw.pop('ignore_start_callback', False)
+        self.ignore_start_callback = 'true' if self.ignore_start_callback else 'false'
         super(PropertyWatch, self).__init__(**kw)
 
     def factory(self, objs):
diff --git a/src/propertywatch.hpp b/src/propertywatch.hpp
index 84b6af7..8a3c07b 100644
--- a/src/propertywatch.hpp
+++ b/src/propertywatch.hpp
@@ -39,9 +39,11 @@
     PropertyWatch& operator=(PropertyWatch&&) = default;
     virtual ~PropertyWatch() = default;
     PropertyWatch(const PropertyIndex& watchIndex,
+                  bool ignoreStartCallback = false,
                   Callback* callback = nullptr) :
         Watch(),
-        index(watchIndex), cb(callback), alreadyRan(false)
+        index(watchIndex), cb(callback), alreadyRan(false),
+        ignoreStartCallback(ignoreStartCallback)
     {
     }
 
@@ -101,6 +103,9 @@
 
     /** @brief The start method should only be invoked once. */
     bool alreadyRan;
+
+    /** @brief Ignore callback on start */
+    bool ignoreStartCallback;
 };
 
 /** @class PropertyWatchOfType
@@ -120,14 +125,18 @@
     PropertyWatchOfType& operator=(PropertyWatchOfType&&) = default;
     ~PropertyWatchOfType() = default;
     PropertyWatchOfType(const PropertyIndex& watchIndex, Callback& callback,
+                        bool ignoreStartCallback = false,
                         Filters* filterOps = nullptr) :
-        PropertyWatch<DBusInterfaceType>(watchIndex, &callback),
+        PropertyWatch<DBusInterfaceType>(watchIndex, ignoreStartCallback,
+                                         &callback),
         filterOps(filterOps)
     {
     }
     PropertyWatchOfType(const PropertyIndex& watchIndex,
+                        bool ignoreStartCallback = false,
                         Filters* filterOps = nullptr) :
-        PropertyWatch<DBusInterfaceType>(watchIndex, nullptr),
+        PropertyWatch<DBusInterfaceType>(watchIndex, ignoreStartCallback,
+                                         nullptr),
         filterOps(filterOps)
     {
     }
diff --git a/src/propertywatchimpl.hpp b/src/propertywatchimpl.hpp
index ef50494..271d9b2 100644
--- a/src/propertywatchimpl.hpp
+++ b/src/propertywatchimpl.hpp
@@ -120,6 +120,12 @@
 template <typename DBusInterfaceType>
 void PropertyWatch<DBusInterfaceType>::callback(Context ctx)
 {
+    // Ignore callback if ignoreStartCallback is true and it's the START
+    // callback
+    if (ctx == Context::START && ignoreStartCallback)
+    {
+        return;
+    }
     // Invoke callback if present.
     if (this->alreadyRan && this->cb)
     {
diff --git a/src/templates/generated.mako.hpp b/src/templates/generated.mako.hpp
index 7b1bf69..9f9475a 100644
--- a/src/templates/generated.mako.hpp
+++ b/src/templates/generated.mako.hpp
@@ -259,15 +259,18 @@
                 ConfigPropertyIndicies::get()[${w.instances}]),
         % else:
                 ConfigPropertyIndicies::get()[${w.instances}],
+                ${w.ignore_start_callback},
                 ConfigPropertyFilters::get()[${w.filters}].get()),
         % endif
     % else:
         % if w.filters is None:
                 ConfigPropertyIndicies::get()[${w.instances}],
-                *ConfigPropertyCallbacks::get()[${w.callback}]),
+                *ConfigPropertyCallbacks::get()[${w.callback}],
+                ${w.ignore_start_callback}),
         % else:
                 ConfigPropertyIndicies::get()[${w.instances}],
                 *ConfigPropertyCallbacks::get()[${w.callback}],
+                ${w.ignore_start_callback},
                 ConfigPropertyFilters::get()[${w.filters}].get()),
         % endif
     % endif
diff --git a/src/test/propertywatchtest.cpp b/src/test/propertywatchtest.cpp
index 9fbd30b..9a449b4 100644
--- a/src/test/propertywatchtest.cpp
+++ b/src/test/propertywatchtest.cpp
@@ -257,7 +257,8 @@
     MockDBusInterface::instance(dbus);
 
     const std::vector<std::string> expectedMapperInterfaces;
-    PropertyWatchOfType<T, MockDBusInterface> watch(watchIndex, opFilters);
+    PropertyWatchOfType<T, MockDBusInterface> watch(watchIndex, false,
+                                                    opFilters);
 
     auto ndx = static_cast<size_t>(0);
     for (const auto& o : convert(watchIndex))