~ev/goget-ubuntu-touch/root-size-option

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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
//
// Helpers to work with an Ubuntu image based Upgrade implementation
//
// Copyright (c) 2013 Canonical Ltd.
//
// Written by Sergio Schvezov <sergio.schvezov@canonical.com>
//
package ubuntuimage

// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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 (
	_ "crypto/sha512"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
)

const (
	channelsPath = "/channels.json"
	indexName    = "index.json"
	FULL_IMAGE   = "full"
)

var client = &http.Client{}

// TLSSkipVerify turns off validation of server TLS certificates. It allows connecting
// to HTTPS servers that use self-signed certificates.
func TLSSkipVerify() {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client = &http.Client{Transport: tr}
}

func NewChannels(server string) (channels Channels, err error) {
	resp, err := client.Get(server + channelsPath)
	if err != nil {
		return channels, err
	}
	defer resp.Body.Close()
	dec := json.NewDecoder(resp.Body)
	if err := dec.Decode(&channels); err != nil {
		return channels, fmt.Errorf("Unable to parse channel information from %s", server)
	}
	return channels, nil
}

func (channels Channels) GetDeviceChannel(server, channel, device string) (deviceChannel DeviceChannel, err error) {
	if _, found := channels[channel]; !found {
		return deviceChannel, fmt.Errorf("Channel %s not found on server %s", channel, server)
	} else if _, found := channels[channel].Devices[device]; !found {
		return deviceChannel, fmt.Errorf("Device %s not found on server %s channel %s",
			device, server, channel)
	}
	channelUri := server + channels[channel].Devices[device].Index
	resp, err := client.Get(channelUri)
	if err != nil {
		return deviceChannel, err
	}
	defer resp.Body.Close()
	dec := json.NewDecoder(resp.Body)
	err = dec.Decode(&deviceChannel)
	if err != nil {
		return deviceChannel, fmt.Errorf("Cannot parse channel information for device on %s", channelUri)
	}
	deviceChannel.Alias = channels[channel].Alias
	order := func(i1, i2 *Image) bool {
		return i1.Version > i2.Version
	}
	ImageBy(order).ImageSort(deviceChannel.Images)

	deviceChannel.Url = channelUri
	return deviceChannel, err
}

func (deviceChannel *DeviceChannel) GetImage(revision int) (image Image, err error) {
	for _, image := range deviceChannel.Images {
		if image.Type == FULL_IMAGE && image.Version == revision {
			return image, nil
		}
	}
	//If we reached this point, that means we haven't found the image we were looking for.
	return image, fmt.Errorf("Failed to locate image %d", revision)
}

func (deviceChannel *DeviceChannel) ListImageVersions() (err error) {

	jsonData := map[string]interface{}{}

	resp, err := client.Get(deviceChannel.Url)
	if err != nil {
		return err
	}

	if resp.StatusCode != 200 {
		statusErr := errors.New(fmt.Sprintf("Invalid HTTP response: %d", resp.StatusCode))
		return statusErr
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	err = json.Unmarshal(body, &jsonData)
	if err != nil {
		return err
	}

	images := jsonData["images"].([]interface{})

	for i := range images {
		entry := images[i].(map[string]interface{})

		imageType := entry["type"]

		if imageType != FULL_IMAGE {
			// ignore delta images as they cannot be used to
			// perform an initial device flash
			continue
		}

		fmt.Printf("%d: description='%s'\n",
			int(entry["version"].(float64)),
			entry["description"])
	}

	return nil
}

func (deviceChannel *DeviceChannel) GetRelativeImage(revision int) (image Image, err error) {
	var steps int
	if revision < 0 {
		revision = -revision
	}
	for _, image := range deviceChannel.Images {
		if image.Type != FULL_IMAGE {
			continue
		}
		if steps == revision {
			return image, nil
		}
		steps++
	}
	//If we reached this point, that means we haven't found the image we were looking for.
	if revision == 0 {
		err = errors.New("Failed to locate latest image information")
	} else {
		err = fmt.Errorf("Failed to locate relative image to latest - %d", revision)
	}
	return Image{}, err
}