source: rtems-source-builder/source-builder/sb/download.py @ 4ce931b

4.104.114.9
Last change on this file since 4ce931b was 4ce931b, checked in by Chris Johns <chrisj@…>, on Apr 20, 2013 at 11:47:28 AM

Add CVS download support.

These changes complete the CVS download support.

  • Property mode set to 100644
File size: 9.9 KB
Line 
1#
2# RTEMS Tools Project (http://www.rtems.org/)
3# Copyright 2010-2013 Chris Johns (chrisj@rtems.org)
4# All rights reserved.
5#
6# This file is part of the RTEMS Tools package in 'rtems-tools'.
7#
8# Permission to use, copy, modify, and/or distribute this software for any
9# purpose with or without fee is hereby granted, provided that the above
10# copyright notice and this permission notice appear in all copies.
11#
12# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20#
21# This code builds a package given a config file. It only builds to be
22# installed not to be package unless you run a packager around this.
23#
24
25import os
26import stat
27import sys
28import urllib2
29import urlparse
30
31import cvs
32import error
33import git
34import log
35import path
36
37def _notice(opts, text):
38    if not opts.quiet() and not log.default.has_stdout():
39        print text
40    log.output(text)
41    log.flush()
42
43def _output(opts, text):
44    if not opts.quiet():
45        log.output(text)
46
47def _http_parser(source, config, opts):
48    #
49    # Is the file compressed ?
50    #
51    esl = source['ext'].split('.')
52    if esl[-1:][0] == 'gz':
53        source['compressed'] = '%{__gzip} -dc'
54    elif esl[-1:][0] == 'bz2':
55        source['compressed'] = '%{__bzip2} -dc'
56    elif esl[-1:][0] == 'bz2':
57        source['compressed'] = '%{__zip} -u'
58    elif esl[-1:][0] == 'xz':
59        source['compressed'] = '%{__xz} -dc'
60
61def _git_parser(source, config, opts):
62    #
63    # Symlink.
64    #
65    us = source['url'].split('?')
66    source['path'] = path.dirname(us[0])
67    source['file'] = path.basename(us[0])
68    source['name'], source['ext'] = path.splitext(source['file'])
69    if len(us) > 1:
70        source['args'] = us[1:]
71    source['local'] = \
72        path.join(source['local_prefix'], 'git', source['file'])
73    source['symlink'] = source['local']
74
75def _cvs_parser(source, config, opts):
76    #
77    # Symlink.
78    #
79    if not source['url'].startswith('cvs://'):
80        raise error.general('invalid cvs path: %s' % (source['url']))
81    us = source['url'].split('?')
82    try:
83        url = us[0]
84        source['file'] = \
85            url[url[6:].index(':') + 7:].replace('/', '_').replace('@', '_').replace('.', '_')
86        source['cvsroot'] = ':%s:' % (url[6:url[6:].index('/') + 6:])
87    except:
88        raise error.general('invalid cvs path: %s' % (source['url']))
89    source['local'] = path.join(source['local_prefix'], 'cvs', source['file'])
90    if 'src_prefix' in source:
91        source['symlink'] = path.join(source['local'])
92    else:
93        source['symlink'] = source['local']
94
95def _file_parser(source, config, opts):
96    #
97    # Symlink.
98    #
99    source['symlink'] = source['local']
100
101parsers = { 'http': _http_parser,
102            'ftp':  _http_parser,
103            'git':  _git_parser,
104            'cvs':  _cvs_parser,
105            'file': _file_parser }
106
107def parse_url(url, pathkey, config, opts):
108    #
109    # Split the source up into the parts we need.
110    #
111    source = {}
112    source['url'] = url
113    source['path'] = path.dirname(url)
114    source['file'] = path.basename(url)
115    source['name'], source['ext'] = path.splitext(source['file'])
116    #
117    # Get the file. Checks the local source directory first.
118    #
119    source['local'] = None
120    for p in config.define(pathkey).split(':'):
121        local = path.join(path.abspath(p), source['file'])
122        if source['local'] is None:
123            source['local_prefix'] = path.abspath(p)
124            source['local'] = local
125        if path.exists(local):
126            source['local_prefix'] = path.abspath(p)
127            source['local'] = local
128            break
129    source['script'] = ''
130    for p in parsers:
131        if url.startswith(p):
132            source['type'] = p
133            if parsers[p](source, config, opts):
134                break
135    return source
136
137def _http_downloader(url, local, config, opts):
138    if path.exists(local):
139        return True
140    #
141    # Hack for GitHub.
142    #
143    if url.startswith('https://api.github.com'):
144        url = urlparse.urljoin(url, config.expand('tarball/%{version}'))
145    _notice(opts, 'download: %s -> %s' % (url, os.path.relpath(path.host(local))))
146    failed = False
147    if not opts.dry_run():
148        _in = None
149        _out = None
150        try:
151            _in = urllib2.urlopen(url)
152            _out = open(path.host(local), 'wb')
153            _out.write(_in.read())
154        except IOError, err:
155            msg = 'download: %s: error: %s' % (url, str(err))
156            _notice(opts, msg)
157            if path.exists(local):
158                os.remove(path.host(local))
159            failed = True
160        except ValueError, err:
161            msg = 'download: %s: error: %s' % (url, str(err))
162            _notice(opts, msg)
163            if path.exists(local):
164                os.remove(path.host(local))
165            failed = True
166        except:
167            msg = 'download: %s: error' % (url)
168            print >> sys.stderr, msg
169            if _out is not None:
170                _out.close()
171            raise
172        if _out is not None:
173            _out.close()
174        if _in is not None:
175            del _in
176        if not failed:
177            if not path.isfile(local):
178                raise error.general('source is not a file: %s' % (path.host(local)))
179    return not failed
180
181def _git_downloader(url, local, config, opts):
182    rlp = os.path.relpath(path.host(local))
183    us = url.split('?')
184    repo = git.repo(local, opts, config.macros)
185    if not repo.valid():
186        _notice(opts, 'git: clone: %s -> %s' % (us[0], rlp))
187        if not opts.dry_run():
188            repo.clone(us[0], local)
189    for a in us[1:]:
190        _as = a.split('=')
191        if _as[0] == 'branch':
192            _notice(opts, 'git: checkout: %s => %s' % (us[0], _as[1]))
193            if not opts.dry_run():
194                repo.checkout(_as[1])
195        elif _as[0] == 'pull':
196            _notice(opts, 'git: pull: %s' % (us[0]))
197            if not opts.dry_run():
198                repo.pull()
199        elif _as[0] == 'fetch':
200            _notice(opts, 'git: fetch: %s -> %s' % (us[0], rlp))
201            if not opts.dry_run():
202                repo.fetch()
203        elif _as[0] == 'reset':
204            arg = []
205            if len(_as) > 1:
206                arg = ['--%s' % (_as[1])]
207            _notice(opts, 'git: reset: %s' % (us[0]))
208            if not opts.dry_run():
209                repo.reset(arg)
210    return True
211
212def _cvs_downloader(url, local, config, opts):
213    rlp = os.path.relpath(path.host(local))
214    us = url.split('?')
215    module = None
216    tag = None
217    date = None
218    src_prefix = None
219    for a in us[1:]:
220        _as = a.split('=')
221        if _as[0] == 'module':
222            if len(_as) != 2:
223                raise error.general('invalid cvs module: %s' % (a))
224            module = _as[1]
225        elif _as[0] == 'src-prefix':
226            if len(_as) != 2:
227                raise error.general('invalid cvs src-prefix: %s' % (a))
228            src_prefix = _as[1]
229        elif _as[0] == 'tag':
230            if len(_as) != 2:
231                raise error.general('invalid cvs tag: %s' % (a))
232            tag = _as[1]
233        elif _as[0] == 'date':
234            if len(_as) != 2:
235                raise error.general('invalid cvs date: %s' % (a))
236            date = _as[1]
237    repo = cvs.repo(local, opts, config.macros, src_prefix)
238    if not repo.valid():
239        _notice(opts, 'cvs: checkout: %s -> %s' % (us[0], rlp))
240        if not opts.dry_run():
241            repo.checkout(':%s' % (us[0][6:]), module, tag, date)
242    for a in us[1:]:
243        _as = a.split('=')
244        if _as[0] == 'update':
245            _notice(opts, 'cvs: update: %s' % (us[0]))
246            if not opts.dry_run():
247                repo.update()
248        elif _as[0] == 'reset':
249            _notice(opts, 'cvs: reset: %s' % (us[0]))
250            if not opts.dry_run():
251                repo.reset()
252    return True
253
254def _file_downloader(url, local, config, opts):
255    if path.exists(local):
256        return True
257    return path.isdir(url)
258
259downloaders = { 'http': _http_downloader,
260                'ftp':  _http_downloader,
261                'git':  _git_downloader,
262                'cvs':  _cvs_downloader,
263                'file': _file_downloader }
264
265def get_file(url, local, opts, config):
266    if local is None:
267        raise error.general('source/patch path invalid')
268    if not path.isdir(path.dirname(local)) and not opts.download_disabled():
269        _notice(opts,
270                'Creating source directory: %s' % (os.path.relpath(path.host(path.dirname(local)))))
271    _output(opts, 'making dir: %s' % (path.host(path.dirname(local))))
272    if not opts.dry_run():
273        path.mkdir(path.dirname(local))
274    if not path.exists(local) and opts.download_disabled():
275        raise error.general('source not found: %s' % (path.host(local)))
276    #
277    # Check if a URL hasbeen provided on the command line.
278    #
279    url_bases = opts.urls()
280    urls = []
281    if url_bases is not None:
282        for base in url_bases:
283            if base[-1:] != '/':
284                base += '/'
285            url_path = urlparse.urlsplit(url)[2]
286            slash = url_path.rfind('/')
287            if slash < 0:
288                url_file = url_path
289            else:
290                url_file = url_path[slash + 1:]
291            urls.append(urlparse.urljoin(base, url_file))
292    urls.append(url)
293    if opts.trace():
294        print '_url:', ','.join(urls), '->', local
295    for url in urls:
296        for dl in downloaders:
297            if url.startswith(dl):
298                if downloaders[dl](url, local, config, opts):
299                    return
300    if not opts.dry_run():
301        raise error.general('downloading %s: all paths have failed, giving up' % (url))
Note: See TracBrowser for help on using the repository browser.