Skip to content

Split GoogleUtilities from FirebaseCore #1370

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 49 commits into from
Jul 6, 2018
Merged

Split GoogleUtilities from FirebaseCore #1370

merged 49 commits into from
Jul 6, 2018

Conversation

paulb777
Copy link
Member

@paulb777 paulb777 commented Jun 1, 2018

Create a new FirebaseUtilities pod consisting of Network, Environment, and Logger subspecs - extracted from FirebaseCore. A follow-on PR will add a Swizzler subspec.

@paulb777
Copy link
Member Author

paulb777 commented Jun 1, 2018

This PR is not yet ready for detailed review. Current status is the six components in the Firebase Xcode project build and pass their unit tests with the new structure. For now, I've left the Utilities unit tests combined with Core.

Next steps:

  • Verify Firestore and Functions
  • Verify static libraries
  • Invent infrastructure to do do pod lib lint when FirebaseCore API's change
  • Run copybara and integrate closed sourced dependencies

cc: @ryanwilson, @baolocdo, @tejasd

@paulb777 paulb777 added this to the M28 milestone Jun 1, 2018
@wilhuff
Copy link
Contributor

wilhuff commented Jun 1, 2018

Does this name (and grouping) at all align with Android? How does this relate to firebase_common over there?

It's getting hard to discuss/reason about dependencies across the platforms.

@paulb777
Copy link
Member Author

paulb777 commented Jun 1, 2018

@wilhuff I discussed with @bjornick and Android doesn't currently have shared utilities other than what might be in GMSCore.

@paulb777 paulb777 force-pushed the pb-utilities branch 3 times, most recently from 916d170 to a5ccdea Compare June 2, 2018 02:11
@paulb777 paulb777 changed the title WIP - Split FirebaseUtilities from FirebaseCore Split FirebaseUtilities from FirebaseCore Jun 2, 2018
@paulb777
Copy link
Member Author

paulb777 commented Jun 2, 2018

Travis is green and the PR is ready for review. I'm planning to wait until after the 5.2.0 merge back to master before merging this one.

Copy link

@baolocdo baolocdo left a comment

Choose a reason for hiding this comment

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

Can we call it Utilities or something different from FirebaseUtilities? The point of having a separate module is that it can be depended on by Analytics without explicitly mentioning Firebase.

@paulb777
Copy link
Member Author

paulb777 commented Jun 2, 2018

@baolocdo Do you have a suggestion for something more specific than Utiliities? Utilities seems too non-descriptive for something being published in the CocoaPods namespace and something that will be used by many different Google products.

What exactly is the reason for not mentioning Firebase? It seems that FirebaseUtilities is the most descriptive since the Firebase team owns the code and it the utilities are primarily used by Firebase. Analytics uses other utility pods already like GoogleToolboxForMac and nanopb.

@paulb777
Copy link
Member Author

paulb777 commented Jun 2, 2018

@salqadri Please help with the naming of the Utilities pod.

@paulb777 paulb777 modified the milestones: 5.3.0, M29 Jun 13, 2018
@paulb777 paulb777 modified the milestones: M29, M30 Jun 25, 2018
@paulb777 paulb777 force-pushed the pb-utilities branch 3 times, most recently from b001565 to bf3a795 Compare June 28, 2018 21:29
@paulb777
Copy link
Member Author

Now ready for review:

  • Split out GoogleUtilities from FirebaseCore
  • Change prefix to GUL (for GoogleUtilitiesLibrary) for moved symbols
  • Replace usage of GoogleToolboxForMac/NSData+zlib with a subspec in GoogleUtilities
  • Add ALT_SOURCES and temporary tag mechanisms to enable pre-release lint testing when dependency pods change
  • Keep FIRLogger as a wrapper around GULLogger with Firebase specific functionality and to make transition easier
  • Split Reachability into its own subspec for FirebaseMessaging
  • Replace GoogleToolboxForMac GTMDevLog usage in Messaging unit tests with NSLog
  • Use Firebase/CoreOnly instead of Firebase/Core so that unit tests build and run without FirebaseAnalytics

