~nskaggs/phablet-tools/add-lp-branch-support

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
# Copyright (C) 2013 Canonical Ltd.
# Author: Sergio Schvezov <sergio.schvezov@canonical.com>

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import logging
import re
import requests
import os.path
import subprocess
import urlparse

from phabletutils import hashes
from phabletutils import fileutils
from phabletutils import resources
from phabletutils import settings

log = logging.getLogger()


def _get_elements(uri):
    '''Scraps cdimage and returns a list of relevant links as elements.'''
    request = requests.get(uri).content
    html_elements = filter(
        lambda x: '<li><a href=' in x and
        'Parent Directory' not in x and
        'daily' not in x and
        'current' not in x,
        request.split('\n'))
    # cdimage lays out the content in more than one way.
    if not html_elements:
        html_elements = filter(
            lambda x: 'alt="[DIR]"' in x and
            'Parent Directory' not in x and
            'daily' not in x and
            'pending' not in x and
            'current' not in x,
            request.split('\n'))
        html_elements = [re.search(r'<a.* href.*>.*</a>', x).group(0)
                         for x in html_elements]
    elements_inter = [re.sub('<[^>]*>', '', i) for i in html_elements]
    elements = [i.strip().strip('/') for i in elements_inter]
    return elements


def _get_releases(uri):
    '''Fetches the available releases for a given cdimage project URI.'''
    releases = [{'release': i, 'uri': '%s/%s' % (uri, i)}
                for i in _get_elements(uri)]
    log.debug('releases: %s', releases)
    return releases


def _get_revisions(uri):
    '''Returns the revisions for a given release URI.'''
    return _get_elements(uri)


def get_available_revisions(cdimage_uri):
    '''Returns all the releases available for a given cdimage project.'''
    if cdimage_uri[-1] != '/':
        cdimage_uri = cdimage_uri + '/'
    releases = _get_releases(cdimage_uri)
    for release in releases:
        release['revisions'] = _get_revisions(release['uri'])
    return releases


def get_latest_revision(cdimage_uri):
    '''Returns the latest revision tagged.'''
    log.debug('cdimage_uri: %s', cdimage_uri)
    try:
        latest_release = _get_releases(cdimage_uri)[-1]
        log.debug('latest_release: %s', latest_release)
        latest_revision = _get_revisions(latest_release['uri'])[-1]
    except IndexError:
        raise EnvironmentError('No releases for current project. Verify '
                               'by checking %s' % cdimage_uri)
    return latest_release['release'], latest_revision


def display_revisions(revisions):
    '''Displays the available revisions for a give cdimage project.'''
    for series in revisions:
        print 'Available releases:'
        if 'revisions' in series:
            for rev in series['revisions']:
                print '\t%s/%s' % (series['release'], rev)
        else:
            print 'No releases for %s available' % rev['release']
    if not revisions:
        print 'No revisions have been tagged for this project yet'


def _get_link_target(uri):
    '''Returns the target for the link in the image.'''
    uri = urlparse.urlparse(uri)
    uri = 'rsync://%s/cdimage%s' % (uri.netloc, uri.path)
    link = subprocess.check_output(['rsync', '-l', uri]).split()[-1]
    return link


def get_build(cdimage_uri, pending=False):
    '''Returns the latest build in current.'''
    if pending:
        uri = '%s/%s' % (cdimage_uri, 'pending')
    else:
        uri = '%s/%s' % (cdimage_uri, 'current')
    build = _get_link_target(uri)
    return build


def get_file(file_key, series, download_dir, project='ubuntu-touch',
             device=None):
    uri = '%s/%s/daily-preinstalled' % (settings.cdimage_uri_base, project)
    build = get_build(uri)
    hash_dict = hashes.load_hash('%s/%s' % (uri, build), 'SHA256SUMS')
    if device:
        file_name = settings.files_arch_any[project][file_key] %\
            (series, device)
        download_dir = fileutils.create_path(
            download_dir, os.path.join(device, build))
    else:
        file_name = settings.files_arch_all[project][file_key] % series
        download_dir = fileutils.create_path(
            download_dir, build)
    log.debug('Download dir for %s set to %s' % (file_name, download_dir))
    return resources.File(
        file_path=os.path.join(download_dir, file_name),
        file_uri='%s/%s/%s' % (uri, build, file_name),
        file_hash=hash_dict[file_name])