package se.chalmers.gdcn.taskbuilder.fileManagement;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import se.chalmers.gdcn.taskbuilder.ExitFailureException;
import java.io.*;
import java.net.URL;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by HalfLeif on 2014-03-04.
*
* Creates directories and files for application data in ~/.gdcn
*/
public class Install {
private static final String SEPARATOR = File.separator;
public static final String APPDATA = System.getProperty("user.home") + SEPARATOR + ".gdcn" + SEPARATOR;
public static final String PATH_DATA = APPDATA + "pathdata.prop";
public static final String HEADER_NAME = "Header.hs";
public static final String HPKG_NAME = "gdcn-trusted";
public static final String BOOTSTRAP_NODE_NAME = "bootstrapnodes";
public static final String LIB_DIR = APPDATA + "lib";
public static final String HDB_DIR = APPDATA + "hdb.conf.d";
public static final String STD_BIN = APPDATA + "bin" + SEPARATOR;
public static final String HASKELL_SUBDIR = "haskell";
public static final String HEADER_LOCATION = STD_BIN+HASKELL_SUBDIR+SEPARATOR;
//private constructor
private Install(){
}
/**
* Creates directory for application data. Creates file containing important paths used by application.
* Must be run from GDCN_proj/ directory.
*/
public static void install(){
File rootPath = new File(APPDATA);
rootPath.mkdirs();
File pathDataFile = new File(PATH_DATA);
Properties pathData = null;
OutputStream outputStream = null;
try {
outputStream = new BufferedOutputStream(new FileOutputStream(pathDataFile));
pathData = paths();
pathData.store(outputStream, " -- Paths for GDCN --");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(outputStream != null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
if (pathData != null) {
installHaskellLibraries();
}
writeBootstrapNodes();
}
/**
* Deletes entire directory for application data.
*
* @return true iff uninstalled correctly
*/
public static boolean uninstall(){
File rootPath = new File(APPDATA);
return deleteContents(rootPath);
}
/**
* Deletes entire directory with contents. Use with care!
* Is currently used in {@link Install#uninstall()} and {@link PathManager#deleteBinaries()} etc.
*
* http://stackoverflow.com/questions/7768071/how-to-delete-folder-content-in-java
* @param directory Folder to delete
* @return true if the directory was deleted, false otherwise
*/
static boolean deleteContents(File directory){
if(!directory.exists()){
return false;
}
File[] files = directory.listFiles();
if(files!=null) { //some JVMs return null for empty dirs
for(File f: files) {
if(f.isDirectory()) {
deleteContents(f);
} else {
f.delete();
}
}
}
return directory.delete();
}
/**
* Creates Property object containing paths critical for the program to work on tasks
* @return standard paths
*/
private static Properties paths(){
Properties props = new Properties();
props.put("bin_path", HEADER_LOCATION);
props.put("data_path", APPDATA + "data" + File.separator);
props.put("job_path", APPDATA + "jobs" + File.separator);
props.put("settings_path", APPDATA + "settings" + File.separator);
return props;
}
private static void installHaskellLibraries() {
final File targetHaskellDir = new File(STD_BIN);
try {
Install obj = new Install();
URL location = obj.getClass().getProtectionDomain().getCodeSource().getLocation();
if(location.getFile().endsWith(".jar")){
System.out.println("Location URL: "+location);
File jar = new File(location.toURI());
JarExtractor.extract(jar, HASKELL_SUBDIR, targetHaskellDir);
} else {
//If executed from within IDE
System.out.println("Couldn't locate jar. Assumes is in source folder, attempt copy directly...");
String subHeaderPath = "TaskBuilder" + SEPARATOR + "src" + SEPARATOR + "main" + SEPARATOR + "haskell" + SEPARATOR;
String path = System.getProperty("user.dir") + SEPARATOR + subHeaderPath;
System.out.println("Path: "+path);
File haskellSourceDir = new File(path);
FileUtils.copyDirectory(haskellSourceDir, new File(HEADER_LOCATION));
}
} catch (Exception e) {
e.printStackTrace();
}
File buildDir = new File(HEADER_LOCATION + SEPARATOR + HPKG_NAME);
System.out.println("Build dir: "+buildDir);
String[] dbCmd = {"ghc-pkg", "init", HDB_DIR};
String[] libCmd = {"runhaskell", "Setup", LIB_DIR, HDB_DIR};
try {
Process makeDb = new ProcessBuilder(dbCmd).start();
if (makeDb.waitFor() != 0) {
StringWriter writer = new StringWriter();
IOUtils.copy(makeDb.getErrorStream(), writer, null);
Pattern pattern = Pattern.compile(".*already exists.*", Pattern.DOTALL);
Matcher matcher = pattern.matcher(writer.toString().toLowerCase());
if (!matcher.matches()) {
throw new ExitFailureException(writer.toString());
}
}
Process makeLib = new ProcessBuilder(libCmd).directory(buildDir).start();
if (makeLib.waitFor() != 0) {
StringWriter writer = new StringWriter();
IOUtils.copy(makeDb.getErrorStream(), writer, null);
throw new ExitFailureException(writer.toString());
}
}
catch (IOException e) {
e.printStackTrace();
}
catch (InterruptedException e) {
e.printStackTrace();
}
catch (ExitFailureException e) {
e.printStackTrace();
}
}
private static void writeBootstrapNodes() {
String host = "narrens.olf.sgsnet.se";
int port = 4001;
String s = paths().getProperty("settings_path") + BOOTSTRAP_NODE_NAME;
File bootstrapFile = new File(s);
bootstrapFile.getParentFile().mkdirs();
try {
BufferedWriter outputStream = new BufferedWriter(new FileWriter(bootstrapFile));
try {
outputStream.write(host + " " + port + "\n");
} finally {
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}