hardlink_*: add hardlink replicating scripts
This commit is contained in:
parent
3023edbfe3
commit
a875dfaa58
73
hardlink_creator.py
Normal file
73
hardlink_creator.py
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
|
||||||
|
def create_hardlinks(json_file, source_dir, target_dir, dry_run: bool = False):
|
||||||
|
"""
|
||||||
|
Reads the JSON file and creates hardlinks based on the mapping of source and target files.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
json_file (str): Path to the JSON file containing the mapping.
|
||||||
|
source_dir (str): Base path of the source directory.
|
||||||
|
target_dir (str): Base path of the target directory.
|
||||||
|
dry_run (bool): If True, no changes will be made; actions will be printed instead.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
with open(json_file, 'r') as f:
|
||||||
|
file_mappings = json.load(f)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to read JSON file {json_file}: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
for source_file, target_file in file_mappings:
|
||||||
|
source_path = os.path.join(source_dir, source_file)
|
||||||
|
target_path = os.path.join(target_dir, target_file)
|
||||||
|
|
||||||
|
# Ensure the source file exists
|
||||||
|
if not os.path.exists(source_path):
|
||||||
|
print(f"Source file does not exist: {source_path}. Skipping...")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Ensure the target directory exists
|
||||||
|
target_dir_path = os.path.dirname(target_path)
|
||||||
|
if not os.path.exists(target_dir_path):
|
||||||
|
if dry_run:
|
||||||
|
print(f"[DRY-RUN] Would create directory: {target_dir_path}")
|
||||||
|
else:
|
||||||
|
print(f"Creating directory: {target_dir_path}")
|
||||||
|
os.makedirs(target_dir_path, exist_ok=True)
|
||||||
|
|
||||||
|
# Create the hard link if the target does not already exist
|
||||||
|
if not os.path.exists(target_path):
|
||||||
|
if dry_run:
|
||||||
|
print(f"[DRY-RUN] Would create hard link: {source_path} -> {target_path}")
|
||||||
|
else:
|
||||||
|
print(f"Creating hard link: {source_path} -> {target_path}")
|
||||||
|
try:
|
||||||
|
os.link(source_path, target_path)
|
||||||
|
except OSError as e:
|
||||||
|
print(f"Failed to create hard link for {target_path}: {e}")
|
||||||
|
else:
|
||||||
|
print(f"Target file already exists, skipping: {target_path}")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Create hardlinks based on JSON output from the first script.")
|
||||||
|
parser.add_argument('json_file', help="Path to the JSON file containing source-target mappings.")
|
||||||
|
parser.add_argument('source_dir', help="Path to the source directory.")
|
||||||
|
parser.add_argument('target_dir', help="Path to the target directory.")
|
||||||
|
parser.add_argument(
|
||||||
|
'--dry-run', '-n',
|
||||||
|
action='store_true',
|
||||||
|
help="Perform a dry run; only print actions without making changes."
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
create_hardlinks(args.json_file, args.source_dir, args.target_dir, args.dry_run)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
65
hardlink_mapper.py
Normal file
65
hardlink_mapper.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
|
||||||
|
# Function to get hard links between source and target directories
|
||||||
|
def get_hard_links(source_dir, target_dir):
|
||||||
|
# Dictionary to store hard links
|
||||||
|
source_links = {}
|
||||||
|
target_links = {}
|
||||||
|
|
||||||
|
# Walk through the source directory to collect hard links
|
||||||
|
for dirpath, _, filenames in os.walk(source_dir):
|
||||||
|
for filename in filenames:
|
||||||
|
filepath = os.path.join(dirpath, filename)
|
||||||
|
try:
|
||||||
|
inode = os.stat(filepath).st_ino
|
||||||
|
if inode not in source_links:
|
||||||
|
source_links[inode] = []
|
||||||
|
source_links[inode].append(filepath)
|
||||||
|
except FileNotFoundError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Walk through the target directory to collect hard links
|
||||||
|
for dirpath, _, filenames in os.walk(target_dir):
|
||||||
|
for filename in filenames:
|
||||||
|
filepath = os.path.join(dirpath, filename)
|
||||||
|
try:
|
||||||
|
inode = os.stat(filepath).st_ino
|
||||||
|
if inode not in target_links:
|
||||||
|
target_links[inode] = []
|
||||||
|
target_links[inode].append(filepath)
|
||||||
|
except FileNotFoundError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Generate the list of tuples (relative_src, relative_dst)
|
||||||
|
hard_links = []
|
||||||
|
for inode, target_files in target_links.items():
|
||||||
|
if inode in source_links:
|
||||||
|
for target_file in target_files:
|
||||||
|
relative_target = os.path.relpath(target_file, target_dir)
|
||||||
|
for source_file in source_links[inode]:
|
||||||
|
relative_source = os.path.relpath(source_file, source_dir)
|
||||||
|
hard_links.append([relative_source, relative_target])
|
||||||
|
|
||||||
|
return hard_links
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Argument parser for CLI arguments
|
||||||
|
parser = argparse.ArgumentParser(description="Collect hard links between source and target directories.")
|
||||||
|
parser.add_argument('source_dir', help="Path to the source directory")
|
||||||
|
parser.add_argument('target_dir', help="Path to the target directory")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
hard_links = get_hard_links(args.source_dir, args.target_dir)
|
||||||
|
print(json.dumps(hard_links, indent=2))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
Reference in New Issue
Block a user