Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
dnkoutso committed Feb 23, 2022
1 parent a0e6e39 commit 6c19c25
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 47 deletions.
16 changes: 13 additions & 3 deletions objectivec/README.md
Expand Up @@ -182,13 +182,23 @@ supported keys are:
having to add the runtime directory to the header search path since the
generate `#import` will be more complete.

* `objc_class_prefix_to_proto_package_mappings_path`: The `value` used for
* `prefix_to_proto_package_mappings_path`: The `value` used for
this key is a path to a file containing a list of prefixes and proto packages.
The generator will use this to locate a ObjC class prefix to use when
The generator will use this to locate which ObjC class prefix to use when
generating sources _unless_ the `objc_class_prefix` file option is set.
This option can be useful if multiple apps consume a common set of
proto files but wish to use a different prefix for the generated sources
between them. This option has a precedent over the `use_package_as_prefix` option.
between them. This option takes precedent over the `use_package_as_prefix`
option.

The format of the file is:
* An entry is a line of "package=prefix".
* Comments start with `#`.
* A comment can go on a line after a expected package/prefix pair.
(i.e. - "package=prefix # comment")
* For files that do NOT have a proto package (not recommended), an
entry can be made as "no_package:PATH=prefix", where PATH is the
path for the .proto file.

* `use_package_as_prefix` and `proto_package_prefix_exceptions_path`: The
`value` for `use_package_as_prefix` can be `yes` or `no`, and indicates
Expand Down
12 changes: 8 additions & 4 deletions src/google/protobuf/compiler/objectivec/objectivec_generator.cc
Expand Up @@ -190,17 +190,21 @@ bool ObjectiveCGenerator::GenerateAll(
// header search path since the generate #import will be more complete.
generation_options.runtime_import_prefix =
StripSuffixString(options[i].second, "/");
} else if (options[i].first == "objc_class_prefix_mappings_path") {
} else if (options[i].first == "prefix_to_proto_package_mappings_path") {
// Path to use for when loading the objc class prefix mappings to use.
// The `objc_class_prefix` file option is always honored first if one is present.
// This option also has precedent over the use_package_as_prefix option.
//
// The format of the file is:
// - An entry is a line of "objc_class_prefix: file.proto, dir/file2.proto".
// - An entry is a line of "package=prefix".
// - Comments start with "#".
// - A comment can go on a line after a expected package/prefix pair.
// (i.e. - "GPB: descriptor.proto # comment")
// (i.e. - "package=prefix # comment")
// - For files that do NOT have a proto package (not recommended), an
// entry can be made as "no_package:PATH=prefix", where PATH is the
// path for the .proto file.
//
SetObjCClassPrefixMappingsPath(options[i].second);
SetPrefixToProtoPackageMappingsPath(options[i].second);
} else if (options[i].first == "use_package_as_prefix") {
// Controls how the symbols should be prefixed to avoid symbols
// collisions. The objc_class_prefix file option is always honored first
Expand Down
83 changes: 46 additions & 37 deletions src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
Expand Up @@ -95,17 +95,28 @@ class SimpleLineCollector : public LineConsumer {
std::unordered_set<std::string>* set_;
};

class ExpectedPrefixesCollector : public LineConsumer {
public:
ExpectedPrefixesCollector(std::map<std::string, std::string>* inout_package_to_prefix_map)
: prefix_map_(inout_package_to_prefix_map) {}

virtual bool ConsumeLine(const StringPiece& line, std::string* out_error) override;

private:
std::map<std::string, std::string>* prefix_map_;
};

class PrefixModeStorage {
public:
PrefixModeStorage();

const std::string objc_class_prefix_mappings_path() const { return objc_class_prefix_mappings_path_; }
void set_objc_class_prefix_mappings_path(const std::string& path) {
objc_class_prefix_mappings_path_ = path;
objc_class_prefix_map_.clear();
const std::string prefix_to_proto_package_mappings_path() const { return prefix_to_proto_package_mappings_path_; }
void set_prefix_to_proto_package_mappings_path(const std::string& path) {
prefix_to_proto_package_mappings_path_ = path;
prefix_to_proto_package_map_.clear();
}

std::string objc_class_prefix(const FileDescriptor* file);
std::string prefix_from_proto_package_mappings(const FileDescriptor* file);

bool use_package_name() const { return use_package_name_; }
void set_use_package_name(bool on_or_off) { use_package_name_ = on_or_off; }
Expand All @@ -124,8 +135,8 @@ class PrefixModeStorage {

private:
bool use_package_name_;
std::map<std::string, std::string> objc_class_prefix_map_;
std::string objc_class_prefix_mappings_path_;
std::map<std::string, std::string> prefix_to_proto_package_map_;
std::string prefix_to_proto_package_mappings_path_;
std::string exception_path_;
std::string forced_prefix_;
std::unordered_set<std::string> exceptions_;
Expand All @@ -150,33 +161,42 @@ PrefixModeStorage::PrefixModeStorage() {
}
}

std::string PrefixModeStorage::objc_class_prefix(const FileDescriptor* file) {
std::string PrefixModeStorage::prefix_from_proto_package_mappings(const FileDescriptor* file) {
if (!file) {
return "";
}

if (objc_class_prefix_map_.empty() && !objc_class_prefix_mappings_path_.empty()) {
if (prefix_to_proto_package_map_.empty() && !prefix_to_proto_package_mappings_path_.empty()) {
std::string error_str;
// Re use the same collector as we use for the named framework paths as the file
// is expected to be in the same format.
ImportWriter::ProtoFrameworkCollector collector(&objc_class_prefix_map_);
if (!ParseSimpleFile(objc_class_prefix_mappings_path_, &collector, &error_str)) {
// Re use the same collector as we use for expected_prefixes_path since the file
// format is the same.
ExpectedPrefixesCollector collector(&prefix_to_proto_package_map_);
if (!ParseSimpleFile(prefix_to_proto_package_mappings_path_, &collector, &error_str)) {
if (error_str.empty()) {
error_str = std::string("protoc:0: warning: Failed to parse")
+ std::string(" objc class prefix mappings file: ")
+ objc_class_prefix_mappings_path_;
+ std::string(" prefix to proto package mappings file: ")
+ prefix_to_proto_package_mappings_path_;
}
std::cerr << error_str << std::endl;
std::cerr.flush();
objc_class_prefix_map_.clear();
prefix_to_proto_package_map_.clear();
}
}

std::map<std::string, std::string>::iterator objc_class_prefix_lookup =
objc_class_prefix_map_.find(file->name());
const std::string package = file->package();
// For files without packages, the can be registered as "no_package:PATH",
// allowing the expected prefixes file.
static const std::string no_package_prefix("no_package:");
const std::string lookup_key = package.empty() ? no_package_prefix + file->name() : package;

std::cerr << lookup_key << std::endl;
std::cerr.flush();

if (objc_class_prefix_lookup != objc_class_prefix_map_.end()) {
return objc_class_prefix_lookup->second;
std::map<std::string, std::string>::const_iterator prefix_lookup =
prefix_to_proto_package_map_.find(lookup_key);

if (prefix_lookup != prefix_to_proto_package_map_.end()) {
return prefix_lookup->second;
}

return "";
Expand Down Expand Up @@ -211,12 +231,12 @@ PrefixModeStorage g_prefix_mode;

} // namespace

std::string GetObjCClassPrefixMappingsPath() {
return g_prefix_mode.objc_class_prefix_mappings_path();
std::string GetPrefixToProtoPackageMappingsPath() {
return g_prefix_mode.prefix_to_proto_package_mappings_path();
}

void SetObjCClassPrefixMappingsPath(const std::string& file_path) {
g_prefix_mode.set_objc_class_prefix_mappings_path(file_path);
void SetPrefixToProtoPackageMappingsPath(const std::string& file_path) {
g_prefix_mode.set_prefix_to_proto_package_mappings_path(file_path);
}

bool UseProtoPackageAsDefaultPrefix() {
Expand Down Expand Up @@ -581,8 +601,8 @@ std::string FileClassPrefix(const FileDescriptor* file) {
return file->options().objc_class_prefix();
}

// If package prefix is specified in an objc class prefix mapping file then use that.
std::string objc_class_prefix = g_prefix_mode.objc_class_prefix(file);
// If package prefix is specified in an prefix to proto mappings file then use that.
std::string objc_class_prefix = g_prefix_mode.prefix_from_proto_package_mappings(file);
if (!objc_class_prefix.empty()) {
return objc_class_prefix;
}
Expand Down Expand Up @@ -1261,17 +1281,6 @@ void RemoveComment(StringPiece* input) {

namespace {

class ExpectedPrefixesCollector : public LineConsumer {
public:
ExpectedPrefixesCollector(std::map<std::string, std::string>* inout_package_to_prefix_map)
: prefix_map_(inout_package_to_prefix_map) {}

virtual bool ConsumeLine(const StringPiece& line, std::string* out_error) override;

private:
std::map<std::string, std::string>* prefix_map_;
};

bool ExpectedPrefixesCollector::ConsumeLine(
const StringPiece& line, std::string* out_error) {
int offset = line.find('=');
Expand Down
6 changes: 3 additions & 3 deletions src/google/protobuf/compiler/objectivec/objectivec_helpers.h
Expand Up @@ -48,8 +48,8 @@ namespace compiler {
namespace objectivec {

// Get/Set the path to a file to load for objc class prefix lookups.
std::string PROTOC_EXPORT GetObjCClassPrefixMappingsPath();
void PROTOC_EXPORT SetObjCClassPrefixMappingsPath(
std::string PROTOC_EXPORT GetPrefixToProtoPackageMappingsPath();
void PROTOC_EXPORT SetPrefixToProtoPackageMappingsPath(
const std::string& file_path);
// Get/Set if the proto package should be used to make the default prefix for
// symbols. This will then impact most of the type naming apis below. It is done
Expand Down Expand Up @@ -315,7 +315,7 @@ class PROTOC_EXPORT ImportWriter {
const std::vector<std::string>& header_to_import,
const std::string& runtime_import_prefix,
bool default_cpp_symbol = false);

private:
class ProtoFrameworkCollector : public LineConsumer {
public:
ProtoFrameworkCollector(std::map<std::string, std::string>* inout_proto_file_to_framework_name)
Expand Down

0 comments on commit 6c19c25

Please sign in to comment.