-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathsource.go
145 lines (115 loc) · 2.47 KB
/
source.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package hbuild
import (
"archive/tar"
"compress/gzip"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
)
type Source struct {
Dir *os.File
Archive *os.File
Get *url.URL
Put *url.URL
}
type SourceJSON struct {
SourceBlob struct {
GetUrl string `json:"get_url"`
PutUrl string `json:"put_url"`
} `json:"source_blob"`
}
func NewSource(token, app, dir string) (source Source, err error) {
client := newHerokuClient(token)
source.Dir, err = os.Open(dir)
if err != nil {
return
}
sourceJson := new(SourceJSON)
err = client.request(sourceRequest(app), &sourceJson)
if err != nil {
return
}
source.Get, err = url.Parse(sourceJson.SourceBlob.GetUrl)
if err != nil {
return
}
source.Put, err = url.Parse(sourceJson.SourceBlob.PutUrl)
if err != nil {
return
}
return
}
func sourceRequest(app string) herokuRequest {
return herokuRequest{"POST", "/apps/" + app + "/sources", nil, http.Header{}}
}
func (s *Source) Compress() (err error) {
s.Archive, err = tarGz(s.Dir.Name())
return
}
func (s *Source) Upload() (err error) {
return uploadFile(s.Put.String(), s.Archive)
}
func targzWalk(dirPath string, tw *tar.Writer) error {
var walkfunc filepath.WalkFunc
prefixPath := filepath.Clean(dirPath) + "/"
walkfunc = func(path string, fi os.FileInfo, err error) error {
// turn the absolute path into a relative path
path = strings.TrimPrefix(path, prefixPath)
// ignore the .git dir
if strings.HasPrefix(path, ".git/") {
return nil
}
h, err := tar.FileInfoHeader(fi, "")
if err != nil {
return err
}
h.Name = "./" + path
if fi.Mode()&os.ModeSymlink != 0 {
linkPath, err := os.Readlink(path)
if err != nil {
return err
}
h.Linkname = linkPath
}
err = tw.WriteHeader(h)
if err != nil {
return err
}
if fi.Mode()&os.ModeDir == 0 && fi.Mode()&os.ModeSymlink == 0 {
fr, err := os.Open(path)
if err != nil {
return err
}
defer fr.Close()
_, err = io.Copy(tw, fr)
if err != nil {
return err
}
}
return nil
}
return filepath.Walk(dirPath, walkfunc)
}
func tarGz(inPath string) (tarArchive *os.File, err error) {
// file write
tempSource, err := ioutil.TempFile("", "source")
if err != nil {
return nil, err
}
tarArchive, err = os.Create(tempSource.Name())
if err != nil {
return
}
// gzip write
gw := gzip.NewWriter(tarArchive)
defer gw.Close()
// tar write
tw := tar.NewWriter(gw)
defer tw.Close()
err = targzWalk(inPath, tw)
return
}