platform2: Move Error class from Buffet to libchromeos

Moved buffet::Error class and related facilities to
libchromeos and changed the namespace to 'chromeos::'.
Updated a bunch of code to include the header files
from the new location and referring to the new
namespace.

BUG=chromium:403604
TEST=USE=buffet ./build_packages
     FEATURES=test emerge-link libchromeos
     USE=buffet FEATURES=test emerge-link platform2

Change-Id: I0b5b37ccd7ee3b7be9467ebfae5d172d9b057cf6
Reviewed-on: https://chromium-review.googlesource.com/212525
Tested-by: Alex Vakulenko <avakulenko@chromium.org>
Reviewed-by: Christopher Wiley <wiley@chromium.org>
Commit-Queue: Alex Vakulenko <avakulenko@chromium.org>
diff --git a/chromeos/error.cc b/chromeos/error.cc
new file mode 100644
index 0000000..8ac0c98
--- /dev/null
+++ b/chromeos/error.cc
@@ -0,0 +1,80 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/error.h"
+
+#include <base/logging.h>
+#include <base/strings/stringprintf.h>
+
+using chromeos::Error;
+using chromeos::ErrorPtr;
+
+ErrorPtr Error::Create(const std::string& domain,
+                       const std::string& code,
+                       const std::string& message) {
+  return Create(domain, code, message, ErrorPtr());
+}
+
+ErrorPtr Error::Create(const std::string& domain,
+                       const std::string& code,
+                       const std::string& message,
+                       ErrorPtr inner_error) {
+  LOG(ERROR) << "Error::Create: Domain=" << domain
+             << ", Code=" << code << ", Message=" << message;
+  return ErrorPtr(new Error(domain, code, message, std::move(inner_error)));
+}
+
+void Error::AddTo(ErrorPtr* error, const std::string& domain,
+                  const std::string& code, const std::string& message) {
+  if (error) {
+    *error = Create(domain, code, message, std::move(*error));
+  } else {
+    // Create already logs the error, but if |error| is nullptr,
+    // we still want to log the error...
+    LOG(ERROR) << "Error::Create: Domain=" << domain
+               << ", Code=" << code << ", Message=" << message;
+  }
+}
+
+void Error::AddToPrintf(ErrorPtr* error, const std::string& domain,
+                        const std::string& code, const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  std::string message = base::StringPrintV(format, ap);
+  va_end(ap);
+  AddTo(error, domain, code, message);
+}
+
+bool Error::HasDomain(const std::string& domain) const {
+  const Error* err = this;
+  while (err) {
+    if (err->GetDomain() == domain)
+      return true;
+    err = err->GetInnerError();
+  }
+  return false;
+}
+
+bool Error::HasError(const std::string& domain, const std::string& code) const {
+  const Error* err = this;
+  while (err) {
+    if (err->GetDomain() == domain && err->GetCode() == code)
+      return true;
+    err = err->GetInnerError();
+  }
+  return false;
+}
+
+const Error* Error::GetFirstError() const {
+  const Error* err = this;
+  while (err->GetInnerError())
+    err = err->GetInnerError();
+  return err;
+}
+
+Error::Error(const std::string& domain, const std::string& code,
+             const std::string& message, ErrorPtr inner_error) :
+    domain_(domain), code_(code), message_(message),
+    inner_error_(std::move(inner_error)) {
+}
diff --git a/chromeos/error.h b/chromeos/error.h
new file mode 100644
index 0000000..df0f4e8
--- /dev/null
+++ b/chromeos/error.h
@@ -0,0 +1,80 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIBCHROMEOS_CHROMEOS_ERROR_H_
+#define LIBCHROMEOS_CHROMEOS_ERROR_H_
+
+#include <memory>
+#include <string>
+
+#include <base/basictypes.h>
+
+namespace chromeos {
+
+class Error;  // Forward declaration.
+
+typedef std::unique_ptr<Error> ErrorPtr;
+
+class Error {
+ public:
+  virtual ~Error() = default;
+
+  // Creates an instance of Error class.
+  static ErrorPtr Create(const std::string& domain, const std::string& code,
+                         const std::string& message);
+  static ErrorPtr Create(const std::string& domain, const std::string& code,
+                         const std::string& message, ErrorPtr inner_error);
+  // If |error| is not nullptr, creates another instance of Error class,
+  // initializes it with specified arguments and adds it to the head of
+  // the error chain pointed to by |error|.
+  static void AddTo(ErrorPtr* error, const std::string& domain,
+                    const std::string& code, const std::string& message);
+  // Same as the Error::AddTo above, but allows to pass in a printf-like
+  // format string and optional parameters to format the error message.
+  static void AddToPrintf(ErrorPtr* error, const std::string& domain,
+                          const std::string& code,
+                          const char* format, ...) PRINTF_FORMAT(4, 5);
+
+  // Returns the error domain, code and message
+  const std::string& GetDomain() const { return domain_; }
+  const std::string& GetCode() const { return code_; }
+  const std::string& GetMessage() const { return message_; }
+
+  // Checks if this or any of the inner error in the chain has the specified
+  // error domain.
+  bool HasDomain(const std::string& domain) const;
+  // Checks if this or any of the inner error in the chain matches the specified
+  // error domain and code.
+  bool HasError(const std::string& domain, const std::string& code) const;
+
+  // Gets a pointer to the inner error, if present. Returns nullptr otherwise.
+  const Error* GetInnerError() const { return inner_error_.get(); }
+
+  // Gets a pointer to the first error occurred.
+  // Returns itself if no inner error are available.
+  const Error* GetFirstError() const;
+
+ protected:
+  // Constructor is protected since this object is supposed to be
+  // created via the Create factory methods.
+  Error(const std::string& domain, const std::string& code,
+        const std::string& message, ErrorPtr inner_error);
+
+  // Error domain. The domain defines the scopes for error codes.
+  // Two errors with the same code but different domains are different errors.
+  std::string domain_;
+  // Error code. A unique error code identifier within the given domain.
+  std::string code_;
+  // Human-readable error message.
+  std::string message_;
+  // Pointer to inner error, if any. This forms a chain of errors.
+  ErrorPtr inner_error_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Error);
+};
+
+}  // namespace chromeos
+
+#endif  // LIBCHROMEOS_CHROMEOS_ERROR_H_
diff --git a/chromeos/error_codes.cc b/chromeos/error_codes.cc
new file mode 100644
index 0000000..83655ab
--- /dev/null
+++ b/chromeos/error_codes.cc
@@ -0,0 +1,22 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/error_codes.h"
+
+namespace chromeos {
+namespace errors {
+
+namespace json {
+const char kDomain[] = "json_parser";
+const char kParseError[] = "json_parse_error";
+const char kObjectExpected[] = "json_object_expected";
+}  // namespace json
+
+namespace file_system {
+const char kDomain[] = "file_system";
+const char kFileReadError[] = "file_read_error";
+}  // namespace file_system
+
+}  // namespace errors
+}  // namespace chromeos
diff --git a/chromeos/error_codes.h b/chromeos/error_codes.h
new file mode 100644
index 0000000..2800335
--- /dev/null
+++ b/chromeos/error_codes.h
@@ -0,0 +1,25 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIBCHROMEOS_CHROMEOS_ERROR_CODES_H_
+#define LIBCHROMEOS_CHROMEOS_ERROR_CODES_H_
+
+namespace chromeos {
+namespace errors {
+
+namespace json {
+extern const char kDomain[];
+extern const char kParseError[];
+extern const char kObjectExpected[];
+}  // namespace json
+
+namespace file_system {
+extern const char kDomain[];
+extern const char kFileReadError[];
+}  // namespace file_system
+
+}  // namespace errors
+}  // namespace chromeos
+
+#endif  // LIBCHROMEOS_CHROMEOS_ERROR_CODES_H_
diff --git a/chromeos/error_unittest.cc b/chromeos/error_unittest.cc
new file mode 100644
index 0000000..2fcd10c
--- /dev/null
+++ b/chromeos/error_unittest.cc
@@ -0,0 +1,56 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <base/files/file_path.h>
+#include <gtest/gtest.h>
+
+#include "chromeos/error.h"
+
+using chromeos::Error;
+
+namespace {
+
+chromeos::ErrorPtr GenerateNetworkError() {
+  return Error::Create("network", "not_found", "Resource not found");
+}
+
+chromeos::ErrorPtr GenerateHttpError() {
+  auto inner = GenerateNetworkError();
+  return Error::Create("HTTP", "404", "Not found", std::move(inner));
+}
+
+}  // namespace
+
+TEST(Error, Single) {
+  auto err = GenerateNetworkError();
+  EXPECT_EQ("network", err->GetDomain());
+  EXPECT_EQ("not_found", err->GetCode());
+  EXPECT_EQ("Resource not found", err->GetMessage());
+  EXPECT_EQ(nullptr, err->GetInnerError());
+  EXPECT_TRUE(err->HasDomain("network"));
+  EXPECT_FALSE(err->HasDomain("HTTP"));
+  EXPECT_FALSE(err->HasDomain("foo"));
+  EXPECT_TRUE(err->HasError("network", "not_found"));
+  EXPECT_FALSE(err->HasError("network", "404"));
+  EXPECT_FALSE(err->HasError("HTTP", "404"));
+  EXPECT_FALSE(err->HasError("HTTP", "not_found"));
+  EXPECT_FALSE(err->HasError("foo", "bar"));
+}
+
+TEST(Error, Nested) {
+  auto err = GenerateHttpError();
+  EXPECT_EQ("HTTP", err->GetDomain());
+  EXPECT_EQ("404", err->GetCode());
+  EXPECT_EQ("Not found", err->GetMessage());
+  EXPECT_NE(nullptr, err->GetInnerError());
+  EXPECT_EQ("network", err->GetInnerError()->GetDomain());
+  EXPECT_TRUE(err->HasDomain("network"));
+  EXPECT_TRUE(err->HasDomain("HTTP"));
+  EXPECT_FALSE(err->HasDomain("foo"));
+  EXPECT_TRUE(err->HasError("network", "not_found"));
+  EXPECT_FALSE(err->HasError("network", "404"));
+  EXPECT_TRUE(err->HasError("HTTP", "404"));
+  EXPECT_FALSE(err->HasError("HTTP", "not_found"));
+  EXPECT_FALSE(err->HasError("foo", "bar"));
+}
diff --git a/libchromeos.gypi b/libchromeos.gypi
index a24da0a..e652e48 100644
--- a/libchromeos.gypi
+++ b/libchromeos.gypi
@@ -60,6 +60,8 @@
         'chromeos/dbus/abstract_dbus_service.cc',
         'chromeos/dbus/dbus.cc',
         'chromeos/dbus_utils.cc',
+        'chromeos/error.cc',
+        'chromeos/error_codes.cc',
         'chromeos/exported_object_manager.cc',
         'chromeos/exported_property_set.cc',
         'chromeos/process.cc',
@@ -200,6 +202,7 @@
           'sources': [
             'chromeos/async_event_sequencer_unittest.cc',
             'chromeos/asynchronous_signal_handler_unittest.cc',
+            'chromeos/error_unittest.cc',
             'chromeos/exported_object_manager_unittest.cc',
             'chromeos/exported_property_set_unittest.cc',
             'chromeos/glib/object_unittest.cc',