Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
turiot committed Jun 5, 2022
1 parent 90cd753 commit 1857c75
Show file tree
Hide file tree
Showing 16 changed files with 1,340 additions and 0 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
The purpose of this small application is to synchronize two initially similar directories, but one of which has renamed and moved files, to apply the same modifications to the second.

The typical use case is that of a backup on 'dir1' of 'dir2'; after classifying files in dir2 (renaming and moving files in sub-directories), if we make a new backup, we are offered copy+deletes on dir1 which is inefficient.

The application detects the actions performed on dir2, relying on the size and the date of update (assumed unchanged by the classification), and proposes to perform the same renaming/moving operations on the target directory dir1.

![sscreenshot](./screenshot.png "")

Operating mode : choose directories 1 (target that will be modified) and 2 (model), press 'search'; select the items to update then press 'execute'.

A setting allows to log the actions in a file, to round the times to the second and to choose the language.
20 changes: 20 additions & 0 deletions nbactions.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<actions>
<action>
<actionName>run</actionName>
<packagings>
<packaging>jar</packaging>
</packagings>
<goals>
<goal>process-classes</goal>
<goal>org.codehaus.mojo:exec-maven-plugin:3.0.0:exec</goal>
</goals>
<properties>
<exec.vmArgs></exec.vmArgs>
<exec.args>${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs}</exec.args>
<exec.appArgs></exec.appArgs>
<exec.mainClass>uriot.renmov.MainFrame</exec.mainClass>
<exec.executable>java</exec.executable>
</properties>
</action>
</actions>
71 changes: 71 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>uriot</groupId>
<artifactId>renmov</artifactId>
<version>1.0</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifestEntries>
<version>${project.version}</version>
</manifestEntries>
<manifest>
<mainClass>uriot.renmov.MainFrame</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<version>2.5.3</version>
<executions>
<execution>
<phase>package</phase>
<goals><goal>proguard</goal></goals>
</execution>
</executions>
<configuration>
<injar>${project.build.finalName}.jar</injar>
<libs>
<lib>${java.home}/jmods/java.base.jmod</lib>
<lib>${java.home}/jmods/java.logging.jmod</lib>
<lib>${java.home}/jmods/java.desktop.jmod</lib>
</libs>
<includeDependencyInjar>true</includeDependencyInjar>
<outjar>${project.build.finalName}-small.jar</outjar>
<outputDirectory>${project.build.directory}</outputDirectory>
<proguardInclude>${basedir}/proguard.conf</proguardInclude>
</configuration>
</plugin>
</plugins>
</build>

</project>
32 changes: 32 additions & 0 deletions proguard.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
-dontnote
-dontwarn

-forceprocessing
-verbose

# {{{ all three of these make the "don't touch anything"
# these are listed in the order they happen in its flow
# -dontshrink
# -dontoptimize
-dontobfuscate
# }}}

-adaptresourcefilenames **.properties,**.xml,META-INF/MANIFEST.MF,META-INF/spring.*
-adaptresourcefilecontents **.properties,**.xml,META-INF/MANIFEST.MF,META-INF/spring.*

-keep public class uriot.renmov.MainFrame {
public static void main(java.lang.String[]);
}

-keep,allowshrinking class * extends java.io.Serializable
-keepclassmembers class * extends java.io.Serializable {
*;
}

-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}

-keepattributes *Annotation*,Signature,InnerClasses,EnclosingMethod

Binary file added screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
129 changes: 129 additions & 0 deletions src/main/java/uriot/renmov/Controller.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package uriot.renmov;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.util.ArrayList;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
import org.apache.commons.io.FileUtils;