Next step is integration with closed source dependencies

@paulb777 paulb777 changed the title Split FirebaseUtilities from FirebaseCore Split GoogleUtilities from FirebaseCore Jun 29, 2018
Copy link
Contributor

@wilhuff wilhuff left a comment

Choose a reason for hiding this comment

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

I'm going to stop reviewing. Github is going to break. I can already feel it slowing down while I'm typing.

This really should have been three PRs:

  • Define GoogleUtilities, forking Core stuff but otherwise not changing it.
  • Integrate GoogleUtilities into the various builds
  • Migrate usage of Core APIs to GoogleUtilities as needed

If you have the stomach for it we should rebase squash this state and then split it up.


@property(nonatomic) id processInfoMock;

@end

@implementation FIRAppEnvironmentUtilTest
@implementation GULAppEnvironmentUtilTest
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this test move along with the sources?

This comment applies both here and to the other tests in Core in this PR.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep. The tests will be factored out in a subsequent PR.

@@ -18,26 +18,27 @@
#import "FIRTestCase.h"

#import <FirebaseCore/FIRLogger.h>
#import <GoogleUtilities/GULLogger.h>
Copy link
Contributor

Choose a reason for hiding this comment

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

It doesn't seem like anything should import both FIRLogger and GULLogger.

Copy link
Member Author

Choose a reason for hiding this comment

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

Agreed. Adding a TODO comment to split FIRLoggerTest from GULLoggerTest.

Example/Podfile Outdated

target 'Core_Example_iOS' do
platform :ios, '8.0'

# The next line is the forcing function for the Firebase pod. The Firebase
# version's subspecs should depend on the component versions in their
# corresponding podspec's.
pod 'Firebase/Core', '5.3.0'
pod 'Firebase/CoreOnly', '5.3.0'
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be "CoreCore" :-P.

Copy link
Member Author

Choose a reason for hiding this comment

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

:) This is the change that excludes FirebaseAnalytics and its no longer valid current dependencies from the unit tests.

#import "FIRLoggerLevel.h"
#import "Private/FIRVersion.h"
#import "third_party/FIRAppEnvironmentUtil.h"
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: import order should be

  • self header
  • system headers
  • other headers

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually all deleted here and reordered in GULLogger.m

sMessageCodeRegex =
[NSRegularExpression regularExpressionWithPattern:kMessageCodePattern options:0 error:NULL];
#endif
GULLoggerInitializeASL([arguments containsObject:kFIRDisableDebugModeApplicationArgument],
Copy link
Contributor

Choose a reason for hiding this comment

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

Was there an API review for this?

If not:

  • Let's drop "ASL", which is deprecated. We should eventually move to os_log.
  • Is there any way we can avoid passing three booleans to this? It's a terrible interface.
  • Is there a way to translate debug modes into a maximum log level instead so that GULLogger doesn't even have to be aware of this wart?

In particular it seems like if argument processing is to be done here, then we should completely figure out if we want debug mode from the arguments locally. Passing two booleans that seem like logical inverses of each other seems wrong.

Copy link
Member

Choose a reason for hiding this comment

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

+1 to moving to os_log but it's only available on iOS 10+, so we'll have to keep ASL around until we drop support for iOS 8 and 9 (will be a while).

Copy link
Member Author

Choose a reason for hiding this comment

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

I moved the UserDefaults stuff back to FIRLogger and reduced to two booleans. Overall, this really needs an overall rewrite with a breaking change.

#include <unistd.h>

/// Arguments passed on launch.
NSString *const kGULDisableDebugModeApplicationArgument = @"-GULDebugDisabled";
Copy link
Contributor

Choose a reason for hiding this comment

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

Unused.

Copy link
Member Author

Choose a reason for hiding this comment

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

deleted

NSString *const kGULLoggerForceSDTERRApplicationArgument = @"-GULLoggerForceSTDERR";

/// Key for the debug mode bit in NSUserDefaults.
NSString *const kGULPersistedDebugModeKey = @"/google/utilities/debug_mode";
Copy link
Contributor

Choose a reason for hiding this comment

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

This implementation is now split-brained. Why are we handling command-line arguments for debug mode in FIRLogger, but NSUserDefaults here?

Either insulate GULLogger from knowing about this gunk, or just put it all in here. This combined approach is even harder to reason about than the old system.

const char *kGULLoggerASLClientFacilityName = "com.google.utilities.app.logger";

/// Keys for the number of errors and warnings logged.
NSString *const kGULLoggerErrorCountKey = @"/google/utilities/count_of_errors_logged";
Copy link
Contributor

Choose a reason for hiding this comment

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

This is declared and defined but appears otherwise unused. Can we just drop it?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

NSString *const kGULPersistedDebugModeKey = @"/google/utilities/debug_mode";

/// ASL client facility name used by GULLogger.
const char *kGULLoggerASLClientFacilityName = "com.google.utilities.app.logger";
Copy link
Contributor

Choose a reason for hiding this comment

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

This no longer really has anything to do with "app". "com.gogle.utilities.logger"?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

}

