@@ -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,53 @@ 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
101
commentPath := filepath .Join (path , strconv .FormatInt (c .ID , 10 )+ ".json" )
85
102
b , err := json .Marshal (c )
86
103
if err != nil {
87
104
return err
88
105
}
89
- if err := ioutil .WriteFile (commentPath , b , 0700 ); err != nil {
106
+ if err := ioutil .WriteFile (commentPath , b , 0600 ); err != nil {
107
+ return err
108
+ }
109
+ if _ , err := manifest .WriteString (fmt .Sprintf ("%s\n " , commentPath )); err != nil {
90
110
return err
91
111
}
92
112
}
93
- return nil
113
+ return manifest . Flush ()
94
114
}
95
115
96
116
func labelsToDisk (path string , labels []* Label ) error {
117
+ f , err := os .Create (filepath .Join (path , manifestPath ))
118
+ if err != nil {
119
+ return err
120
+ }
121
+ defer f .Close ()
122
+ manifest := bufio .NewWriter (f )
123
+
97
124
for _ , l := range labels {
98
125
name := url .QueryEscape (l .Text )
99
126
labelPath := filepath .Join (path , name )
100
- if err := ioutil .WriteFile (labelPath , []byte {}, 0700 ); err != nil {
127
+ if err := ioutil .WriteFile (labelPath , []byte {}, 0600 ); err != nil {
128
+ return err
129
+ }
130
+ if _ , err := manifest .WriteString (fmt .Sprintf ("%s\n " , labelPath )); err != nil {
101
131
return err
102
132
}
133
+
103
134
}
104
- return nil
135
+ return manifest . Flush ()
105
136
}
106
137
107
138
func statusToDisk (path string , statuses []* Status ) error {
@@ -127,57 +158,86 @@ func refToDisk(name, path string, r *GitReference) error {
127
158
return ioutil .WriteFile (filepath .Join (path , name + ".json" ), b , 0700 )
128
159
}
129
160
161
+ // Manifest is a list of sub-resources that exist within the PR resource to
162
+ // determine whether an item existed when the resource was initialized.
163
+ type Manifest map [string ]bool
164
+
130
165
// FromDisk outputs a PullRequest object from an on-disk representation at the specified path.
131
- func FromDisk (path string ) (* PullRequest , error ) {
166
+ func FromDisk (path string ) (* PullRequest , map [ string ] Manifest , error ) {
132
167
labelsPath := filepath .Join (path , "labels" )
133
168
commentsPath := filepath .Join (path , "comments" )
134
169
statusesPath := filepath .Join (path , "status" )
135
170
136
171
pr := PullRequest {}
172
+ manifests := make (map [string ]Manifest )
137
173
138
174
var err error
175
+ var manifest Manifest
139
176
140
177
// 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
184
// Now Labels
147
- pr .Labels , err = labelsFromDisk (labelsPath )
185
+ pr .Labels , manifest , err = labelsFromDisk (labelsPath )
148
186
if err != nil {
149
- return nil , err
187
+ return nil , nil , err
150
188
}
189
+ manifests ["labels" ] = manifest
151
190
152
191
// Now statuses
153
192
pr .Statuses , err = statusesFromDisk (statusesPath )
154
193
if err != nil {
155
- return nil , err
194
+ return nil , nil , err
156
195
}
157
196
158
197
// Finally refs
159
198
160
199
pr .Base , err = refFromDisk (path , "base.json" )
161
200
if err != nil {
162
- return nil , err
201
+ return nil , nil , err
163
202
}
164
203
pr .Head , err = refFromDisk (path , "head.json" )
204
+ if err != nil {
205
+ return nil , nil , err
206
+ }
207
+ return & pr , manifests , nil
208
+ }
209
+
210
+ func manifestFromDisk (path string ) (map [string ]bool , error ) {
211
+ f , err := os .Open (path )
165
212
if err != nil {
166
213
return nil , err
167
214
}
168
- return & pr , nil
215
+ defer f .Close ()
216
+
217
+ out := make (map [string ]bool )
218
+ s := bufio .NewScanner (f )
219
+ for s .Scan () {
220
+ out [s .Text ()] = true
221
+ }
222
+ if s .Err () != nil {
223
+ return nil , err
224
+ }
225
+ return out , nil
169
226
}
170
227
171
- func commentsFromDisk (path string ) ([]* Comment , error ) {
228
+ func commentsFromDisk (path string ) ([]* Comment , Manifest , error ) {
172
229
fis , err := ioutil .ReadDir (path )
173
230
if err != nil {
174
- return nil , err
231
+ return nil , nil , err
175
232
}
176
233
comments := []* Comment {}
177
234
for _ , fi := range fis {
235
+ if fi .Name () == manifestPath {
236
+ continue
237
+ }
178
238
b , err := ioutil .ReadFile (filepath .Join (path , fi .Name ()))
179
239
if err != nil {
180
- return nil , err
240
+ return nil , nil , err
181
241
}
182
242
comment := Comment {}
183
243
if err := json .Unmarshal (b , & comment ); err != nil {
@@ -186,23 +246,38 @@ func commentsFromDisk(path string) ([]*Comment, error) {
186
246
}
187
247
comments = append (comments , & comment )
188
248
}
189
- return comments , nil
249
+
250
+ manifest , err := manifestFromDisk (filepath .Join (path , manifestPath ))
251
+ if err != nil {
252
+ return nil , nil , err
253
+ }
254
+
255
+ return comments , manifest , nil
190
256
}
191
257
192
- func labelsFromDisk (path string ) ([]* Label , error ) {
258
+ func labelsFromDisk (path string ) ([]* Label , Manifest , error ) {
193
259
fis , err := ioutil .ReadDir (path )
194
260
if err != nil {
195
- return nil , err
261
+ return nil , nil , err
196
262
}
197
263
labels := []* Label {}
198
264
for _ , fi := range fis {
265
+ if fi .Name () == manifestPath {
266
+ continue
267
+ }
199
268
text , err := url .QueryUnescape (fi .Name ())
200
269
if err != nil {
201
- return nil , err
270
+ return nil , nil , err
202
271
}
203
272
labels = append (labels , & Label {Text : text })
204
273
}
205
- return labels , nil
274
+
275
+ manifest , err := manifestFromDisk (filepath .Join (path , manifestPath ))
276
+ if err != nil {
277
+ return nil , nil , err
278
+ }
279
+
280
+ return labels , manifest , nil
206
281
}
207
282
208
283
func statusesFromDisk (path string ) ([]* Status , error ) {
0 commit comments