|
1 #!/usr/bin/python2.6 |
|
2 # |
|
3 # CDDL HEADER START |
|
4 # |
|
5 # The contents of this file are subject to the terms of the |
|
6 # Common Development and Distribution License (the "License"). |
|
7 # You may not use this file except in compliance with the License. |
|
8 # |
|
9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
|
10 # or http://www.opensolaris.org/os/licensing. |
|
11 # See the License for the specific language governing permissions |
|
12 # and limitations under the License. |
|
13 # |
|
14 # When distributing Covered Code, include this CDDL HEADER in each |
|
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
|
16 # If applicable, add the following below this CDDL HEADER, with the |
|
17 # fields enclosed by brackets "[]" replaced with your own identifying |
|
18 # information: Portions Copyright [yyyy] [name of copyright owner] |
|
19 # |
|
20 # CDDL HEADER END |
|
21 # |
|
22 # Copyright (c) 2010, Oracle and/or it's affiliates. All rights reserved. |
|
23 # |
|
24 # |
|
25 # fetch.py - a file download utility |
|
26 # |
|
27 # A simple program similiar to wget(1), but handles local file copy, ignores |
|
28 # directories, and verifies file hashes. |
|
29 # |
|
30 |
|
31 import os |
|
32 import sys |
|
33 |
|
34 def validate(filename, hash): |
|
35 import hashlib |
|
36 |
|
37 try: |
|
38 file = open(filename, 'r') |
|
39 except IOError: |
|
40 return False |
|
41 |
|
42 if (hash == None): |
|
43 return True |
|
44 |
|
45 algorithm, value = hash.split(':') |
|
46 try: |
|
47 m = hashlib.new(algorithm) |
|
48 except ValueError: |
|
49 return False |
|
50 |
|
51 while True: |
|
52 block = file.read() |
|
53 m.update(block) |
|
54 if block == '': |
|
55 break |
|
56 |
|
57 return m.hexdigest() == value |
|
58 |
|
59 def download(url, filename = None, hash = None, verbose = False): |
|
60 from urllib import splittype, urlopen |
|
61 import hashlib |
|
62 |
|
63 src = None |
|
64 filename = None |
|
65 |
|
66 #print "Downloading %s from %s" % (filename, url) |
|
67 |
|
68 # open the download source |
|
69 if splittype(url)[0]: |
|
70 try: |
|
71 src = urlopen(url) |
|
72 except IOError: |
|
73 return None |
|
74 remote_name = src.geturl().split('/')[-1] |
|
75 elif os.path.isfile(url): |
|
76 os.symlink(url, filename) |
|
77 return filename, filehash(filename) |
|
78 src = open(url, 'r') |
|
79 remote_name = url.split('/')[-1] |
|
80 else: |
|
81 return None |
|
82 |
|
83 if filename == None: |
|
84 filename = remote_name |
|
85 |
|
86 # if we have a source to download, open a destination and copy the data |
|
87 if src: |
|
88 dst = open(filename, 'wb'); |
|
89 if verbose: |
|
90 print "Downloading %s from %s" % (filename, url) |
|
91 while True: |
|
92 block = src.read() |
|
93 if block == '': |
|
94 break; |
|
95 dst.write(block) |
|
96 dst.close() |
|
97 |
|
98 # return the name of the file that we downloaded the data to. |
|
99 return filename |
|
100 |
|
101 def download_paths(search, filename): |
|
102 tmp = os.getenv('DOWNLOAD_SEARCH_PATH') |
|
103 if tmp: |
|
104 search += tmp.split(' ') |
|
105 base = os.path.basename(filename) |
|
106 |
|
107 urls = list() |
|
108 |
|
109 for path in search: |
|
110 urls.append(path+'/'+base) |
|
111 |
|
112 return urls |
|
113 |
|
114 def usage(): |
|
115 print "Usage: %s [-v|--verbose] [-f|--file (file)] [-h|--hash (hash)] --url (url)" % (sys.argv[0].split('/')[-1]) |
|
116 sys.exit(1) |
|
117 |
|
118 def main(): |
|
119 from urllib import splittype, urlopen |
|
120 import getopt |
|
121 import sys |
|
122 |
|
123 # FLUSH STDOUT |
|
124 sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) |
|
125 |
|
126 verbose = False |
|
127 filename = None |
|
128 url = None |
|
129 hash = None |
|
130 search = list() |
|
131 |
|
132 try: |
|
133 opts, args = getopt.getopt(sys.argv[1:], "f:h:s:u:v", |
|
134 ["file=", "hash=", "search=", "url=", "verbose"]) |
|
135 except getopt.GetoptError, err: |
|
136 print str(err) |
|
137 usage() |
|
138 |
|
139 for opt, arg in opts: |
|
140 if opt in [ "-f", "--file" ]: |
|
141 filename = arg |
|
142 elif opt in [ "-h", "--hash" ]: |
|
143 hash = arg |
|
144 elif opt in [ "-s", "--search" ]: |
|
145 search.append(arg) |
|
146 elif opt in [ "-u", "--url" ]: |
|
147 url = arg |
|
148 elif opt in [ "-v", "--verbose" ]: |
|
149 verbose = True |
|
150 else: |
|
151 assert False, "unknown option" |
|
152 |
|
153 if url == None: |
|
154 usage() |
|
155 |
|
156 print "Fetching %s" % filename |
|
157 |
|
158 if validate(filename, hash): |
|
159 print "\tcurrent copy is ok, nothing to do" |
|
160 sys.exit(0) |
|
161 |
|
162 # generate a list of URLS to search for a suitable download |
|
163 urls = download_paths(search, filename) |
|
164 urls.append(url) |
|
165 |
|
166 for url in urls: |
|
167 print "\tTrying %s..." % url, |
|
168 |
|
169 if os.path.isfile(url): |
|
170 os.symlink(url, filename) |
|
171 elif splittype(url)[0]: |
|
172 if download(url, filename) == None: |
|
173 print "failed" |
|
174 continue |
|
175 |
|
176 print "retrieved...", |
|
177 |
|
178 if validate(filename, hash): |
|
179 print "validated" |
|
180 sys.exit(0) |
|
181 else: |
|
182 print "corrupt" |
|
183 |
|
184 try: |
|
185 os.remove(filename) |
|
186 except OSError: |
|
187 pass |
|
188 |
|
189 sys.exit(1) |
|
190 |
|
191 if __name__ == "__main__": |
|
192 main() |