public class Controller {

public Logger log;
public Settings settings;
public ResourceBundle bundle;

void search(ArrayList<Item> items, String dir1, String dir2, int[] res) {
items.clear();

if (!new File(dir1).exists() || !new File(dir2).exists()) {
res[0] = 1;
return;
}

var map = new ArrayListValuedHashMap<Criteria, Item>();
try (var walk = Files.walk(Path.of(new URI("file:///" + dir2)))) {
walk.filter(Files::isRegularFile).map(path -> {
var file = path.toFile();
Criteria key = null;
try {
var date = ((FileTime) Files.getAttribute(path, "creationTime")).toInstant();
key = new Criteria(date, file.length(), settings.roundToSecond);
}
catch (IOException ex) {
log.log(Level.SEVERE, null, ex);
res[0] = 2;
}
var item = new Item(key);
item.path2 = file.getPath();
return item;
})
.forEach(item -> {
map.put(item.criteria, item);
});
}
catch (URISyntaxException | IOException ex) {
log.log(Level.SEVERE, null, ex);
res[0] = 2;
}

try (var walk = Files.walk(Path.of(new URI("file:///" + dir1)))) {
walk.filter(Files::isRegularFile)
.<Item>mapMulti((path, consumer) -> {
var file1 = path.toFile();
Criteria key = null;
try {
var date = ((FileTime) Files.getAttribute(path, "creationTime")).toInstant();
key = new Criteria(date, file1.length(), settings.roundToSecond);
}
catch (IOException ex) {
log.log(Level.SEVERE, null, ex);
res[0] = 2;
}
var found = map.get(key);
if (found != null && !found.isEmpty()) {
found.forEach(item -> {
var relPath1 = file1.getPath().substring(dir1.length() + 1);
var relPath2 = item.path2.substring(dir2.length() + 1);
if (!relPath1.equals(relPath2)) {
var file2 = new File(item.path2);
var d1 = relPath1.substring(0, relPath1.lastIndexOf(file1.getName()));
var d2 = relPath2.substring(0, relPath2.lastIndexOf(file2.getName()));
var out = new Item(item.criteria);
out.select = found.size() <= 1;
if (d1.equals(d2)) {
out.action = bundle.getString("action.rename");
}
else if (file1.getName().equals(file2.getName())) {
out.action = bundle.getString("action.move");
}
else {
out.action = bundle.getString("action.both");
}
out.path1 = file1.getPath();
out.path2 = item.path2;
consumer.accept(out);
}
});
}
})
.filter(item -> item != null)
.forEach(item -> {
items.add(item);
});
}
catch (URISyntaxException | IOException ex) {
log.log(Level.SEVERE, null, ex);
res[0] = 2;
}
}

void execute(ArrayList<Item> items, String dir1, String dir2, int[] cpt) {
var i = items.iterator();
while (i.hasNext()) {
var item = i.next();
if (item.select) {
var relPath2 = item.path2.substring(dir2.length() + 1);
var relPath1 = dir1 + "/" + relPath2;
log.log(Level.INFO, "{0} {1} to {2}", new Object[]{item.action, item.path1, relPath1});
try {
FileUtils.moveFile(FileUtils.getFile(item.path1), FileUtils.getFile(relPath1));
cpt[0]++;
}
catch (IOException ex) {
log.log(Level.SEVERE, null, ex);
cpt[1]++;
}
i.remove();
}
}
}

}
47 changes: 47 additions & 0 deletions src/main/java/uriot/renmov/Criteria.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package uriot.renmov;

import java.time.Instant;

public class Criteria {
public Instant date;
public long size;
private final long millis;

public Criteria(Instant date, long size, boolean roundToSecond) {
this.date = date;
this.size = size;
this.millis = roundToSecond ? date.toEpochMilli() / 1000L : date.toEpochMilli();
}

@Override
public int hashCode() {
var hash = 7;
hash = 71 * hash + (int) (this.size ^ (this.size >>> 32));
hash = 71 * hash + (int) (this.millis ^ (this.millis >>> 32));
return hash;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
var other = (Criteria) obj;
if (this.size != other.size) {
return false;
}
return other.millis == millis;
}

@Override
public String toString() {
return "Criteria{" + "date=" + date + ", size=" + size + '}';
}

}
29 changes: 29 additions & 0 deletions src/main/java/uriot/renmov/Item.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package uriot.renmov;

import java.time.Instant;

public class Item {
Criteria criteria;
boolean select;
String path1;
String path2;
String action;

public Item(Criteria criteria) {
this.criteria = criteria;
select = true;
}

public static final String[] columnNames = {
"Sél", "Fichier 1", "Fichier 2", "Date", "Taille", "Action" // i18n override
};

public static final Class[] columnClasses = {
Boolean.class, String.class, String.class, Instant.class, Long.class, String.class
};

@Override
public String toString() {
return "Item{" + "criteria=" + criteria + ", select=" + select + ", path1=" + path1 + ", path2=" + path2 + ", action=" + action + '}';
}
}
Loading

0 comments on commit 1857c75

Please sign in to comment.