package org.nodeclipse.ui.wizards;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
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.debug.core.ILaunchManager;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.dialogs.IOverwriteQuery;
import org.eclipse.ui.ide.undo.CreateProjectOperation;
import org.eclipse.ui.ide.undo.WorkspaceUndoUtil;
import org.eclipse.ui.wizards.datatransfer.ImportOperation;
import org.eclipse.wst.jsdt.internal.ui.workingsets.JavaWorkingSetUpdater;
import org.nodeclipse.ui.Activator;
import org.nodeclipse.ui.npm.InstallLaunchShortcut;
import org.nodeclipse.ui.preferences.PreferenceConstants;
import org.nodeclipse.ui.util.Constants;
import org.nodeclipse.ui.util.LogUtil;
import org.nodeclipse.ui.util.NodeclipseConsole;
import org.nodeclipse.ui.util.ProcessUtils;
import org.osgi.framework.Bundle;
/**
* @author Tomoyuki Inagaki
*/
public class ExpressProjectWizard extends AbstractNodeProjectWizard {
private final String WINDOW_TITLE = "New Express Project";
private ExpressProjectWizardPage mainPage;
public ExpressProjectWizard() {
super();
setWindowTitle(WINDOW_TITLE);
}
@Override
public void addPages() {
mainPage = new ExpressProjectWizardPage("ExpressNewProjectPage") { //$NON-NLS-1$
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.dialogs.WizardNewProjectCreationPage#createControl
* (org.eclipse.swt.widgets.Composite)
*/
public void createControl(Composite parent) {
super.createControl(parent);
createWorkingSetGroup(
(Composite) getControl(),
getSelection(),
new String[] { JavaWorkingSetUpdater.ID, "org.eclipse.ui.resourceWorkingSetPage" }); //$NON-NLS-1$
Dialog.applyDialogFont(getControl());
}
};
mainPage.setTitle("Create an Express Project");
mainPage.setDescription("Create a new Node.js Express project (using `express` CLI underneath,\n"
+"that should be installed before with `npm install -g express`\n"
+"Used `Express` location can be configured in Preferences \"Express path\").");
addPage(mainPage);
}
@Override
protected IProject createNewProject() {
final IProject newProjectHandle = mainPage.getProjectHandle();
URI location = null;
if (!mainPage.useDefaults()) {
location = mainPage.getLocationURI();
}
/*
IWorkspace workspace = ResourcesPlugin.getWorkspace();
final IProjectDescription description = workspace
.newProjectDescription(newProjectHandle.getName());
description.setLocationURI(location);
String[] natures = description.getNatureIds();
String[] newNatures = new String[natures.length + 1];
System.arraycopy(natures, 0, newNatures, 0, natures.length);
newNatures[natures.length] = NodeNature.NATURE_ID;
description.setNatureIds(newNatures);
*/
final IProjectDescription description = createProjectDescription(newProjectHandle, location);
final boolean exists = isExistingProjectFolder(description);
final String projectName = mainPage.getProjectName();
final String templateEngine = mainPage.getSelectedTemplateEngine();
final String stylesheetEngine = mainPage.getSelectedStylesheetEngine();
IRunnableWithProgress op = new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor)
throws InvocationTargetException, InterruptedException {
createProject(description, monitor);
if(exists == true) {
return;
}
String tempdir = System.getProperty("java.io.tmpdir")
+ "/express-work/"
+ new Long(System.currentTimeMillis()).toString();
File workingDirectory = new File(tempdir);
if (workingDirectory.mkdirs() == false) {
throw new InvocationTargetException(new IOException(
"failed creation of working directory."));
}
generateExpressApplication(monitor, projectName, newProjectHandle,
templateEngine, stylesheetEngine, workingDirectory);
importExpressApplication(monitor, newProjectHandle,
workingDirectory);
monitor.beginTask("Generating Express Project...", 3);
deleteFiles(monitor, workingDirectory);
monitor.worked(1);
try {
// universal method for all templates
generateTemplates("templates/common-templates", newProjectHandle);
rewriteFile("README.md", newProjectHandle);
rewritePackageJson(monitor, newProjectHandle);
boolean addTernNature = store.getBoolean(PreferenceConstants.ADD_TERN_NATURE);
if (addTernNature){
generateTemplates("templates/tern-node", newProjectHandle);
}
// JSHint support
runJSHint(newProjectHandle);
} catch (CoreException e1) {
throw new InvocationTargetException(e1);
}
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
try {
launchNpmInstall(newProjectHandle);
} catch (Exception e) {
// throw new InvocationTargetException(e);
}
}
});
try {
newProjectHandle.refreshLocal(1, monitor);
} catch (CoreException e) {
throw new InvocationTargetException(e);
}
monitor.done();
}
};
try {
getContainer().run(true, true, op);
} catch (InvocationTargetException e) {
LogUtil.error(e);
} catch (InterruptedException e) {
}
if (newProjectHandle != null) {
// add to workingsets
IWorkingSet[] workingSets = mainPage.getSelectedWorkingSets();
getWorkbench().getWorkingSetManager().addToWorkingSets(
newProjectHandle, workingSets);
}
return newProjectHandle;
}
private void createProject(IProjectDescription description,
IProgressMonitor monitor) throws InvocationTargetException {
CreateProjectOperation op = new CreateProjectOperation(description,
WINDOW_TITLE);
try {
op.execute(monitor, WorkspaceUndoUtil.getUIInfoAdapter(getShell()));
} catch (ExecutionException e) {
throw new InvocationTargetException(e);
}
}
private void generateExpressApplication(IProgressMonitor monitor,
String projectName, IProject projectHandle, String templateEngine, String stylesheetEngine, File workingDirectory)
throws InvocationTargetException {
Bundle bundle = Activator.getDefault().getBundle();
if (bundle == null) {
throw new InvocationTargetException(
new CoreException(
new Status(IStatus.ERROR, Activator.PLUGIN_ID, "bundle not found")));
}
List<String> cmdLine = new ArrayList<String>();
cmdLine.add(ProcessUtils.getNodePath());
cmdLine.add(ProcessUtils.getExpressPath());
cmdLine.add(workingDirectory.getAbsolutePath() + "/" + projectName);
if (!templateEngine.equals(Constants.BLANK_STRING)) {
int ver = ProcessUtils.getExpressMajorVersion();
if (ver < 3) {
cmdLine.add("-t");
cmdLine.add(templateEngine);
} else {
cmdLine.add("--" + templateEngine);
}
}
if (!stylesheetEngine.equals(Constants.BLANK_STRING)) {
cmdLine.add("--css " + stylesheetEngine);
}
for(String s : cmdLine) NodeclipseConsole.write(s+" ");
NodeclipseConsole.write("\n");
ProcessUtils.exec(cmdLine, workingDirectory);
}
private void importExpressApplication(IProgressMonitor monitor,
IProject projectHandle, File workingDirectory)
throws InvocationTargetException, InterruptedException {
String projectName = projectHandle.getName();
File[] children = workingDirectory.listFiles();
File root = null;
for (File child : children) {
if (child.getName().equals(projectName)) {
root = child;
break;
}
}
if (root == null) {
throw new InvocationTargetException(new IOException("Express app("
+ projectName + ") is not found. "));
}
RelativityFileSystemStructureProvider structureProvider = new RelativityFileSystemStructureProvider(
workingDirectory);
ImportOperation operation = new ImportOperation(
projectHandle.getFullPath(), root, structureProvider,
new IOverwriteQuery() {
@Override
public String queryOverwrite(String pathString) {
return IOverwriteQuery.ALL;
}
}, structureProvider.collectFiles(root));
operation.setCreateContainerStructure(false);
operation.setContext(getShell());
operation.run(monitor);
}
private void deleteFiles(IProgressMonitor monitor, File f) {
if (f.exists() == false) {
return;
}
if (f.isFile()) {
f.delete();
}
if (f.isDirectory()) {
File[] files = f.listFiles();
for (int i = 0; i < files.length; i++) {
deleteFiles(monitor, files[i]);
}
f.delete();
}
}
private void rewritePackageJson(IProgressMonitor monitor, IProject projectHandle) throws CoreException {
String newLine = System.getProperty("line.separator");
IFile file = projectHandle.getFile("package.json");
if(!file.exists()) {
throw new CoreException(new Status(IStatus.ERROR,
Activator.PLUGIN_ID, "package.json not found"));
}
InputStreamReader ir = new InputStreamReader(file.getContents());
BufferedReader br = new BufferedReader(ir);
StringBuilder sb = new StringBuilder();
String line;
try {
while((line = br.readLine()) != null) {
if(line.contains("application-name")) {
line = line.replace("application-name", projectHandle.getName());
}
sb.append(line);
sb.append(newLine);
}
ByteArrayInputStream source = new ByteArrayInputStream(sb.toString().getBytes());
file.setContents(source, true, true, null);
} catch (IOException e) {
throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Cannot read package.json"));
} finally {
try {
ir.close();
br.close();
} catch (IOException e) {
}
ir = null;
br = null;
}
}
private void launchNpmInstall(IProject projectHandle) throws InvocationTargetException, CoreException {
InstallLaunchShortcut launcher = new InstallLaunchShortcut();
IFile path = projectHandle.getFile(Constants.PACKAGE_JSON);
launcher.launchFile(path, ILaunchManager.DEBUG_MODE);
}
}