/* * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jetbrains.osgi.bnd.resolve; import aQute.bnd.build.Run; import aQute.bnd.build.Workspace; import aQute.bnd.build.model.BndEditModel; import aQute.bnd.build.model.clauses.VersionedClause; import aQute.bnd.header.Attrs; import aQute.bnd.osgi.Constants; import aQute.bnd.properties.IDocument; import biz.aQute.resolve.ProjectResolver; import com.intellij.codeInsight.FileModificationService; import com.intellij.notification.NotificationType; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.osgi.bnd.BndFileType; import org.osgi.resource.Resource; import org.osgi.resource.Wire; import org.osgi.service.resolver.ResolutionException; import org.osmorc.i18n.OsmorcBundle; import javax.swing.*; import java.io.File; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import static com.intellij.openapi.command.WriteCommandAction.writeCommandAction; import static org.osmorc.i18n.OsmorcBundle.message; public class ResolveAction extends AnAction { private static final Logger LOG = Logger.getInstance(ResolveAction.class); @Override public void actionPerformed(@NotNull AnActionEvent event) { VirtualFile virtualFile = event.getData(CommonDataKeys.VIRTUAL_FILE); Project project = event.getProject(); if (virtualFile == null || project == null) return; Document document = FileDocumentManager.getInstance().getDocument(virtualFile); if (document == null) return; FileDocumentManager.getInstance().saveAllDocuments(); new Task.Backgroundable(project, message("bnd.resolve.requirements.title"), true) { private Map<Resource, List<Wire>> resolveResult; private String updatedText; @Override public void run(@NotNull ProgressIndicator indicator) { indicator.setIndeterminate(true); File file = new File(virtualFile.getPath()); try (Workspace workspace = Workspace.findWorkspace(file); Run run = Run.createRun(workspace, file); ProjectResolver projectResolver = new ProjectResolver(run)) { resolveResult = projectResolver.resolve(); List<VersionedClause> versionedClauses = projectResolver.getRunBundles().stream() .map(c -> { Attrs attrs = new Attrs(); attrs.put(Constants.VERSION_ATTRIBUTE, c.getVersion()); return new VersionedClause(c.getBundleSymbolicName(), attrs); }) .sorted(Comparator.comparing(VersionedClause::getName)) .collect(Collectors.toList()); BndEditModel editModel = new BndEditModel(); IDocument bndDocument = new aQute.bnd.properties.Document(document.getImmutableCharSequence().toString()); editModel.loadFrom(bndDocument); editModel.setRunBundles(versionedClauses); editModel.saveChangesTo(bndDocument); updatedText = bndDocument.get(); } catch (ProcessCanceledException e) { throw e; } catch (Exception e) { throw new WrappingException(e); } indicator.checkCanceled(); } @Override public void onSuccess() { if (new ResolutionSucceedDialog(project, resolveResult).showAndGet() && FileModificationService.getInstance().prepareVirtualFilesForWrite(project, Collections.singleton(virtualFile))) { writeCommandAction(project) .withName("Bndrun Resolve") .run(() -> document.setText(updatedText)); } } @Override public void onThrowable(@NotNull Throwable t) { Throwable cause = t instanceof WrappingException ? t.getCause() : t; LOG.warn("Resolution failed", cause); if (cause instanceof ResolutionException) { new ResolutionFailedDialog(project, (ResolutionException)cause).show(); } else { OsmorcBundle.notification(message("bnd.resolve.failed.title"), cause.getMessage(), NotificationType.ERROR).notify(project); } } }.queue(); } @Override public void update(@NotNull AnActionEvent event) { VirtualFile virtualFile = event.getData(CommonDataKeys.VIRTUAL_FILE); event.getPresentation().setEnabledAndVisible(virtualFile != null && BndFileType.BND_RUN_EXT.equals(virtualFile.getExtension())); } private static class WrappingException extends RuntimeException { private WrappingException(Throwable cause) { super(cause); } } private static class ResolutionSucceedDialog extends DialogWrapper { private final Map<Resource, List<Wire>> myResolveResult; public ResolutionSucceedDialog(Project project, Map<Resource, List<Wire>> resolveResult) { super(project); myResolveResult = resolveResult; init(); setTitle(message("bnd.resolve.succeed.title")); } @Nullable @Override protected JComponent createCenterPanel() { return new ResolveConfirm(myResolveResult).getContentPane(); } @NotNull @Override protected Action[] createActions() { return new Action[]{getOKAction(), getCancelAction()}; } } private static class ResolutionFailedDialog extends DialogWrapper { private final ResolutionException myResolutionException; public ResolutionFailedDialog(Project project, ResolutionException resolutionException) { super(project); myResolutionException = resolutionException; init(); setTitle(message("bnd.resolve.failed.title")); } @Nullable @Override protected JComponent createCenterPanel() { return new ResolutionFailed(myResolutionException).getContentPane(); } @NotNull @Override protected Action[] createActions() { return new Action[]{getOKAction()}; } } }