acloud: Add in AVDSpec class and basic arg parsing.

Add in a very barebones implementation of AVDSpec. The real meat of the
class will come later once we add in the new options (e.g. --local_instance)
and we do the magic for our users.

I intentionally did not do any of the remote image arg inferring logic
as that will require a new arg and some google api calls (to Android
Build) so that deserves its own cl.

Bug: 112598956
Test: m acloud && acloud create
m acloud_test && acloud_test

$ acloud create --build_id 1234 --branch rand_branch
We will (but not yet) create an AVD with these details:
 - avd type: cuttlefish
  - num of instances requested: 1
   - remote image details: {'build_id': '1234', 'build_branch':
   'git_rand_branch'}.

Change-Id: Ia27bf86e55f3a171ba39663bb2c1db407119a54f
diff --git a/create/avd_spec.py b/create/avd_spec.py
new file mode 100644
index 0000000..c9566ac
--- /dev/null
+++ b/create/avd_spec.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+#
+# Copyright 2018 - 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.
+r"""AVDSpec class.
+
+AVDSpec will take in args from the user and be the main data type that will
+get passed into the create classes. The inferring magic will happen within
+initialization of AVDSpec (like LKGB build id, image branch, etc).
+"""
+
+_BUILD_TARGET = "build_target"
+_BUILD_BRANCH = "build_branch"
+_BUILD_ID = "build_id"
+
+
+class AVDSpec(object):
+    """Class to store data on the type of AVD to create."""
+
+    def __init__(self, args):
+        """Process the args into class vars.
+
+        Args:
+            args: Namespace object from argparse.parse_args.
+        """
+        # Let's define the private class vars here and then process the user
+        # args afterwards.
+        self._avd_type = None
+        self._remote_image = None
+        self._num_of_instances = None
+
+        self._ProcessArgs(args)
+
+    def __repr__(self):
+        """Let's make it easy to see what this class is holding."""
+        # TODO: I'm pretty sure there's a better way to do this, but I'm not
+        # quite sure what that would be.
+        representation = []
+        representation.append("")
+        representation.append(" - avd type: %s" % self._avd_type)
+        representation.append(" - num of instances requested: %s" %
+                              self._num_of_instances)
+        representation.append(" - remote image details: %s" %
+                              self._remote_image)
+        return "\n".join(representation)
+
+    def _ProcessArgs(self, args):
+        """Main entry point to process args for the different type of args.
+
+        Split up the arg processing into related areas (image, instance type,
+        etc) so that we don't have one huge monolilthic method that does
+        everything. It makes it easier to review, write tests, and maintain.
+
+        Args:
+            args: Namespace object from argparse.parse_args.
+        """
+        self._ProcessMiscArgs(args)
+        self._ProcessRemoteBuildArgs(args)
+
+    def _ProcessMiscArgs(self, args):
+        """These args we can take as and don't belong to a group of args.
+
+        Args:
+            args: Namespace object from argparse.parse_args.
+        """
+        self._avd_type = args.avd_type
+        self._num_of_instances = args.num
+
+    def _ProcessRemoteBuildArgs(self, args):
+        """Get the remote build args.
+
+        Some of the acloud magic happens here, we will infer some of these
+        values if the user hasn't specified them.
+
+        Args:
+            args: Namespace object from argparse.parse_args.
+        """
+        # TODO: We need some logic here to determine if we should infer remote
+        # build info or not.
+        self._remote_image = {}
+        if args.build_target:
+            self._remote_image[_BUILD_TARGET] = args.build_target
+        else:
+            # TODO: actually figure out what we want here.
+            pass
+
+        if args.branch:
+            self._remote_image[_BUILD_BRANCH] = args.branch
+        else:
+            # TODO: infer from user workspace
+            pass
+
+        if args.build_id:
+            self._remote_image[_BUILD_ID] = args.build_id
+        else:
+            #  TODO: extract this info from Android Build.
+            pass
diff --git a/create/base_avd_create.py b/create/base_avd_create.py
index 54a78dd..937e622 100644
--- a/create/base_avd_create.py
+++ b/create/base_avd_create.py
@@ -25,6 +25,13 @@
     """Base class for all AVD intance creation classes."""
 
     # pylint: disable=no-self-use
-    def Create(self):
-        """Create the AVD."""
-        print("Feature coming soon.")
+    def Create(self, avd_spec):
+        """Create the AVD.
+
+        Args:
+            avd_spec: AVDSpec object that tells us what we're going to create.
+        """
+        # TODO: rewrite this function to raise NotImplemented once actual device
+        # classes are here.
+        print("We will (but not yet) create an AVD with these details: %s." %
+              avd_spec)
diff --git a/create/create.py b/create/create.py
index 0d6e6d7..88c0ac7 100644
--- a/create/create.py
+++ b/create/create.py
@@ -20,14 +20,16 @@
 image artifacts.
 """
 
+from acloud.create import avd_spec
 from acloud.create import base_avd_create
 
 
-def Run():
+def Run(args):
     """Run create.
 
     Args:
         args: Namespace object from argparse.parse_args.
     """
+    spec = avd_spec.AVDSpec(args)
     avd_creator = base_avd_create.BaseAVDCreate()
-    avd_creator.Create()
+    avd_creator.Create(spec)
diff --git a/public/acloud_main.py b/public/acloud_main.py
index 88727e3..196d404 100644
--- a/public/acloud_main.py
+++ b/public/acloud_main.py
@@ -393,7 +393,7 @@
             logcat_file=args.logcat_file,
             autoconnect=args.autoconnect)
     elif args.which == create_args.CMD_CREATE:
-        create.Run()
+        create.Run(args)
     elif args.which == CMD_CREATE_CUTTLEFISH:
         report = create_cuttlefish_action.CreateDevices(
             cfg=cfg,