blob: d848c646018559cc6f096ac76aca7faab4670844 [file] [log] [blame]
// Copyright 2018 The Fuchsia 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 "peridot/lib/module_manifest_source/module_package_source.h"
#include <dirent.h>
#include <sys/types.h>
#include <fs/service.h>
#include <lib/async/cpp/task.h>
#include <lib/fxl/files/directory.h>
#include <lib/fxl/files/file.h>
#include <lib/fxl/functional/make_copyable.h>
#include <lib/fxl/logging.h>
#include <lib/fxl/memory/weak_ptr.h>
#include <lib/fxl/strings/split_string.h>
#include <lib/fxl/strings/string_printf.h>
#include "peridot/lib/module_manifest_source/json.h"
#include "peridot/lib/module_manifest_source/package_util.h"
namespace modular {
namespace {
// NOTE: This must match the path specified in
// //peridot/build/module_manifest.gni
constexpr char kInitialModulePackagesIndexDir[] =
"/system/data/initial_module_packages";
} // namespace
using ::fuchsia::maxwell::internal::ModulePackageIndexer;
ModulePackageSource::ModulePackageSource(
component::StartupContext* const context)
: weak_factory_(this) {
context->outgoing().debug_dir()->AddEntry(
ModulePackageIndexer::Name_,
fbl::AdoptRef(new fs::Service([this](zx::channel channel) {
indexer_bindings_.AddBinding(
this,
fidl::InterfaceRequest<ModulePackageIndexer>(std::move(channel)));
return ZX_OK;
})));
}
ModulePackageSource::~ModulePackageSource() {}
void ModulePackageSource::IndexManifest(std::string package_name,
std::string module_manifest_path) {
FXL_DCHECK(dispatcher_);
FXL_DCHECK(new_entry_fn_);
std::string data;
if (!files::ReadFileToString(module_manifest_path, &data)) {
FXL_LOG(ERROR) << "Couldn't read module manifest from: "
<< module_manifest_path;
return;
}
fuchsia::modular::ModuleManifest entry;
if (!ModuleManifestEntryFromJson(data, &entry)) {
FXL_LOG(WARNING) << "Couldn't parse module manifest from: "
<< module_manifest_path;
return;
}
async::PostTask(
dispatcher_,
fxl::MakeCopyable([weak_this = weak_factory_.GetWeakPtr(), package_name,
entry = std::move(entry)]() mutable {
if (!weak_this) {
return;
}
weak_this->new_entry_fn_(entry.binary, std::move(entry));
}));
}
// TODO(vardhan): Move this into garnet's fxl.
void IterateDirectory(fxl::StringView dirname,
std::function<void(fxl::StringView)> callback) {
DIR* fd = opendir(dirname.data());
if (fd == nullptr) {
perror("Could not open module package index directory: ");
return;
}
struct dirent* dp = nullptr;
while ((dp = readdir(fd)) != nullptr) {
if (dp->d_name[0] != '.') {
callback(dp->d_name);
}
}
closedir(fd);
}
void ModulePackageSource::Watch(async_dispatcher_t* dispatcher, IdleFn idle_fn,
NewEntryFn new_fn, RemovedEntryFn removed_fn) {
dispatcher_ = dispatcher;
new_entry_fn_ = new_fn;
IterateDirectory(
kInitialModulePackagesIndexDir, [this](fxl::StringView filename) {
std::string contents;
if (!files::ReadFileToString(
fxl::StringPrintf("%s/%s", kInitialModulePackagesIndexDir,
filename.data()),
&contents)) {
FXL_LOG(ERROR) << "Could not read module package index: "
<< filename.data();
}
auto module_pkgs = fxl::SplitString(
contents, "\n", fxl::kTrimWhitespace, fxl::kSplitWantNonEmpty);
for (auto module_pkg_view : module_pkgs) {
auto module_pkg = module_pkg_view.ToString();
// TODO(vardhan): We only index module package with version=0. Do
// better.
IndexManifest(module_pkg,
GetModuleManifestPathFromPackage(module_pkg, "0"));
}
});
idle_fn();
}
} // namespace modular