package org.openlca.app.navigation.actions; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.jface.action.Action; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.openlca.app.App; import org.openlca.app.M; import org.openlca.app.cloud.index.Diff; import org.openlca.app.cloud.index.DiffIndex; import org.openlca.app.cloud.index.DiffType; import org.openlca.app.cloud.ui.CommitDialog; import org.openlca.app.cloud.ui.ReferencesResultDialog; import org.openlca.app.cloud.ui.commits.HistoryView; import org.openlca.app.cloud.ui.diff.DiffNode; import org.openlca.app.cloud.ui.diff.DiffNodeBuilder; import org.openlca.app.cloud.ui.diff.DiffResult; import org.openlca.app.cloud.ui.diff.DiffResult.DiffResponse; import org.openlca.app.cloud.ui.library.LibraryResultDialog; import org.openlca.app.cloud.ui.preferences.CloudPreference; import org.openlca.app.db.Database; import org.openlca.app.navigation.INavigationElement; import org.openlca.app.navigation.Navigator; import org.openlca.app.util.Error; import org.openlca.app.util.Info; import org.openlca.app.util.TimeEstimatingMonitor; import org.openlca.app.util.UI; import org.openlca.cloud.api.RepositoryClient; import org.openlca.cloud.model.data.Dataset; import org.openlca.core.database.IDatabase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; class CloudCommitAction extends Action implements INavigationAction { private final Logger log = LoggerFactory.getLogger(getClass()); private IDatabase database; private DiffIndex index; private RepositoryClient client; private List<INavigationElement<?>> selection; public CloudCommitAction() { setText(M.Commit); } @Override public void run() { Runner runner = new Runner(); runner.run(); if (runner.error != null) { log.error("Error during commit action", runner.error); Error.showBox(runner.error.getMessage()); } else if (!runner.upToDate) Error.showBox(M.RejectMessage); else if (runner.noChanges) Info.showBox(M.NoChangesInLocalDb); HistoryView.refresh(); } @Override public boolean accept(INavigationElement<?> element) { if (!Database.isConnected()) return false; index = Database.getDiffIndex(); client = Database.getRepositoryClient(); database = Database.get(); selection = Collections.singletonList(element); return true; } @Override public boolean accept(List<INavigationElement<?>> elements) { if (!Database.isConnected()) return false; index = Database.getDiffIndex(); client = Database.getRepositoryClient(); database = Database.get(); selection = elements; return true; } private class Runner { private boolean upToDate; private boolean noChanges; private String message; private List<DiffResult> changes; private List<DiffResult> selected; private List<DiffResult> references; private Map<Dataset, String> checkResult; private Exception error; public void run() { App.runWithProgress(M.ComparingWithRepository, this::getDifferences); if (!upToDate) return; boolean doContinue = openCommitDialog(); if (!doContinue) return; App.runWithProgress(M.SearchingForReferencedChanges, this::searchForReferences); doContinue = showReferences(); if (!doContinue) return; if (CloudPreference.doCheckAgainstLibraries()) { App.runWithProgress(M.CheckingAgainstLibraries, this::checkAgainstLibraries); doContinue = openLibraryResultDialog(); } if (!doContinue) return; checkUpToDate(client); if (!upToDate || error != null) return; Set<Dataset> datasets = new HashSet<>(); for (DiffResult change : selected) { Dataset dataset = change.getDataset(); if (change.getType() == DiffResponse.DELETE_FROM_REMOTE) { dataset.fullPath = change.local.dataset.fullPath; } datasets.add(dataset); } commit(datasets); if (!upToDate) return; Navigator.refresh(Navigator.getNavigationRoot()); } private void commit(Set<Dataset> datasets) { ProgressMonitorDialog dialog = new ProgressMonitorDialog(UI.shell()); try { dialog.run(true, false, (m) -> { TimeEstimatingMonitor monitor = new TimeEstimatingMonitor(m); monitor.beginTask(M.CommitingChanges, datasets.size()); try { client.commit(message, datasets, (dataset) -> monitor.worked()); } catch (Exception e) { throw new InvocationTargetException(e); } monitor.done(); }); dialog.run(true, false, (m) -> { TimeEstimatingMonitor monitor = new TimeEstimatingMonitor(m); monitor.beginTask("#Indexing datasets", datasets.size()); orderResults(); for (DiffResult change : selected) { Dataset dataset = change.getDataset(); DiffType before = index.get(dataset.refId).type; if (before == DiffType.DELETED) index.remove(dataset.refId); else index.update(dataset, DiffType.NO_DIFF); monitor.worked(); } index.commit(); monitor.done(); }); } catch (Exception e) { error = e; } } // must order diffs by length of path, so when removing from index, // parent updating always works private void orderResults() { Collections.sort(selected, (d1, d2) -> { int depth1 = 0; String path = d1.getDataset().fullPath; while (path.contains("/")) { path = path.substring(path.indexOf("/") + 1); depth1++; } int depth2 = 0; path = d2.getDataset().fullPath; while (path.contains("/")) { path = path.substring(path.indexOf("/") + 1); depth2++; } return Integer.compare(depth2, depth1); }); } private void getDifferences() { checkUpToDate(client); if (!upToDate) return; changes = createDifferences(index, index.getChanged()); } private void checkUpToDate(RepositoryClient client) { try { upToDate = client.requestCommit(); } catch (Exception e) { error = e; upToDate = false; } } private boolean openCommitDialog() { DiffNode node = new DiffNodeBuilder(Database.get(), Database.getDiffIndex()).build(changes); if (node == null) { noChanges = true; return false; } CommitDialog dialog = new CommitDialog(node, client); dialog.setBlockOnOpen(true); Set<String> refIds = new RefIdListBuilder(selection, changes, index).build(); dialog.setInitialSelection(refIds); if (dialog.open() != IDialogConstants.OK_ID) return false; message = dialog.getMessage(); selected = dialog.getSelected(); return true; } private void searchForReferences() { ReferenceSearcher searcher = new ReferenceSearcher(database, index); references = searcher.run(selected); } private boolean showReferences() { if (error != null) return false; if (references == null || references.isEmpty()) return true; DiffNode node = new DiffNodeBuilder(Database.get(), Database.getDiffIndex()).build(references); ReferencesResultDialog dialog = new ReferencesResultDialog(node, client); if (dialog.open() != IDialogConstants.OK_ID) return false; selected.addAll(dialog.getSelected()); return true; } private boolean openLibraryResultDialog() { if (error != null) return false; if (checkResult == null || checkResult.isEmpty()) return true; LibraryResultDialog libraryDialog = new LibraryResultDialog(checkResult); if (libraryDialog.open() != IDialogConstants.OK_ID) return false; return true; } private void checkAgainstLibraries() { Set<Dataset> datasets = new HashSet<>(); for (DiffResult result : selected) datasets.add(result.getDataset()); try { checkResult = client.performLibraryCheck(datasets); } catch (Exception e) { error = e; } } private List<DiffResult> createDifferences(DiffIndex index, List<Diff> changes) { List<DiffResult> differences = new ArrayList<>(); for (Diff diff : changes) { DiffResult diffResult = new DiffResult(diff); diffResult.ignoreRemote = true; differences.add(diffResult); } return differences; } } }