Files
firebase-ios-sdk/GoogleDataTransportCCTSupport/ProtoSupport/proto_generator.py
T
Michael Haney 783ee5b126 Implement Firebase CoreDiagnostics (#3129)
* Implement CoreDiagnostics interop

For use by FirebaseCore.

Please pay special attention to the changes in FIRApp, I've replaced passing FIRApp in the notification with a data object that will eventually replace the same information that FIRDiagnostics extracted.

* Add CoreDiagnosticsInterop to the Example Podfile

* Style and xcodeproj updates

* Update Podfiles that dep on FirebaseCore

So that they also have a dep on FirebaseCoreDiagnosticsInterop

* ran pod deintegrate to remove unintended xcodeproj changes

* Fix Podfile paths

* Add FCD to if_changed and travis.yml

* Fix building with Firestore

* Style

* Whitespace

* Fix a changed internal API

* Make pod paths consistent

* Restore connectivity_monitor_noop.cc style

* Remove logging prior to [FIRApp configure]

Also remove sendLogsWithServiceName:version:

* style

* Remove nil checks from diagnostics data

* Put back some deleted symbols

* Restore the sendLogsWithServiceName:version: method, but as a no-op

* Restore the original version of sendLogs...

* Allow an unused parameter

* Remove obsolete nsnotificationcenter related stuff

* Whoops, missed the header change.

* Final changes to support FIRCoreDiagnostics

These changes are necessary because FIRCore has a hard dep on FIRCoreDiagnostics (FIRCD) and FIRCoreDiagnosticsInterop.

Components can't be used because FIRCD would need to have a hard dep on FIRCore to get access to FIRLibrary, FIRComponent, FIRComponentContainer, and FIRComponentCreationBlock and this would create a dep cycle. So, an extern has been put into the interop lib and the variable is implemented in the connector class inside of FIRCore, but it's unset. FIRCD actually sets that variable in +load, allowing use of FIRCD.

FIRCD can also be removed as a dependency with no ill effect by end users setting the environment variable DISABLE_FIREBASE_DIAGNOSTICS=1

* Add nanopb and project generation infrastructure

* Convert FIRCoreDiagnostics to canonical nanopb, and move to OSS.

* Remove custom build steps for CoreDiagnostics

* Addressing review comments

* Update versions, tags, and port the relevant unit tests for FIRCD

* Version and platform fixes

* Fix podspec expected tags

* A hack to solve a chicken-and-egg problem with pod lib linting.

* Heartbeat implementation

* FIRDiagnosticsDateFileStorageTests

* Fix tests for non-iOS platforms

* Heartbeat tests

* Fix initialization.

* Cleanup Installation ID.

* Fix testProtoPopulation.

* Merge conflict fix

* Typo fix.

* Remove FIRCore dep from FIRCD unit tests and move symbols to interop

* Run ./scripts/style.sh

* Typo

* #ifdef comment

* File license header.

* Import FIRDiagnosticsDateFileStorage.h using relative path.

* FIRDiagnostics -> FIRCoreDiagnostics

* Docs syntax

* Docs

* Docs typo

* Add shared variables to the interop lib

I know this goes against the convention, but it's actually the only way to resolve this very unique problem.

* Fix comment

* Style

* Removed lib version passing.

* Remove env checking for conditional deps

* Style

* Address whitespace issues

* Add copyright notice

* Add new deps to Podfiles

* Fix trailing space

* Some changes to fix working in an extension.

* Fix type in Podfile

* GDT: begin/end background task only for iOS and TVOS applications.

* Fix typo

* Style

* Stop sharing kFIRService strings across pods

* Travis test

* Change all TARGET_OS_TVOS macros to TARGET_OS_TV

TARGET_OS_TVOS doesn't exist.

Also macro out a UIApplication reference.

* style

* Update all Podfiles with deps on FIRCore

* Fix trailing whitespace

* Update Firestore cmake

* Fix FIAM build break (#3254)

* Additional cmake changes

* Fix linker issue with deprecated CoreDiagnostics (#3257)

* Adding more deps to cmake

* Fix linker error (#3266)

* Rerun only IAM tests

* whitespace

* No xcpretty or frameworks run

* Fix typo

* Revert "No xcpretty or frameworks run"

This reverts commit afc1abba37.

* Revert "whitespace"

This reverts commit fd06955a56.

* Revert "Rerun only IAM tests"

This reverts commit 98ce07600f.

* Run travis on this branch

* Add support for expanding PODS_TARGET_SRCROOT in CMake (#3267)

* Fix a few things that should have been splatted but weren't

* Define PODS_TARGET_SRCROOT in CMake for compatibility with CocoaPods

* Compile pods we depend upon with looser settings

* Rename the nanopb dependency to match what CMake actually has

* Make #include <nanopb/pb.h> work

Remove the old way of #include <pb.h> once we change the Firestore
nanopb generator to match.

* Fix warnings that fail the build

* Remove typed enum and fix a comment.

* Fix an import

* Change a line so it's not altered by Copybara

* More changes to stop copybara from altering the wrong sources

* Remove trailing whitespace

* Fix copybara modifying python.

* Add additional field in firebasecore.proto (#3273)

* Remove the dependency on interop to populate a shared variable.

* style

* Create travis jobs for FirebaseCoreDiagnostics (#3245)

* Create travis jobs for FirebaseCoreDiagnostics

And update the pod lib lints for GDT.

Remove the mph-master branch before merging to master.

* Add support for FIRCD to if_changed.sh

* Adjust tests

* Unavailable init methods should not be nullable (#3276)

* Allow firestore api to work with Codable objects + ExplicitNull + Integration tests (#3261)

* Convinience api for codables

* Integration Tests

* ExplicitNull implementation

* Update to CocoaPods 1.7.3 (#3280)

* Import GULLoggerLevel.h via public framework header (#3277)

* Put the need to include Firestore/Source/Public in the podspec (#3288)

This removes the need to munge the pods project after the fact and makes
it so that customers can click through to our headers too.

* Ensure Storage initializer doesn't get called (#3294)

* FIROptions.appGroupID introduced (#3293)

* Use a consistent set of dependencies on all platforms (#3289)

* Use a consistent set of dependencies on all platforms

* pod install for uniform dependencies

* Store the coerced base value in the BaseMutation (#3292)

* In card message: set the text color on the body text view (#3286)

* In card message: set the text color on the body text view

* Fix bug where card messages in test app were showing up with two of the same buttons

* Revert change to text color

* [docs] add missing semicolon (#3305)

Add missing semicolon to code example

* Add explicit Foundation import. (#3309)

This is causing issues when building an XCFramework.

* Pass the correct compiler flag for CoreDiagnostics. (#3312)

* Pass the correct compiler flag for CoreDiagnostics.

When CoreDiagnostics is open sourced, we'll need to ensure that the
right compiler flag is passed. This doesn't add support for Carthage yet
but allows the frameworkbuilder to pass the flag for carthage as well.
An update to the zipbuilder to allow for carthage will follow shortly.

* Remove accidental change.

* Fix and rewrite sync_project.rb (#3296)

* Fix and rewrite sync_project.rb

Ever since we added multiple platforms, removing a file has been broken.
This fixes that issue.

Also, rewrite target synchronization to make more sense. Essentially now
there's one diff between the filesystem and the groups and then an
explicit diff is done between project files and target contents.

* Run sync_project.rb on post-install

* pod lib linting should output something every minute while running

* DEBUG: This commit should be reverted

* DEBUG: This commit should be reverted

* DEBUG: This commit should be reverted

* Remove mph-master from travis

* Fix constant name conflic between old and new diagnostics (#3329)

* Rename kFIRDiagnosticsHeartbeatDateFileName -> kFIRCoreDiagnosticsHeartbeatDateFileName to avoid conflicts with FIRDiagnostics.

* Travis: temporary add `mph-master` to run tests.

* Rempve mph-master again

* Fix imports in FIRCDConnector

* Fix another import

* Fix yet another import

* Attempt to read crashing test logs from disk

* Implement printing of failed/crashed test logs.

* Print only crashed tests, rmdir between runs

* Revert reading crashing log changes

* Write CHANGELOG for all new FIRCD associated libraries

* Change all GUL deps to >= 6.2

* Revert ZipBuilder changes and do some last bits of cleanup

* Remove an assertion and populate an error instead
2019-07-18 09:54:06 -07:00

323 lines
8.8 KiB
Python
Executable File

#! /usr/bin/env python
# Copyright 2019 Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Generates and massages protocol buffer outputs.
Example usage:
python GoogleDataTransportCCTSupport/GoogleDataTransportCCTSupport/ProtoSupport/build_protos.py \
--nanopb \
--protos_dir=GoogleDataTransportCCTSupport/GoogleDataTransportCCTSupport/Classes/Protos/ \
--pythonpath=~/Downloads/nanopb-0.3.9.2-macosx-x86/generator/ \
--output_dir=GoogleDataTransportCCTSupport/GoogleDataTransportCCTSupport/Classes/Protogen/
"""
from __future__ import print_function
import sys
import argparse
import os
import os.path
import re
import subprocess
OBJC_GENERATOR='nanopb_objc_generator.py'
COPYRIGHT_NOTICE = '''
/*
* Copyright 2019 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'''.lstrip()
def main():
parser = argparse.ArgumentParser(
description='Generates proto messages.')
parser.add_argument(
'--nanopb', action='store_true',
help='Generates nanopb messages.')
parser.add_argument(
'--objc', action='store_true',
help='Generates Objective-C messages.')
parser.add_argument(
'--protos_dir',
help='Source directory containing .proto files.')
parser.add_argument(
'--output_dir', '-d',
help='Directory to write files; subdirectories will be created.')
parser.add_argument(
'--protoc', default='protoc',
help='Location of the protoc executable')
parser.add_argument(
'--pythonpath',
help='Location of the protoc python library.')
parser.add_argument(
'--include', '-I', action='append', default=[],
help='Adds INCLUDE to the proto path.')
args = parser.parse_args()
if args.nanopb is None and args.objc is None:
parser.print_help()
sys.exit(1)
if args.protos_dir is None:
root_dir = os.path.abspath(os.path.dirname(__file__))
args.protos_dir = os.path.join(root_dir, 'protos')
if args.output_dir is None:
root_dir = os.path.abspath(os.path.dirname(__file__))
args.output_dir = os.path.join(root_dir, 'protogen-please-supply-an-outputdir')
all_proto_files = collect_files(args.protos_dir, '.proto')
if args.nanopb:
NanopbGenerator(args, all_proto_files).run()
proto_files = remove_well_known_protos(all_proto_files)
if args.objc:
ObjcProtobufGenerator(args, proto_files).run()
class NanopbGenerator(object):
"""Builds and runs the nanopb plugin to protoc."""
def __init__(self, args, proto_files):
self.args = args
self.proto_files = proto_files
def run(self):
"""Performs the action of the generator."""
nanopb_out = os.path.join(self.args.output_dir, 'nanopb')
mkdir(nanopb_out)
self.__run_generator(nanopb_out)
sources = collect_files(nanopb_out, '.nanopb.h', '.nanopb.c')
post_process_files(
sources,
add_copyright,
nanopb_remove_extern_c,
nanopb_rename_delete,
nanopb_use_module_import
)
def __run_generator(self, out_dir):
"""Invokes protoc using the nanopb plugin."""
cmd = protoc_command(self.args)
gen = os.path.join(os.path.dirname(__file__), OBJC_GENERATOR)
cmd.append('--plugin=protoc-gen-nanopb=%s' % gen)
nanopb_flags = [
'--extension=.nanopb',
'--source-extension=.c',
'--no-timestamp'
]
nanopb_flags.extend(['-I%s' % path for path in self.args.include])
cmd.append('--nanopb_out=%s:%s' % (' '.join(nanopb_flags), out_dir))
cmd.extend(self.proto_files)
run_protoc(self.args, cmd)
def protoc_command(args):
"""Composes the initial protoc command-line including its include path."""
cmd = [args.protoc]
if args.include is not None:
cmd.extend(['-I=%s' % path for path in args.include])
return cmd
def run_protoc(args, cmd):
"""Actually runs the given protoc command.
Args:
args: The command-line args (including pythonpath)
cmd: The command to run expressed as a list of strings
"""
kwargs = {}
if args.pythonpath:
env = os.environ.copy()
old_path = env.get('PYTHONPATH')
env['PYTHONPATH'] = os.path.expanduser(args.pythonpath)
if old_path is not None:
env['PYTHONPATH'] += os.pathsep + old_path
kwargs['env'] = env
try:
print(subprocess.check_output(cmd, stderr=subprocess.STDOUT, **kwargs))
except subprocess.CalledProcessError as error:
print('command failed: ', ' '.join(cmd), '\nerror: ', error.output)
def remove_well_known_protos(filenames):
"""Remove "well-known" protos for objc.
On those platforms we get these for free as a part of the protobuf runtime.
We only need them for nanopb.
Args:
filenames: A list of filenames, each naming a .proto file.
Returns:
The filenames with members of google/protobuf removed.
"""
return [f for f in filenames if 'protos/google/protobuf/' not in f]
def post_process_files(filenames, *processors):
for filename in filenames:
lines = []
with open(filename, 'r') as fd:
lines = fd.readlines()
for processor in processors:
lines = processor(lines)
write_file(filename, lines)
def write_file(filename, lines):
mkdir(os.path.dirname(filename))
with open(filename, 'w') as fd:
fd.write(''.join(lines))
def add_copyright(lines):
"""Adds a copyright notice to the lines."""
result = [COPYRIGHT_NOTICE, '\n']
result.extend(lines)
return result
def nanopb_remove_extern_c(lines):
"""Removes extern "C" directives from nanopb code.
Args:
lines: A nanobp-generated source file, split into lines.
Returns:
A list of strings, similar to the input but modified to remove extern "C".
"""
result = []
state = 'initial'
for line in lines:
if state == 'initial':
if '#ifdef __cplusplus' in line:
state = 'in-ifdef'
continue
result.append(line)
elif state == 'in-ifdef':
if '#endif' in line:
state = 'initial'
return result
def nanopb_rename_delete(lines):
"""Renames a delete symbol to delete_.
If a proto uses a field named 'delete', nanopb happily uses that in the
message definition. Works fine for C; not so much for C++.
Args:
lines: The lines to fix.
Returns:
The lines, fixed.
"""
delete_keyword = re.compile(r'\bdelete\b')
return [delete_keyword.sub('delete_', line) for line in lines]
def nanopb_use_module_import(lines):
"""Changes #include <pb.h> to include <nanopb/pb.h>""" # Don't let Copybara alter these lines.
return [line.replace('#include <pb.h>', '{}include <nanopb/pb.h>'.format("#")) for line in lines]
def strip_trailing_whitespace(lines):
"""Removes trailing whitespace from the given lines."""
return [line.rstrip() + '\n' for line in lines]
def objc_flatten_imports(lines):
"""Flattens the import statements for compatibility with CocoaPods."""
long_import = re.compile(r'#import ".*/')
return [long_import.sub('#import "', line) for line in lines]
def objc_strip_extension_registry(lines):
"""Removes extensionRegistry methods from the classes."""
skip = False
result = []
for line in lines:
if '+ (GPBExtensionRegistry*)extensionRegistry {' in line:
skip = True
if not skip:
result.append(line)
elif line == '}\n':
skip = False
return result
def collect_files(root_dir, *extensions):
"""Finds files with the given extensions in the root_dir.
Args:
root_dir: The directory from which to start traversing.
*extensions: Filename extensions (including the leading dot) to find.
Returns:
A list of filenames, all starting with root_dir, that have one of the given
extensions.
"""
result = []
for root, _, files in os.walk(root_dir):
for basename in files:
for ext in extensions:
if basename.endswith(ext):
filename = os.path.join(root, basename)
result.append(filename)
return result
def mkdir(dirname):
if not os.path.isdir(dirname):
os.makedirs(dirname)
if __name__ == '__main__':
main()