Compare commits

...

7 Commits

Author SHA1 Message Date
a0eb371a65 Merge branch 'dev'
Got to a state that seems stable enough to go into main
2026-01-01 23:26:10 +01:00
addbdb87df main : adds subcommands, move to Path and improve
Multiple changes to the main file, after this unisync becomes kind of
usable.
Add subcommands : this uses the 2 previous commits to add the
subcommands to unisync it is now possible to sync, add and mount.
pathlib : move from PosixPath to Path
Remove unused imports
Rename base_namespace to cli_args
Add some comments and TODOs
2026-01-01 23:19:57 +01:00
885050cf84 argparser : adds subcommands to the argparser
this adds subcommands to the argparser using subparsers, we also set a
default value for func depending on which of the subcommands is
selected.
Also change the formatting of the epilog so it is on two lines.
2026-01-01 23:18:52 +01:00
bd65c623a4 runners : Create runners file and basic runnners
This adds runners.py, it contains a set of functions that peform all the
various task that unisync can do (sync, add and mount for now).
They are simple function that put together all the rest.
2026-01-01 23:15:02 +01:00
89fa5bca70 paths : fixes write_new_paths writing of the file
I was writing the file using 'w' instead of 'a' so the old paths were
deleted use 'a'.
2026-01-01 18:51:45 +01:00
5af5374f77 config : fallback to 22 instead of None
The configparser fallback option was None set it to use 22 instead as
None doesn't make sense
2026-01-01 17:30:28 +01:00
138bc6d24a Update README to reflect the state of the project 2025-12-31 00:04:53 +01:00
6 changed files with 67 additions and 28 deletions

View File

@@ -23,5 +23,4 @@ The issue is that you need to know what data is stored on the server to avoid co
# Developement
Unisync was at first a simple bash script but as it grew more complex I started struggling to maintain it which is why I am porting it to python. It will make everything more robust, easier to maintain and to add functionalities.
I am in the early stages of the developement process, this should be usable in the upcoming weeks.
Help will be welcome in the future but is not desirable right now as I want to shape this the way I want to.
I am in the early stages of the developement process, this should be usable someday (hopefully).

View File

@@ -3,20 +3,34 @@
import argparse
def create_argparser() -> argparse.ArgumentParser:
def create_argparser(sync_function, add_function, mount_function) -> argparse.ArgumentParser:
"""
Creates an argument parser to parse the command line arguments.
We use subparsers and set a default function for each to perform the correct action.
"""
parser = argparse.ArgumentParser(
prog='unisync',
description='File synchronisation application',
epilog="""
Copyright © 2025 Paul Retourné.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>."""
epilog="Copyright © 2025 Paul Retourné.\n"
"License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.",
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument("local", nargs="?")
parser.add_argument("remote", nargs="?")
parser.set_defaults(func=sync_function)
remote_addr_group = parser.add_mutually_exclusive_group()
remote_addr_group.add_argument("--ip")
remote_addr_group.add_argument("--hostname")
parser.add_argument("--config", help="Path to the configuration file", metavar="path_to_config")
subparsers = parser.add_subparsers(help='Actions other than synchronisation')
parser_add = subparsers.add_parser('add', help='Add files to be synchronised.')
parser_add.set_defaults(func=add_function)
parser_mount = subparsers.add_parser('mount', help='Mount the remote.')
parser_mount.set_defaults(func=mount_function)
return parser

View File

@@ -16,7 +16,7 @@ class ServerConfig:
sshargs: str = ""
hostname: str = ""
ip: str = ""
port: int | None = 22
port: int = 22
def __post_init__(self):
"""
@@ -85,7 +85,7 @@ def load_config(config_path:str) -> Config:
config.get(server_section, "sshargs", fallback=""),
config.get(server_section, "hostname", fallback=""),
config.get(server_section, "ip", fallback=""),
config.getint(server_section, "port", fallback=None)
config.getint(server_section, "port", fallback=22)
)
roots_config = RootsConfig(
config.get(roots_section, "local"),

View File

@@ -3,24 +3,29 @@
import os
from argparser import create_argparser
from config import RootsConfig, ServerConfig, Config, load_config
from runners import unisync_sync, unisync_add, unisync_mount
from config import load_config
from synchroniser import Synchroniser
from pathlib import Path, PosixPath
from pathlib import Path
from paths import *
def main():
parser = create_argparser()
base_namespace = parser.parse_args()
parser = create_argparser(unisync_sync, unisync_add, unisync_mount)
cli_args = parser.parse_args()
config_path = os.path.expanduser("~/.config/unisync/config.ini")
if base_namespace.config != None and os.path.isfile(base_namespace.config):
config = load_config(base_namespace.config)
# Check if --config is set
if cli_args.config != None and os.path.isfile(cli_args.config):
config = load_config(cli_args.config)
elif os.path.isfile(config_path):
config = load_config(config_path)
else:
# TODO make the command line arguments work and override the config options
# TODO replace the next line with something to do if no config file is found
config = load_config(config_path)
pass
# TODO make the command line arguments work and override the config options
synchroniser = Synchroniser(
config.roots.remote,
config.roots.local,
@@ -33,18 +38,7 @@ def main():
paths_manager = PathsManager(Path(config.roots.local), config.other.cache_dir_path)
if synchroniser.create_ssh_master_connection() != 0:
print("Connection failed quitting")
return 1
print("Connected to the remote.")
#synchroniser.sync_files()
#synchroniser.update_links(background=False)
#synchroniser.mount_remote_dir()
synchroniser.close_ssh_master_connection()
print(paths_manager.get_paths_to_sync())
cli_args.func(synchroniser, paths_manager)
if __name__ == "__main__":

View File

@@ -106,7 +106,7 @@ class PathsManager:
if not is_contained and new_path not in paths_to_add:
paths_to_add.append(new_path)
with self.paths_file.open("w") as f:
with self.paths_file.open("a") as f:
for p in paths_to_add:
f.write(p + "\n")

32
src/unisync/runners.py Normal file
View File

@@ -0,0 +1,32 @@
from synchroniser import Synchroniser
from paths import PathsManager
def unisync_sync(synchroniser:Synchroniser, paths_manager:PathsManager):
if synchroniser.create_ssh_master_connection() != 0:
print("Connection failed quitting")
return 1
print("Connected to the remote.")
synchroniser.sync_files(paths_manager.get_paths_to_sync())
synchroniser.update_links(background=False)
# TODO check the config options
#synchroniser.mount_remote_dir()
synchroniser.close_ssh_master_connection()
def unisync_add(synchroniser:Synchroniser, paths_manager:PathsManager):
if synchroniser.create_ssh_master_connection() != 0:
print("Connection failed quitting")
return 1
print("Connected to the remote.")
paths_manager.add_files_to_sync()
synchroniser.close_ssh_master_connection()
def unisync_mount(synchroniser:Synchroniser, paths_manager:PathsManager):
synchroniser.mount_remote_dir()