private <V extends FilePatch, T extends ApplyFilePatchBase<V>> ApplyPatchStatus applyList( final List<Pair<VirtualFile, T>> patches, final ApplyPatchContext context, ApplyPatchStatus status, CommitContext commiContext) throws IOException { for (Pair<VirtualFile, T> patch : patches) { ApplyPatchStatus patchStatus = ApplyPatchAction.applyOnly( myProject, patch.getSecond(), context, patch.getFirst(), commiContext, myReverseConflict, myLeftConflictPanelTitle, myRightConflictPanelTitle); if (patchStatus == ApplyPatchStatus.ABORT) return patchStatus; status = ApplyPatchStatus.and(status, patchStatus); if (patchStatus == ApplyPatchStatus.FAILURE) { myFailedPatches.add(patch.getSecond().getPatch()); continue; } if (patchStatus != ApplyPatchStatus.SKIP) { myVerifier.doMoveIfNeeded(patch.getFirst()); myRemainingPatches.remove(patch.getSecond().getPatch()); } } return status; }
@Nullable private ApplyPatchStatus actualApply( final List<Pair<VirtualFile, ApplyTextFilePatch>> textPatches, final List<Pair<VirtualFile, ApplyFilePatchBase<BinaryType>>> binaryPatches, final CommitContext commitContext) { final ApplyPatchContext context = new ApplyPatchContext(myBaseDirectory, 0, true, true); ApplyPatchStatus status; try { status = applyList(textPatches, context, null, commitContext); if (status == ApplyPatchStatus.ABORT) return status; if (myCustomForBinaries == null) { status = applyList(binaryPatches, context, status, commitContext); } else { ApplyPatchStatus patchStatus = myCustomForBinaries.apply(binaryPatches); final List<FilePatch> appliedPatches = myCustomForBinaries.getAppliedPatches(); moveForCustomBinaries(binaryPatches, appliedPatches); status = ApplyPatchStatus.and(status, patchStatus); myRemainingPatches.removeAll(appliedPatches); } } catch (IOException e) { showError(myProject, e.getMessage(), true); return ApplyPatchStatus.ABORT; } return status; }
@CalledInAwt public void run() { myRemainingPatches.addAll(myPatches); final ApplyPatchStatus patchStatus = nonWriteActionPreCheck(); final Label beforeLabel = LocalHistory.getInstance().putSystemLabel(myProject, "Before patch"); final TriggerAdditionOrDeletion trigger = new TriggerAdditionOrDeletion(myProject); final ApplyPatchStatus applyStatus = getApplyPatchStatus(trigger); myStatus = ApplyPatchStatus.SUCCESS.equals(patchStatus) ? applyStatus : ApplyPatchStatus.and(patchStatus, applyStatus); // listeners finished, all 'legal' file additions/deletions with VCS are done trigger.processIt(); LocalHistory.getInstance() .putSystemLabel( myProject, "After patch"); // insert a label to be visible in local history dialog if (myStatus == ApplyPatchStatus.FAILURE) { suggestRollback(myProject, Collections.singletonList(PatchApplier.this), beforeLabel); } else if (myStatus == ApplyPatchStatus.ABORT) { rollbackUnderProgress(myProject, myProject.getBaseDir(), beforeLabel); } if (myShowNotification || !ApplyPatchStatus.SUCCESS.equals(myStatus)) { showApplyStatus(myProject, myStatus); } refreshFiles(trigger.getAffected()); }
@Nullable protected ApplyPatchStatus executeWritable() { final ReadonlyStatusHandler.OperationStatus readOnlyFilesStatus = getReadOnlyFilesStatus(myVerifier.getWritableFiles()); if (readOnlyFilesStatus.hasReadonlyFiles()) { showError(myProject, readOnlyFilesStatus.getReadonlyFilesMessage(), true); return ApplyPatchStatus.ABORT; } myFailedPatches.addAll(myVerifier.filterBadFileTypePatches()); ApplyPatchStatus result = myFailedPatches.isEmpty() ? null : ApplyPatchStatus.FAILURE; final List<Pair<VirtualFile, ApplyTextFilePatch>> textPatches = myVerifier.getTextPatches(); try { markInternalOperation(textPatches, true); return ApplyPatchStatus.and( result, actualApply(textPatches, myVerifier.getBinaryPatches(), myCommitContext)); } finally { markInternalOperation(textPatches, false); } }
@CalledInAwt public static ApplyPatchStatus executePatchGroup( final Collection<PatchApplier> group, final LocalChangeList localChangeList) { if (group.isEmpty()) return ApplyPatchStatus.SUCCESS; // ? final Project project = group.iterator().next().myProject; ApplyPatchStatus result = ApplyPatchStatus.SUCCESS; for (PatchApplier patchApplier : group) { result = ApplyPatchStatus.and(result, patchApplier.nonWriteActionPreCheck()); } final Label beforeLabel = LocalHistory.getInstance().putSystemLabel(project, "Before patch"); final TriggerAdditionOrDeletion trigger = new TriggerAdditionOrDeletion(project); final Ref<ApplyPatchStatus> refStatus = new Ref<>(result); try { CommandProcessor.getInstance() .executeCommand( project, new Runnable() { @Override public void run() { for (PatchApplier applier : group) { refStatus.set(ApplyPatchStatus.and(refStatus.get(), applier.createFiles())); applier.addSkippedItems(trigger); } trigger.prepare(); if (refStatus.get() == ApplyPatchStatus.SUCCESS) { // all pre-check results are valuable only if not successful; actual status we // can receive after executeWritable refStatus.set(null); } for (PatchApplier applier : group) { refStatus.set(ApplyPatchStatus.and(refStatus.get(), applier.executeWritable())); if (refStatus.get() == ApplyPatchStatus.ABORT) break; } } }, VcsBundle.message("patch.apply.command"), null); } finally { VcsFileListenerContextHelper.getInstance(project).clearContext(); LocalHistory.getInstance().putSystemLabel(project, "After patch"); } result = refStatus.get(); result = result == null ? ApplyPatchStatus.FAILURE : result; trigger.processIt(); final Set<FilePath> directlyAffected = new HashSet<>(); final Set<VirtualFile> indirectlyAffected = new HashSet<>(); for (PatchApplier applier : group) { directlyAffected.addAll(applier.getDirectlyAffected()); indirectlyAffected.addAll(applier.getIndirectlyAffected()); } directlyAffected.addAll(trigger.getAffected()); final Consumer<Collection<FilePath>> mover = localChangeList == null ? null : createMover(project, localChangeList); refreshPassedFilesAndMoveToChangelist(project, directlyAffected, indirectlyAffected, mover); if (result == ApplyPatchStatus.FAILURE) { suggestRollback(project, group, beforeLabel); } else if (result == ApplyPatchStatus.ABORT) { rollbackUnderProgress(project, project.getBaseDir(), beforeLabel); } showApplyStatus(project, result); return result; }