1 | 6 | |
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 | |
package com.jcabi.github.mock; |
31 | |
|
32 | |
import com.jcabi.aspects.Immutable; |
33 | |
import com.jcabi.aspects.Loggable; |
34 | |
import com.jcabi.github.Content; |
35 | |
import com.jcabi.github.Contents; |
36 | |
import com.jcabi.github.Coordinates; |
37 | |
import com.jcabi.github.Repo; |
38 | |
import com.jcabi.github.RepoCommit; |
39 | |
import com.jcabi.xml.XML; |
40 | |
import java.io.IOException; |
41 | |
import java.util.ArrayList; |
42 | |
import java.util.Collection; |
43 | |
import javax.json.JsonObject; |
44 | |
import lombok.EqualsAndHashCode; |
45 | |
import lombok.ToString; |
46 | |
import org.apache.commons.lang3.RandomStringUtils; |
47 | |
import org.xembly.Directives; |
48 | |
|
49 | |
|
50 | |
|
51 | |
|
52 | |
|
53 | |
|
54 | |
|
55 | |
|
56 | |
@Immutable |
57 | |
@Loggable(Loggable.DEBUG) |
58 | 0 | @ToString |
59 | 0 | @EqualsAndHashCode(of = { "storage", "self", "coords" }) |
60 | |
@SuppressWarnings({ "PMD.AvoidDuplicateLiterals", "PMD.TooManyMethods" }) |
61 | |
final class MkContents implements Contents { |
62 | |
|
63 | |
|
64 | |
|
65 | |
|
66 | |
private final transient MkStorage storage; |
67 | |
|
68 | |
|
69 | |
|
70 | |
|
71 | |
private final transient String self; |
72 | |
|
73 | |
|
74 | |
|
75 | |
|
76 | |
private final transient Coordinates coords; |
77 | |
|
78 | |
|
79 | |
|
80 | |
|
81 | |
|
82 | |
|
83 | |
|
84 | |
|
85 | |
public MkContents( |
86 | |
final MkStorage stg, |
87 | |
final String login, |
88 | |
final Coordinates rep |
89 | 22 | ) throws IOException { |
90 | 22 | this.storage = stg; |
91 | 22 | this.self = login; |
92 | 22 | this.coords = rep; |
93 | 44 | this.storage.apply( |
94 | 22 | new Directives().xpath( |
95 | 22 | String.format("/github/repos/repo[@coords='%s']", this.coords) |
96 | 22 | ).addIf("contents").up().addIf("commits") |
97 | |
); |
98 | 22 | } |
99 | |
|
100 | |
@Override |
101 | |
public Repo repo() { |
102 | 48 | return new MkRepo(this.storage, this.self, this.coords); |
103 | |
} |
104 | |
|
105 | |
@Override |
106 | |
public Content readme() throws IOException { |
107 | |
|
108 | 2 | return this.readme("master"); |
109 | |
} |
110 | |
|
111 | |
@Override |
112 | |
public Content readme( |
113 | |
final String branch |
114 | |
) throws IOException { |
115 | 4 | return new MkContent( |
116 | |
this.storage, this.self, this.coords, "README.md", branch |
117 | |
); |
118 | |
} |
119 | |
|
120 | |
@Override |
121 | |
public Content create( |
122 | |
final JsonObject json |
123 | |
) throws IOException { |
124 | 38 | this.storage.lock(); |
125 | |
|
126 | |
final String branch; |
127 | |
try { |
128 | 19 | if (json.containsKey("ref")) { |
129 | 8 | branch = json.getString("ref"); |
130 | |
} else { |
131 | 11 | branch = "master"; |
132 | |
} |
133 | 37 | this.storage.apply( |
134 | 19 | new Directives().xpath(this.xpath()).add("content") |
135 | 18 | .attr("ref", branch) |
136 | 18 | .add("name").set(json.getString("path")).up() |
137 | 19 | .add("path").set(json.getString("path")).up() |
138 | 19 | .add("content").set(json.getString("content")).up() |
139 | 19 | .add("type").set("file").up() |
140 | 19 | .add("encoding").set("base64").up() |
141 | 19 | .add("sha").set(fakeSha()).up() |
142 | 18 | .add("url").set("http://localhost/1").up() |
143 | 18 | .add("git_url").set("http://localhost/2").up() |
144 | 19 | .add("html_url").set("http://localhost/3").up() |
145 | |
); |
146 | 19 | this.commit(json); |
147 | |
} finally { |
148 | 19 | this.storage.unlock(); |
149 | 19 | } |
150 | 38 | return new MkContent( |
151 | 19 | this.storage, this.self, this.coords, json.getString("path"), branch |
152 | |
); |
153 | |
} |
154 | |
|
155 | |
@Override |
156 | |
public Content get( |
157 | |
final String path, |
158 | |
final String ref |
159 | |
) throws IOException { |
160 | 6 | return new MkContent(this.storage, this.self, this.coords, path, ref); |
161 | |
} |
162 | |
|
163 | |
@Override |
164 | |
public Content get( |
165 | |
final String path |
166 | |
) throws IOException { |
167 | 2 | return new MkContent( |
168 | |
this.storage, this.self, this.coords, path, "master" |
169 | |
); |
170 | |
} |
171 | |
|
172 | |
@Override |
173 | |
public Iterable<Content> iterate( |
174 | |
final String pattern, |
175 | |
final String ref |
176 | |
) throws IOException { |
177 | 3 | final Collection<XML> nodes = this.storage.xml().nodes( |
178 | 1 | String.format("%s/content[@ref='%s']", this.xpath(), ref) |
179 | |
); |
180 | 1 | final Collection<Content> result = new ArrayList<Content>(nodes.size()); |
181 | 1 | for (final XML node : nodes) { |
182 | 4 | final String path = node.xpath("path/text()").get(0); |
183 | 4 | if (path.startsWith(pattern)) { |
184 | 4 | result.add( |
185 | 2 | this.mkContent(ref, path) |
186 | |
); |
187 | |
} |
188 | 4 | } |
189 | 1 | return result; |
190 | |
} |
191 | |
|
192 | |
@Override |
193 | |
public RepoCommit remove( |
194 | |
final JsonObject content |
195 | |
) throws IOException { |
196 | 4 | this.storage.lock(); |
197 | 2 | final String path = content.getString("path"); |
198 | |
|
199 | |
final String branch; |
200 | |
try { |
201 | 2 | if (content.containsKey("ref")) { |
202 | 1 | branch = content.getString("ref"); |
203 | |
} else { |
204 | 1 | branch = "master"; |
205 | |
} |
206 | 4 | this.storage.apply( |
207 | |
new Directives() |
208 | 2 | .xpath(this.xpath()) |
209 | 2 | .xpath(String.format("content[path='%s']", path)) |
210 | 2 | .attr("ref", branch) |
211 | 2 | .remove() |
212 | |
); |
213 | 4 | return this.commit(content); |
214 | |
} finally { |
215 | 2 | this.storage.unlock(); |
216 | 0 | } |
217 | |
} |
218 | |
|
219 | |
|
220 | |
|
221 | |
|
222 | |
|
223 | |
|
224 | |
|
225 | |
|
226 | |
@Override |
227 | |
public RepoCommit update( |
228 | |
final String path, |
229 | |
final JsonObject json |
230 | |
) throws IOException { |
231 | 6 | this.storage.lock(); |
232 | |
try { |
233 | 3 | final String ref = "ref"; |
234 | |
final String branch; |
235 | 3 | if (json.containsKey(ref)) { |
236 | 1 | branch = json.getString(ref); |
237 | |
} else { |
238 | 2 | branch = "master"; |
239 | |
} |
240 | 3 | final String xpath = String.format( |
241 | |
|
242 | |
"/github/repos/repo[@coords='%s']/contents/content[path='%s' and @ref='%s']", |
243 | |
this.coords, path, branch |
244 | |
); |
245 | 3 | new JsonPatch(this.storage).patch(xpath, json); |
246 | 6 | return this.commit(json); |
247 | |
} finally { |
248 | 3 | this.storage.unlock(); |
249 | 0 | } |
250 | |
} |
251 | |
|
252 | |
@Override |
253 | |
public boolean exists(final String path, final String ref) |
254 | |
throws IOException { |
255 | 8 | return this.storage.xml().nodes( |
256 | 2 | String.format("%s/content[path='%s']", this.xpath(), path) |
257 | 2 | ).size() > 0; |
258 | |
} |
259 | |
|
260 | |
|
261 | |
|
262 | |
|
263 | |
|
264 | |
|
265 | |
|
266 | |
|
267 | |
private MkContent mkContent(final String ref, final String path) |
268 | |
throws IOException { |
269 | 2 | return new MkContent(this.storage, this.self, this.coords, path, ref); |
270 | |
} |
271 | |
|
272 | |
|
273 | |
|
274 | |
|
275 | |
|
276 | |
private String xpath() { |
277 | 23 | return String.format( |
278 | |
"/github/repos/repo[@coords='%s']/contents", |
279 | |
this.coords |
280 | |
); |
281 | |
} |
282 | |
|
283 | |
|
284 | |
|
285 | |
|
286 | |
|
287 | |
private String commitXpath() { |
288 | 24 | return String.format( |
289 | |
"/github/repos/repo[@coords='%s']/commits", |
290 | |
this.coords |
291 | |
); |
292 | |
} |
293 | |
|
294 | |
|
295 | |
|
296 | |
|
297 | |
|
298 | |
|
299 | |
|
300 | |
private MkRepoCommit commit( |
301 | |
final JsonObject json |
302 | |
) throws IOException { |
303 | 24 | final String sha = fakeSha(); |
304 | |
|
305 | 24 | final Directives commit = new Directives().xpath(this.commitXpath()) |
306 | 24 | .add("commit") |
307 | 24 | .add("sha").set(sha).up() |
308 | 24 | .add("url").set("http://localhost/4").up() |
309 | 24 | .add("html_url").set("http://localhost/5").up() |
310 | 24 | .add("message").set(json.getString("message")).up(); |
311 | 24 | if (json.containsKey("committer")) { |
312 | 6 | final JsonObject committer = json.getJsonObject("committer"); |
313 | 6 | commit.add("committer") |
314 | 6 | .add("email").set(committer.getString("email")).up() |
315 | 6 | .add("name").set(committer.getString("name")).up(); |
316 | |
} |
317 | 24 | if (json.containsKey("author")) { |
318 | 0 | final JsonObject author = json.getJsonObject("author"); |
319 | 0 | commit.add("author") |
320 | 0 | .add("email").set(author.getString("email")).up() |
321 | 0 | .add("name").set(author.getString("name")).up(); |
322 | |
} |
323 | 24 | this.storage.apply(commit); |
324 | 24 | return new MkRepoCommit(this.storage, this.repo(), sha); |
325 | |
} |
326 | |
|
327 | |
|
328 | |
|
329 | |
|
330 | |
|
331 | |
|
332 | |
private static String fakeSha() { |
333 | |
|
334 | 43 | return RandomStringUtils.random(40, "0123456789abcdef"); |
335 | |
} |
336 | |
} |