commit | author | age
|
bd0e83
|
1 |
/* |
PM |
2 |
* Copyright 2015 gitblit.com. |
|
3 |
* |
|
4 |
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
5 |
* you may not use this file except in compliance with the License. |
|
6 |
* You may obtain a copy of the License at |
|
7 |
* |
|
8 |
* http://www.apache.org/licenses/LICENSE-2.0 |
|
9 |
* |
|
10 |
* Unless required by applicable law or agreed to in writing, software |
|
11 |
* distributed under the License is distributed on an "AS IS" BASIS, |
|
12 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 |
* See the License for the specific language governing permissions and |
|
14 |
* limitations under the License. |
|
15 |
*/ |
|
16 |
package com.gitblit.models; |
|
17 |
|
|
18 |
import java.io.Serializable; |
|
19 |
import java.util.ArrayList; |
|
20 |
import java.util.Date; |
|
21 |
import java.util.List; |
|
22 |
import java.util.NoSuchElementException; |
46f33f
|
23 |
import java.util.regex.Matcher; |
PM |
24 |
import java.util.regex.Pattern; |
|
25 |
|
|
26 |
import com.gitblit.Constants; |
bd0e83
|
27 |
|
PM |
28 |
/** |
|
29 |
* A FilestoreModel represents a file stored outside a repository but referenced by the repository using a unique objectID |
|
30 |
* |
|
31 |
* @author Paul Martin |
|
32 |
* |
|
33 |
*/ |
|
34 |
public class FilestoreModel implements Serializable { |
|
35 |
|
|
36 |
private static final long serialVersionUID = 1L; |
|
37 |
|
46f33f
|
38 |
private static final String metaRegexText = new StringBuilder() |
PM |
39 |
.append("version\\shttps://git-lfs.github.com/spec/v1\\s+") |
|
40 |
.append("oid\\ssha256:(" + Constants.REGEX_SHA256 + ")\\s+") |
|
41 |
.append("size\\s([0-9]+)") |
|
42 |
.toString(); |
|
43 |
|
|
44 |
private static final Pattern metaRegex = Pattern.compile(metaRegexText); |
|
45 |
|
|
46 |
private static final int metaRegexIndexSHA = 1; |
|
47 |
|
|
48 |
private static final int metaRegexIndexSize = 2; |
|
49 |
|
bd0e83
|
50 |
public final String oid; |
PM |
51 |
|
|
52 |
private Long size; |
|
53 |
private Status status; |
|
54 |
|
|
55 |
//Audit |
|
56 |
private String stateChangedBy; |
|
57 |
private Date stateChangedOn; |
|
58 |
|
|
59 |
//Access Control |
|
60 |
private List<String> repositories; |
|
61 |
|
46f33f
|
62 |
public FilestoreModel(String id, long definedSize) { |
PM |
63 |
oid = id; |
|
64 |
size = definedSize; |
|
65 |
status = Status.ReferenceOnly; |
|
66 |
} |
|
67 |
|
bd0e83
|
68 |
public FilestoreModel(String id, long expectedSize, UserModel user, String repo) { |
PM |
69 |
oid = id; |
|
70 |
size = expectedSize; |
|
71 |
status = Status.Upload_Pending; |
|
72 |
stateChangedBy = user.getName(); |
|
73 |
stateChangedOn = new Date(); |
|
74 |
repositories = new ArrayList<String>(); |
|
75 |
repositories.add(repo); |
46f33f
|
76 |
} |
PM |
77 |
|
|
78 |
/* |
|
79 |
* Attempts to create a FilestoreModel from the given meta string |
|
80 |
* |
|
81 |
* @return A valid FilestoreModel if successful, otherwise null |
|
82 |
*/ |
|
83 |
public static FilestoreModel fromMetaString(String meta) { |
|
84 |
|
|
85 |
Matcher m = metaRegex.matcher(meta); |
|
86 |
|
|
87 |
if (m.find()) { |
|
88 |
try |
|
89 |
{ |
|
90 |
final Long size = Long.parseLong(m.group(metaRegexIndexSize)); |
|
91 |
final String sha = m.group(metaRegexIndexSHA); |
|
92 |
return new FilestoreModel(sha, size); |
|
93 |
} catch (Exception e) { |
|
94 |
//Fail silent - it is not a valid filestore item |
|
95 |
} |
|
96 |
} |
|
97 |
|
|
98 |
return null; |
bd0e83
|
99 |
} |
PM |
100 |
|
|
101 |
public synchronized long getSize() { |
|
102 |
return size; |
|
103 |
} |
|
104 |
|
|
105 |
public synchronized Status getStatus() { |
|
106 |
return status; |
|
107 |
} |
|
108 |
|
|
109 |
public synchronized String getChangedBy() { |
|
110 |
return stateChangedBy; |
|
111 |
} |
|
112 |
|
|
113 |
public synchronized Date getChangedOn() { |
|
114 |
return stateChangedOn; |
|
115 |
} |
|
116 |
|
|
117 |
public synchronized void setStatus(Status status, UserModel user) { |
|
118 |
this.status = status; |
|
119 |
stateChangedBy = user.getName(); |
|
120 |
stateChangedOn = new Date(); |
|
121 |
} |
|
122 |
|
|
123 |
public synchronized void reset(UserModel user, long size) { |
|
124 |
status = Status.Upload_Pending; |
|
125 |
stateChangedBy = user.getName(); |
|
126 |
stateChangedOn = new Date(); |
|
127 |
this.size = size; |
|
128 |
} |
|
129 |
|
|
130 |
/* |
|
131 |
* Handles possible race condition with concurrent connections |
|
132 |
* @return true if action can proceed, false otherwise |
|
133 |
*/ |
|
134 |
public synchronized boolean actionUpload(UserModel user) { |
|
135 |
if (status == Status.Upload_Pending) { |
|
136 |
status = Status.Upload_In_Progress; |
|
137 |
stateChangedBy = user.getName(); |
|
138 |
stateChangedOn = new Date(); |
|
139 |
return true; |
|
140 |
} |
|
141 |
|
|
142 |
return false; |
|
143 |
} |
|
144 |
|
|
145 |
public synchronized boolean isInErrorState() { |
|
146 |
return (this.status.value < 0); |
|
147 |
} |
|
148 |
|
|
149 |
public synchronized void addRepository(String repo) { |
46f33f
|
150 |
if (status != Status.ReferenceOnly) { |
PM |
151 |
if (!repositories.contains(repo)) { |
|
152 |
repositories.add(repo); |
|
153 |
} |
|
154 |
} |
bd0e83
|
155 |
} |
PM |
156 |
|
|
157 |
public synchronized void removeRepository(String repo) { |
46f33f
|
158 |
if (status != Status.ReferenceOnly) { |
PM |
159 |
repositories.remove(repo); |
|
160 |
} |
bd0e83
|
161 |
} |
PM |
162 |
|
697905
|
163 |
public synchronized boolean isInRepositoryList(List<String> repoList) { |
46f33f
|
164 |
if (status != Status.ReferenceOnly) { |
PM |
165 |
for (String name : repositories) { |
|
166 |
if (repoList.contains(name)) { |
|
167 |
return true; |
|
168 |
} |
697905
|
169 |
} |
PM |
170 |
} |
|
171 |
return false; |
|
172 |
} |
|
173 |
|
bd0e83
|
174 |
public static enum Status { |
PM |
175 |
|
46f33f
|
176 |
ReferenceOnly(-42), |
PM |
177 |
|
bd0e83
|
178 |
Deleted(-30), |
PM |
179 |
AuthenticationRequired(-20), |
|
180 |
|
|
181 |
Error_Unknown(-8), |
|
182 |
Error_Unexpected_Stream_End(-7), |
|
183 |
Error_Invalid_Oid(-6), |
|
184 |
Error_Invalid_Size(-5), |
|
185 |
Error_Hash_Mismatch(-4), |
|
186 |
Error_Size_Mismatch(-3), |
|
187 |
Error_Exceeds_Size_Limit(-2), |
|
188 |
Error_Unauthorized(-1), |
|
189 |
//Negative values provide additional information and may be treated as 0 when not required |
|
190 |
Unavailable(0), |
|
191 |
Upload_Pending(1), |
|
192 |
Upload_In_Progress(2), |
|
193 |
Available(3); |
|
194 |
|
|
195 |
final int value; |
|
196 |
|
|
197 |
Status(int value) { |
|
198 |
this.value = value; |
|
199 |
} |
|
200 |
|
|
201 |
public int getValue() { |
|
202 |
return value; |
|
203 |
} |
|
204 |
|
|
205 |
@Override |
|
206 |
public String toString() { |
|
207 |
return name().toLowerCase().replace('_', ' '); |
|
208 |
} |
|
209 |
|
|
210 |
public static Status fromState(int state) { |
|
211 |
for (Status s : values()) { |
|
212 |
if (s.getValue() == state) { |
|
213 |
return s; |
|
214 |
} |
|
215 |
} |
|
216 |
throw new NoSuchElementException(String.valueOf(state)); |
|
217 |
} |
|
218 |
} |
|
219 |
|
|
220 |
} |
|
221 |
|