Skip to content

Commit

Permalink
Merge pull request #43 from asebak/deployment-algorithm
Browse files Browse the repository at this point in the history
smarter deployment algorithm implementation
  • Loading branch information
asebak committed Jun 21, 2015
2 parents 1ba1bfa + a151093 commit 51108fe
Show file tree
Hide file tree
Showing 11 changed files with 219 additions and 26 deletions.
10 changes: 8 additions & 2 deletions META-INF/plugin.xml
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
<idea-plugin version="2">
<id>com.atsebak.raspberrypi</id>
<name>Embedded Linux JVM Debugger (Raspberry Pi, Intel x86, ARM processors)</name>
<version>0.42</version>
<version>0.45</version>
<vendor email="[email protected]" url="http://www.atsebak.com">At Sebak</vendor>

<description><![CDATA[
<p>Java Debugger for Embedded Systems that run on Embedded Linux or on the <a href="https://www.yoctoproject.org/">Yocto Project Kernel</a></p>
]]></description>

<change-notes><![CDATA[
<b>Version 0.42</b>
<b>Version 0.45</b>
<ul>
<li>
Fixed Null pointer exception on startup after adding run configuration.
</li>
<li>
Smarter deployment algorithm to not deploy libs that already exist on target device.
</li>
</ul>
<b>Version 0.41</b>
<ul>
Expand Down Expand Up @@ -80,6 +83,9 @@
<configurationType implementation="com.atsebak.embeddedlinuxjvm.runner.conf.EmbeddedLinuxJVMConfigurationType"/>
<projectService serviceImplementation="com.atsebak.embeddedlinuxjvm.console.EmbeddedLinuxJVMConsoleView"/>
<moduleBuilder builderClass="com.atsebak.embeddedlinuxjvm.project.RPiJavaModuleBuilder"/>

<projectService serviceImplementation="com.atsebak.embeddedlinuxjvm.services.ClasspathService"
serviceInterface="com.atsebak.embeddedlinuxjvm.services.ClasspathService"/>
</extensions>

</idea-plugin>
2 changes: 1 addition & 1 deletion embeddedlinux-jvmdebugger.iml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<sourceFolder url="file://$MODULE_DIR$/Resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
</content>
<orderEntry type="jdk" jdkName="IntelliJ IDEA Community Edition IC-141.178.9 (1)" jdkType="IDEA JDK" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="lombok" level="project" />
<orderEntry type="library" name="bcprov-ext-jdk15on-1.47" level="project" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.atsebak.embeddedlinuxjvm.protocol.ssh.SSHHandlerTarget;
import com.atsebak.embeddedlinuxjvm.runner.conf.EmbeddedLinuxJVMRunConfiguration;
import com.atsebak.embeddedlinuxjvm.runner.data.EmbeddedLinuxJVMRunConfigurationRunnerParameters;
import com.atsebak.embeddedlinuxjvm.services.ClasspathService;
import com.atsebak.embeddedlinuxjvm.utils.FileUtilities;
import com.atsebak.embeddedlinuxjvm.utils.RemoteCommandLineBuilder;
import com.intellij.execution.*;
Expand All @@ -24,6 +25,7 @@
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.progress.ProgressIndicator;
Expand Down Expand Up @@ -203,8 +205,9 @@ public void run() {
@Override
public void run() {
try {
List<File> files = invokeClassPathResolver(classPath.getPathList(), manager.getProjectSdk());
File classpathArchive = FileUtilities.createClasspathArchive(files, project);
ClasspathService service = ServiceManager.getService(project, ClasspathService.class);
List<File> hostLibraries = invokeClassPathResolver(classPath.getPathList(), manager.getProjectSdk());
File classpathArchive = FileUtilities.createClasspathArchive(service.deltaOfDeployedJars(hostLibraries), project);
invokeDeployment(classpathArchive.getPath(), commandLineTarget);
} catch (Exception e) {
EmbeddedLinuxJVMConsoleView.getInstance(project).print(EmbeddedLinuxJVMBundle.message("pi.connection.failed", e.getLocalizedMessage()),
Expand Down Expand Up @@ -270,6 +273,7 @@ private void invokeDeployment(String projectOutput, CommandLineTarget commandLin
target.upload(new File(projectOutput), commandLineTarget.toString());
}


/**
* Creates debugging settings for server
*
Expand Down
13 changes: 13 additions & 0 deletions src/com/atsebak/embeddedlinuxjvm/deploy/DeployedLibrary.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.atsebak.embeddedlinuxjvm.deploy;

import lombok.Builder;
import lombok.Getter;


@Builder
@Getter
public class DeployedLibrary {
private String jarName;
private String size;
private String lastModified;
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package com.atsebak.embeddedlinuxjvm.project;

import com.atsebak.embeddedlinuxjvm.localization.EmbeddedLinuxJVMBundle;
import com.atsebak.embeddedlinuxjvm.ui.PIJavaModuleStep;
import com.atsebak.embeddedlinuxjvm.utils.FileUtilities;
import com.atsebak.embeddedlinuxjvm.utils.ProjectUtils;
import com.atsebak.embeddedlinuxjvm.utils.Template;
import com.atsebak.embeddedlinuxjvm.utils.UrlDownloader;
import com.atsebak.embeddedlinuxjvm.ui.PIJavaModuleStep;
import com.google.common.io.Files;
import com.intellij.icons.AllIcons;
import com.intellij.ide.util.projectWizard.JavaModuleBuilder;
Expand Down Expand Up @@ -90,15 +89,15 @@ public void run() {
String[] directoriesToMake = packageName.split(Pattern.quote("."));
for (String directory : directoriesToMake) {
try {
VfsUtil.createDirectories(srcPath + FileUtilities.separator + directory);
VfsUtil.createDirectories(srcPath + FileUtilities.SEPARATOR + directory);
} catch (IOException e) {

}
srcPath += FileUtilities.separator + directory;
srcPath += FileUtilities.SEPARATOR + directory;
}
Template.builder().name("main.ftl")
.classContext(this.getClass())
.outputFile(srcPath + FileUtilities.separator + "Main.java")
.outputFile(srcPath + FileUtilities.SEPARATOR + "Main.java")
.data(new HashMap<String, Object>() {{
put("packagename", packageName);
}}).build()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.atsebak.embeddedlinuxjvm.commandline.LinuxCommand;
import com.atsebak.embeddedlinuxjvm.console.EmbeddedLinuxJVMConsoleView;
import com.atsebak.embeddedlinuxjvm.deploy.DeployedLibrary;
import com.atsebak.embeddedlinuxjvm.localization.EmbeddedLinuxJVMBundle;
import com.atsebak.embeddedlinuxjvm.runner.data.EmbeddedLinuxJVMRunConfigurationRunnerParameters;
import com.atsebak.embeddedlinuxjvm.utils.FileUtilities;
Expand All @@ -11,16 +12,21 @@
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import lombok.Builder;
import lombok.SneakyThrows;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.common.StreamCopier;
import net.schmizz.sshj.connection.channel.direct.Session;
import net.schmizz.sshj.sftp.SFTPClient;
import net.schmizz.sshj.xfer.FileSystemFile;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Builder
public class SSHHandlerTarget {
Expand All @@ -30,6 +36,51 @@ public class SSHHandlerTarget {
private EmbeddedLinuxJVMConsoleView consoleView;
private SSH ssh;

/**
* Can get this information from the IDE
*
* @return
* @throws IOException
* @throws RuntimeConfigurationException
*/
public List<DeployedLibrary> listAlreadyUploadedJars() throws IOException, RuntimeConfigurationException {
final String remoteDir = FileUtilities.SEPARATOR + "home" + FileUtilities.SEPARATOR
+ piRunnerParameters.getUsername() + FileUtilities.SEPARATOR + OUTPUT_LOCATION;
String path = remoteDir + FileUtilities.SEPARATOR + consoleView.getProject().getName();
String deploymentPathJars = path + FileUtilities.SEPARATOR + FileUtilities.LIB;
SSHClient ssh = this.ssh.toClient();
connect(ssh);
Session session = ssh.startSession();
String cmd = LinuxCommand.builder().commands(
Arrays.asList(
String.format("cd %s", deploymentPathJars),
"du -h --max-depth=0 * --time"
))
.build()
.toString();
List<DeployedLibrary> libraries = new ArrayList<DeployedLibrary>();
try {
Session.Command exec = session.exec(cmd);
String files = IOUtils.readFully(exec.getInputStream()).toString();
if (StringUtils.isNotBlank(files)) {
String[] unparsedFiles = files.split("\\r?\\n");
for (int i = 0; i < unparsedFiles.length; i++) {
String[] splitDescription = unparsedFiles[i].split("\t");
libraries.add(DeployedLibrary.builder()
.size(splitDescription[0])
.lastModified(splitDescription[1])
.jarName(splitDescription[2])
.build());
}
}
} finally {
session.close();
ssh.disconnect();
}

return libraries;
}

/** Uploads Java application output folders
* @param compileOutput Output directory folder where to store the java application
* @param cmd The command to execute on the java files
Expand All @@ -39,9 +90,9 @@ public class SSHHandlerTarget {
*/
public void uploadAndRunJavaApp(@NotNull final File compileOutput, @NotNull final String cmd)
throws IOException, ClassNotFoundException, RuntimeConfigurationException {
final String remoteDir = FileUtilities.separator + "home" + FileUtilities.separator
+ piRunnerParameters.getUsername() + FileUtilities.separator + OUTPUT_LOCATION;
String deploymentPath = remoteDir + FileUtilities.separator + consoleView.getProject().getName();
final String remoteDir = FileUtilities.SEPARATOR + "home" + FileUtilities.SEPARATOR
+ piRunnerParameters.getUsername() + FileUtilities.SEPARATOR + OUTPUT_LOCATION;
String deploymentPath = remoteDir + FileUtilities.SEPARATOR + consoleView.getProject().getName();
genericUpload(deploymentPath, compileOutput);
consoleView.print(EmbeddedLinuxJVMBundle.getString("pi.deployment.finished") + NEW_LINE, ConsoleViewContentType.SYSTEM_OUTPUT);
runJavaApp(deploymentPath, cmd);
Expand All @@ -62,6 +113,9 @@ private void forceCreateDirectories(String path) throws IOException, RuntimeConf
Arrays.asList(
String.format("mkdir -p %s", path),
String.format("cd %s", path),
String.format("mkdir -p %s", FileUtilities.CLASSES),
String.format("mkdir -p %s", FileUtilities.LIB),
String.format("cd %s", path + FileUtilities.SEPARATOR + FileUtilities.CLASSES),
"rm -rf *"
))
.build()
Expand Down Expand Up @@ -127,7 +181,8 @@ private void runJavaApp(String path, String cmd) throws IOException, RuntimeConf
* @throws IOException
* @throws RuntimeConfigurationException
*/
private void connect(SSHClient client) throws IOException, RuntimeConfigurationException {
@SneakyThrows({IOException.class, RuntimeConfigurationException.class})
private void connect(SSHClient client) {
if (!client.isAuthenticated()) {
client.connect(piRunnerParameters.getHostname());
client.authPassword(piRunnerParameters.getUsername(), piRunnerParameters.getPassword());
Expand Down
70 changes: 70 additions & 0 deletions src/com/atsebak/embeddedlinuxjvm/services/ClasspathService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.atsebak.embeddedlinuxjvm.services;


import com.atsebak.embeddedlinuxjvm.console.EmbeddedLinuxJVMConsoleView;
import com.atsebak.embeddedlinuxjvm.deploy.DeployedLibrary;
import com.atsebak.embeddedlinuxjvm.protocol.ssh.SSH;
import com.atsebak.embeddedlinuxjvm.protocol.ssh.SSHHandlerTarget;
import com.atsebak.embeddedlinuxjvm.runner.data.EmbeddedLinuxJVMRunConfigurationRunnerParameters;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class ClasspathService {
@NotNull
private final Project project;
private List<File> previousDeployFiles;

/**
* Clear up static file list of deployments
*/
public ClasspathService(@NotNull Project project) {
this.project = project;
previousDeployFiles = new ArrayList<File>();
}

/**
* Gets the delta of jars between host and target machines. It will always add the normal project output path but not necessarily the external libs
* Some potential problems can be that the user stops it midway while deploying so the jars don't go on the target.
*
* @param hostLibraries
* @return targetLibraries
*/
public List<File> deltaOfDeployedJars(List<File> hostLibraries) {
List<File> newLibraries = new ArrayList<File>();
for (File hostFile : hostLibraries) {
if (!hostFile.getName().contains("jar")) {
newLibraries.add(hostFile);
} else if (!previousDeployFiles.contains(hostFile)) {
newLibraries.add(hostFile);
}
}
previousDeployFiles = hostLibraries;
return newLibraries;
}

/**
* Gets the deployed jars on target machine
*
* @return
* @throws IOException
* @throws RuntimeConfigurationException
* @deprecated use deltaOfDeployedJars instead
*/
@Deprecated
public List<DeployedLibrary> invokeFindDeployedJars(EmbeddedLinuxJVMRunConfigurationRunnerParameters runnerParameters)
throws IOException, RuntimeConfigurationException {
SSHHandlerTarget target = SSHHandlerTarget.builder().piRunnerParameters(runnerParameters)
.consoleView(EmbeddedLinuxJVMConsoleView.getInstance(project))
.ssh(SSH.builder()
.connectionTimeout(30000)
.timeout(30000)
.build()).build();
return target.listAlreadyUploadedJars();
}
}
15 changes: 9 additions & 6 deletions src/com/atsebak/embeddedlinuxjvm/utils/FileUtilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@

public class FileUtilities {

public static String separator = "/";
public static final String LIB = "lib";
public static final String CLASSES = "classes";
public static final String SEPARATOR = "/";

/**
* Unzips a file all into one directory
Expand All @@ -40,7 +42,7 @@ public static void unzip(InputStream inputStream, String outputFolder) {
continue;
}
fileName = new File(fileName).getName();
File newFile = new File(outputFolder + FileUtilities.separator + fileName);
File newFile = new File(outputFolder + SEPARATOR + fileName);
new File(newFile.getParent()).mkdirs();

FileOutputStream fos = new FileOutputStream(newFile);
Expand Down Expand Up @@ -83,10 +85,10 @@ public static File createClasspathArchive(Collection<File> classpathEntries, Pro
LinkedList<String> pathElements = new LinkedList<String>();
for (File f : classpathEntries) {
if (f.isFile()) { //is a jar file
pathElements.addLast("lib");
pathElements.addLast(LIB);
writeClassPath(pathElements, f, archiveOutputStream);
} else {
pathElements.addLast("classes"); // is output of the project
pathElements.addLast(CLASSES); // is output of the project
for (File child : f.listFiles()) {
writeClassPath(pathElements, child, archiveOutputStream);
}
Expand All @@ -113,7 +115,7 @@ public static File createClasspathArchive(Collection<File> classpathEntries, Pro
private static void writeClassPath(LinkedList<String> pathElements, File entry, TarArchiveOutputStream archiveOutputStream) throws IOException {
if (entry.isFile()) {
archiveOutputStream.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
archiveOutputStream.putArchiveEntry(new TarArchiveEntry(entry, getPath(pathElements) + FileUtilities.separator + entry.getName()));
archiveOutputStream.putArchiveEntry(new TarArchiveEntry(entry, getPath(pathElements) + SEPARATOR + entry.getName()));
copy(entry, archiveOutputStream);
archiveOutputStream.closeArchiveEntry();
} else {
Expand Down Expand Up @@ -154,10 +156,11 @@ public static String getPath(LinkedList<String> pathElements) {
StringBuilder buf = new StringBuilder();
for (int i = 0; i < pathElements.size(); i++) {
if (i != 0) {
buf.append(FileUtilities.separator);
buf.append(SEPARATOR);
}
buf.append(pathElements.get(i));
}
return buf.toString();
}

}
2 changes: 1 addition & 1 deletion src/com/atsebak/embeddedlinuxjvm/utils/Notifications.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ public class Notifications {
/**
* ID for notifications
*/
public static final String GROUPDISPLAY_ID = "Raspbery PI Notifications";
public static final String GROUPDISPLAY_ID = "EmbeddedLinux JVM Notifications";
}
Loading

0 comments on commit 51108fe

Please sign in to comment.