Fix shell_apptest for android.
This CL introduces mojo/tools/embed/rules.gni that allows to embed a
file in the data section of an object file. It refactors icu_data to use
this, and uses it in shell_apptest to bundle the ping application.
R=abarth@chromium.org, davemoore@chromium.org
Review URL: https://codereview.chromium.org/979043003
diff --git a/mojo/tools/embed/data.h b/mojo/tools/embed/data.h
new file mode 100644
index 0000000..50bf074
--- /dev/null
+++ b/mojo/tools/embed/data.h
@@ -0,0 +1,22 @@
+// Copyright 2015 The Chromium 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 MOJO_TOOLS_EMBED_DATA_H_
+#define MOJO_TOOLS_EMBED_DATA_H_
+
+#include <stddef.h> // For size_t.
+
+namespace mojo {
+namespace embed {
+
+struct Data {
+ const char* const hash;
+ const char* const data;
+ const size_t size;
+};
+
+} // namespace embed
+} // namespace mojo
+
+#endif // MOJO_TOOLS_EMBED_DATA_H_
diff --git a/mojo/tools/embed/embed_data.py b/mojo/tools/embed/embed_data.py
new file mode 100755
index 0000000..f34348a
--- /dev/null
+++ b/mojo/tools/embed/embed_data.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import argparse
+import hashlib
+import os
+import sys
+
+def main():
+ """Command line utility to embed file in a C executable."""
+ parser = argparse.ArgumentParser(
+ description='Generate a source file to embed the content of a file')
+
+ parser.add_argument('source')
+ parser.add_argument('out_dir')
+ parser.add_argument('namespace')
+ parser.add_argument('variable')
+
+ opts = parser.parse_args()
+
+ if not os.path.exists(opts.out_dir):
+ os.makedirs(opts.out_dir)
+
+ header = os.path.join(opts.out_dir, '%s.h' % opts.variable)
+ c_file = os.path.join(opts.out_dir, '%s.cc' % opts.variable)
+ namespaces = opts.namespace.split('::')
+
+ data = None
+ with open(opts.source, "rb") as f:
+ data = f.read()
+
+ with open(header, "w") as f:
+ f.write('// Generated file. Do not modify.\n')
+ f.write('\n')
+ f.write('#include "mojo/tools/embed/data.h"\n')
+ f.write('\n')
+ for n in namespaces:
+ f.write('namespace %s {\n' % n)
+ f.write('extern const mojo::embed::Data %s;\n' % opts.variable);
+ for n in reversed(namespaces):
+ f.write('} // namespace %s\n' % n)
+
+ sha1hash = hashlib.sha1(data).hexdigest()
+ values = ["0x%02x" % ord(c) for c in data]
+ lines = []
+ chunk_size = 16
+ for i in range(0, len(values), chunk_size):
+ lines.append(" " + ", ".join(values[i: i + chunk_size]))
+
+ with open(c_file, "w") as f:
+ f.write('// Generated file. Do not modify.\n')
+ f.write('\n')
+ f.write('#include "mojo/tools/embed/data.h"\n')
+ f.write('\n')
+ for n in namespaces:
+ f.write('namespace %s {\n' % n)
+ f.write('namespace {\n')
+ f.write("const char data[%d] = {\n" % len(data))
+ f.write(",\n".join(lines))
+ f.write("\n};\n")
+ f.write('} // namespace\n')
+ f.write('\n')
+ f.write('extern const mojo::embed::Data %s;\n' % opts.variable);
+ f.write('const mojo::embed::Data %s = {\n' % opts.variable);
+ f.write(' "%s",\n' % sha1hash)
+ f.write(' data,\n')
+ f.write(' sizeof(data)\n')
+ f.write('};\n');
+ f.write('\n')
+ for n in reversed(namespaces):
+ f.write('} // namespace %s\n' % n)
+
+if __name__ == '__main__':
+ main()
diff --git a/mojo/tools/embed/rules.gni b/mojo/tools/embed/rules.gni
new file mode 100644
index 0000000..6171812
--- /dev/null
+++ b/mojo/tools/embed/rules.gni
@@ -0,0 +1,49 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+template("embed_file") {
+ assert(defined(invoker.variable))
+ assert(defined(invoker.source))
+ assert(defined(invoker.namespace))
+
+ variable = invoker.variable
+ generator_target_name = "__${target_name}_generator"
+ generator_outputs = [
+ "${target_gen_dir}/${variable}.cc",
+ "${target_gen_dir}/${variable}.h",
+ ]
+
+ action(generator_target_name) {
+ script = "//mojo/tools/embed/embed_data.py"
+ sources = [
+ invoker.source,
+ ]
+ outputs = generator_outputs
+ args = [
+ rebase_path(invoker.source),
+ rebase_path(target_gen_dir),
+ invoker.namespace,
+ variable,
+ ]
+
+ if (defined(invoker.testonly)) {
+ testonly = invoker.testonly
+ }
+ if (defined(invoker.deps)) {
+ deps = invoker.deps
+ }
+ }
+
+ source_set(target_name) {
+ sources = generator_outputs
+
+ if (defined(invoker.testonly)) {
+ testonly = invoker.testonly
+ }
+
+ deps = [
+ ":${generator_target_name}",
+ ]
+ }
+}
diff --git a/services/icu_data/BUILD.gn b/services/icu_data/BUILD.gn
index 98b5a56..069e451 100644
--- a/services/icu_data/BUILD.gn
+++ b/services/icu_data/BUILD.gn
@@ -4,19 +4,12 @@
import("//mojo/public/mojo_application.gni")
import("//mojo/public/tools/bindings/mojom.gni")
+import("//mojo/tools/embed/rules.gni")
-action("embed_icu_data") {
- script = "embed_icu_data.py"
-
- inputs = [
- "$root_build_dir/icudtl.dat",
- ]
-
- outputs = [
- "$root_gen_dir/mojo/icu_data/data.cc",
- ]
-
- args = rebase_path(inputs + outputs, root_build_dir)
+embed_file("embed_icu_data") {
+ source = "$root_build_dir/icudtl.dat"
+ namespace = "icu_data"
+ variable = "kICUData"
deps = [
"//third_party/icu:icudata",
@@ -26,8 +19,6 @@
mojo_native_application("icu_data") {
sources = [
"icu_data_impl.cc",
- "data.h",
- "$root_gen_dir/mojo/icu_data/data.cc",
]
deps = [
diff --git a/services/icu_data/data.h b/services/icu_data/data.h
deleted file mode 100644
index 49097e5..0000000
--- a/services/icu_data/data.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2015 The Chromium 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 SERVICES_ICU_DATA_DATA_H_
-#define SERVICES_ICU_DATA_DATA_H_
-
-#include <cstddef>
-
-namespace icu_data {
-
-extern const char kICUDataTableHash[];
-extern const char kICUDataTable[];
-extern const size_t kICUDataTableSize;
-}
-
-#endif // SERVICES_ICU_DATA_DATA_H_
diff --git a/services/icu_data/embed_icu_data.py b/services/icu_data/embed_icu_data.py
deleted file mode 100755
index 515a3bb..0000000
--- a/services/icu_data/embed_icu_data.py
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import os
-import sys
-import hashlib
-
-in_file = sys.argv[1]
-out_file = sys.argv[2]
-
-out_dir = os.path.dirname(out_file)
-
-data = None
-with open(in_file, "rb") as f:
- data = f.read()
-
-if not os.path.exists(out_dir):
- os.makedirs(out_dir)
-
-sha1hash = hashlib.sha1(data).hexdigest()
-
-values = ["0x%02x" % ord(c) for c in data]
-lines = []
-chunk_size = 16
-for i in range(0, len(values), chunk_size):
- lines.append(", ".join(values[i: i + chunk_size]))
-
-with open(out_file, "w") as f:
- f.write('#include "services/icu_data/data.h"\n')
- f.write("namespace icu_data {\n")
- f.write("const char kICUDataTable[%d] = {\n" % len(data))
- f.write(",\n".join(lines))
- f.write("\n};\n")
- f.write("const size_t kICUDataTableSize = sizeof(kICUDataTable);\n")
- f.write("const char kICUDataTableHash[] = \"%s\";\n" % sha1hash)
- f.write("}\n")
diff --git a/services/icu_data/icu_data_impl.cc b/services/icu_data/icu_data_impl.cc
index a2eb6f6..be52bc0 100644
--- a/services/icu_data/icu_data_impl.cc
+++ b/services/icu_data/icu_data_impl.cc
@@ -9,8 +9,8 @@
#include "mojo/public/cpp/application/application_delegate.h"
#include "mojo/public/cpp/application/interface_factory.h"
#include "mojo/public/cpp/bindings/interface_ptr.h"
-#include "services/icu_data/data.h"
#include "services/icu_data/icu_data.mojom.h"
+#include "services/icu_data/kICUData.h"
namespace icu_data {
@@ -37,8 +37,8 @@
void Map(const mojo::String& sha1hash,
const mojo::Callback<void(mojo::ScopedSharedBufferHandle)>& callback)
override {
- if (std::string(sha1hash) != std::string(kICUDataTableHash)) {
- LOG(WARNING) << "Failed to match sha1sum. Expected " << kICUDataTableHash;
+ if (std::string(sha1hash) != std::string(kICUData.hash)) {
+ LOG(WARNING) << "Failed to match sha1sum. Expected " << kICUData.hash;
callback.Run(mojo::ScopedSharedBufferHandle());
return;
}
@@ -53,12 +53,12 @@
void EnsureBuffer() {
if (buffer_)
return;
- buffer_.reset(new mojo::SharedBuffer(kICUDataTableSize));
+ buffer_.reset(new mojo::SharedBuffer(kICUData.size));
void* ptr = nullptr;
- MojoResult rv = mojo::MapBuffer(buffer_->handle.get(), 0, kICUDataTableSize,
+ MojoResult rv = mojo::MapBuffer(buffer_->handle.get(), 0, kICUData.size,
&ptr, MOJO_MAP_BUFFER_FLAG_NONE);
CHECK_EQ(rv, MOJO_RESULT_OK);
- memcpy(ptr, kICUDataTable, kICUDataTableSize);
+ memcpy(ptr, kICUData.data, kICUData.size);
rv = mojo::UnmapBuffer(ptr);
CHECK_EQ(rv, MOJO_RESULT_OK);
}
diff --git a/shell/BUILD.gn b/shell/BUILD.gn
index e20c0e5..8e0e5ff 100644
--- a/shell/BUILD.gn
+++ b/shell/BUILD.gn
@@ -6,6 +6,7 @@
import("//mojo/public/mojo.gni")
import("//mojo/public/mojo_application.gni")
import("//mojo/public/tools/bindings/mojom.gni")
+import("//mojo/tools/embed/rules.gni")
import("//testing/test.gni")
# We don't support building in the component build since mojo apps are
@@ -507,6 +508,17 @@
}
}
+embed_file("embed_pingable") {
+ source = "$root_build_dir/pingable_app.mojo"
+ namespace = "mojo"
+ variable = "kPingable"
+ testonly = true
+
+ deps = [
+ "//shell/test:pingable_app",
+ ]
+}
+
mojo_native_application("apptests") {
output_name = "shell_apptests"
@@ -528,10 +540,8 @@
"//services/http_server/public",
"//services/http_server/public:util",
"//shell/test:bindings",
+ ":embed_pingable",
]
- data_deps = [
- "//services/http_server:http_server",
- "//shell/test:pingable_app",
- ]
+ data_deps = [ "//services/http_server:http_server" ]
}
diff --git a/shell/shell_apptest.cc b/shell/shell_apptest.cc
index 30f4fd7..7b610a7 100644
--- a/shell/shell_apptest.cc
+++ b/shell/shell_apptest.cc
@@ -18,8 +18,8 @@
#include "services/http_server/public/http_server.mojom.h"
#include "services/http_server/public/http_server_factory.mojom.h"
#include "services/http_server/public/http_server_util.h"
+#include "shell/kPingable.h"
#include "shell/test/pingable.mojom.h"
-
namespace mojo {
namespace {
@@ -34,9 +34,6 @@
public:
GetHandler(InterfaceRequest<http_server::HttpHandler> request, uint16_t port)
: binding_(this, request.Pass()), port_(port) {
- CHECK(PathService::Get(base::FILE_MODULE, &app_path_));
- app_path_ = app_path_.DirName().Append("pingable_app.mojo");
- CHECK(base::PathExists(app_path_));
}
~GetHandler() override {}
@@ -47,10 +44,8 @@
const Callback<void(http_server::HttpResponsePtr)>& callback) override {
http_server::HttpResponsePtr response;
if (StartsWithASCII(request->relative_url, "/app", true)) {
- // Super inefficient, but meh.
- std::string data;
- base::ReadFileToString(app_path_, &data);
- response = http_server::CreateHttpResponse(200, data);
+ response = http_server::CreateHttpResponse(
+ 200, std::string(kPingable.data, kPingable.size));
response->content_type = "application/octet-stream";
} else if (request->relative_url == "/redirect") {
response = http_server::HttpResponse::New();
@@ -64,7 +59,6 @@
}
Binding<http_server::HttpHandler> binding_;
- base::FilePath app_path_;
uint16_t port_;
MOJO_DISALLOW_COPY_AND_ASSIGN(GetHandler);
@@ -120,10 +114,6 @@
MOJO_DISALLOW_COPY_AND_ASSIGN(ShellHTTPAppTest);
};
-#if defined(OS_ANDROID)
-// These tests rely on data that needs to be bundled into the apptest binary in
-// order to work on Android.
-#else // !OS_ANDROID
// Test that we can load apps over http.
TEST_F(ShellHTTPAppTest, Http) {
InterfacePtr<Pingable> pingable;
@@ -188,7 +178,6 @@
pingable2->Ping("hello", callback);
base::RunLoop().Run();
}
-#endif // OS_ANDROID
// mojo: URLs can have querystrings too
TEST_F(ShellAppTest, MojoURLQueryHandling) {