From 268736c6c7299109662400eeb2a5dc2e6b4b0a0b Mon Sep 17 00:00:00 2001 From: Ivan Olexyn Date: Sat, 20 Jul 2019 12:36:56 +0200 Subject: [PATCH] Old code, new UI. --- src/app/Artifacts.java | 24 +++++++ src/app/Controller.java | 117 ++++++++++++++++++++++++++++++++++ src/app/Execute.java | 34 ++++++++++ src/app/Main.java | 34 ++++++++++ src/app/QuicksortMd5.java | 76 ++++++++++++++++++++++ src/app/README.md | 35 +++++++++++ src/app/Routines.java | 92 +++++++++++++++++++++++++++ src/app/Tools.java | 29 +++++++++ src/app/Write.java | 56 +++++++++++++++++ src/app/layout.fxml | 129 ++++++++++++++++++++++++++++++++++++++ src/app/toFile.sh | 6 ++ 11 files changed, 632 insertions(+) create mode 100644 src/app/Artifacts.java create mode 100644 src/app/Controller.java create mode 100644 src/app/Execute.java create mode 100644 src/app/Main.java create mode 100644 src/app/QuicksortMd5.java create mode 100644 src/app/README.md create mode 100644 src/app/Routines.java create mode 100644 src/app/Tools.java create mode 100644 src/app/Write.java create mode 100644 src/app/layout.fxml create mode 100755 src/app/toFile.sh diff --git a/src/app/Artifacts.java b/src/app/Artifacts.java new file mode 100644 index 0000000..af17b83 --- /dev/null +++ b/src/app/Artifacts.java @@ -0,0 +1,24 @@ +package app; + +import java.io.File; + +public class Artifacts { + + Tools tools = new Tools(); + + + public MFile getMFile(File file) { + MFile mfile = new MFile(); + mfile.file = file; + mfile.md5 = tools.getMd5(file.getPath()); + return mfile; + + + } + + public class MFile { + public File file; + public String md5; + } + +} diff --git a/src/app/Controller.java b/src/app/Controller.java new file mode 100644 index 0000000..9ce0a8c --- /dev/null +++ b/src/app/Controller.java @@ -0,0 +1,117 @@ +package app; + +import javafx.beans.property.StringProperty; +import javafx.concurrent.Task; +import javafx.fxml.FXML; +import javafx.scene.control.*; +import javafx.scene.control.cell.PropertyValueFactory; +import javafx.scene.text.Text; + + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Map; + +import app.Artifacts.MFile; + +public class Controller { + + + Map doubles; + + + @FXML + protected Text loadDirState; + + @FXML + protected Text calcMd5State; + + @FXML + protected Text sortFileState; + + @FXML + protected Text findDoubleState; + + @FXML + protected Text delDoubleState; + + @FXML + protected Text fileNr; + + @FXML + protected Text doubleNr; + + @FXML + protected TextField dir; + + + @FXML + protected void loadDir() { + + Task loadDirTask = new Task() { + @Override + public Void call() throws Exception { + + loadDirState.setText(""); + calcMd5State.setText(""); + sortFileState.setText(""); + findDoubleState.setText(""); + delDoubleState.setText(""); + fileNr.setText("Number of Files:"); + doubleNr.setText("Number of Doubles:"); + + + Path path = Paths.get(dir.getText()); + + if (!Files.isDirectory(path)) { + loadDirState.setText("ERROR."); + + } else { + + Map pool = new Routines().loadPool(dir.getText(), "file"); + new Write().textPool("pool", pool); + loadDirState.setText("OK."); + fileNr.setText("Number of Files: " + pool.size()); + + Map md5Pool = new Routines().md5Pool(pool); + new Write().textMd5Pool("md5Pool", md5Pool); + calcMd5State.setText("OK."); + + Map qsMd5Pool = new QuicksortMd5().quicksortMd5(md5Pool); + new Write().textMd5Pool("qsMd5Pool", qsMd5Pool); + sortFileState.setText("OK."); + + doubles = new Routines().doubles(qsMd5Pool); + new Write().textMd5Pool("doubles", doubles); + findDoubleState.setText("OK."); + doubleNr.setText("Number of Doubles: " + doubles.size()); + + } + return null; + } + }; + new Thread(loadDirTask).start(); + } + + @FXML + protected void deleteDoubles() { + + Task delDoubleTask = new Task() { + @Override + public Void call() throws Exception { + + for (int i = 0; i < doubles.size(); i++) { + new Execute().execute(new String[]{"rm", doubles.get(i).file.getAbsolutePath()}); + + } + delDoubleState.setText("OK."); + return null; + } + }; + new Thread(delDoubleTask).start(); + } + + +} diff --git a/src/app/Execute.java b/src/app/Execute.java new file mode 100644 index 0000000..d2ceb92 --- /dev/null +++ b/src/app/Execute.java @@ -0,0 +1,34 @@ +package app; + +import java.io.BufferedReader; +import java.io.InputStreamReader; + +public class Execute { + + + /** + * + * @param cmd an array representing a shell command + * @return TwoBr class, containing two BufferedReaders, + * output and error + * @see output BufferedReader, corresponds to STDOUT + * error 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 class TwoBr { + public BufferedReader output; + public BufferedReader error; + } +} diff --git a/src/app/Main.java b/src/app/Main.java new file mode 100644 index 0000000..6fd3d9a --- /dev/null +++ b/src/app/Main.java @@ -0,0 +1,34 @@ +package app; + +import javafx.application.Application; +import javafx.fxml.FXMLLoader; +import javafx.geometry.Insets; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.control.TextField; +import javafx.scene.layout.GridPane; +import javafx.stage.Stage; + + +public class Main extends Application { + + static String foo; + + @Override + public void start(Stage primaryStage) throws Exception{ + Parent root = FXMLLoader.load(getClass().getResource("layout.fxml")); + Scene scene = new Scene(root, 300, 275); + + + primaryStage.setTitle("mucc"); + primaryStage.setScene(scene); + primaryStage.show(); + } + + + public static void main(String[] args) { + launch(args); + + } +} diff --git a/src/app/QuicksortMd5.java b/src/app/QuicksortMd5.java new file mode 100644 index 0000000..2c60145 --- /dev/null +++ b/src/app/QuicksortMd5.java @@ -0,0 +1,76 @@ +package app; + +import app.Artifacts.MFile; + +import java.util.Map; + +public class QuicksortMd5 { + private Map md5Pool; + private int i; + private int j; + private int p; + + public Map quicksortMd5(Map md5Pool) { + this.md5Pool = md5Pool; + + quicksort(0, md5Pool.size() - 1); + return this.md5Pool; + } + + private void quicksort(int low, int high) { + i = low; + j = high; + p = low + (high - low) / 2; + + while (i < j) { + + // a < b a.compareto(b) = -1 + // a = b a.compareto(b) = 0 + // a > b a.compareto(b) = 1 + + while (i < p) { + if (imd5().compareTo(pmd5()) <= 0) { + i++; + } else { + swap(i, p); + j = high; + } + } + + while (p < j) { + if (jmd5().compareTo(pmd5()) >= 0) { + j--; + } else { + swap(p, j); + i = low; + } + } + } + + if (high - p > 2) { + quicksort(p, high); + } + if (p - low > 2) { + quicksort(low, p); + } + } + + private void swap(int a, int b) { + MFile temp = md5Pool.get(a); + md5Pool.put(a, md5Pool.get(b)); + md5Pool.put(b, temp); + } + + private String imd5() { + return md5Pool.get(i).md5; + } + + private String jmd5() { + return md5Pool.get(j).md5; + } + + private String pmd5() { + return md5Pool.get(p).md5; + } + +} diff --git a/src/app/README.md b/src/app/README.md new file mode 100644 index 0000000..c2a4d7e --- /dev/null +++ b/src/app/README.md @@ -0,0 +1,35 @@ +### What is `mucc`? +`mucc` is an example for interactions between Linux, Java and JavaFX. +It is a tool for purging duplicates from +a filesystem. + +It does this by calculating a hash of each file +and sorting the files by hash. +If two files have the same hash, the older file will be deleted. + +It also displays some information about what is happening. +This ensures the user never suspects something went horribly wrong. + + +### Package Contents + +| Class | Description | +|---------------|-------------| +| Artifacts | Simple objects used by other classes.| +| Controller | JavaFX class containing application logic. | +| Execute | Issues shell commands.| +| layout.fxml | Contains layout data.| +| Main | Main JavaFX class. Run from here.| +| QuicksortMd5 | Quicksort algorithm.| +| README.md | You are here.| +| Routines | Higher level routines called by Controller.| +| Tools | Simple tools.| +| Write | Writes to /tmp. Used for data storage.| + + +### Issues and Features +- Add proper directory selection. +- Fix issues where nested duplicates would not be deleted on first pass. +- Make UI prettier. +- Make code prettier. + diff --git a/src/app/Routines.java b/src/app/Routines.java new file mode 100644 index 0000000..32f6182 --- /dev/null +++ b/src/app/Routines.java @@ -0,0 +1,92 @@ +package app; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import app.Artifacts.MFile; + +public class Routines { + + + Execute x = null; + + Tools tools = new Tools(); + Write write = new Write(); + + + public Routines() { + this.x = new Execute(); + + this.tools = new Tools(); + } + + + /** + * [1] Write output of find srcdir to /tmp/find
+ * [2] Read /tmp/find into List>String>
+ * [3] Add List>String> entries to Map>String,File> , where + * String is an int key.
+ * + * @param srcdir + * @param type file OR directory + * @return filepool + */ + public Map loadPool(String srcdir, String type) { + // [1] + x.execute(new String[]{System.getProperty("user.dir") + "/src/app/toFile.sh", "find", srcdir, "/tmp/find"}); + // [2] + List lines = null; + try { + lines = Files.readAllLines(Paths.get("/tmp/find")); + } catch (IOException e) { + e.printStackTrace(); + } + // [3] + Map filepool = new HashMap(); + int j = 0; + for (int i = 0; i < lines.size(); i++) { + File file = new File(lines.get(i)); + if (type == "directory" && file.isDirectory() || type == "file" && file.isFile()) { + filepool.put(j, file); + j++; + } + } + return filepool; + } + + + public Map md5Pool(Map pool) { + Map md5Pool = new HashMap<>(); + for (int i = 0; i < pool.size(); i++) { + File file = pool.get(i); + md5Pool.put(i, new Artifacts().getMFile(file)); + } + return md5Pool; + } + + + public Map doubles(Map md5Pool) { + Map doubles = new HashMap<>(); + int d = 0; + for (int i = 0; i < md5Pool.size() - 1; i++) { + MFile iF = md5Pool.get(i); + MFile jF = md5Pool.get(i + 1); + if (iF.md5.equals(jF.md5)) { + if (iF.file.lastModified() >= jF.file.lastModified()) { + doubles.put(d, iF); + d++; + } else { + doubles.put(d, jF); + d++; + } + } + } + return doubles; + } + +} diff --git a/src/app/Tools.java b/src/app/Tools.java new file mode 100644 index 0000000..313b618 --- /dev/null +++ b/src/app/Tools.java @@ -0,0 +1,29 @@ +package app; + +import java.io.BufferedReader; +import java.io.IOException; + +public class Tools { + + Execute x; + + public Tools() { + x = new Execute(); + } + + + /** + * @return Md5 of File at @param path + */ + public String getMd5(String path) { + // output of md5sum: "md5 filepath" + BufferedReader md5reader = x.execute(new String[] { "md5sum", path }).output; + String md5 = null; + try { + md5 = md5reader.readLine().split(" ")[0]; + } catch (IOException e) { + e.printStackTrace(); + } + return md5; + } +} diff --git a/src/app/Write.java b/src/app/Write.java new file mode 100644 index 0000000..b5c8e4d --- /dev/null +++ b/src/app/Write.java @@ -0,0 +1,56 @@ +package app; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.util.Map; +import app.Artifacts.MFile; + +public class Write { + + /** + * writes text to file at path + *

+ */ + public void textFile(String path, StringBuilder text) { + try { + BufferedWriter bw = new BufferedWriter(new FileWriter(new File(path))); + bw.write(text.toString()); + bw.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + + /** + * append all elements of pool to StringBuilder and write to + * /tmp/name + *

+ * + * @param pool + */ + public void textPool(String name, Map pool) { + StringBuilder text = new StringBuilder(); + for (int i = 0; i < pool.size(); i++) { + text.append(i + " " + pool.get(i) + "\n"); + } + textFile("/tmp/" + name, text); + } + + + /** + * append all elements of md5Pool to StringBuilder and write to + * /tmp/name + *

+ * + * @param md5Pool + */ + public void textMd5Pool(String name, Map md5Pool) { + StringBuilder text = new StringBuilder(); + for (int i = 0; i < md5Pool.size(); i++) { + text.append(i + " " + md5Pool.get(i).md5 + " " + md5Pool.get(i).file + "\n"); + } + textFile("/tmp/" + name, text); + } +} diff --git a/src/app/layout.fxml b/src/app/layout.fxml new file mode 100644 index 0000000..bba9d9f --- /dev/null +++ b/src/app/layout.fxml @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +