|
2 | 2 |
|
3 | 3 | import java.io.ByteArrayOutputStream; |
4 | 4 | import java.io.IOException; |
| 5 | +import java.io.ByteArrayInputStream; |
| 6 | +import java.nio.charset.StandardCharsets; |
| 7 | +import java.nio.file.Files; |
5 | 8 | import java.text.SimpleDateFormat; |
6 | 9 | import java.util.List; |
7 | 10 | import java.util.Objects; |
|
21 | 24 | import org.eclipse.jgit.diff.RawTextComparator; |
22 | 25 | import org.eclipse.jgit.lib.BranchTrackingStatus; |
23 | 26 | import org.eclipse.jgit.lib.ObjectId; |
| 27 | +import org.eclipse.jgit.lib.ObjectInserter; |
| 28 | +import org.eclipse.jgit.lib.Constants; |
| 29 | +import org.eclipse.jgit.dircache.DirCache; |
| 30 | +import org.eclipse.jgit.dircache.DirCacheEntry; |
| 31 | +import org.eclipse.jgit.dircache.DirCacheEditor; |
24 | 32 | import org.eclipse.jgit.lib.PersonIdent; |
25 | 33 | import org.eclipse.jgit.lib.Repository; |
26 | 34 | import org.eclipse.jgit.revwalk.RevCommit; |
@@ -204,6 +212,99 @@ public String addFiles(String projectName, String filePattern) |
204 | 212 | } |
205 | 213 | } |
206 | 214 |
|
| 215 | + public String stagePatch(String projectName, String patch) |
| 216 | + { |
| 217 | + Repository repository = getRepository(projectName); |
| 218 | + try (Git gitCmd = new Git(repository)) |
| 219 | + { |
| 220 | + java.io.File workTree = repository.getWorkTree(); |
| 221 | + |
| 222 | + // Parse the patch to find affected files |
| 223 | + org.eclipse.jgit.patch.Patch parsedPatch = new org.eclipse.jgit.patch.Patch(); |
| 224 | + parsedPatch.parse(new ByteArrayInputStream(patch.getBytes(StandardCharsets.UTF_8))); |
| 225 | + |
| 226 | + if (parsedPatch.getFiles().isEmpty()) |
| 227 | + { |
| 228 | + return "No files affected by patch."; |
| 229 | + } |
| 230 | + |
| 231 | + // For each file in the patch: save working tree, restore HEAD, apply patch, stage, restore working tree |
| 232 | + java.util.Map<java.io.File, byte[]> savedWorkingTree = new java.util.HashMap<>(); |
| 233 | + |
| 234 | + for (var fileHeader : parsedPatch.getFiles()) |
| 235 | + { |
| 236 | + String filePath = fileHeader.getNewPath(); |
| 237 | + java.io.File file = new java.io.File(workTree, filePath); |
| 238 | + if (file.exists()) |
| 239 | + { |
| 240 | + savedWorkingTree.put(file, Files.readAllBytes(file.toPath())); |
| 241 | + } |
| 242 | + } |
| 243 | + |
| 244 | + // Checkout affected files from HEAD to restore original content |
| 245 | + var checkoutCmd = gitCmd.checkout(); |
| 246 | + for (var fileHeader : parsedPatch.getFiles()) |
| 247 | + { |
| 248 | + checkoutCmd.addPath(fileHeader.getNewPath()); |
| 249 | + } |
| 250 | + checkoutCmd.call(); |
| 251 | + |
| 252 | + // Apply the patch to the now-clean working tree files |
| 253 | + org.eclipse.jgit.api.ApplyResult result = gitCmd.apply() |
| 254 | + .setPatch(new ByteArrayInputStream(patch.getBytes(StandardCharsets.UTF_8))) |
| 255 | + .call(); |
| 256 | + |
| 257 | + // Stage the patched files |
| 258 | + DirCache dirCache = repository.lockDirCache(); |
| 259 | + try |
| 260 | + { |
| 261 | + DirCacheEditor editor = dirCache.editor(); |
| 262 | + ObjectInserter inserter = repository.newObjectInserter(); |
| 263 | + |
| 264 | + for (var file : result.getUpdatedFiles()) |
| 265 | + { |
| 266 | + byte[] content = Files.readAllBytes(file.toPath()); |
| 267 | + ObjectId blobId = inserter.insert(Constants.OBJ_BLOB, content); |
| 268 | + |
| 269 | + String repoRelativePath = workTree.toPath() |
| 270 | + .relativize(file.toPath()).toString().replace('\\', '/'); |
| 271 | + |
| 272 | + editor.add(new DirCacheEditor.PathEdit(repoRelativePath) |
| 273 | + { |
| 274 | + @Override |
| 275 | + public void apply(DirCacheEntry ent) |
| 276 | + { |
| 277 | + ent.setObjectId(blobId); |
| 278 | + ent.setFileMode(org.eclipse.jgit.lib.FileMode.REGULAR_FILE); |
| 279 | + ent.setLength(content.length); |
| 280 | + ent.setLastModified(java.time.Instant.now()); |
| 281 | + } |
| 282 | + }); |
| 283 | + } |
| 284 | + |
| 285 | + inserter.flush(); |
| 286 | + editor.commit(); |
| 287 | + } |
| 288 | + finally |
| 289 | + { |
| 290 | + dirCache.unlock(); |
| 291 | + } |
| 292 | + |
| 293 | + // Restore working tree to the original modified state |
| 294 | + for (var entry : savedWorkingTree.entrySet()) |
| 295 | + { |
| 296 | + Files.write(entry.getKey().toPath(), entry.getValue()); |
| 297 | + } |
| 298 | + |
| 299 | + refreshProject(projectName); |
| 300 | + return "Patch staged successfully. Files: " + result.getUpdatedFiles().size(); |
| 301 | + } |
| 302 | + catch (Exception e) |
| 303 | + { |
| 304 | + throw new RuntimeException("Failed to stage patch: " + e.getMessage(), e); |
| 305 | + } |
| 306 | + } |
| 307 | + |
207 | 308 | public String commit(String projectName, String message) |
208 | 309 | { |
209 | 310 | Repository repository = getRepository(projectName); |
|
0 commit comments