void GULSetAnalyticsDebugMode(BOOL analyticsDebugMode) {
GULLoggerInitializeASL(NO, NO, NO);
Copy link
Contributor

Choose a reason for hiding this comment

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

This is now functionally different than what came before.

Previously if your first call was FIRSetAnalyticsDebugMode we would initialize FIRLogger, including evaluating the command-line arguments. This now disregards the command-line arguments.

@wilhuff
Copy link
Contributor

wilhuff commented Jun 29, 2018

At a high level I think we should try really hard to avoid putting any kind of "debug mode" in GULLogger. As implemented it's broken.

From my reading of the initialization code, debug mode has the effect of calling

asl_set_filter(sGULLoggerClient, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));

But it also sets sGULAnalyticsDebugMode and sGULLoggerDebugMode.

But GULLogBasic now has a "force" parameter and does not even concern itself with analytics debug mode.

GULIsLoggableLevel allows you to query by whether or not it's an analytics component but GULLogBasic doesn't. How is this supposed to work in practice?

I propose that analytics debug mode be pushed up into FIRLogger completely.

I'd also propose that we try to eliminate logger debug mode. Why isn't this equivalent to GULSetLoggerLevel to the max?

I also suggest moving the NSUserDefaults gunk up into FIRLogger as well.

@@ -17,7 +17,7 @@
#import "ApplicationDelegate.h"

#import <FirebaseCore/FIRApp.h>
#import <FirebaseCore/FIRLogger.h>
#import <GoogleUtilities/FIRLogger.h>
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this stay as FirebaseCore?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes.

@@ -15,17 +15,17 @@
#import <Foundation/Foundation.h>
#import <XCTest/XCTest.h>

#import <FirebaseCore/FIRAppEnvironmentUtil.h>
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
Copy link
Member

Choose a reason for hiding this comment

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

Should this eventually just be moved to a GoogleUtilities test suite?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes. The tests will be factored out in a subsequent PR.

@@ -0,0 +1,273 @@
// Copyright 2017 Google
Copy link
Member

Choose a reason for hiding this comment

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

I realize this was copied over, but does this count as new code and an updated copyright?

Copy link
Member Author

Choose a reason for hiding this comment

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

My interpretation was that since it was copied that it should keep the copyright.

