Add hardlinking with cp -al

This commit is contained in:
Maks Snegov 2021-06-10 22:19:26 +03:00
parent a867dadb75
commit 170b73834b

View File

@ -4,7 +4,6 @@ Module with filesystem-related functions.
import logging import logging
import os import os
import pathlib
import subprocess import subprocess
from typing import Iterable from typing import Iterable
@ -82,6 +81,47 @@ def rsync(src_dir, dst_dir=None):
_lg.info("Updating %s", src_entry) _lg.info("Updating %s", src_entry)
def _hardlink_dir_ext(src, dst):
"""
Make hardlink for a directory using cp -al. Both src and dst should exist.
:param src: absolute path to source directory.
:param dst: absolute path to target directory.
:return: None
"""
res = subprocess.run(["cp", "-v", "-a", "-l", f"{src}/*", dst])
return res
def _recursive_hardlink(src, dst):
"""
Do hardlink directory recursively using python only.
Both src and dst directories should exist.
:param src: absolute path to source directory.
:param dst: absolute path to target directory.
:return: None
"""
with os.scandir(src) as it:
ent: os.DirEntry
for ent in it:
ent_dst_path = os.path.join(dst, ent.name)
if ent.is_dir(follow_symlinks=False):
_lg.debug(f"Copying directory: {ent.path} -> {ent_dst_path}")
os.mkdir(ent_dst_path)
ent_stat = ent.stat(follow_symlinks=False)
os.chown(ent_dst_path, ent_stat.st_uid, ent_stat.st_gid)
os.chmod(ent_dst_path, ent_stat.st_mode)
# process directory children
_recursive_hardlink(ent.path, ent_dst_path)
continue
if ent.is_file(follow_symlinks=False) or ent.is_symlink():
_lg.debug(f"Hardlink file: {ent.path} -> {ent_dst_path}")
os.link(ent.path, ent_dst_path, follow_symlinks=False)
continue
# something that is not a file, symlink or directory
raise NotImplementedError(ent.path)
def hardlink_dir(src_dir, dst_dir): def hardlink_dir(src_dir, dst_dir):
""" """
Make hardlink for a directory with all its content. Make hardlink for a directory with all its content.
@ -93,28 +133,6 @@ def hardlink_dir(src_dir, dst_dir):
src_abs = os.path.abspath(src_dir) src_abs = os.path.abspath(src_dir)
dst_abs = os.path.abspath(dst_dir) dst_abs = os.path.abspath(dst_dir)
def recursive_hardlink(src, dst):
with os.scandir(src) as it:
ent: os.DirEntry
for ent in it:
ent_dst_path = os.path.join(dst, ent.name)
if ent.is_dir(follow_symlinks=False):
_lg.debug(f"Copying directory: {ent.path} -> {ent_dst_path}")
os.mkdir(ent_dst_path)
ent_stat = ent.stat(follow_symlinks=False)
os.chown(ent_dst_path, ent_stat.st_uid, ent_stat.st_gid)
os.chmod(ent_dst_path, ent_stat.st_mode)
# process directory children
recursive_hardlink(ent.path, ent_dst_path)
continue
if ent.is_file(follow_symlinks=False) or ent.is_symlink():
_lg.debug(f"Hardlink file: {ent.path} -> {ent_dst_path}")
os.link(ent.path, ent_dst_path, follow_symlinks=False)
continue
# something that is not a file, symlink or directory
raise NotImplementedError(ent.path)
if not os.path.isdir(src_abs): if not os.path.isdir(src_abs):
_lg.error(f"Error reading source directory: {src_dir}") _lg.error(f"Error reading source directory: {src_dir}")
raise RuntimeError(f"Error reading source directory: {src_dir}") raise RuntimeError(f"Error reading source directory: {src_dir}")
@ -125,5 +143,5 @@ def hardlink_dir(src_dir, dst_dir):
_lg.debug(f"Creating directory: {dst_abs}") _lg.debug(f"Creating directory: {dst_abs}")
os.mkdir(dst_abs) os.mkdir(dst_abs)
recursive_hardlink(src_abs, dst_abs) _recursive_hardlink(src_abs, dst_abs)
return return