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 package org.eclipse.jgit.api;
44
45 import java.io.File;
46 import java.io.IOException;
47 import java.text.MessageFormat;
48
49 import org.eclipse.jgit.api.errors.GitAPIException;
50 import org.eclipse.jgit.api.errors.JGitInternalException;
51 import org.eclipse.jgit.api.errors.NoFilepatternException;
52 import org.eclipse.jgit.errors.ConfigInvalidException;
53 import org.eclipse.jgit.internal.JGitText;
54 import org.eclipse.jgit.internal.submodule.SubmoduleValidator;
55 import org.eclipse.jgit.lib.ConfigConstants;
56 import org.eclipse.jgit.lib.Constants;
57 import org.eclipse.jgit.lib.NullProgressMonitor;
58 import org.eclipse.jgit.lib.ProgressMonitor;
59 import org.eclipse.jgit.lib.Repository;
60 import org.eclipse.jgit.lib.StoredConfig;
61 import org.eclipse.jgit.storage.file.FileBasedConfig;
62 import org.eclipse.jgit.submodule.SubmoduleWalk;
63 import org.eclipse.jgit.treewalk.filter.PathFilter;
64 import org.eclipse.jgit.treewalk.filter.TreeFilter;
65
66
67
68
69
70
71
72
73
74
75
76
77 public class SubmoduleAddCommand extends
78 TransportCommand<SubmoduleAddCommand, Repository> {
79
80 private String name;
81
82 private String path;
83
84 private String uri;
85
86 private ProgressMonitor monitor;
87
88
89
90
91
92
93
94 public SubmoduleAddCommand(Repository repo) {
95 super(repo);
96 }
97
98
99
100
101
102
103
104
105 public SubmoduleAddCommand setName(String name) {
106 this.name = name;
107 return this;
108 }
109
110
111
112
113
114
115
116
117 public SubmoduleAddCommand setPath(String path) {
118 this.path = path;
119 return this;
120 }
121
122
123
124
125
126
127
128
129 public SubmoduleAddCommand setURI(String uri) {
130 this.uri = uri;
131 return this;
132 }
133
134
135
136
137
138
139
140
141
142
143 public SubmoduleAddCommand setProgressMonitor(ProgressMonitor monitor) {
144 this.monitor = monitor;
145 return this;
146 }
147
148
149
150
151
152
153
154 protected boolean submoduleExists() throws IOException {
155 TreeFilter filter = PathFilter.create(path);
156 try (SubmoduleWalk w = SubmoduleWalk.forIndex(repo)) {
157 return w.setFilter(filter).next();
158 }
159 }
160
161
162
163
164
165
166
167
168
169
170
171 @Override
172 public Repository call() throws GitAPIException {
173 checkCallable();
174 if (path == null || path.length() == 0)
175 throw new IllegalArgumentException(JGitText.get().pathNotConfigured);
176 if (uri == null || uri.length() == 0)
177 throw new IllegalArgumentException(JGitText.get().uriNotConfigured);
178 if (name == null || name.length() == 0) {
179
180 name = path;
181 }
182 if (name.contains("/../") || name.contains("\\..\\")
183 || name.startsWith("../") || name.startsWith("..\\")
184 || name.endsWith("/..") || name.endsWith("\\..")) {
185
186
187
188
189
190
191
192
193
194 throw new IllegalArgumentException(MessageFormat
195 .format(JGitText.get().invalidNameContainsDotDot, name));
196 }
197
198 try {
199 SubmoduleValidator.assertValidSubmoduleName(name);
200 SubmoduleValidator.assertValidSubmodulePath(path);
201 SubmoduleValidator.assertValidSubmoduleUri(uri);
202 } catch (SubmoduleValidator.SubmoduleValidationException e) {
203 throw new IllegalArgumentException(e.getMessage());
204 }
205
206 try {
207 if (submoduleExists())
208 throw new JGitInternalException(MessageFormat.format(
209 JGitText.get().submoduleExists, path));
210 } catch (IOException e) {
211 throw new JGitInternalException(e.getMessage(), e);
212 }
213
214 final String resolvedUri;
215 try {
216 resolvedUri = SubmoduleWalk.getSubmoduleRemoteUrl(repo, uri);
217 } catch (IOException e) {
218 throw new JGitInternalException(e.getMessage(), e);
219 }
220
221 File moduleDirectory = SubmoduleWalk.getSubmoduleDirectory(repo, path);
222 CloneCommand clone = Git.cloneRepository();
223 configure(clone);
224 clone.setDirectory(moduleDirectory);
225 clone.setGitDir(new File(new File(repo.getDirectory(),
226 Constants.MODULES), path));
227 clone.setURI(resolvedUri);
228 if (monitor != null)
229 clone.setProgressMonitor(monitor);
230 Repository subRepo = null;
231 try (Git git = clone.call()) {
232 subRepo = git.getRepository();
233 subRepo.incrementOpen();
234 }
235
236
237 StoredConfig config = repo.getConfig();
238 config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, name,
239 ConfigConstants.CONFIG_KEY_URL, resolvedUri);
240 try {
241 config.save();
242 } catch (IOException e) {
243 throw new JGitInternalException(e.getMessage(), e);
244 }
245
246
247 FileBasedConfig modulesConfig = new FileBasedConfig(new File(
248 repo.getWorkTree(), Constants.DOT_GIT_MODULES), repo.getFS());
249 try {
250 modulesConfig.load();
251 modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
252 name, ConfigConstants.CONFIG_KEY_PATH, path);
253 modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
254 name, ConfigConstants.CONFIG_KEY_URL, uri);
255 modulesConfig.save();
256 } catch (IOException e) {
257 throw new JGitInternalException(e.getMessage(), e);
258 } catch (ConfigInvalidException e) {
259 throw new JGitInternalException(e.getMessage(), e);
260 }
261
262 AddCommand add = new AddCommand(repo);
263
264 add.addFilepattern(Constants.DOT_GIT_MODULES);
265
266 add.addFilepattern(path);
267 try {
268 add.call();
269 } catch (NoFilepatternException e) {
270 throw new JGitInternalException(e.getMessage(), e);
271 }
272
273 return subRepo;
274 }
275 }