@@ -137,7 +137,7 @@ + (BOOL)isProductionApp {

NSError *error = nil;

Class envClass = NSClassFromString(@"FIRAppEnvironmentUtil");
Class envClass = NSClassFromString(@"GULAppEnvironmentUtil");
Copy link
Member

Choose a reason for hiding this comment

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

Since Auth relies on GoogleUtilities/GULAppEnvironmentUtil already, can we remove the string based selectors here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes - done.

sMessageCodeRegex =
[NSRegularExpression regularExpressionWithPattern:kMessageCodePattern options:0 error:NULL];
#endif
GULLoggerInitializeASL([arguments containsObject:kFIRDisableDebugModeApplicationArgument],
Copy link
Member

Choose a reason for hiding this comment

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

+1 to moving to os_log but it's only available on iOS 10+, so we'll have to keep ASL around until we drop support for iOS 8 and 9 (will be a while).

@@ -25,13 +27,12 @@ Firebase Core includes FIRApp and FIROptions which provide central configuration
s.prefix_header_file = false

s.source_files = 'Firebase/Core/**/*.[mh]'
s.public_header_files = 'Firebase/Core/Public/*.h', 'Firebase/Core/Private/*.h'
s.private_header_files = 'Firebase/Core/Private/*.h', 'Firebase/Core/third_party/*.h'
s.public_header_files = 'Firebase/Core/Public/*.h'
Copy link
Member

Choose a reason for hiding this comment

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

What was the reason for having Private/ here as well again?

Copy link
Member Author

Choose a reason for hiding this comment

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

To CocoaPods, "private" means publicly available but not included by default by importing the module - only by explicitly importing the header.

s.summary = 'Firebase Utilities for iOS (plus community support for macOS and tvOS)'

s.description = <<-DESC
Firebase Utilities including Network, Environment, Logger, and Swizzling.
Copy link
Member

Choose a reason for hiding this comment

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

Do we want to have a note here saying not for public use, or "Internal Google Utilities for iOS including Network, Environment, Logger, and Swizzling"

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

Pod::Spec.new do |s|
s.name = 'GoogleUtilities'
s.version = '5.0.4'
s.summary = 'Firebase Utilities for iOS (plus community support for macOS and tvOS)'
Copy link
Member

Choose a reason for hiding this comment

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

Nit: s/Firebase/Google

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

Copy link
Member

@ryanwilson ryanwilson left a comment

Choose a reason for hiding this comment

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

LGTM with some small nits!

@@ -4887,6 +4887,10 @@
INFOPLIST_FILE = "$(SRCROOT)/Core/App/macOS/Core-Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
MTL_ENABLE_DEBUG_INFO = YES;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Copy link
Member

Choose a reason for hiding this comment

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

Was this missed before, or why does it need to be added now?

Copy link
Member Author

Choose a reason for hiding this comment

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

The new pod structure exposed macOS test failures from categories not being linked in. There's no change to iOS since their tests are linked with -all_load.

#import "FIRLoggerLevel.h"
#import <FirebaseCore/FIRLoggerLevel.h>
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
#import <GoogleUtilities/GULLogger.h>
Copy link
Member

Choose a reason for hiding this comment

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

Nit: Should have vertical whitespace between the framework imports and file import.

aslOptions = 0;
}
#endif // TARGET_OS_SIMULATOR
// Register Firebase Version with GULLogger
Copy link
Member

Choose a reason for hiding this comment

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

Nit: punctuation.

kFIRNetworkLogLevelInfo = FIRLoggerLevelInfo,
kFIRNetworkLogLevelDebug = FIRLoggerLevelDebug,
#import <GoogleUtilities/GULLoggerLevel.h>
#import "GULNetworkMessageCode.h"
Copy link
Member

Choose a reason for hiding this comment

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

Nit: Vertical whitespace between framework and file imports.

other Google CocoaPods. They're not intended for direct public usage.
DESC

s.homepage = 'https://firebase.google.com'
Copy link
Member

Choose a reason for hiding this comment

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

Should this be a more general homepage?

# :tag => 'Utilities-' + s.version.to_s
:tag => 'pre-5.3-' + s.version.to_s
}
s.social_media_url = 'https://twitter.com/Firebase'
Copy link
Member

Choose a reason for hiding this comment

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

Same as above - maybe this should be @googledevs?

Copy link
Member

@ryanwilson ryanwilson left a comment

Choose a reason for hiding this comment

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

Thanks! LGTM, please make sure @wilhuff is okay with this as well since he previously requested changes.

@paulb777
Copy link
Member Author

paulb777 commented Jul 6, 2018

