package com.jaumard.sails;
import com.intellij.execution.RunManager;
import com.intellij.execution.RunManagerEx;
import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.execution.configurations.ConfigurationFactory;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.ide.browsers.StartBrowserSettings;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.ide.util.projectWizard.WebProjectTemplate;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.platform.DirectoryProjectGenerator;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import com.jaumard.sails.bundle.SailsJSBundle;
import com.jaumard.sails.icons.SailsJSIcons;
import com.jaumard.sails.settings.SailsJSConfig;
import com.jaumard.sails.utils.SailsJSCommandLine;
import com.jaumard.sails.utils.SailsJSUtil;
import com.jetbrains.nodejs.run.NodeJSRunConfiguration;
import com.jetbrains.nodejs.run.NodeJSRunConfigurationType;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import java.io.*;
/**
* Created by jaumard on 04/04/2015.
*/
public class SailsJSProjectGenerator extends WebProjectTemplate<SailsJSProjectGenerator.SailsJSProjectSettings> implements DirectoryProjectGenerator<SailsJSProjectGenerator.SailsJSProjectSettings>
{
private static final Logger LOG = Logger.getInstance(SailsJSProjectGenerator.class);
public SailsJSProjectGenerator()
{
}
@Nls
@NotNull
@Override
public String getName()
{
return SailsJSBundle.message("sails.conf.name");
}
@Override
public String getDescription()
{
return "<html>This project is an application skeleton for a typical <a href=\"http://www.sailsjs.org\">Sails</a> or <a href=\"http://treeline.io\">Treeline</a> server app.<br></html>";
}
@Override
public javax.swing.Icon getIcon()
{
return SailsJSIcons.SailsJS;
}
@Override
public void generateProject(@NotNull final Project project, @NotNull final VirtualFile baseDir,
@NotNull final SailsJSProjectSettings settings, @NotNull Module module
)
{
try
{
ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable()
{
@Override
public void run()
{
try
{
ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
indicator.setText("Creating...");
File tempProject = createTemp();
SailsJSCommandLine commandLine = new SailsJSCommandLine(settings.getExecutable(), tempProject.getPath());
if (!commandLine.isCorrectExecutable())
{
showErrorMessage("Incorrect path");
return;
}
settings.setName(project.getName());
commandLine.createNewProject(settings.name());
if (settings.getPpCSS().equals(SailsJSProjectSettings.PPCSS_SASS))
{
File sassFolder = new File(tempProject.getPath() + "/" + baseDir.getName() + "/assets/sass/");
sassFolder.mkdirs();
File lessFile = new File(tempProject.getPath() + "/" + baseDir.getName() + "/assets/styles/importer.less");
if (lessFile.exists())
{
lessFile.delete();
}
InputStream sassFile = getClass().getResourceAsStream("/js/sass.js");
SailsJSUtil.copyFileFromAssets(sassFile, tempProject.getPath() + "/" + baseDir.getName() + "/tasks/config/sass.js");
InputStream cAssetFile = getClass().getResourceAsStream("/js/compileAssets.js");
SailsJSUtil.copyFileFromAssets(cAssetFile, tempProject.getPath() + "/" + baseDir.getName() + "/tasks/register/compileAssets.js");
InputStream sAssetFile = getClass().getResourceAsStream("/js/syncAssets.js");
SailsJSUtil.copyFileFromAssets(sAssetFile, tempProject.getPath() + "/" + baseDir.getName() + "/tasks/register/syncAssets.js");
modifyPackage(tempProject.getPath() + "/" + baseDir.getName() + "/package.json");
}
File[] array = tempProject.listFiles();
if (array != null && array.length != 0)
{
File from = ContainerUtil.getFirstItem(ContainerUtil.newArrayList(array));
assert from != null;
FileUtil.copyDir(from, new File(baseDir.getPath()), new FileFilter()
{
@Override
public boolean accept(File pathname)
{
if (pathname.getName().equals("node_modules"))
{
return false;
}
return true;
}
});
deleteTemp(tempProject);
SailsJSCommandLine nodeCommandLine = new SailsJSCommandLine(SailsJSConfig.getInstance().getNpmExecutable(), baseDir.getPath());
try
{
nodeCommandLine.npmInstall();
}
catch (Exception e)
{
LOG.info("npm install fail, need to be done manually");
}
}
else
{
showErrorMessage("Cannot find files in the directory " + tempProject.getAbsolutePath());
}
}
catch (Exception e)
{
throw new RuntimeException(e.getMessage(), e);
}
}
}, "Creating Sails project", false, project);
ApplicationManager.getApplication().runWriteAction(new Runnable()
{
@Override
public void run()
{
PropertiesComponent propertiesComponent = PropertiesComponent.getInstance(project);
propertiesComponent.setValue(SailsJSConfig.SAILSJS_WORK_DIRECTORY, project.getBasePath());
SailsJSConfig state = SailsJSConfig.getInstance().getState();
if (!StringUtil.equals(settings.getExecutable(), state.getExecutablePath()))
{
SailsJSConfig.getInstance().loadState(new SailsJSConfig());
}
VfsUtil.markDirty(false, true, project.getBaseDir());
createRunConfiguration(project, settings);
baseDir.refresh(true, true, new Runnable()
{
@Override
public void run()
{
}
});
}
});
}
catch (Exception e)
{
showErrorMessage(e.getMessage());
}
}
private void modifyPackage(String path)
{
BufferedReader br = null;
BufferedWriter bw = null;
try
{
br = new BufferedReader(new FileReader(path));
bw = new BufferedWriter(new FileWriter(path + ".tmp"));
String line;
while ((line = br.readLine()) != null)
{
if (line.contains("grunt-contrib-less"))
{
line = " \"grunt-contrib-sass\" : \"^0.9.2\",";
}
bw.write(line + "\n");
}
}
catch (Exception e)
{
return;
}
finally
{
try
{
if (br != null)
{
br.close();
}
}
catch (IOException e)
{
//
}
try
{
if (bw != null)
{
bw.close();
}
}
catch (IOException e)
{
//
}
}
// Once everything is complete, delete old file..
File oldFile = new File(path);
oldFile.delete();
// And rename tmp file's name to old file name
File newFile = new File(path + ".tmp");
newFile.renameTo(oldFile);
}
private void createRunConfiguration(final Project project, SailsJSProjectSettings settings)
{
final Ref<VirtualFile> appFileRef = Ref.create();
final VirtualFile baseDir = project.getBaseDir();
final String name = "Launch server";
ApplicationManager.getApplication().runReadAction(new Runnable()
{
@Override
public void run()
{
RunManagerEx runManager = RunManagerEx.getInstanceEx(project);
for (RunConfiguration configuration : runManager.getAllConfigurationsList())
{
if (name.equals(configuration.getName()))
{
return;
}
}
appFileRef.set(VfsUtil.findRelativeFile(baseDir, "app.js"));
}
});
if (appFileRef.isNull())
{
return;
}
ApplicationManager.getApplication().runWriteAction(new Runnable()
{
@Override
public void run()
{
ConfigurationFactory configurationFactory = NodeJSRunConfigurationType.getInstance().getDefaultConfigurationFactory();
RunnerAndConfigurationSettings rac = RunManager.getInstance(project).createRunConfiguration("", configurationFactory);
NodeJSRunConfiguration runConfig = ObjectUtils.tryCast(rac.getConfiguration(), NodeJSRunConfiguration.class);
if (runConfig == null)
{
return;
}
VirtualFile appFile = appFileRef.get();
runConfig.setName(name);
runConfig.setWorkingDirectory(baseDir.getPath());
runConfig.setInputPath(VfsUtilCore.getRelativePath(appFile, baseDir, File.separatorChar));
//runConfig.getEnvs().put("DEBUG", baseDir.getName() + ":*");
StartBrowserSettings browserSettings = new StartBrowserSettings();
browserSettings.setUrl("http://localhost:1337/");
runConfig.setStartBrowserSettings(browserSettings);
RunManagerEx runManager = RunManagerEx.getInstanceEx(project);
runManager.addConfiguration(rac, true);
runManager.setSelectedConfiguration(rac);
}
});
}
protected File createTemp() throws IOException
{
return FileUtil.createTempDirectory("intellij-sails-generator", null, false);
}
protected void deleteTemp(File tempProject)
{
if (!SystemInfo.isWindows)//FIXME On windows, delete temp dir break sails installation !!
{
if (!SailsJSUtil.deleteDir(tempProject))
{
LOG.warn("Cannot delete " + tempProject);
}
else
{
LOG.info("Successfully deleted " + tempProject);
}
}
}
@NotNull
@Override
public GeneratorPeer<SailsJSProjectSettings> createPeer()
{
return new SailsJSProjectPeer();
}
static public class SailsJSProjectSettings
{
public static final String PPCSS_SASS = "SASS";
public static final String PPCSS_LESS = "LESS";
private String name = "example";
private String npmExecutable = null;
private String ppCSS = null;
private String executable;
public SailsJSProjectSettings()
{
}
public String getNpmExecutable()
{
return npmExecutable;
}
public void setNpmExecutable(String npmExecutable)
{
this.npmExecutable = npmExecutable;
}
public void setExecutable(String executable)
{
this.executable = executable;
}
public String getExecutable()
{
return executable;
}
public String name()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getPpCSS()
{
return ppCSS;
}
public void setPpCSS(String ppCSS)
{
this.ppCSS = ppCSS;
}
}
private static void showErrorMessage(@NotNull String message)
{
String fullMessage = "Error creating Sails App. " + message;
String title = "Create Sails Project";
Notifications.Bus.notify(
new Notification("Sails Generator", title, fullMessage, NotificationType.ERROR)
);
}
/*
@NotNull
@Override
protected String getDisplayName()
{
return "SailsJS";
}
@NotNull
@Override
public String getGithubUserName()
{
return "balderdashy";
}
@NotNull
@Override
public String getGithubRepositoryName()
{
return "sails";
}
@Nullable
@Override
public String getDescription()
{
return "<html>This project is an application skeleton for a typical <a href=\"https://sails.org\">SailsJS</a> server app.<br>" +
"Don't forget to install dependencies by running<pre>npm install</pre></html>";
}
@Override
public Icon getIcon()
{
return SailsJSIcons.SailsJS;
}
@Nullable
@Override
public String getPrimaryZipArchiveUrlForDownload(@NotNull GithubTagInfo tag)
{
return null;
}
*/
}