blob: 427ea1d28aa0b58cd788b52991c5499b8dbe66b5 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2013, 2018 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.rj.services.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.MessageFormat;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.statet.rj.data.RDataUtils;
import org.eclipse.statet.rj.data.RIntegerStore;
import org.eclipse.statet.rj.data.RVector;
import org.eclipse.statet.rj.data.UnexpectedRDataException;
import org.eclipse.statet.rj.renv.core.RNumVersion;
import org.eclipse.statet.rj.renv.core.RPkg;
import org.eclipse.statet.rj.renv.core.RPkgType;
import org.eclipse.statet.rj.renv.core.RPkgUtils;
import org.eclipse.statet.rj.services.FunctionCall;
import org.eclipse.statet.rj.services.RJServices;
import org.eclipse.statet.rj.services.RService;
/**
* Utility to install an R package from a local file.
* <p>
* Run {@link #install(RService, IProgressMonitor)} to install the package.</p>
* <p>
* The class can be reused.</p>
*
* @since de.walware.rj.services 2.0
*/
public class RPkgInstallation {
private final RPkg pkgInfo;
private final File file;
public RPkgInstallation(final File file) throws CoreException {
if (file == null) {
throw new NullPointerException();
}
this.pkgInfo= RPkgUtils.checkPkgFileName(file.getName());
this.file= file;
}
public RPkg getPkg() {
return this.pkgInfo;
}
protected String getPkgFileName() {
return this.file.getName();
}
protected void uploadPkgFile(final String target, final RService r,
final IProgressMonitor monitor) throws CoreException, IOException {
FileInputStream in= null;
try {
in= new FileInputStream(this.file);
r.uploadFile(in, this.file.length(), target, 0, monitor);
}
finally {
if (in != null) {
try {
in.close();
}
catch (final IOException e) {}
}
}
}
public void install(final RService r, final IProgressMonitor monitor) throws CoreException {
final String source= getPkgFileName();
final RPkgType pkgType= RPkgUtils.checkPkgType(source, r.getPlatform());
Exception error= null;
String serverFile= null;
String libLoc= null;
try {
{ final RVector<RIntegerStore> data= RDataUtils.checkRIntVector(r.evalData(
"rj:::renv.isValidLibLoc(.libPaths()[1])", monitor )); //$NON-NLS-1$
final int state= RDataUtils.checkSingleIntValue(data);
libLoc= data.getNames().getChar(0);
if (state != 0) {
throw new CoreException(new Status(IStatus.ERROR, RJServices.BUNDLE_ID,
MessageFormat.format("The library location ''{0}'' is not writable.", libLoc) ));
}
}
{ final FunctionCall call= r.createFunctionCall("dir.create"); //$NON-NLS-1$
call.addChar("rpkgs"); //$NON-NLS-1$
call.addLogi("showWarnings", false); //$NON-NLS-1$
call.evalVoid(monitor);
serverFile= "rpkgs/" + source; //$NON-NLS-1$
}
uploadPkgFile(serverFile, r, monitor);
{ final FunctionCall call= r.createFunctionCall("install.packages"); //$NON-NLS-1$
call.addChar(serverFile);
call.addChar("lib", libLoc); //$NON-NLS-1$
call.addNull("repos"); //$NON-NLS-1$
call.addChar("type", RPkgUtils.getPkgTypeInstallKey(r.getPlatform(), pkgType)); //$NON-NLS-1$
call.evalVoid(monitor);
}
{ final FunctionCall call= r.createFunctionCall("packageDescription"); //$NON-NLS-1$
call.addChar("pkg", this.pkgInfo.getName()); //$NON-NLS-1$
call.addChar("lib.loc", libLoc); //$NON-NLS-1$
call.addChar("fields", "Version"); //$NON-NLS-1$ //$NON-NLS-2$
final RVector<?> data= RDataUtils.checkRVector(call.evalData(monitor));
try {
final String s= RDataUtils.checkSingleCharValue(data);
final RNumVersion installedVersion= RNumVersion.create(s);
if (!installedVersion.equals(this.pkgInfo.getVersion())) {
throw new CoreException(new Status(IStatus.ERROR, RJServices.BUNDLE_ID,
MessageFormat.format("Validation of package installation failed: installed package has different version (found= {0}, expected= {1}).",
installedVersion.toString(), this.pkgInfo.getVersion().toString() )));
}
}
catch (final UnexpectedRDataException e) {
throw new CoreException(new Status(IStatus.ERROR, RJServices.BUNDLE_ID,
"Validation of package installation failed: no installed package found." ));
}
}
clear(serverFile, r, monitor);
serverFile= null;
}
catch (final IOException e) {
error= e;
}
catch (final CoreException e) {
error= e;
}
catch (final UnexpectedRDataException e) {
error= e;
}
finally {
if (serverFile != null) {
try {
clear(serverFile, r, monitor);
}
catch (final Exception e) {}
}
}
if (error != null) {
throw new CoreException(new Status(IStatus.ERROR, RJServices.BUNDLE_ID,
MessageFormat.format("An error occurred when installing R package from {0}.",
source), error ));
}
}
private void clear(final String target, final RService r, final IProgressMonitor monitor) throws CoreException {
final FunctionCall call= r.createFunctionCall("file.remove"); //$NON-NLS-1$
call.addChar(target);
call.evalVoid(monitor);
}
}