@ryanwilson Thanks for the review! I'm going to merge now to unblock other tasks. I believe I've addressed most, if not all, of @wilhuff's requests. If there are more, I'll address them in a follow-up PR.

@paulb777 paulb777 merged commit 98b6eef into master Jul 6, 2018
@paulb777 paulb777 deleted the pb-utilities branch July 6, 2018 16:37
Copy link
Contributor

@wilhuff wilhuff left a comment

Choose a reason for hiding this comment

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

I still have plenty of reservations about this code.

I wish this had gone through API review because this is a new public API that isn't very good.

For example, it's still not clear to me why we need forceLog. Why can't setting analytics debug mode in FIRLogger translate into a SetLoggerLevel down here?

I don't think this should have been submitted because now we have to release it (unless you revert it, which I suggest you do).

/**
* Logs a message to the Xcode console and the device log. If running from AppStore, will
* not log any messages with a level higher than GULLoggerLevelNotice to avoid log spamming.
* (required) log level (one of the GULLoggerLevel enum values).
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not the way to format documentation. It ends up looking like a mess of run-on text in the Xcode help.

screen shot 2018-07-07 at 3 44 26 pm

See examples for how to do this correctly in http://google.github.io/styleguide/objcguide.html.

In particular, use @param variableName to introduce each parameter and @return to describe what's being returned.

* (required) overrideSTDERR Override the aslOptions to ASL_OPT_STDERR.
* (required) forceDebugMode Force the asl level to ASL_LEVEL_DEBUG.
*/
extern void GULLoggerInitializeASL(BOOL overrideSTDERR, BOOL forceDebugMode);
Copy link
Contributor

Choose a reason for hiding this comment

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

We should drop the "ASL" in this name and references to specific ASL options here.

NSString *message,
// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable
// See: http://stackoverflow.com/q/29095469
#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX
Copy link
Contributor

Choose a reason for hiding this comment

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

This #if makes no sense. There's no useful way to write code that passes NULL here since code we write must be testable on simulators (and 64-bit is our most common width).

In FIRLogger this was a pre-existing wart that we couldn't change, but we should get rid of this here before we publish it.

Additionally, this just passed directly to [NSString stringWithFormat:message arguments:args_ptr] and that function has no similar decorations.

Meanwhile, if you're calling this function and don't want to pass any arguments you can instantiate a va_list, not initialize it, and pass it here.

Finally note that message is always a format string, even if you pass no arguments. For example, to get a literal % in the output you still need to escape it (i.e. pass @"%%").

Also a va_list is not necessarily a pointer, so we should call this "args" not "args_ptr".

* not log any messages with a level higher than GULLoggerLevelNotice to avoid log spamming.
* (required) log level (one of the GULLoggerLevel enum values).
* (required) service name of type GULLoggerService.
* (required) message code starting with "I-" which means iOS, followed by a capitalized
Copy link
Contributor

Choose a reason for hiding this comment

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

This is missing a description of forceLog.

@paulb777
Copy link
Member Author

paulb777 commented Jul 9, 2018

Thanks @wilhuff. I'll make another PR to address these in the next few days.

Like FIRLogger, the only part of the GULLogger API that is technically public is GULLoggerLevel.h. See https://github.com/firebase/firebase-ios-sdk/blob/master/GoogleUtilities.podspec#L38. However, the GoogleUtilities pod documents itself as to not supporting non-Google usage. We can incrementally improve everything else without impacting the public API.

I don't think we should revert since this PR is an incremental step forward. It unblocks other projects that need to use GoogleUtilities. It provides size improvements for many Firebase configurations. And is a step towards cleaning up FIRLogger.

@wilhuff
Copy link
Contributor

wilhuff commented Jul 9, 2018

Ah, interesting! I saw these listed in the public headers and thought this was a public API.

https://github.com/firebase/firebase-ios-sdk/blob/master/GoogleUtilities.podspec#L37

In that case please don't revert, but yes, let's address some of these rough edges as we get time.

@firebase firebase locked and limited conversation to collaborators Nov 1, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants