1 # -*- coding: utf-8 -*-
\r
3 ############################################################################
\r
6 # This file is a SCons (http://www.scons.org/) builder #
\r
7 # Copyright (c) 2012-14, Philipp Kraus, <philipp.kraus@flashpixx.de> #
\r
8 # Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved. #
\r
9 # This program is free software: you can redistribute it and/or modify #
\r
10 # it under the terms of the GNU General Public License as #
\r
11 # published by the Free Software Foundation, either version 3 of the #
\r
12 # License, or (at your option) any later version. #
\r
14 # This program is distributed in the hope that it will be useful, #
\r
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
\r
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
\r
17 # GNU General Public License for more details. #
\r
19 # You should have received a copy of the GNU General Public License #
\r
20 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
\r
21 ############################################################################
\r
23 # the URLDownload-Builder can download any data from an URL into a target
\r
24 # file. The target name is used are the file name of the downloaded file.
\r
26 # This builder originated from work by Philipp Kraus and flashpixx project
\r
27 # (see https://github.com/flashpixx). It has been modified to leverage
\r
28 # the HTTP ETag header to be used as the csig. This allows the download
\r
29 # builder to determine if the file should be downloaded again when the
\r
30 # ETag header is supported
\r
33 import urllib2, urlparse
\r
34 import SCons.Builder, SCons.Node, SCons.Errors
\r
36 # Define a source node to represent the remote file. The construction of the
\r
37 # node will query the hosting site to get the ETag, size and last-modified
\r
38 # date. This node also defines the method by which we will determine if
\r
39 # the file should be downloaded again.
\r
41 # This node derives from the Python.Value node
\r
43 class URLNode(SCons.Node.Python.Value) :
\r
44 def make_ready(self) :
\r
46 stream = urllib2.urlopen( str(self.value) )
\r
47 info = stream.info()
\r
49 self.url_etag = None
\r
50 self.url_last_modified = None
\r
51 self.url_content_length = None
\r
54 self.url_etag = info['ETag']
\r
55 if 'Last-Modified' in info :
\r
56 self.url_last_modified = time.mktime(time.strptime(info['Last-Modified'], '%a, %d %b %Y %H:%M:%S GMT'))
\r
57 if 'Content-Length' in info :
\r
58 self.url_content_legth = info['Content-Length']
\r
59 except Exception, e :
\r
60 raise SCons.Errors.StopError( '%s [%s]' % (e, self.value) )
\r
63 ninfo = self.get_ninfo()
\r
66 ninfo.csig = self.url_etag
\r
67 if self.url_last_modified :
\r
68 ninfo.timestamp = self.url_last_modified
\r
69 if self.url_content_length :
\r
70 ninfo.size = self.url_content_length
\r
71 SCons.Node.Node.visited(self);
\r
73 def changed_since_last_build(self, target, prev_ni):
\r
76 if prev_ni.csig == self.url_etag :
\r
77 # print 'Matched on ETag:'+prev_ni.csig
\r
80 if not self.url_last_modified :
\r
81 # print 'Last modified date is not available'
\r
83 if not self.url_content_length :
\r
84 # print 'Content length is not available'
\r
86 if prev_ni.timestamp != self.url_last_modified :
\r
87 # print 'Modified since last build'
\r
89 if prev_ni.size != self.url_content_length :
\r
90 # print 'Content length has changed'
\r
95 # print 'Not previous built'
\r
98 # Creates the output message
\r
99 # @param s original message
\r
100 # @param target target name
\r
101 # @param source source name
\r
102 # @param env environment object
\r
103 def __message( s, target, source, env ) :
\r
104 print 'downloading [%s] from [%s] ...' % (target[0], source[0])
\r
106 # Creates the action ie. the download function.
\r
107 # This reads the data from the URL and writes it down to the file
\r
108 # @param target target file on the local drive
\r
109 # @param source URL for download
\r
110 # @@param env environment object
\r
111 def __action( target, source, env ) :
\r
113 source_name = str(source[0])
\r
114 target_name = str(target[0])
\r
115 stream = urllib2.urlopen(source_name)
\r
116 file = open( target_name, 'wb' )
\r
117 file.write(stream.read())
\r
120 # Change the access/modified time to match
\r
121 # the date on the downloaded file, if available
\r
122 ninfo = source[0].get_ninfo()
\r
123 if hasattr(ninfo, 'timestamp') :
\r
124 mtime = ninfo.timestamp
\r
126 os.utime(target_name, (mtime, mtime))
\r
127 except Exception, e :
\r
128 raise SCons.Errors.StopError( '%s [%s]' % (e, source[0]) )
\r
131 # Defines the emitter of the builder
\r
132 # @param target target file on the local drive
\r
133 # @param source URL for download
\r
134 # @param env environment object
\r
135 def __emitter( target, source, env ) :
\r
136 return target, source
\r
138 # generate function, that adds the builder to the environment,
\r
139 # @param env environment object
\r
140 def generate( env ) :
\r
141 env['BUILDERS']['URLDownload'] = SCons.Builder.Builder( action = __action, emitter = __emitter, target_factory = SCons.Node.FS.File, source_factory = URLNode, single_source = True, PRINT_CMD_LINE_FUNC = __message )
\r
143 # existing function of the builder
\r
144 # @param env environment object
\r