| /******************************************************************************* |
| * Copyright (c) 2016 Red Hat Inc. and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Red Hat - Initial Contribution |
| *******************************************************************************/ |
| package org.eclipse.linuxtools.internal.docker.ui.commands; |
| |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.List; |
| |
| import org.apache.commons.compress.archivers.tar.TarArchiveEntry; |
| import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; |
| import org.eclipse.core.commands.AbstractHandler; |
| import org.eclipse.core.commands.ExecutionEvent; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.linuxtools.docker.core.DockerException; |
| import org.eclipse.linuxtools.docker.core.IDockerConnection; |
| import org.eclipse.linuxtools.docker.core.IDockerContainer; |
| import org.eclipse.linuxtools.docker.ui.Activator; |
| import org.eclipse.linuxtools.docker.ui.wizards.ImageSearch; |
| import org.eclipse.linuxtools.internal.docker.core.ContainerFileProxy; |
| import org.eclipse.linuxtools.internal.docker.core.DockerConnection; |
| import org.eclipse.linuxtools.internal.docker.ui.wizards.ContainerCopyFrom; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.ui.IWorkbenchPart; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.handlers.HandlerUtil; |
| |
| /** |
| * Command handler that opens the {@link ImageSearch} wizard and pulls the |
| * selected image in background on completion. |
| * |
| */ |
| public class CopyFromContainerCommandHandler extends AbstractHandler { |
| |
| private static final String ERROR_COPYING_FROM_CONTAINER_NO_CONNECTION = "command.copyfromcontainer.failure.no_connection"; //$NON-NLS-1$ |
| private static final String MISSING_CONNECTION = "missing_connection"; //$NON-NLS-1$ |
| private static final String ERROR_COPYING_FROM_CONTAINER = "command.copyfromcontainer.error.msg"; //$NON-NLS-1$ |
| private static final String COPY_FROM_CONTAINER_JOB_TASK = "command.copyfromcontainer.job.task"; //$NON-NLS-1$ |
| private static final String COPY_FROM_CONTAINER_JOB_TITLE = "command.copyfromcontainer.job.title"; //$NON-NLS-1$ |
| private static final String COPY_FROM_CONTAINER_JOB_SUBTASK = "command.copyfromcontainer.job.subtask"; //$NON-NLS-1$ |
| |
| @Override |
| public Object execute(final ExecutionEvent event) { |
| final IWorkbenchPart activePart = HandlerUtil.getActivePart(event); |
| final IDockerConnection connection = CommandUtils |
| .getCurrentConnection(activePart); |
| final List<IDockerContainer> selectedContainers = CommandUtils |
| .getSelectedContainers(activePart); |
| if (selectedContainers.size() != 1) { |
| return null; |
| } |
| final IDockerContainer container = selectedContainers.get(0); |
| if (connection == null) { |
| MessageDialog.openError( |
| PlatformUI.getWorkbench().getActiveWorkbenchWindow() |
| .getShell(), |
| CommandMessages.getString(MISSING_CONNECTION), |
| CommandMessages |
| .getString( |
| ERROR_COPYING_FROM_CONTAINER_NO_CONNECTION)); |
| } else { |
| final ContainerCopyFrom wizard = new ContainerCopyFrom(connection, |
| container); |
| final boolean copyFromContainer = CommandUtils.openWizard(wizard, |
| HandlerUtil.getActiveShell(event)); |
| if (copyFromContainer) { |
| performCopyFromContainer(connection, container, |
| wizard.getTarget(), wizard.getSources()); |
| } |
| } |
| return null; |
| } |
| |
| private void performCopyFromContainer(final IDockerConnection connection, |
| final IDockerContainer container, final String target, |
| final List<ContainerFileProxy> files) { |
| final Job copyFromContainerJob = new Job( |
| CommandMessages.getFormattedString( |
| COPY_FROM_CONTAINER_JOB_TITLE, container.name())) { |
| |
| @Override |
| protected IStatus run(final IProgressMonitor monitor) { |
| monitor.beginTask( |
| CommandMessages.getString(COPY_FROM_CONTAINER_JOB_TASK), |
| files.size()); |
| try { |
| for (ContainerFileProxy proxy : files) { |
| if (monitor.isCanceled()) { |
| monitor.done(); |
| return Status.CANCEL_STATUS; |
| } |
| try { |
| monitor.setTaskName( |
| CommandMessages.getFormattedString( |
| COPY_FROM_CONTAINER_JOB_SUBTASK, |
| proxy.getFullPath())); |
| monitor.worked(1); |
| InputStream in = ((DockerConnection) connection) |
| .copyContainer(container.id(), |
| proxy.getLink()); |
| /* |
| * The input stream from copyContainer might be |
| * incomplete or non-blocking so we should wrap it |
| * in a stream that is guaranteed to block until |
| * data is available. |
| */ |
| TarArchiveInputStream k = new TarArchiveInputStream( |
| new BlockingInputStream(in)); |
| TarArchiveEntry te = null; |
| while ((te = k.getNextTarEntry()) != null) { |
| long size = te.getSize(); |
| IPath path = new Path(target); |
| path = path.append(te.getName()); |
| File f = new File(path.toOSString()); |
| if (te.isDirectory()) { |
| f.mkdir(); |
| continue; |
| } else { |
| f.createNewFile(); |
| } |
| FileOutputStream os = new FileOutputStream(f); |
| int bufferSize = ((int) size > 4096 ? 4096 |
| : (int) size); |
| byte[] barray = new byte[bufferSize]; |
| int result = -1; |
| while ((result = k.read(barray, 0, |
| bufferSize)) > -1) { |
| if (monitor.isCanceled()) { |
| monitor.done(); |
| k.close(); |
| os.close(); |
| return Status.CANCEL_STATUS; |
| } |
| os.write(barray, 0, result); |
| } |
| os.close(); |
| } |
| k.close(); |
| } catch (final DockerException e) { |
| Display.getDefault() |
| .syncExec(() -> MessageDialog.openError( |
| PlatformUI.getWorkbench() |
| .getActiveWorkbenchWindow() |
| .getShell(), |
| CommandMessages.getFormattedString( |
| ERROR_COPYING_FROM_CONTAINER, |
| proxy.getLink(), |
| container.name()), |
| e.getCause() != null |
| ? e.getCause().getMessage() |
| : e.getMessage())); |
| } |
| } |
| } catch (InterruptedException e) { |
| // do nothing |
| } catch (IOException e) { |
| Activator.log(e); |
| } finally { |
| monitor.done(); |
| } |
| return Status.OK_STATUS; |
| } |
| |
| }; |
| |
| copyFromContainerJob.schedule(); |
| |
| } |
| |
| /** |
| * A blocking input stream that waits until data is available. |
| */ |
| public class BlockingInputStream extends InputStream { |
| private InputStream in; |
| |
| public BlockingInputStream(InputStream in) { |
| this.in = in; |
| } |
| |
| @Override |
| public int read() throws IOException { |
| return in.read(); |
| } |
| } |
| |
| } |