1# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import errno
6import os
7import shutil
8import urllib2
9
10from autotest_lib.client.common_lib import global_config
11
12def rm_dir_if_exists(dir_to_remove):
13    """
14    Removes a directory. Does not fail if the directory does NOT exist.
15
16    @param dir_to_remove: path, directory to be removed.
17
18    """
19    try:
20        shutil.rmtree(dir_to_remove)
21    except OSError as e:
22        if e.errno != errno.ENOENT:
23            raise
24
25
26def rm_dirs_if_exist(dirs_to_remove):
27    """
28    Removes multiple directories. Does not fail if directories do NOT exist.
29
30    @param dirs_to_remove: list of directory paths to be removed.
31
32    """
33    for dr in dirs_to_remove:
34        rm_dir_if_exists(dr)
35
36
37def ensure_file_exists(filepath):
38    """
39    Verifies path given points to an existing file.
40
41    @param filepath: path, path to check.
42
43    @raises IOError if the path given does not point to a valid file.
44
45    """
46    error_msg = 'File %s does not exist.' % filepath
47    if not os.path.isfile(filepath):
48        raise IOError(error_msg)
49
50
51def ensure_all_files_exist(filepaths):
52    """
53    Verifies all paths given point to existing files.
54
55    @param filepaths: List of paths to check.
56
57    @raises IOError if given paths do not point to existing files.
58
59    """
60    for filepath in filepaths:
61        ensure_file_exists(filepath)
62
63
64def ensure_dir_exists(dirpath):
65    """
66    Verifies path given points to an existing directory.
67
68    @param dirpath: path, dir to check.
69
70    @raises IOError if path does not point to an existing directory.
71
72    """
73    error_msg = 'Directory %s does not exist.' % dirpath
74    if not os.path.isdir(dirpath):
75        raise IOError(error_msg)
76
77
78def ensure_all_dirs_exist(dirpaths):
79    """
80    Verifies all paths given point to existing directories.
81
82    @param dirpaths: list of directory paths to check.
83
84    @raises IOError if given paths do not point to existing directories.
85
86    """
87    for dirpath in dirpaths:
88        ensure_dir_exists(dirpath)
89
90
91def make_leaf_dir(dirpath):
92    """
93    Creates a directory, also creating parent directories if they do not exist.
94
95    @param dirpath: path, directory to create.
96
97    @raises whatever exception raised other than "path already exist".
98
99    """
100    try:
101        os.makedirs(dirpath)
102    except OSError as e:
103        if e.errno != errno.EEXIST:
104            raise
105
106
107def make_leaf_dirs(dirpaths):
108    """
109    Creates multiple directories building all respective parent directories if
110    they do not exist.
111
112    @param dirpaths: list of directory paths to create.
113
114    @raises whatever exception raised other than "path already exists".
115    """
116    for dirpath in dirpaths:
117        make_leaf_dir(dirpath)
118
119
120def download_file(remote_path, local_path):
121    """
122    Download file from a remote resource.
123
124    @param remote_path: path, complete path to the remote file.
125    @param local_path: path, complete path to save downloaded file.
126
127    @raises: urllib2.HTTPError or urlib2.URLError exception. Both with added
128            debug information
129
130    """
131    client_config = global_config.global_config.get_section_values('CLIENT')
132    proxies = {}
133
134    for name, value in client_config.items('CLIENT'):
135        if value and name.endswith('_proxy'):
136            proxies[name[:-6]] = value
137
138    if proxies:
139        proxy_handler = urllib2.ProxyHandler(proxies)
140        opener = urllib2.build_opener(proxy_handler)
141        urllib2.install_opener(opener)
142
143    # Unlike urllib.urlopen urllib2.urlopen will immediately throw on error
144    # If we could not find the file pointed by remote_path we will get an
145    # exception, catch the exception to log useful information then re-raise
146
147    try:
148        remote_file = urllib2.urlopen(remote_path)
149
150        # Catch exceptions, extract exception properties and then re-raise
151        # This helps us with debugging what went wrong quickly as we get to see
152        # test_that output immediately
153
154    except urllib2.HTTPError as e:
155        e.msg = (("""HTTPError raised while retrieving file %s\n.
156                       Http Code = %s.\n. Reason = %s\n. Headers = %s.\n
157                       Original Message = %s.\n""")
158                 % (remote_path, e.code, e.reason, e.headers, e.msg))
159        raise
160
161    except urllib2.URLError as e:
162        e.msg = (("""URLError raised while retrieving file %s\n.
163                        Reason = %s\n. Original Message = %s\n.""")
164                 % (remote_path, e.reason, e.message))
165        raise
166
167    with open(local_path, 'wb') as local_file:
168        local_file.write(remote_file.read())