From c2579a5041568592913165bc0a167bd0b70f46a2 Mon Sep 17 00:00:00 2001 From: Alex Humesky Date: Mon, 28 Sep 2015 23:32:55 +0000 Subject: Refactors proguard_whitelister. -- MOS_MIGRATED_REVID=104150148 --- tools/android/BUILD | 2 +- tools/android/proguard_whitelister.py | 78 +++++++++++++---------- tools/android/proguard_whitelister_input.cfg | 48 -------------- tools/android/proguard_whitelister_test.py | 62 +++++++++++------- tools/android/proguard_whitelister_test_input.cfg | 48 ++++++++++++++ 5 files changed, 133 insertions(+), 105 deletions(-) delete mode 100644 tools/android/proguard_whitelister_input.cfg create mode 100644 tools/android/proguard_whitelister_test_input.cfg (limited to 'tools') diff --git a/tools/android/BUILD b/tools/android/BUILD index 5021f541ff..c2aeb9a667 100644 --- a/tools/android/BUILD +++ b/tools/android/BUILD @@ -72,7 +72,7 @@ py_binary( py_test( name = "proguard_whitelister_test", srcs = ["proguard_whitelister_test.py"], - data = ["proguard_whitelister_input.cfg"], + data = ["proguard_whitelister_test_input.cfg"], deps = [ ":proguard_whitelister", ], diff --git a/tools/android/proguard_whitelister.py b/tools/android/proguard_whitelister.py index a372bfb112..e5b000fb57 100644 --- a/tools/android/proguard_whitelister.py +++ b/tools/android/proguard_whitelister.py @@ -31,42 +31,54 @@ FLAGS = gflags.FLAGS PROGUARD_COMMENTS_PATTERN = '#.*(\n|$)' -def main(): - with open(FLAGS.path) as config: - config_string = config.read() - invalid_configs = Validate(config_string) - if invalid_configs: - raise RuntimeError('Invalid proguard config parameters: ' - + str(invalid_configs)) - with open(FLAGS.output, 'w+') as outconfig: - config_string = ('# Merged from %s \n' % FLAGS.path) + config_string - outconfig.write(config_string) - - -def Validate(config): - """Checks the config for illegal arguments.""" - config = re.sub(PROGUARD_COMMENTS_PATTERN, '', config) - args = config.split('-') - invalid_configs = [] - for arg in args: - arg = arg.strip() - if not arg: - continue - elif arg.startswith('checkdiscard'): - continue - elif arg.startswith('keep'): - continue - elif arg.startswith('assumenosideeffects'): - continue - elif arg.split()[0] == 'dontnote': - if len(arg.split()) > 1: +class ProguardConfigValidator(object): + """Validates a proguard config.""" + + # Must be a tuple for str.startswith() + _VALID_ARGS = ('keep', 'assumenosideeffects') + + def __init__(self, config_path, outconfig_path): + self._config_path = config_path + self._outconfig_path = outconfig_path + + def ValidateAndWriteOutput(self): + with open(self._config_path) as config: + config_string = config.read() + invalid_configs = self._Validate(config_string) + if invalid_configs: + raise RuntimeError( + 'Invalid proguard config parameters: ' + str(invalid_configs)) + with open(self._outconfig_path, 'w+') as outconfig: + config_string = '# Merged from %s \n%s' % ( + self._config_path, config_string) + outconfig.write(config_string) + + def _Validate(self, config): + """Checks the config for illegal arguments.""" + config = re.sub(PROGUARD_COMMENTS_PATTERN, '', config) + args = config.split('-') + invalid_configs = [] + for arg in args: + arg = arg.strip() + if not arg or self._ValidateArg(arg): continue - elif arg.split()[0] == 'dontwarn': + invalid_configs.append('-' + arg.split()[0]) + + return invalid_configs + + def _ValidateArg(self, arg): + if arg.startswith(ProguardConfigValidator._VALID_ARGS): + return True + elif arg.split()[0] in ['dontnote', 'dontwarn']: if len(arg.split()) > 1: - continue - invalid_configs.append('-' + arg.split()[0]) + return True + return False + + +def main(): + validator = ProguardConfigValidator(FLAGS.path, FLAGS.output) + validator.ValidateAndWriteOutput() - return invalid_configs if __name__ == '__main__': FLAGS(sys.argv) diff --git a/tools/android/proguard_whitelister_input.cfg b/tools/android/proguard_whitelister_input.cfg deleted file mode 100644 index ceb3709dd8..0000000000 --- a/tools/android/proguard_whitelister_input.cfg +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2015 The Bazel Authors. All rights reserved. -# -# 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. - -# Note: put any environment specific flags in their respective proguard files: -# proguard_test.flags, proguard_dev.flags, proguard_release.flags, etc - -# These classes reference resources that don't exist in pre-v11 builds --dontwarn com.google.android.apps.testapp.TestActivity - -# References to a hidden class --dontnote android.os.SystemProperties --keep class android.os.SystemProperties { *** get(...);} - -# Keep all classes extended from com.google.android.apps.testapp.MyBaseClass -# because, e.g., we use reflection. --keep class * extends com.google.android.apps.testapp.MyBaseClass { - @com.google.android.apps.testapp.MyBaseClass$Inner ; -} - -# Needed because this field is accessed reflectively, and it exists in generated code. --keepclassmembers class * extends com.google.protobuf.nano.MessageNano { - *** apiHeader; -} - -# Extensions are deserialized with a reflective call to newInstance(). --keepclassmembers class * extends com.google.protobuf.nano.Extension { - (); -} - --dontnote android.support.v?.app.Fragment - --keepnames class com.google.android.testapp.** extends com.google.android.testapp.resources.Resource { *; } - --keepclasseswithmembers class derp.foo { bar;} -keepattributes * - -# This is a comment, so this should not cause problems -dontobfuscate -# This is a comment, so # this should not cause problems -dontnote diff --git a/tools/android/proguard_whitelister_test.py b/tools/android/proguard_whitelister_test.py index 1cb7e3d58d..2229cfbd12 100644 --- a/tools/android/proguard_whitelister_test.py +++ b/tools/android/proguard_whitelister_test.py @@ -18,39 +18,55 @@ import unittest from tools.android import proguard_whitelister -class ValidateProguardTest(unittest.TestCase): +class ProguardConfigValidatorTest(unittest.TestCase): + + def _CreateValidator(self, input_path, output_path): + return proguard_whitelister.ProguardConfigValidator(input_path, output_path) def testValidConfig(self): - path = os.path.join( - os.path.dirname(__file__), "proguard_whitelister_input.cfg") - with open(path) as config: - self.assertEqual([], proguard_whitelister.Validate(config.read())) + input_path = os.path.join( + os.path.dirname(__file__), "proguard_whitelister_test_input.cfg") + tmpdir = os.environ["TEST_TMPDIR"] + output_path = os.path.join(tmpdir, "proguard_whitelister_test_output.cfg") + # This will raise an exception if the config is invalid. + self._CreateValidator(input_path, output_path).ValidateAndWriteOutput() + with file(output_path) as output: + self.assertTrue(("# Merged from %s" % input_path) in output.read()) + + def _TestInvalidConfig(self, invalid_args, config): + tmpdir = os.environ["TEST_TMPDIR"] + input_path = os.path.join(tmpdir, "proguard_whitelister_test_input.cfg") + with open(input_path, "w") as f: + f.write(config) + output_path = os.path.join(tmpdir, "proguard_whitelister_test_output.cfg") + validator = self._CreateValidator(input_path, output_path) + try: + validator.ValidateAndWriteOutput() + self.fail() + except RuntimeError as e: + for invalid_arg in invalid_args: + self.assertTrue(invalid_arg in str(e)) def testInvalidNoteConfig(self): - self.assertEqual(["-dontnote"], proguard_whitelister.Validate( - """# We don't want libraries disabling notes globally. - -dontnote - """)) + self._TestInvalidConfig(["-dontnote"], """\ +# We don"t want libraries disabling notes globally. +-dontnote""") def testInvalidWarnConfig(self): - self.assertEqual(["-dontwarn"], proguard_whitelister.Validate( - """# We don't want libraries disabling warnings globally. - -dontwarn - """)) + self._TestInvalidConfig(["-dontwarn"], """\ +# We don"t want libraries disabling warnings globally. +-dontwarn""") def testInvalidOptimizationConfig(self): - self.assertEqual(["-optimizations"], proguard_whitelister.Validate( - """#We don't want libraries disabling global optimizations. - -optimizations !class/merging/*,!code/allocation/variable - """)) + self._TestInvalidConfig(["-optimizations"], """\ +# We don"t want libraries disabling global optimizations. +-optimizations !class/merging/*,!code/allocation/variable""") def testMultipleInvalidArgs(self): - self.assertEqual( - ["-optimizations", "-dontnote"], proguard_whitelister.Validate( - """#We don't want libraries disabling global optimizations. - -optimizations !class/merging/*,!code/allocation/variable - -dontnote - """)) + self._TestInvalidConfig(["-optimizations", "-dontnote"], """\ +# We don"t want libraries disabling global optimizations. +-optimizations !class/merging/*,!code/allocation/variable +-dontnote""") if __name__ == "__main__": diff --git a/tools/android/proguard_whitelister_test_input.cfg b/tools/android/proguard_whitelister_test_input.cfg new file mode 100644 index 0000000000..ceb3709dd8 --- /dev/null +++ b/tools/android/proguard_whitelister_test_input.cfg @@ -0,0 +1,48 @@ +# Copyright 2015 The Bazel Authors. All rights reserved. +# +# 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. + +# Note: put any environment specific flags in their respective proguard files: +# proguard_test.flags, proguard_dev.flags, proguard_release.flags, etc + +# These classes reference resources that don't exist in pre-v11 builds +-dontwarn com.google.android.apps.testapp.TestActivity + +# References to a hidden class +-dontnote android.os.SystemProperties +-keep class android.os.SystemProperties { *** get(...);} + +# Keep all classes extended from com.google.android.apps.testapp.MyBaseClass +# because, e.g., we use reflection. +-keep class * extends com.google.android.apps.testapp.MyBaseClass { + @com.google.android.apps.testapp.MyBaseClass$Inner ; +} + +# Needed because this field is accessed reflectively, and it exists in generated code. +-keepclassmembers class * extends com.google.protobuf.nano.MessageNano { + *** apiHeader; +} + +# Extensions are deserialized with a reflective call to newInstance(). +-keepclassmembers class * extends com.google.protobuf.nano.Extension { + (); +} + +-dontnote android.support.v?.app.Fragment + +-keepnames class com.google.android.testapp.** extends com.google.android.testapp.resources.Resource { *; } + +-keepclasseswithmembers class derp.foo { bar;} -keepattributes * + +# This is a comment, so this should not cause problems -dontobfuscate +# This is a comment, so # this should not cause problems -dontnote -- cgit v1.2.3