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