Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -497,11 +497,18 @@ DEFINE_string(fuchsia_root_image, CF_DEFAULTS_FUCHSIA_ROOT_IMAGE,

DEFINE_string(
custom_partition_path, CF_DEFAULTS_CUSTOM_PARTITION_PATH,
"Location of custom image that will be passed as a \"custom\" partition"
"to rootfs and can be used by /dev/block/by-name/custom. Multiple images "
"can be passed, separated by semicolons and can be used as "
"/dev/block/by-name/custom_1, /dev/block/by-name/custom_2, etc. Example: "
"--custom_partition_path=\"/path/to/custom.img;/path/to/other.img\"");
"Location of custom image that will be passed as a custom partition "
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is both valid and useful. My only concern is that the new syntax relies on segment ordering and specific positioning, which will be difficult to manage as we introduce additional segments in the future.

What do you think about using a key=value syntax separated by commas instead? It would look something like this: name=oem,path=./oem.img,ab=true;name=oem2,path=./oem2.img;.... Utilizing the absl library should make the parsing code simple to implement and easy to maintain.

"to rootfs. Multiple entries can be passed, separated by semicolons. "
"Each entry uses key=value pairs separated by commas. "
"Supported keys: name (partition label), path (image file path), "
"ab (true/false for A/B slots). 'path' is required; 'name' defaults to "
"'custom', 'custom_1', etc.; 'ab' defaults to false. "
"Example with A/B: "
"--custom_partition_path=\"name=oem1,path=./oem1.img,ab=true;"
"name=oem2,path=./oem2.img\" "
"Example without names (legacy): "
"--custom_partition_path=\"/path/to/custom.img;/path/to/other.img\" "
"For multi-instance, separate per-instance values with '|'.");

DEFINE_string(
blank_sdcard_image_mb, CF_DEFAULTS_BLANK_SDCARD_IMAGE_MB,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <string_view>
#include <vector>

#include "absl/log/log.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_split.h"

Expand Down Expand Up @@ -72,6 +73,63 @@ std::optional<ImagePartition> HibernationImage(
return FileExists(path) ? std::optional<ImagePartition>(image) : std::nullopt;
}

struct CustomPartitionSpec {
std::string label;
std::string path;
bool ab_enabled;
};

Result<CustomPartitionSpec> ParseCustomPartitionSpec(std::string_view spec,
int index) {
std::string label;
std::string path;
bool ab_enabled = false;

// Key=value format: "name=oem,path=./oem.img,ab=true"
if (spec.find('=') != std::string_view::npos) {
std::vector<std::string_view> kvpairs = absl::StrSplit(spec, ',');
for (const auto& kvpair : kvpairs) {
std::vector<std::string_view> kv = absl::StrSplit(kvpair, '=');
CF_EXPECTF(kv.size() == 2,
"Invalid key=value pair '{}' in custom partition spec '{}'",
kvpair, spec);
std::string_view key = kv[0];
std::string_view value = kv[1];
if (key == "name") {
label = std::string(value);
} else if (key == "path") {
path = std::string(value);
} else if (key == "ab") {
CF_EXPECTF(value == "true" || value == "false",
"Invalid value '{}' for key 'ab' in custom partition spec "
"'{}'. Expected 'true' or 'false'",
value, spec);
ab_enabled = (value == "true");
} else {
return CF_ERRF("Unknown key '{}' in custom partition spec '{}'. "
"Valid keys are: name, path, ab",
key, spec);
}
}
CF_EXPECTF(!path.empty(),
"Missing required 'path' key in custom partition spec '{}'",
spec);
if (label.empty()) {
label = index > 0 ? "custom_" + std::to_string(index) : "custom";
}
} else {
// Legacy format: plain path only
label = index > 0 ? "custom_" + std::to_string(index) : "custom";
path = std::string(spec);
}

return CustomPartitionSpec{
.label = std::move(label),
.path = std::move(path),
.ab_enabled = ab_enabled,
};
}

} // namespace

Result<std::vector<ImagePartition>> AndroidCompositeDiskConfig(
Expand Down Expand Up @@ -214,10 +272,26 @@ Result<std::vector<ImagePartition>> AndroidCompositeDiskConfig(
std::vector<std::string_view> custom_partition_paths =
absl::StrSplit(custom_partition_path, ';');
for (int i = 0; i < custom_partition_paths.size(); i++) {
partitions.push_back(ImagePartition{
.label = i > 0 ? "custom_" + std::to_string(i) : "custom",
.image_file_path = AbsolutePath(custom_partition_paths[i]),
});
CustomPartitionSpec spec =
CF_EXPECT(ParseCustomPartitionSpec(custom_partition_paths[i], i));
if (spec.ab_enabled) {
VLOG(1) << "Adding custom partition: " << spec.label + "_a";
partitions.push_back(ImagePartition{
.label = spec.label + "_a",
.image_file_path = AbsolutePath(spec.path),
});
VLOG(1) << "Adding custom partition: " << spec.label + "_b";
partitions.push_back(ImagePartition{
.label = spec.label + "_b",
.image_file_path = AbsolutePath(spec.path),
});
} else {
VLOG(1) << "Adding custom partition: " << spec.label;
partitions.push_back(ImagePartition{
.label = spec.label,
.image_file_path = AbsolutePath(spec.path),
});
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ Result<std::string> DiskBuilder::TextConfig() {
CF_EXPECT(!partitions_.empty() ^ !entire_disk_.empty(),
"Specify either partitions or a whole disk");
for (auto& partition : partitions_) {
disk_conf << partition.image_file_path << "\n";
disk_conf << partition.label << ":" << partition.image_file_path << "\n";
}
if (!entire_disk_.empty()) {
disk_conf << entire_disk_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,10 @@ Result<void> DiskImageFlagsVectorization(
std::vector<std::string> fuchsia_root_image =
absl::StrSplit(FLAGS_fuchsia_root_image, ',');

// custom_partition_path uses ',' inside key=value entries, so split
// on '|' for multi-instance separation instead of ','.
std::vector<std::string> custom_partition_path =
absl::StrSplit(FLAGS_custom_partition_path, ',');
absl::StrSplit(FLAGS_custom_partition_path, '|');

std::vector<std::string> blank_sdcard_image_mb =
absl::StrSplit(FLAGS_blank_sdcard_image_mb, ',');
Expand Down