@@ -17,7 +17,9 @@ limitations under the License.
17
17
package main
18
18
19
19
import (
20
+ "bufio"
20
21
"encoding/json"
22
+ "fmt"
21
23
"io/ioutil"
22
24
"net/url"
23
25
"os"
@@ -40,6 +42,10 @@ import (
40
42
41
43
// Filenames for labels and statuses are URL encoded for safety.
42
44
45
+ const (
46
+ manifestPath = ".MANIFEST"
47
+ )
48
+
43
49
// ToDisk converts a PullRequest object to an on-disk representation at the specified path.
44
50
func ToDisk (pr * PullRequest , path string ) error {
45
51
labelsPath := filepath .Join (path , "labels" )
@@ -80,28 +86,54 @@ func ToDisk(pr *PullRequest, path string) error {
80
86
}
81
87
82
88
func commentsToDisk (path string , comments []* Comment ) error {
89
+ // Create a manifest to keep track of the comments that existed when the
90
+ // resource was initialized. This is used to verify that a comment that
91
+ // doesn't exist on disk was actually deleted by the user and not newly
92
+ // created during upload.
93
+ f , err := os .Create (filepath .Join (path , manifestPath ))
94
+ if err != nil {
95
+ return err
96
+ }
97
+ defer f .Close ()
98
+ manifest := bufio .NewWriter (f )
99
+
83
100
for _ , c := range comments {
84
- commentPath := filepath .Join (path , strconv .FormatInt (c .ID , 10 )+ ".json" )
101
+ id := strconv .FormatInt (c .ID , 10 )
102
+ commentPath := filepath .Join (path , id + ".json" )
85
103
b , err := json .Marshal (c )
86
104
if err != nil {
87
105
return err
88
106
}
89
- if err := ioutil .WriteFile (commentPath , b , 0700 ); err != nil {
107
+ if err := ioutil .WriteFile (commentPath , b , 0600 ); err != nil {
108
+ return err
109
+ }
110
+ if _ , err := manifest .WriteString (fmt .Sprintf ("%s\n " , id )); err != nil {
90
111
return err
91
112
}
92
113
}
93
- return nil
114
+ return manifest . Flush ()
94
115
}
95
116
96
117
func labelsToDisk (path string , labels []* Label ) error {
118
+ f , err := os .Create (filepath .Join (path , manifestPath ))
119
+ if err != nil {
120
+ return err
121
+ }
122
+ defer f .Close ()
123
+ manifest := bufio .NewWriter (f )
124
+
97
125
for _ , l := range labels {
98
126
name := url .QueryEscape (l .Text )
99
127
labelPath := filepath .Join (path , name )
100
- if err := ioutil .WriteFile (labelPath , []byte {}, 0700 ); err != nil {
128
+ if err := ioutil .WriteFile (labelPath , []byte {}, 0600 ); err != nil {
129
+ return err
130
+ }
131
+ if _ , err := manifest .WriteString (fmt .Sprintf ("%s\n " , l .Text )); err != nil {
101
132
return err
102
133
}
134
+
103
135
}
104
- return nil
136
+ return manifest . Flush ()
105
137
}
106
138
107
139
func statusToDisk (path string , statuses []* Status ) error {
@@ -127,57 +159,81 @@ func refToDisk(name, path string, r *GitReference) error {
127
159
return ioutil .WriteFile (filepath .Join (path , name + ".json" ), b , 0700 )
128
160
}
129
161
162
+ // Manifest is a list of sub-resources that exist within the PR resource to
163
+ // determine whether an item existed when the resource was initialized.
164
+ type Manifest map [string ]bool
165
+
130
166
// FromDisk outputs a PullRequest object from an on-disk representation at the specified path.
131
- func FromDisk (path string ) (* PullRequest , error ) {
167
+ func FromDisk (path string ) (* PullRequest , map [ string ] Manifest , error ) {
132
168
labelsPath := filepath .Join (path , "labels" )
133
169
commentsPath := filepath .Join (path , "comments" )
134
170
statusesPath := filepath .Join (path , "status" )
135
171
136
172
pr := PullRequest {}
173
+ manifests := make (map [string ]Manifest )
137
174
138
175
var err error
176
+ var manifest Manifest
139
177
140
- // Start with comments
141
- pr .Comments , err = commentsFromDisk (commentsPath )
178
+ pr .Comments , manifest , err = commentsFromDisk (commentsPath )
142
179
if err != nil {
143
- return nil , err
180
+ return nil , nil , err
144
181
}
182
+ manifests ["comments" ] = manifest
145
183
146
- // Now Labels
147
- pr .Labels , err = labelsFromDisk (labelsPath )
184
+ pr .Labels , manifest , err = labelsFromDisk (labelsPath )
148
185
if err != nil {
149
- return nil , err
186
+ return nil , nil , err
150
187
}
188
+ manifests ["labels" ] = manifest
151
189
152
- // Now statuses
153
190
pr .Statuses , err = statusesFromDisk (statusesPath )
154
191
if err != nil {
155
- return nil , err
192
+ return nil , nil , err
156
193
}
157
194
158
- // Finally refs
159
-
160
195
pr .Base , err = refFromDisk (path , "base.json" )
161
196
if err != nil {
162
- return nil , err
197
+ return nil , nil , err
163
198
}
164
199
pr .Head , err = refFromDisk (path , "head.json" )
165
200
if err != nil {
201
+ return nil , nil , err
202
+ }
203
+ return & pr , manifests , nil
204
+ }
205
+
206
+ func manifestFromDisk (path string ) (map [string ]bool , error ) {
207
+ f , err := os .Open (path )
208
+ if err != nil {
209
+ return nil , err
210
+ }
211
+ defer f .Close ()
212
+
213
+ out := make (map [string ]bool )
214
+ s := bufio .NewScanner (f )
215
+ for s .Scan () {
216
+ out [s .Text ()] = true
217
+ }
218
+ if s .Err () != nil {
166
219
return nil , err
167
220
}
168
- return & pr , nil
221
+ return out , nil
169
222
}
170
223
171
- func commentsFromDisk (path string ) ([]* Comment , error ) {
224
+ func commentsFromDisk (path string ) ([]* Comment , Manifest , error ) {
172
225
fis , err := ioutil .ReadDir (path )
173
226
if err != nil {
174
- return nil , err
227
+ return nil , nil , err
175
228
}
176
229
comments := []* Comment {}
177
230
for _ , fi := range fis {
231
+ if fi .Name () == manifestPath {
232
+ continue
233
+ }
178
234
b , err := ioutil .ReadFile (filepath .Join (path , fi .Name ()))
179
235
if err != nil {
180
- return nil , err
236
+ return nil , nil , err
181
237
}
182
238
comment := Comment {}
183
239
if err := json .Unmarshal (b , & comment ); err != nil {
@@ -186,23 +242,38 @@ func commentsFromDisk(path string) ([]*Comment, error) {
186
242
}
187
243
comments = append (comments , & comment )
188
244
}
189
- return comments , nil
245
+
246
+ manifest , err := manifestFromDisk (filepath .Join (path , manifestPath ))
247
+ if err != nil {
248
+ return nil , nil , err
249
+ }
250
+
251
+ return comments , manifest , nil
190
252
}
191
253
192
- func labelsFromDisk (path string ) ([]* Label , error ) {
254
+ func labelsFromDisk (path string ) ([]* Label , Manifest , error ) {
193
255
fis , err := ioutil .ReadDir (path )
194
256
if err != nil {
195
- return nil , err
257
+ return nil , nil , err
196
258
}
197
259
labels := []* Label {}
198
260
for _ , fi := range fis {
261
+ if fi .Name () == manifestPath {
262
+ continue
263
+ }
199
264
text , err := url .QueryUnescape (fi .Name ())
200
265
if err != nil {
201
- return nil , err
266
+ return nil , nil , err
202
267
}
203
268
labels = append (labels , & Label {Text : text })
204
269
}
205
- return labels , nil
270
+
271
+ manifest , err := manifestFromDisk (filepath .Join (path , manifestPath ))
272
+ if err != nil {
273
+ return nil , nil , err
274
+ }
275
+
276
+ return labels , manifest , nil
206
277
}
207
278
208
279
func statusesFromDisk (path string ) ([]* Status , error ) {
0 commit comments