This repository has been archived by the owner on Nov 13, 2020. It is now read-only.
/
aciarchive.go
130 lines (110 loc) · 3.55 KB
/
aciarchive.go
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
// Copyright 2016 The rkt Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package distribution
import (
"fmt"
"net/url"
"path/filepath"
"github.com/PuerkitoBio/purell"
"github.com/appc/spec/schema"
"github.com/hashicorp/errwrap"
)
const (
distACIArchiveVersion = 0
// TypeACIArchive represents the ACIArchive distribution type
TypeACIArchive Type = "aci-archive"
)
func init() {
Register(TypeACIArchive, NewACIArchive)
}
// ACIArchive defines a distribution using an ACI file
// The format is:
// cimd:aci-archive:v=0:ArchiveURL?query...
// The distribution type is "archive"
// ArchiveURL must be query escaped
// Examples:
// cimd:aci-archive:v=0:file%3A%2F%2Fabsolute%2Fpath%2Fto%2Ffile
// cimd:aci-archive:v=0:https%3A%2F%2Fexample.com%2Fapp.aci
type ACIArchive struct {
cimdURL *url.URL // the cimd URL as explained in the examples
transportURL *url.URL // the transport URL of the target ACI archive, i.e. https://example.com/app.aci
str string // the string representation
}
// NewACIArchive creates a new aci-archive distribution from the provided distribution uri.
func NewACIArchive(u *url.URL) (Distribution, error) {
c, err := parseCIMD(u)
if err != nil {
return nil, fmt.Errorf("cannot parse URI: %q: %v", u.String(), err)
}
if c.Type != TypeACIArchive {
return nil, fmt.Errorf("illegal ACI archive distribution type: %q", c.Type)
}
// This should be a valid URL
data, err := url.QueryUnescape(c.Data)
if err != nil {
return nil, errwrap.Wrap(fmt.Errorf("error unescaping url %q", c.Data), err)
}
aciu, err := url.Parse(data)
if err != nil {
return nil, errwrap.Wrap(fmt.Errorf("error parsing url %q", c.Data), err)
}
// save the URI as sorted to make it ready for comparison
purell.NormalizeURL(u, purell.FlagSortQuery)
str := u.String()
if path := aciu.String(); filepath.Ext(path) == schema.ACIExtension {
str = path
}
return &ACIArchive{
cimdURL: u,
transportURL: aciu,
str: str,
}, nil
}
// NewACIArchiveFromTransportURL creates a new aci-archive distribution from the provided transport URL
// Example: file:///full/path/to/aci/file.aci -> cimd:aci-archive:v=0:file%3A%2F%2F%2Ffull%2Fpath%2Fto%2Faci%2Ffile.aci
func NewACIArchiveFromTransportURL(u *url.URL) (Distribution, error) {
urlStr := NewCIMDString(TypeACIArchive, distACIArchiveVersion, url.QueryEscape(u.String()))
u, err := url.Parse(urlStr)
if err != nil {
return nil, err
}
return NewACIArchive(u)
}
func (a *ACIArchive) CIMD() *url.URL {
// Create a copy of the URL.
u, err := url.Parse(a.cimdURL.String())
if err != nil {
panic(err)
}
return u
}
func (a *ACIArchive) Equals(d Distribution) bool {
a2, ok := d.(*ACIArchive)
if !ok {
return false
}
return a.CIMD().String() == a2.CIMD().String()
}
func (a *ACIArchive) String() string {
return a.str
}
// TransportURL returns a copy of the transport URL.
func (a *ACIArchive) TransportURL() *url.URL {
// Create a copy of the transport URL
tu, err := url.Parse(a.transportURL.String())
if err != nil {
panic(fmt.Errorf("invalid transport URL: %v", err))
}
return tu
}