delete copies

pull/1/head
Ivan Olexyn 4 years ago
parent 89f1a3f4bb
commit 00e90843f4

@ -1,100 +0,0 @@
@startuml
title __ENSYNC's Class Diagram__\n
namespace com.olexyn.ensync {
class com.olexyn.ensync.Execute {
}
}
namespace com.olexyn.ensync {
class com.olexyn.ensync.Flow {
}
}
namespace com.olexyn.ensync {
class com.olexyn.ensync.Main {
}
}
namespace com.olexyn.ensync {
class com.olexyn.ensync.Tools {
}
}
namespace com.olexyn.ensync {
namespace artifacts {
class com.olexyn.ensync.artifacts.SyncDirectory {
}
}
}
namespace com.olexyn.ensync {
namespace artifacts {
class com.olexyn.ensync.artifacts.SyncFile {
}
}
}
namespace com.olexyn.ensync {
namespace artifacts {
class com.olexyn.ensync.artifacts.SyncMap {
}
}
}
namespace com.olexyn.ensync {
namespace ui {
class com.olexyn.ensync.ui.Bridge {
}
}
}
namespace com.olexyn.ensync {
namespace ui {
class com.olexyn.ensync.ui.Controller {
}
}
}
namespace com.olexyn.ensync {
namespace ui {
class com.olexyn.ensync.ui.UI {
}
}
}
com.olexyn.ensync.Flow .up.|> java.lang.Runnable
com.olexyn.ensync.Flow o-- com.olexyn.ensync.Tools : tools
com.olexyn.ensync.Tools o-- com.olexyn.ensync.Execute : x
com.olexyn.ensync.artifacts.SyncDirectory o-- com.olexyn.ensync.Tools : tools
com.olexyn.ensync.artifacts.SyncDirectory o-- com.olexyn.ensync.Execute : x
com.olexyn.ensync.artifacts.SyncDirectory o-- com.olexyn.ensync.artifacts.SyncMap : syncMap
com.olexyn.ensync.artifacts.SyncDirectory o-- com.olexyn.ensync.artifacts.SyncDirectory : thisSD
com.olexyn.ensync.artifacts.SyncFile -up-|> java.io.File
com.olexyn.ensync.artifacts.SyncFile o-- com.olexyn.ensync.artifacts.SyncDirectory : sd
com.olexyn.ensync.artifacts.SyncMap o-- com.olexyn.ensync.Tools : tools
com.olexyn.ensync.ui.Controller .up.|> javafx.fxml.Initializable
com.olexyn.ensync.ui.Controller o-- com.olexyn.ensync.ui.Bridge : bridge
com.olexyn.ensync.ui.UI .up.|> java.lang.Runnable
com.olexyn.ensync.ui.UI -up-|> javafx.application.Application
right footer
PlantUML diagram generated by SketchIt! (https://bitbucket.org/pmesmeur/sketch.it)
For more information about this tool, please contact philippe.mesmeur@gmail.com
endfooter
@enduml

@ -1,54 +0,0 @@
package com.olexyn.ensync;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.List;
public class Execute {
/**
* @param cmd an array representing a shell command
* @return <i>TwoBr</i> class, containing two BufferedReaders,
* <i>output</i> and <i>error</i>
* @see <i>output</i> BufferedReader, corresponds to STDOUT
* <i>error</i> BufferedReader, corresponds to STDERR
*/
public TwoBr execute(String cmd[]) {
TwoBr twobr = new TwoBr();
try {
Process process = Runtime.getRuntime().exec(cmd);
process.waitFor();
twobr.output = new BufferedReader(new InputStreamReader(process.getInputStream()));
twobr.error = new BufferedReader(new InputStreamReader(process.getErrorStream()));
} catch (Exception e) {
e.printStackTrace();
}
return twobr;
}
public TwoBr execute(List<String> cmd) {
String[] cmdArr = new String[cmd.size()];
for (int i = 0; i < cmd.size(); i++) {
cmdArr[i] = cmd.get(i);
}
return execute(cmdArr);
}
public void executeBatch(List<String[]> batch) {
for (String[] strings : batch) {
execute(strings);
}
}
public class TwoBr {
public BufferedReader output;
public BufferedReader error;
}
}

@ -1,93 +0,0 @@
package com.olexyn.ensync;
import com.olexyn.ensync.artifacts.SyncDirectory;
import com.olexyn.ensync.artifacts.SyncMap;
import java.io.File;
import static com.olexyn.ensync.Main.MAP_OF_SYNCMAPS;
public class Flow implements Runnable {
Tools tools = new Tools();
private String state;
public void run() {
while (true) {
synchronized (MAP_OF_SYNCMAPS) {
readOrMakeStateFile();
for (var syncMapEntry : MAP_OF_SYNCMAPS.entrySet()) {
for (var SDEntry : syncMapEntry.getValue().syncDirectories.entrySet()) {
SyncDirectory SD = SDEntry.getValue();
state = "READ";
SD.readFreshState();
SD.listCreated = SD.makeListCreated();
SD.listDeleted = SD.makeListDeleted();
SD.listModified = SD.makeListModified();
SD.doCreate();
SD.doDelete();
SD.doModify();
SD.writeStateFile(SD.path);
}
}
}
try {
long pause = 2000;
System.out.println("Pausing... for "+pause+ "ms.");
Thread.sleep(pause);
} catch (InterruptedException ignored) {
}
}
}
public String getState() {
return state == null ? "NONE" : state;
}
/**
* For every single SyncDirectory try to read it's StateFile. <p>
* If the StateFile is missing, then create a StateFile.
*/
private void readOrMakeStateFile() {
for (var syncMapEntry : MAP_OF_SYNCMAPS.entrySet()) {
SyncMap syncMap = syncMapEntry.getValue();
state = syncMap.toString();
for (var stringSyncDirectoryEntry : syncMap.syncDirectories.entrySet()) {
SyncDirectory SD = stringSyncDirectoryEntry.getValue();
String path = SD.path;
String stateFilePath = tools.stateFilePath(path);
if (new File(stateFilePath).exists()) {
state = "READ-STATE-FILE-" + SD.readStateFile();
} else {
SD.writeStateFile(path);
}
}
}
}
}

@ -1,45 +0,0 @@
package com.olexyn.ensync;
import com.olexyn.ensync.artifacts.SyncMap;
import com.olexyn.ensync.ui.UI;
import java.util.HashMap;
public class Main{
final public static Thread UI_THREAD = new Thread(new UI(), "ui");
final public static Thread FLOW_THREAD = new Thread(new Flow(), "flow");
final public static HashMap<String, SyncMap> MAP_OF_SYNCMAPS = new HashMap<>();
public static void main(String[] args) {
UI_THREAD.start();
FLOW_THREAD.start();
}
}

@ -1,147 +0,0 @@
package com.olexyn.ensync;
import com.olexyn.ensync.artifacts.SyncFile;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Tools {
private final Execute x;
public Tools() {
x = new Execute();
}
/**
* Convert BufferedReader to String.
*
* @param br BufferedReader
* @return String
*/
public String brToString(BufferedReader br) {
StringBuilder sb = new StringBuilder();
Object[] br_array = br.lines().toArray();
for (int i = 0; i < br_array.length; i++) {
sb.append(br_array[i].toString() + "\n");
}
return sb.toString();
}
/**
* Convert BufferedReader to List of Strings.
*
* @param br BufferedReader
* @return List
*/
public List<String> brToListString(BufferedReader br) {
List<String> list = new ArrayList<>();
Object[] br_array = br.lines().toArray();
for (int i = 0; i < br_array.length; i++) {
list.add(br_array[i].toString());
}
return list;
}
public List<String> fileToLines(File file) {
String filePath = file.getPath();
List<String> lines = null;
try {
lines = Files.readAllLines(Paths.get(filePath));
} catch (IOException e) {
e.printStackTrace();
}
return lines;
}
public String fileToString(File file){
List<String> lineList = fileToLines(file);
StringBuilder sb = new StringBuilder();
for (String line : lineList){
sb.append(line).append("\n");
}
return sb.toString();
}
public Map<String, SyncFile> mapMinus(Map<String, SyncFile> fromA, Map<String, SyncFile> substractB) {
Map<String, SyncFile> difference = new HashMap<>();
for (Map.Entry<String, SyncFile> entry : fromA.entrySet()) {
String key = entry.getKey();
if (fromA.containsKey(key) && !substractB.containsKey(key)) {
SyncFile file = fromA.get(key);
difference.put(key, file);
}
}
return difference;
}
public StringBuilder stringListToSb(List<String> list) {
StringBuilder sb = new StringBuilder();
for (String line : list) {
sb.append(line + "\n");
}
return sb;
}
/**
* Write sb to file at path .
*
* @param path <i>String</i>
* @param sb <i>StringBuilder</i>
*/
public void writeSbToFile(String path, StringBuilder sb) {
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(new File(path)));
bw.write(sb.toString());
bw.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Write List of String to file at path .
*
* @param path <i>String</i>
* @param list <i>StringBuilder</i>
*/
public void writeStringListToFile(String path, List<String> list) {
File file = new File(path);
File parent = new File(file.getParent());
if (!parent.exists()) {
x.execute(new String[]{"mkdir",
"-p",
parent.getPath()});
}
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(new File(path)));
StringBuilder sb = stringListToSb(list);
bw.write(sb.toString());
bw.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public String stateFilePath(String path) {
return "/tmp/ensync/state" + path.replace("/", "-");
}
}

@ -1,362 +0,0 @@
package com.olexyn.ensync.artifacts;
import com.olexyn.ensync.Execute;
import com.olexyn.ensync.Tools;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* A SyncDirectory is an occurrence of a particular directory somewhere across the filesystems.
*/
public class SyncDirectory {
private String flowState;
private SyncDirectory thisSD = this;
private SyncMap syncMap;
public String path = null;
public Map<String, SyncFile> listCreated = new HashMap<>();
public Map<String, SyncFile> listDeleted = new HashMap<>();
public Map<String, SyncFile> listModified = new HashMap<>();
Tools tools = new Tools();
Execute x = new Execute();
/**
* Create a SyncDirectory from realPath.
*
* @see SyncMap
*/
public SyncDirectory(String path, SyncMap syncMap) {
this.path = path;
this.syncMap = syncMap;
}
/**
* Get the current state by using the `find` command.
*/
public Map<String, SyncFile> readFreshState() {
//NOTE that the SFile().lastModifiedOld is not set here, so it is 0 by default.
Map<String, SyncFile> filemap = new HashMap<>();
Execute.TwoBr find = x.execute(new String[]{"find",
path});
List<String> pathList = tools.brToListString(find.output);
for (String filePath : pathList) {
SyncFile file = new SyncFile(this, filePath);
filemap.put(filePath, file);
}
return filemap;
}
/**
* READ the contents of StateFile to Map.
*/
public Map<String, SyncFile> readStateFile() {
Map<String, SyncFile> filemap = new HashMap<>();
List<String> lines = tools.fileToLines(new File(tools.stateFilePath(path)));
for (String line : lines) {
// this is a predefined format: "modification-time path"
String modTimeString = line.split(" ")[0];
long modTime = Long.parseLong(modTimeString);
String sFilePath = line.replace(modTimeString + " ", "");
SyncFile sfile = new SyncFile(this, sFilePath);
sfile.setTimeModifiedFromStateFile(modTime);
filemap.put(sFilePath, sfile);
}
return filemap;
}
/**
* Compare the OLD and NEW pools.
* List is cleared and created each time.
*/
public Map<String, SyncFile> makeListCreated() {
Map<String, SyncFile> fromA = readFreshState();
Map<String, SyncFile> substractB = readStateFile();
return tools.mapMinus(fromA, substractB);
}
/**
* Compare the OLD and NEW pools.
* List is cleared and created each time.
*/
public Map<String, SyncFile> makeListDeleted() {
Map<String, SyncFile> fromA = readStateFile();
Map<String, SyncFile> substractB = readFreshState();
Map<String, SyncFile> listDeleted = tools.mapMinus(fromA, substractB);
Map<String, SyncFile> swap = new HashMap<>();
for (var entry : listDeleted.entrySet()) {
String key = entry.getKey();
String parentKey = entry.getValue().getParent();
if (listDeleted.containsKey(parentKey) || swap.containsKey(parentKey)) {
swap.put(key, listDeleted.get(key));
}
}
return tools.mapMinus(listDeleted, swap);
}
/**
* Compare the OLD and NEW pools.
* List is cleared and created each time.
*/
public Map<String, SyncFile> makeListModified() {
Map<String, SyncFile> listModified = new HashMap<>();
Map<String, SyncFile> stateFileMap = readStateFile();
for (var freshFileEntry : readFreshState().entrySet()) {
String freshFileKey = freshFileEntry.getKey();
SyncFile freshFile = freshFileEntry.getValue();
if (freshFile.isDirectory()) { continue;} // no need to modify Directories, the Filesystem will do that, if a File changed.
// If KEY exists in OLD , thus FILE was NOT created.
boolean oldFileExists = stateFileMap.containsKey(freshFileKey);
boolean fileIsFresher = freshFile.getTimeModified() > freshFile.getTimeModifiedFromStateFile();
if (oldFileExists && fileIsFresher) {
listModified.put(freshFileKey, freshFile);
}
}
return listModified;
}
/**
* QUERY state of the filesystem at realPath.
* WRITE the state of the filesystem to file.
*/
public void writeStateFile(String path) {
List<String> outputList = new ArrayList<>();
Execute.TwoBr find = x.execute(new String[]{"find",
path});
List<String> pathList = tools.brToListString(find.output);
for (String filePath : pathList) {
long lastModified = new File(filePath).lastModified();
outputList.add("" + lastModified + " " + filePath);
}
tools.writeStringListToFile(tools.stateFilePath(path), outputList);
}
private class Info {
private String thisFilePath;
private String otherFilePath;
private String otherParentPath;
private File otherParentFile;
private Info(SyncDirectory thisSD, SyncFile sFile, SyncDirectory otherSD) {
// Example:
// syncDirectory /foo
// otherSyncDirectory /bar
// createdFile /foo/hello/created-file.gif
// relativePath /hello/created-file.gif
String relativePath = sFile.getPath().replace(thisSD.path, "");
this.thisFilePath = sFile.getPath();
this.otherFilePath = otherSD.path + relativePath;
File otherFile = new File(otherFilePath);
this.otherParentPath = otherFile.getParent();
this.otherParentFile = new File(otherParentPath);
}
}
public void doCreate() {
for (var entry : listCreated.entrySet()) {
SyncFile createdFile = entry.getValue();
for (var otherEntry : syncMap.syncDirectories.entrySet()) {
SyncDirectory otherSD = otherEntry.getValue();
if (this.equals(otherSD)) { continue; }
Info info = new Info(this, createdFile, otherSD);
writeFile(info, this, createdFile, otherSD);
}
}
}
/**
*
*/
public void doDelete() {
for (var entry : listDeleted.entrySet()) {
SyncFile deletedFile = entry.getValue();
for (var otherEntry : syncMap.syncDirectories.entrySet()) {
SyncDirectory otherSD = otherEntry.getValue();
if (this.equals(otherSD)) { continue; }
Info info = new Info(thisSD, deletedFile, otherSD);
deleteFile(info, thisSD, deletedFile, otherSD);
}
}
}
private void deleteFile(Info info, SyncDirectory thisSD, SyncFile thisFile, SyncDirectory otherSD) {
SyncFile otherFile = new SyncFile(otherSD, otherSD.path + thisFile.relativePath);
if (!otherFile.exists()) { return;}
// if the otherFile was created with ensync it will have the == TimeModified.
long thisFileTimeModified = thisFile.getTimeModified();
long otherFileTimeModified = otherFile.getTimeModified();
if (thisFile.getTimeModified() >= otherFile.getTimeModified()) {
List<String> cmd = List.of("rm", "-r", info.otherFilePath);
x.execute(cmd);
}
}
public void doModify() {
for (var entry : listModified.entrySet()) {
SyncFile modifiedFile = entry.getValue();
for (var otherEntry : syncMap.syncDirectories.entrySet()) {
SyncDirectory otherSD = otherEntry.getValue();
if (this.equals(otherSD)) { continue; }
Info info = new Info(this, modifiedFile, otherSD);
writeFile(info, this, modifiedFile, otherSD);
}
}
}
private void writeFile(Info info, SyncDirectory thisSD, SyncFile thisFile, SyncDirectory otherSD) {
SyncFile otherFile = new SyncFile(otherSD, otherSD.path + thisFile.relativePath);
if (otherFile.exists() && thisFile.getTimeModified() < otherFile.getTimeModified()) { return;}
if (thisFile.isDirectory() && !otherFile.exists()) {
List<String> cmd = List.of("mkdir", "-p", info.otherFilePath);
x.execute(cmd);
return;
}
if (thisFile.isFile()) {
if (!info.otherParentFile.exists()) {
makeParentChain(otherFile, thisFile);
// List<String> cmd = List.of("mkdir", "-p", info.otherParentPath);
//x.execute(cmd);
}
List<String> cmd = List.of("cp", "-p", info.thisFilePath, info.otherFilePath);
x.execute(cmd);
copyModifDate(thisFile.getParentFile(), otherFile.getParentFile());
}
}
private void makeParentChain(File otherFile, File thisFile) {
try {
File otherParent = new File(otherFile.getParent());
File thisParent = new File(thisFile.getParent());
if (!otherParent.exists()) {
makeParentChain(otherParent, thisParent);
makeParentChain(otherFile, thisFile);
} else if (thisFile.isDirectory()) {
List<String> cmd = List.of("mkdir", otherFile.getPath());
x.execute(cmd);
cmd = List.of("stat", "--format", "%y", thisFile.getPath());
String mDate = x.execute(cmd).output.readLine();
cmd = List.of("touch", "-m", "--date=" + mDate, otherFile.getPath());
String error = x.execute(cmd).error.readLine();
int br = 0;
}
} catch (Exception ignored) {}
}
private void copyModifDate(File fromFile, File toFile) {
try {
List<String> cmd = List.of("stat", "--format", "%y", fromFile.getPath());
String mDate = x.execute(cmd).output.readLine();
cmd = List.of("touch", "-m", "--date=" + mDate, toFile.getPath());
x.execute(cmd);
} catch (Exception ignored) {}
}
}

@ -1,63 +0,0 @@
package com.olexyn.ensync.artifacts;
import java.io.File;
import java.util.Map;
public class SyncFile extends File {
// Very IMPORTANT field. Allows to store lastModified as it is stored in the StateFile.
public long timeModifiedFromStateFile = 0;
public String relativePath;
private SyncDirectory sd;
public SyncFile(SyncDirectory sd , String pathname) {
super(pathname);
this.sd = sd;
relativePath = this.getPath().replace(sd.path, "");
}
public void setTimeModifiedFromStateFile(long value){
timeModifiedFromStateFile = value;
}
public long getTimeModifiedFromStateFile(){
SyncFile record = sd.readStateFile().get(this.getPath());
return record == null ? 0 : record.timeModifiedFromStateFile;
}
/**
* If File exists on Disk get the TimeModified from there.
* Else try to read it from StateFile.
* Else return 0 ( = oldest possible time - a value of 0 can be seen as equal to "never existed").
* EXAMPLES:
* If a File was deleted, then the time will be taken from statefile.
* If a File never existed, it will have time = 0, and thus will always be overwritten.
*/
public long getTimeModified(){
if (this.exists()){
return lastModified();
}
if (sd.readStateFile().get(this.getPath())!=null){
return getTimeModifiedFromStateFile();
}
return 0;
}
}

@ -1,45 +0,0 @@
package com.olexyn.ensync.artifacts;
import com.olexyn.ensync.Tools;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
/**
* A SyncMap is the set of such SyncDirectories. The purpose of the SyncMap is to help syncronize the SyncDirectories.
*/
public class SyncMap {
public String name;
public Map<String, SyncDirectory> syncDirectories = new HashMap<>();
Tools tools = new Tools();
/**
* @see SyncMap
*/
public SyncMap(String name) {
this.name = name;
}
/**
* Creates a new Syncdirectory. <p>
* Adds the created SyncDirectory to this SyncMap.
*
* @param realPath the path from which the SyncDirectory is created.
* @see SyncDirectory
*/
public void addDirectory(String realPath) {
if (new File(realPath).isDirectory()) {
syncDirectories.put(realPath, new SyncDirectory(realPath, this));
}
}
public void removeDirectory(String realPath) {
syncDirectories.remove(realPath);
}
}

@ -1,89 +0,0 @@
@startuml
title __ARTIFACTS's Class Diagram__\n
namespace com.olexyn.ensync {
namespace artifacts {
class com.olexyn.ensync.artifacts.SyncDirectory {
+ listCreated : Map<String, SyncFile>
+ listDeleted : Map<String, SyncFile>
+ listModified : Map<String, SyncFile>
+ path : String
- flowState : String
+ SyncDirectory()
+ doCreate()
+ doDelete()
+ doModify()
+ makeListCreated()
+ makeListDeleted()
+ makeListModified()
+ readFreshState()
+ readStateFile()
+ writeStateFile()
- copyModifDate()
- deleteFile()
- makeParentChain()
- writeFile()
}
}
}
namespace com.olexyn.ensync {
namespace artifacts {
class com.olexyn.ensync.artifacts.SyncDirectory.Info {
- otherFilePath : String
- otherParentFile : File
- otherParentPath : String
- thisFilePath : String
- Info()
}
}
}
namespace com.olexyn.ensync {
namespace artifacts {
class com.olexyn.ensync.artifacts.SyncFile {
+ relativePath : String
+ timeModifiedFromStateFile : long
+ SyncFile()
+ getTimeModified()
+ getTimeModifiedFromStateFile()
+ setTimeModifiedFromStateFile()
}
}
}
namespace com.olexyn.ensync {
namespace artifacts {
class com.olexyn.ensync.artifacts.SyncMap {
+ name : String
+ syncDirectories : Map<String, SyncDirectory>
+ SyncMap()
+ addDirectory()
+ removeDirectory()
}
}
}
com.olexyn.ensync.artifacts.SyncDirectory o-- com.olexyn.ensync.Tools : tools
com.olexyn.ensync.artifacts.SyncDirectory o-- com.olexyn.ensync.Execute : x
com.olexyn.ensync.artifacts.SyncDirectory o-- com.olexyn.ensync.artifacts.SyncMap : syncMap
com.olexyn.ensync.artifacts.SyncDirectory o-- com.olexyn.ensync.artifacts.SyncDirectory : thisSD
com.olexyn.ensync.artifacts.SyncDirectory +-down- com.olexyn.ensync.artifacts.SyncDirectory.Info
com.olexyn.ensync.artifacts.SyncFile -up-|> java.io.File
com.olexyn.ensync.artifacts.SyncFile o-- com.olexyn.ensync.artifacts.SyncDirectory : sd
com.olexyn.ensync.artifacts.SyncMap o-- com.olexyn.ensync.Tools : tools
right footer
PlantUML diagram generated by SketchIt! (https://bitbucket.org/pmesmeur/sketch.it)
For more information about this tool, please contact philippe.mesmeur@gmail.com
endfooter
@enduml

@ -1,70 +0,0 @@
@startuml
title __ENSYNC's Class Diagram__\n
namespace com.olexyn.ensync {
class com.olexyn.ensync.Execute {
+ execute()
+ execute()
+ executeBatch()
}
}
namespace com.olexyn.ensync {
class com.olexyn.ensync.Execute.TwoBr {
+ error : BufferedReader
+ output : BufferedReader
}
}
namespace com.olexyn.ensync {
class com.olexyn.ensync.Flow {
- state : String
+ getState()
+ run()
- readOrMakeStateFile()
}
}
namespace com.olexyn.ensync {
class com.olexyn.ensync.Main {
{static} + FLOW_THREAD : Thread
{static} + MAP_OF_SYNCMAPS : HashMap<String, SyncMap>
{static} + UI_THREAD : Thread
{static} + main()
}
}
namespace com.olexyn.ensync {
class com.olexyn.ensync.Tools {
+ Tools()
+ brToListString()
+ brToString()
+ fileToLines()
+ mapMinus()
+ stateFilePath()
+ stringListToSb()
+ writeSbToFile()
+ writeStringListToFile()
}
}
com.olexyn.ensync.Execute +-down- com.olexyn.ensync.Execute.TwoBr
com.olexyn.ensync.Flow .up.|> java.lang.Runnable
com.olexyn.ensync.Flow o-- com.olexyn.ensync.Tools : tools
com.olexyn.ensync.Tools o-- com.olexyn.ensync.Execute : x
right footer
PlantUML diagram generated by SketchIt! (https://bitbucket.org/pmesmeur/sketch.it)
For more information about this tool, please contact philippe.mesmeur@gmail.com
endfooter
@enduml

@ -1,11 +0,0 @@
<syncmap>
<name>SyncMap1</name>
<syncdirectory>
<name>SyncDirectory1</name>
<path>/foo/dir</path>
</syncdirectory>
<syncdirectory>
<name>SyncDirectory2</name>
<path>/bar/dir</path>
</syncdirectory>
</syncmap>

@ -1,6 +0,0 @@
#!/bin/bash
a=$1
b=$2
$a | $b
# this is a pipe

@ -1,7 +0,0 @@
#!/bin/bash
a=$1
b=$2
c=$3
$a | $b | $c
# this is a double pipe

@ -1,7 +0,0 @@
#!/bin/bash
a=$1
b=$2
c=$3
$a $b > $c

@ -1,54 +0,0 @@
package com.olexyn.ensync.ui;
import com.olexyn.ensync.artifacts.SyncMap;
import java.io.File;
import static com.olexyn.ensync.Main.MAP_OF_SYNCMAPS;
/**
* Connect the Controller and the Flow
*/
public class Bridge {
void newCollection(String collectionName) {
synchronized (MAP_OF_SYNCMAPS) {
MAP_OF_SYNCMAPS.put(collectionName, new SyncMap(collectionName));
}
}
void removeCollection(String collectionName) {
synchronized (MAP_OF_SYNCMAPS) {
MAP_OF_SYNCMAPS.remove(collectionName);
}
}
void addDirectory(String collectionName, File diretory) {
synchronized (MAP_OF_SYNCMAPS) {
MAP_OF_SYNCMAPS.get(collectionName).addDirectory(diretory.getAbsolutePath());
}
//TODO pause syning when adding
}
/**
* This works, because a directory, which here is an unique ablsolute path,
* is only supposed to present once across entire SYNC.
*/
void removeDirectory(String directoryAbsolutePath) {
//TODO fix ConcurrentModificationException. This will possibly resolve further errors.
synchronized (MAP_OF_SYNCMAPS) {
for (var syncMap : MAP_OF_SYNCMAPS.entrySet()) {
syncMap.getValue().removeDirectory(directoryAbsolutePath);
}
}
}
}

@ -1,237 +0,0 @@
package com.olexyn.ensync.ui;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.text.Text;
import javafx.stage.DirectoryChooser;
import javafx.stage.Window;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
/***
* Controller class for JavaFX. Contains the application logic.
*/
public class Controller implements Initializable {
final static int COLUMN_COUNT = 5; // How many columns should the GridPane have? Adjust if necessary.
final static Text SPACE = new Text(""); // Placeholder
int collection_count = 0;
Bridge bridge = new Bridge();
@FXML
protected GridPane gridPane;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
Text end = new Text("");
end.setId("end");
Button newCollectionButton = new Button("New Collection");
newCollectionButton.setId("newCollectionButton");
newCollectionButton.setOnAction(event -> { this.newCollection();});
gridPane.add(end, 0, 0);
List<Node> nodeList = new ArrayList<>(gridPane.getChildren());
List<Node> payload = Arrays.asList(new Text(""), new Text(""), new Text(""), new Text(""), newCollectionButton);
insertPayload(nodeList, payload, "end", 0);
redraw(gridPane, nodeList);
}
private void newCollection() {
String collectionName = "name" + collection_count++;
bridge.newCollection(collectionName);
TextField collectionStateTextField = new TextField();
collectionStateTextField.setText("STATE");
collectionStateTextField.setStyle("-fx-text-fill: green");
collectionStateTextField.setDisable(true);
collectionStateTextField.setId("collectionStateTextField-" + collectionName);
Button removeCollectionButton = new Button("Remove Collection");
removeCollectionButton.setId("removeCollectionButton-" + collectionName);
removeCollectionButton.setOnAction(event -> { this.removeCollection(collectionName);});
TextField addDirectoryTextField = new TextField();
addDirectoryTextField.setId("addDirectoryTextField-" + collectionName);
Button addDirectoryButton = new Button("Add Directory");
addDirectoryButton.setId("addDirectoryButton-" + collectionName);
addDirectoryButton.setOnAction(event -> { this.addDirectory(collectionName);});
List<Node> nodeList = new ArrayList<>(gridPane.getChildren());
List<Node> payload = new ArrayList<>();
payload.addAll(Arrays.asList(new Text(""), new Text(""), collectionStateTextField, new Text(""), removeCollectionButton));
payload.addAll(Arrays.asList(addDirectoryTextField, new Text(""), new Text(""), new Text(""), addDirectoryButton));
insertPayload(nodeList, payload, "newCollectionButton", -4);
redraw(gridPane, nodeList);
}
/**
* For the order & number of Nodes see ui-design.png .
* Remove the "Remove-Collection-Line" and the consecutive lines until and including the "Add-Directory-Line".
* The !=null expression protects from Text("") placeholders, who have id==null.
*/
private void removeCollection(String collectionName) {
bridge.removeCollection(collectionName);
List<Node> nodeList = new ArrayList<>(gridPane.getChildren());
here:
for (Node node : nodeList) {
if (node.getId() != null && node.getId().equals("removeCollectionButton-" + collectionName)) {
int i = nodeList.indexOf(node) - 4;
while (i < nodeList.size()) {
nodeList.remove(i);
if (nodeList.get(i).getId() != null && nodeList.get(i).getId().equals("addDirectoryButton-" + collectionName)) {
nodeList.remove(i);
break here;
}
}
}
}
redraw(gridPane, nodeList);
}
/**
*
*/
private void addDirectory(String collectionName) {
// TODO throw error if other collection already contains absollutepath
Window stage = gridPane.getScene().getWindow();
final DirectoryChooser directoryChooser = new DirectoryChooser();
directoryChooser.setTitle("Select Directory.");
directoryChooser.setInitialDirectory(new File(System.getProperty("user.home")));
File directory = directoryChooser.showDialog(stage);
if (directory != null) {
bridge.addDirectory(collectionName, directory);
TextField directoryPathTextField = new TextField();
directoryPathTextField.setText(directory.getAbsolutePath());
directoryPathTextField.setDisable(true);
directoryPathTextField.setId("directoryPathTextField-" + directory.getAbsolutePath());
TextField directoryStateTextField = new TextField();
directoryStateTextField.setText("STATE");
directoryStateTextField.setStyle("-fx-text-fill: green");
directoryStateTextField.setDisable(true);
directoryStateTextField.setId("directoryStateTextField-" + directory.getAbsolutePath());
Button removeDirectoryButton = new Button("Remove");
removeDirectoryButton.setId("removeDirectoryButton-" + directory.getAbsolutePath());
removeDirectoryButton.setOnAction(event -> { this.removeDirectory(directory.getAbsolutePath());});
List<Node> nodeList = new ArrayList<>(gridPane.getChildren());
List<Node> payload = Arrays.asList(directoryPathTextField, new Text(""), directoryStateTextField, new Text(""), removeDirectoryButton);
insertPayload(nodeList, payload, "addDirectoryTextField-" + collectionName, 0);
redraw(gridPane, nodeList);
}
}
/**
* Find the Node with @param id.
* Insert the contents of the @param payload starting from the last.
* This pushes the Node with @param id forward.
*/
private void insertPayload(List<Node> nodeList, List<Node> payload, String id, int offset) {
for (Node node : nodeList) {
if (node.getId() != null && node.getId().equals(id)) {
int i = nodeList.indexOf(node) + offset;
for (int j = payload.size() - 1; j >= 0; j--) {
nodeList.add(i, payload.get(j));
}
break;
}
}
}
/**
* Clear the gridPane and redraw it with contents of nodeList.
*/
private void redraw(GridPane gridPane, List<Node> nodeList) {
gridPane.getChildren().clear();
int col = 0, row = 0;
for (Node node : nodeList) {
if (nodeList.indexOf(node) % COLUMN_COUNT == 0) {
row++;
col = 0;
}
gridPane.add(node, col, row);
col++;
}
}
private void removeDirectory(String directoryAbsolutePath) {
bridge.removeDirectory(directoryAbsolutePath);
List<Node> nodeList = new ArrayList<>(gridPane.getChildren());
for (Node node : nodeList) {
if (node.getId() != null && node.getId().equals("removeDirectoryButton-" +directoryAbsolutePath)) {
int i = nodeList.indexOf(node) - 4;
for (int j = 0; j < 5; j++) {
nodeList.remove(i);
}
break;
}
}
redraw(gridPane, nodeList);
}
}

@ -1,37 +0,0 @@
package com.olexyn.ensync.ui;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class UI extends Application implements Runnable {
@Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("layout.fxml"));
Scene scene = new Scene(root, 500, 500);
primaryStage.setTitle("EnSync");
primaryStage.setScene(scene);
primaryStage.show();
}
@Override
public void run() {
UI.launch();
}
}

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.*?>
<ScrollPane fitToHeight="true" fitToWidth="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="394.0" prefWidth="672.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.olexyn.ensync.ui.Controller">
<content>
<GridPane fx:id="gridPane">
<columnConstraints>
<ColumnConstraints halignment="LEFT" hgrow="ALWAYS" maxWidth="1.7976931348623157E308" minWidth="200.0" prefWidth="200.0" />
<ColumnConstraints fillWidth="false" halignment="CENTER" hgrow="NEVER" maxWidth="20.0" minWidth="20.0" prefWidth="20.0" />
<ColumnConstraints fillWidth="false" halignment="CENTER" hgrow="NEVER" maxWidth="100.0" minWidth="100.0" prefWidth="100.0" />
<ColumnConstraints fillWidth="false" halignment="CENTER" hgrow="NEVER" maxWidth="20.0" minWidth="20.0" prefWidth="20.0" />
<ColumnConstraints fillWidth="false" halignment="LEFT" hgrow="NEVER" maxWidth="200.0" minWidth="200.0" prefWidth="200.0" />
</columnConstraints>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER" />
</rowConstraints>
</GridPane>
</content>
</ScrollPane>

