1#!/usr/bin/env vpython3 2# Copyright 2017 The Chromium Authors 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6import errno 7import logging 8import os 9import shutil 10import sys 11 12sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..')) 13import devil_chromium # pylint: disable=unused-import 14from devil.utils import cmd_helper 15from devil.utils import parallelizer 16 17 18def _MakeDirsIfAbsent(path): 19 try: 20 os.makedirs(path) 21 except OSError as err: 22 if err.errno != errno.EEXIST or not os.path.isdir(path): 23 raise 24 25 26class MavenDownloader: 27 ''' 28 Downloads and installs the requested artifacts from the Google Maven repo. 29 The artifacts are expected to be specified in the format 30 "group_id:artifact_id:version:file_type", as the default file type is JAR 31 but most Android libraries are provided as AARs, which would otherwise fail 32 downloading. See Install() 33 ''' 34 35 # Remote repository to download the artifacts from. The support library and 36 # Google Play service are only distributed there, but third party libraries 37 # could use Maven Central or JCenter for example. The default Maven remote 38 # is Maven Central. 39 _REMOTE_REPO = 'https://maven.google.com' 40 41 # Default Maven repository. 42 _DEFAULT_REPO_PATH = os.path.join( 43 os.path.expanduser('~'), '.m2', 'repository') 44 45 def __init__(self, debug=False): 46 self._repo_path = MavenDownloader._DEFAULT_REPO_PATH 47 self._remote_url = MavenDownloader._REMOTE_REPO 48 self._debug = debug 49 50 def Install(self, target_repo, artifacts, include_poms=False): 51 logging.info('Installing %d artifacts...', len(artifacts)) 52 downloaders = [_SingleArtifactDownloader(self, artifact, target_repo) 53 for artifact in artifacts] 54 if self._debug: 55 for downloader in downloaders: 56 downloader.Run(include_poms) 57 else: 58 parallelizer.SyncParallelizer(downloaders).Run(include_poms) 59 logging.info('%d artifacts installed to %s', len(artifacts), target_repo) 60 61 @property 62 def repo_path(self): 63 return self._repo_path 64 65 @property 66 def remote_url(self): 67 return self._remote_url 68 69 @property 70 def debug(self): 71 return self._debug 72 73 74class _SingleArtifactDownloader: 75 '''Handles downloading and installing a single Maven artifact.''' 76 77 _POM_FILE_TYPE = 'pom' 78 79 def __init__(self, download_manager, artifact, target_repo): 80 self._download_manager = download_manager 81 self._artifact = artifact 82 self._target_repo = target_repo 83 84 def Run(self, include_pom=False): 85 parts = self._artifact.split(':') 86 if len(parts) != 4: 87 raise Exception('Artifacts expected as ' 88 '"group_id:artifact_id:version:file_type".') 89 group_id, artifact_id, version, file_type = parts 90 self._InstallArtifact(group_id, artifact_id, version, file_type) 91 92 if include_pom and file_type != _SingleArtifactDownloader._POM_FILE_TYPE: 93 self._InstallArtifact(group_id, artifact_id, version, 94 _SingleArtifactDownloader._POM_FILE_TYPE) 95 96 def _InstallArtifact(self, group_id, artifact_id, version, file_type): 97 logging.debug('Processing %s', self._artifact) 98 99 download_relpath = self._DownloadArtifact( 100 group_id, artifact_id, version, file_type) 101 logging.debug('Downloaded.') 102 103 install_path = self._ImportArtifact(download_relpath) 104 logging.debug('Installed %s', os.path.relpath(install_path)) 105 106 def _DownloadArtifact(self, group_id, artifact_id, version, file_type): 107 ''' 108 Downloads the specified artifact using maven, to its standard location, see 109 MavenDownloader._DEFAULT_REPO_PATH. 110 ''' 111 cmd = ['mvn', 112 'org.apache.maven.plugins:maven-dependency-plugin:RELEASE:get', 113 '-DremoteRepositories={}'.format(self._download_manager.remote_url), 114 '-Dartifact={}:{}:{}:{}'.format(group_id, artifact_id, version, 115 file_type)] 116 117 stdout = None if self._download_manager.debug else open(os.devnull, 'wb') 118 119 try: 120 ret_code = cmd_helper.Call(cmd, stdout=stdout) 121 if ret_code != 0: 122 raise Exception('Command "{}" failed'.format(' '.join(cmd))) 123 except OSError as e: 124 if e.errno == errno.ENOENT: 125 raise Exception('mvn command not found. Please install Maven.') from e 126 raise 127 128 return os.path.join(os.path.join(*group_id.split('.')), 129 artifact_id, 130 version, 131 '{}-{}.{}'.format(artifact_id, version, file_type)) 132 133 def _ImportArtifact(self, artifact_path): 134 src_dir = os.path.join(self._download_manager.repo_path, artifact_path) 135 dst_dir = os.path.join(self._target_repo, os.path.dirname(artifact_path)) 136 137 _MakeDirsIfAbsent(dst_dir) 138 shutil.copy(src_dir, dst_dir) 139 140 return dst_dir 141