| #!/usr/bin/env python3 |
| # Copyright (C) 2020 The Android Open Source Project |
| # |
| # 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. |
| |
| # Exports AppSearch Androidx code to Framework |
| # |
| # NOTE: This will remove and replace all files in the |
| # frameworks/base/apex/appsearch path. |
| # |
| # Example usage (from root dir of androidx workspace): |
| # $ ./frameworks/support/appsearch/exportToFramework.py "$HOME/android/master" "<jetpack changeid>" |
| import os |
| import re |
| import sys |
| |
| |
| JETPACK_API_ROOT = 'appsearch/src/main/java/androidx/appsearch' |
| JETPACK_API_TEST_ROOT = 'appsearch/src/androidTest/java/androidx/appsearch' |
| JETPACK_IMPL_ROOT = 'local-storage/src/main/java/androidx/appsearch' |
| JETPACK_IMPL_TEST_ROOT = 'local-storage/src/androidTest/java/androidx/appsearch' |
| FRAMEWORK_API_ROOT = 'framework/java/android/app/appsearch' |
| FRAMEWORK_API_TEST_ROOT = ( |
| '../../core/tests/coretests/src/' |
| 'android/app/appsearch/external') |
| FRAMEWORK_IMPL_ROOT = 'service/java/com/android/server/appsearch/external' |
| FRAMEWORK_IMPL_TEST_ROOT = ( |
| '../../services/tests/servicestests/src/' |
| 'com/android/server/appsearch/external') |
| CHANGEID_FILE_NAME = 'synced_jetpack_changeid.txt' |
| |
| |
| def _PruneDir(dest_dir, allow_list=None): |
| all_files = [] |
| for walk_path, walk_folders, walk_files in os.walk(dest_dir): |
| for walk_filename in walk_files: |
| abs_path = os.path.join(walk_path, walk_filename) |
| all_files.append(abs_path) |
| |
| for abs_path in all_files: |
| rel_path = os.path.relpath(abs_path, dest_dir) |
| if allow_list and rel_path in allow_list: |
| print('Prune: skip "%s"' % abs_path) |
| else: |
| print('Prune: remove "%s"' % abs_path) |
| os.remove(abs_path) |
| |
| |
| def _TransformAndCopyFile(source_path, dest_path, transform_func=None): |
| with open(source_path, 'r') as fh: |
| contents = fh.read() |
| |
| if '@exportToFramework:skipFile()' in contents: |
| print('Skipping: "%s" -> "%s"' % (source_path, dest_path), file=sys.stderr) |
| return |
| |
| print('Copy: "%s" -> "%s"' % (source_path, dest_path), file=sys.stderr) |
| if transform_func: |
| contents = transform_func(contents) |
| os.makedirs(os.path.dirname(dest_path), exist_ok=True) |
| with open(dest_path, 'w') as fh: |
| fh.write(contents) |
| |
| |
| def _TransformCommonCode(contents): |
| return (contents |
| .replace('androidx.appsearch.app', 'android.app.appsearch') |
| .replace( |
| 'androidx.appsearch.localstorage.', |
| 'com.android.server.appsearch.external.localstorage.') |
| .replace('androidx.appsearch', 'android.app.appsearch') |
| .replace( |
| 'androidx.annotation.GuardedBy', |
| 'com.android.internal.annotations.GuardedBy') |
| .replace( |
| 'androidx.annotation.VisibleForTesting', |
| 'com.android.internal.annotations.VisibleForTesting') |
| .replace('androidx.collection.ArrayMap', 'android.util.ArrayMap') |
| .replace('androidx.collection.ArraySet', 'android.util.ArraySet') |
| .replace( |
| 'androidx.core.util.ObjectsCompat', |
| 'java.util.Objects') |
| .replace( |
| 'androidx.core.util.Preconditions', |
| 'com.android.internal.util.Preconditions') |
| .replace('import androidx.annotation.RestrictTo;', '') |
| .replace('@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)', '') |
| .replace('ObjectsCompat.', 'Objects.') |
| .replace('androidx.', 'android.') |
| ) |
| |
| |
| def _TransformTestCode(contents): |
| contents = (contents |
| .replace('org.junit.Assert.assertThrows', |
| 'org.testng.Assert.expectThrows') |
| .replace('assertThrows(', 'expectThrows(') |
| ) |
| return _TransformCommonCode(contents) |
| |
| |
| def _TransformAndCopyFolder(source_dir, dest_dir, transform_func=None): |
| for currentpath, folders, files in os.walk(source_dir): |
| dir_rel_to_root = os.path.relpath(currentpath, source_dir) |
| for filename in files: |
| source_abs_path = os.path.join(currentpath, filename) |
| dest_path = os.path.join(dest_dir, dir_rel_to_root, filename) |
| _TransformAndCopyFile(source_abs_path, dest_path, transform_func) |
| |
| |
| def _CopyAllApi(source_dir, dest_dir): |
| api_source_dir = os.path.join(source_dir, JETPACK_API_ROOT) |
| api_test_source_dir = os.path.join(source_dir, JETPACK_API_TEST_ROOT) |
| api_dest_dir = os.path.join(dest_dir, FRAMEWORK_API_ROOT) |
| api_test_dest_dir = os.path.join(dest_dir, FRAMEWORK_API_TEST_ROOT) |
| |
| # Prune existing files |
| _PruneDir(api_dest_dir, allow_list=[ |
| 'AppSearchBatchResult.java', |
| 'AppSearchManager.java', |
| 'AppSearchManagerFrameworkInitializer.java', |
| 'AppSearchResult.java', |
| 'IAppSearchManager.aidl', |
| 'SearchResults.java', |
| ]) |
| _PruneDir(api_test_dest_dir) |
| |
| # Copy api classes. We can't use _TransformAndCopyFolder here because we |
| # need to specially handle the 'app' package. |
| def _TransformApiCode(contents): |
| contents = contents.replace( |
| 'package androidx.appsearch.app;', |
| 'package android.app.appsearch;') |
| return _TransformCommonCode(contents) |
| for currentpath, folders, files in os.walk(api_source_dir): |
| dir_rel_to_root = os.path.relpath(currentpath, api_source_dir) |
| for filename in files: |
| # Figure out what folder to place them into |
| source_abs_path = os.path.join(currentpath, filename) |
| if dir_rel_to_root == 'app': |
| # Files in the 'app' folder live in the root of the platform tree |
| dest_path = os.path.join(api_dest_dir, filename) |
| else: |
| dest_path = os.path.join( |
| api_dest_dir, dir_rel_to_root, filename) |
| _TransformAndCopyFile(source_abs_path, dest_path, _TransformApiCode) |
| |
| # Copy api test classes. |
| _TransformAndCopyFolder( |
| api_test_source_dir, api_test_dest_dir, |
| transform_func=_TransformTestCode) |
| |
| |
| def _CopyAllImpl(source_dir, dest_dir): |
| impl_source_dir = os.path.join(source_dir, JETPACK_IMPL_ROOT) |
| impl_test_source_dir = os.path.join(source_dir, JETPACK_IMPL_TEST_ROOT) |
| impl_dest_dir = os.path.join(dest_dir, FRAMEWORK_IMPL_ROOT) |
| impl_test_dest_dir = os.path.join(dest_dir, FRAMEWORK_IMPL_TEST_ROOT) |
| |
| # Prune |
| _PruneDir(impl_dest_dir) |
| _PruneDir(impl_test_dest_dir) |
| |
| # Copy impl classes |
| def _TransformImplCode(contents): |
| contents = (contents |
| .replace('package androidx.appsearch', |
| 'package com.android.server.appsearch.external') |
| .replace('com.google.android.icing.protobuf.', 'com.google.protobuf.') |
| ) |
| return _TransformCommonCode(contents) |
| _TransformAndCopyFolder(impl_source_dir, impl_dest_dir, transform_func=_TransformImplCode) |
| |
| # Copy servicestests |
| def _TransformImplTestCode(contents): |
| contents = (contents |
| .replace('package androidx.appsearch', |
| 'package com.android.server.appsearch.external') |
| .replace('com.google.android.icing.proto.', |
| 'com.android.server.appsearch.proto.') |
| .replace('com.google.android.icing.protobuf.', |
| 'com.android.server.appsearch.protobuf.') |
| ) |
| return _TransformTestCode(contents) |
| _TransformAndCopyFolder( |
| impl_test_source_dir, impl_test_dest_dir, transform_func=_TransformImplTestCode) |
| |
| |
| def _CopyChangeIdFile(changeid, dest_dir): |
| """Copies the changeid of the most recent public CL into a file on the framework side. |
| |
| This file is used for tracking, to determine what framework is synced to. |
| |
| You must always provide a changeid of an exported, preferably even submitted CL. If you abandon |
| the CL pointed to by this changeid, the next person syncing framework will be unable to find |
| what CL it is synced to. |
| """ |
| file_path = os.path.join(dest_dir, CHANGEID_FILE_NAME) |
| with open(file_path, 'w') as fh: |
| print(changeid, file=fh) |
| print('Wrote "%s"' % file_path) |
| |
| |
| def _CopyMain(source_dir, dest_dir, changeid): |
| _CopyAllApi(source_dir, dest_dir) |
| _CopyAllImpl(source_dir, dest_dir) |
| _CopyChangeIdFile(changeid, dest_dir) |
| |
| |
| if __name__ == '__main__': |
| if len(sys.argv) != 3: |
| print('Usage: %s <path/to/frameworks/base> <changeId of head jetpack commit>' % sys.argv[0], |
| file=sys.stderr) |
| sys.exit(1) |
| source_dir = os.path.normpath(os.path.dirname(sys.argv[0])) |
| dest_dir = os.path.normpath(sys.argv[1]) |
| if os.path.basename(dest_dir) == 'appsearch': |
| pass |
| elif os.path.basename(dest_dir) == 'base': |
| dest_dir = os.path.join(dest_dir, 'apex/appsearch') |
| else: |
| dest_dir = os.path.join(dest_dir, 'frameworks/base/apex/appsearch') |
| if not os.path.isdir(dest_dir): |
| print('Destination path "%s" does not exist or is not a directory' % ( |
| dest_dir), |
| file=sys.stderr) |
| sys.exit(1) |
| _CopyMain(source_dir, dest_dir, sys.argv[2]) |