@ -1,59 +0,0 @@
@startuml
title __UI's Class Diagram__\n
namespace com.olexyn.ensync {
namespace ui {
class com.olexyn.ensync.ui.Bridge {
~ addDirectory()
~ newCollection()
~ removeCollection()
~ removeDirectory()
}
}
}
namespace com.olexyn.ensync {
namespace ui {
class com.olexyn.ensync.ui.Controller {
# gridPane : GridPane
{static} ~ COLUMN_COUNT : int
{static} ~ SPACE : Text
~ collection_count : int
+ initialize()
- addDirectory()
- insertPayload()
- newCollection()
- redraw()
- removeCollection()
- removeDirectory()
}
}
}
namespace com.olexyn.ensync {
namespace ui {
class com.olexyn.ensync.ui.UI {
+ run()
+ start()
}
}
}
com.olexyn.ensync.ui.Controller .up.|> javafx.fxml.Initializable
com.olexyn.ensync.ui.Controller o-- com.olexyn.ensync.ui.Bridge : bridge
com.olexyn.ensync.ui.UI .up.|> java.lang.Runnable
com.olexyn.ensync.ui.UI -up-|> javafx.application.Application
right footer
PlantUML diagram generated by SketchIt! (https://bitbucket.org/pmesmeur/sketch.it)
For more information about this tool, please contact philippe.mesmeur@gmail.com
endfooter
@enduml

@ -1,119 +0,0 @@
package files;
import com.olexyn.ensync.Execute;
import com.olexyn.ensync.Tools;
public class FileTest {
Execute x = new Execute();
Tools tools = new Tools();
private static final String PATH = System.getProperty("user.dir");;
public static void main(String... args){
}
/**
* Simulates user activity on disk.
*/
void createFiles() throws InterruptedException {
StringBuilder sbA = new StringBuilder("a");
StringBuilder sbB = new StringBuilder("b");
// dv (deleted-void)
// TODO
// dd
tools.writeSbToFile(PATH+"/a/dd", sbA);
Thread.sleep(10);
tools.writeSbToFile(PATH+"/b/dd", sbB);
Thread.sleep(10);Thread.sleep(10);
x.execute(new String[]{"rm", PATH+"/a/dd"});
Thread.sleep(10);
x.execute(new String[]{"rm", PATH+"/b/dd"});
Thread.sleep(10);
// dc
tools.writeSbToFile(PATH+"/a/dc", sbA);
Thread.sleep(10);
x.execute(new String[]{"rm", PATH+"/a/dc"});
Thread.sleep(10);
tools.writeSbToFile(PATH+"/b/dc", sbB);
Thread.sleep(10);
// dm
tools.writeSbToFile(PATH+"/a/dm", sbA);
Thread.sleep(10);
x.execute(new String[]{"rm", PATH+"/a/dm"});
Thread.sleep(10);
tools.writeSbToFile(PATH+"/b/dm", sbB);
Thread.sleep(10);
// dv (deleted-void)
// TODO
// cd
// TODO
// cc
// TODO
// cm
// TODO
// cv (created-void)
// TODO
// md
// TODO
// mc
// TODO
// mm
// TODO
}
/**
* Checks if end-state is as desired.
* @throws Exception otherwise.
*/
void fileTest() throws Exception {
// Files where the second (= the newer) file was deleted. Thus both files should not exist in the end-state.
String[] arrayToDelete = {"/a/dd", "/b/dd" , "/a/cd", "/b/cd", "/a/md", "/b/md"};
for (String path : arrayToDelete){
if (new TestableFile(path).exists()) throw new Exception();
}
// Files where the second (= the newer) file was created or modified. Thus both files should contain "b" in the end-state.
String[] arrayToB = {"/a/dc", "/b/dc" , "/a/dm", "/b/dm", "/a/cc", "/b/cc"};
for (String path : arrayToB){
if (!new TestableFile(path).hasContent("b")) throw new Exception();
}
}
// Assertion Exception
}

@ -1,21 +0,0 @@
package files;
import com.olexyn.ensync.Tools;
import java.io.File;
public class TestableFile extends File {
Tools tools = new Tools();
public TestableFile(String pathname) {
super(pathname);
}
public boolean hasContent(String s){
String line = tools.fileToLines(this).get(0);
return line.equals(s);
}
}

@ -1,14 +0,0 @@
@startuml
title __FILES's Class Diagram__\n
right footer
PlantUML diagram generated by SketchIt! (https://bitbucket.org/pmesmeur/sketch.it)
For more information about this tool, please contact philippe.mesmeur@gmail.com
endfooter
@enduml

@ -1,26 +0,0 @@
### Testing Scenario
Test two configs:
1. FileOps happen while System is down.
1. FileOps happen while System is running.
<br>
| Symbol | Description|
---|---
`a` | File `a` in directory `A`
`b` | File `b` in directory `B`
`d(x)` | File `x` is deleted.
`c(x)` | File `x` is created.
`m(x)` | File `x` is modified.
<br>
| `Given` | | `When` | | `Then` | |
---|---|---|---|---|---
| `A` | `B`| `A` | `B`|`A` | `B`|
| `a` | | `d(a)` | | | |
| `a` | `b` | `d(a)` | `d(b)` | | |

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save