1#
2# Copyright (C) 2018 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the 'License');
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an 'AS IS' BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
17import logging
18import os
19
20from host_controller import common
21from host_controller.command_processor import base_command_processor
22
23
24class CommandFetch(base_command_processor.BaseCommandProcessor):
25    """Command processor for fetch command.
26
27    Attributes:
28        arg_parser: ConsoleArgumentParser object, argument parser.
29        console: cmd.Cmd console object.
30        command: string, command name which this processor will handle.
31        command_detail: string, detailed explanation for the command.
32    """
33
34    command = "fetch"
35    command_detail = "Fetch a build artifact."
36
37    # @Override
38    def SetUp(self):
39        """Initializes the parser for fetch command."""
40        self.arg_parser.add_argument(
41            '--type',
42            default='pab',
43            choices=('local_fs', 'gcs', 'pab', 'ab'),
44            help='Build provider type')
45        self.arg_parser.add_argument(
46            '--method',
47            default='GET',
48            choices=('GET', 'POST'),
49            help='Method for fetching')
50        self.arg_parser.add_argument(
51            "--path",  # required for local_fs
52            help="The path of a local directory which keeps the artifacts.")
53        self.arg_parser.add_argument(
54            "--branch",  # required for pab
55            help="Branch to grab the artifact from.")
56        self.arg_parser.add_argument(
57            "--target",  # required for pab
58            help="Target product to grab the artifact from.")
59        # TODO(lejonathan): find a way to not specify this?
60        self.arg_parser.add_argument(
61            "--account_id",
62            default=common._DEFAULT_ACCOUNT_ID,
63            help="Partner Android Build account_id to use.")
64        self.arg_parser.add_argument(
65            '--build_id',
66            default='latest',
67            help='Build ID to use default latest.')
68        self.arg_parser.add_argument(
69            "--artifact_name",  # required for pab
70            help=
71            "Name of the artifact to be fetched. {id} replaced with build id.")
72        self.arg_parser.add_argument(
73            "--userinfo-file",
74            help=
75            "Location of file containing email and password, if using POST.")
76        self.arg_parser.add_argument(
77            "--noauth_local_webserver",
78            default=False,
79            type=bool,
80            help="True to not use a local webserver for authentication.")
81        self.arg_parser.add_argument(
82            "--fetch_signed_build",
83            default=False,
84            type=bool,
85            help="True to fetch only signed build images.")
86        self.arg_parser.add_argument(
87            "--full_device_images",
88            default=False,
89            type=bool,
90            help="True to skip checking whether the fetched artifacts are "
91            "fully packaged device images.")
92        self.arg_parser.add_argument(
93            "--gsi",
94            default=False,
95            type=bool,
96            help="True if a target is GSI. Only system.img and "
97            "vbmeta.img are taken.")
98        self.arg_parser.add_argument(
99            "--set_suite_as",
100            default="",
101            choices=("", "vts", "cts", "gts", "sts"),
102            help="To specify the type of a test suite that is being fetched."
103            "Used when the artifact's file name does not follow the "
104            "standard naming convention.")
105
106    # @Override
107    def Run(self, arg_line):
108        """Makes the host download a build artifact from PAB."""
109        args = self.arg_parser.ParseLine(arg_line)
110
111        if args.type not in self.console._build_provider:
112            logging.error("ERROR: uninitialized fetch type %s", args.type)
113            return False
114
115        provider = self.console._build_provider[args.type]
116        if args.type == "pab":
117            # do we want this somewhere else? No harm in doing multiple times
118            provider.Authenticate(args.userinfo_file,
119                                  args.noauth_local_webserver)
120            if not args.fetch_signed_build:
121                (device_images, test_suites, fetch_environment,
122                 _) = provider.GetArtifact(
123                     account_id=args.account_id,
124                     branch=args.branch,
125                     target=args.target,
126                     artifact_name=args.artifact_name,
127                     build_id=args.build_id,
128                     method=args.method,
129                     full_device_images=args.full_device_images)
130                self.console.fetch_info["fetch_signed_build"] = False
131            else:
132                (device_images, test_suites, fetch_environment,
133                 _) = provider.GetSignedBuildArtifact(
134                     account_id=args.account_id,
135                     branch=args.branch,
136                     target=args.target,
137                     artifact_name=args.artifact_name,
138                     build_id=args.build_id,
139                     method=args.method,
140                     full_device_images=args.full_device_images)
141                self.console.fetch_info["fetch_signed_build"] = True
142
143            self.console.fetch_info["build_id"] = fetch_environment["build_id"]
144        elif args.type == "local_fs":
145            device_images, test_suites = provider.Fetch(
146                args.path, args.full_device_images)
147            self.console.fetch_info["build_id"] = None
148        elif args.type == "gcs":
149            device_images, test_suites, tools = provider.Fetch(
150                args.path, args.full_device_images, args.set_suite_as)
151            self.console.fetch_info["build_id"] = None
152        elif args.type == "ab":
153            device_images, test_suites, fetch_environment = provider.Fetch(
154                branch=args.branch,
155                target=args.target,
156                artifact_name=args.artifact_name,
157                build_id=args.build_id,
158                full_device_images=args.full_device_images)
159            self.console.fetch_info["build_id"] = fetch_environment["build_id"]
160        else:
161            logging.error("ERROR: unknown fetch type %s", args.type)
162            return False
163
164        if args.gsi:
165            filtered_images = {}
166            image_names = device_images.keys()
167            for image_name in image_names:
168                if image_name.endswith(".img") and image_name not in [
169                        "system.img", "vbmeta.img"
170                ]:
171                    provider.RemoveDeviceImage(image_name)
172                    continue
173                filtered_images[image_name] = device_images[image_name]
174            device_images = filtered_images
175
176        if args.type == "gcs":
177            gcs_path, filename = os.path.split(args.path)
178            self.console.fetch_info["branch"] = gcs_path
179            self.console.fetch_info["target"] = filename
180            self.console.fetch_info["build_id"] = "latest"
181            self.console.fetch_info["account_id"] = ""
182        else:
183            self.console.fetch_info["branch"] = args.branch
184            self.console.fetch_info["target"] = args.target
185            self.console.fetch_info["account_id"] = args.account_id
186
187        self.console.UpdateFetchInfo(provider.GetFetchedArtifactType())
188
189        self.console.device_image_info.update(device_images)
190        self.console.test_suite_info.update(test_suites)
191        self.console.tools_info.update(provider.GetAdditionalFile())
192
193        if self.console.device_image_info:
194            logging.info("device images:\n%s", "\n".join(
195                image + ": " + path
196                for image, path in self.console.device_image_info.iteritems()))
197        if self.console.test_suite_info:
198            logging.info("test suites:\n%s", "\n".join(
199                suite + ": " + path
200                for suite, path in self.console.test_suite_info.iteritems()))
201        if self.console.tools_info:
202            logging.info("additional files:\n%s", "\n".join(
203                rel_path + ": " + full_path for rel_path, full_path in
204                self.console.tools_info.iteritems()))
205