Add support for creating new extensions sdks

Add a new action 'new_sdk' that can be used to create a new extension
sdk level with a given set of module requirements.

Also add a test that we can re-create the test database correctly.

Bug: 173188089
Test: atest gen_sdk_test
Change-Id: I91b97c9638958ff39ffb6c52470a70bad0ea6697
diff --git a/gen_sdk/gen_sdk.py b/gen_sdk/gen_sdk.py
index 588d30f..c85243c 100644
--- a/gen_sdk/gen_sdk.py
+++ b/gen_sdk/gen_sdk.py
@@ -18,6 +18,9 @@
 Example usages:
 # Print a binary representation of the proto database.
 $ gen_sdk --action print_binary
+
+# Create a new SDK
+$ gen_sdk --action new_sdk --sdk 1 --modules=IPSEC,SDK_EXTENSIONS
 """
 
 import argparse
@@ -42,10 +45,21 @@
   )
   parser.add_argument(
     '--action',
-    choices=['print_binary'],
+    choices=['print_binary', 'new_sdk'],
     metavar='ACTION',
     required=True,
-    help='Which action to take (print_binary).'
+    help='Which action to take (print_binary|new_sdk).'
+  )
+  parser.add_argument(
+    '--sdk',
+    type=int,
+    metavar='SDK',
+    help='The extension SDK level to deal with (int)'
+  )
+  parser.add_argument(
+    '--modules',
+    metavar='MODULES',
+    help='Comma-separated list of modules providing new APIs. Required for action=new_sdk.'
   )
   return parser.parse_args(argv)
 
@@ -55,15 +69,43 @@
   sys.stdout.buffer.write(database.SerializeToString())
 
 
+def NewSdk(database, new_version, modules):
+  new_requirements = {}
+
+  # Gather the previous highest requirement of each module
+  for prev_version in sorted(database.versions, key=lambda v: v.version):
+    for prev_requirement in prev_version.requirements:
+      new_requirements[prev_requirement.module] = prev_requirement.version
+
+  # Add new requirements of this version
+  for module in modules:
+    new_requirements[module] = SdkVersion(version=new_version)
+
+  to_proto = lambda m : ExtensionVersion.ModuleRequirement(module=m, version=new_requirements[m])
+  module_requirements = [to_proto(m) for m in new_requirements]
+  extension_version = ExtensionVersion(version=new_version, requirements=module_requirements)
+  database.versions.append(extension_version)
+
+  module_names = ','.join([SdkModule.Name(m) for m in modules])
+  print('Created a new extension SDK level %d with modules %s' % (new_version, module_names))
+
+
 def main(argv):
   args = ParseArgs(argv)
   with args.database.open('r') as f:
     database = google.protobuf.text_format.Parse(f.read(), ExtensionDatabase())
 
+  if args.modules:
+    modules = [SdkModule.Value(m) for m in args.modules.split(',')]
+
   {
     'print_binary': lambda : PrintBinary(database),
+    'new_sdk': lambda : NewSdk(database, args.sdk, modules)
   }[args.action]()
 
+  if args.action in ['new_sdk']:
+    with args.database.open('w') as f:
+      f.write(google.protobuf.text_format.MessageToString(database))
 
 if __name__ == '__main__':
   main(sys.argv[1:])
diff --git a/gen_sdk/gen_sdk_test.sh b/gen_sdk/gen_sdk_test.sh
index adb76e0..80e21ca 100644
--- a/gen_sdk/gen_sdk_test.sh
+++ b/gen_sdk/gen_sdk_test.sh
@@ -30,3 +30,15 @@
   diff golden_binary <(gen_sdk --action print_binary --database testdata/test_extensions_db.textpb | xxd -p)
 }
 test_print_binary
+
+# Verifies the tool is able to re-create the test DB correctly.
+function test_new_sdk() {
+  rm -f extensions_db.textpb && touch extensions_db.textpb
+  gen_sdk --action new_sdk --sdk 1 --modules MEDIA_PROVIDER
+  gen_sdk --action new_sdk --sdk 2 --modules MEDIA,IPSEC
+  gen_sdk --action new_sdk --sdk 3 --modules MEDIA_PROVIDER
+  gen_sdk --action new_sdk --sdk 4 --modules SDK_EXTENSIONS,IPSEC
+
+  diff -u0 testdata/test_extensions_db.textpb extensions_db.textpb
+}
+test_new_sdk