-
Notifications
You must be signed in to change notification settings - Fork 0
/
strategyrename.py
110 lines (98 loc) · 5.17 KB
/
strategyrename.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#!/usr/bin/python
from color import cDim
from pathlib import Path
from scanfile import PlainFileReader, ScanFile
from strategy import Strategy
from tosecdat import TosecGameRom
import logging
import os
import stat
class Matcher:
"""
Search files in the given ROM list. May return a list of TOSEC rom entries matching
the file or None if no match could be found.
Only accept matches with SHA1, MD5, size & CRC equal the TOSEC entry"""
def __init__(self, romList: dict):
self.__romList = romList
def findMatch(self, scanFile: ScanFile) -> list[TosecGameRom]:
if scanFile.isLoaded:
if scanFile.sha1 in self.__romList:
entry = self.__romList[scanFile.sha1]
logging.debug("found file %s as ROM %s",
cDim(scanFile.fileName.as_posix()), cDim(entry[0].name))
if entry[0].isMatching(scanFile):
return entry
logging.error("file %s matching sha1 but not other values for entry %s",
cDim(scanFile.fileName.as_posix()), cDim(entry[0].name))
return None
class StrategyRename(Strategy):
"""
Strategy to move/rename every matching file from the source directory
to the target directory. Ignore all files not matching in source.
If a file should be renamed following cases are handeled:
- target paths are not exising -> paths are created
- target files already exists and is identical -> either skip or delete source @see --delDupes
- target files already exists and it not identical -> move is skiped
- several target files and move of first worked -> softlink other targets to first target"""
def __init__(self, destPath: Path, matcher: Matcher, delDupes: bool, noWritePermission: bool):
super().__init__()
self.__destPath = destPath
self.__matcher = matcher
self.__delDupes = delDupes
self.__noWritePermission = noWritePermission
def doStrategyMatch(self, scanFile: ScanFile, tosecRomMatches: list[TosecGameRom]) -> ScanFile:
super().doStrategyMatch(scanFile, tosecRomMatches)
destFile = tosecRomMatches[0].getFileName(self.__destPath)
self.createParentDirectories(destFile)
if self.renameOrDeleteFoundFile(scanFile, destFile, tosecRomMatches[0]):
for rom in tosecRomMatches[1:]:
otherDestFile = rom.getFileName(self.__destPath)
self.createParentDirectories(otherDestFile)
self.softLink(scanFile, otherDestFile, destFile, rom)
return ScanFile(PlainFileReader(destFile))
if len(tosecRomMatches) > 1:
logging.warning("other entries found for %s skipped due to previous error",
cDim(tosecRomMatches[0].name))
return None
def createParentDirectories(self, destFile: Path):
if not destFile.parent.exists():
logging.debug("creating directory %s", cDim(destFile.parent.as_posix()))
destFile.parent.mkdir(parents=True)
def softLink(self, scanFile: ScanFile, destFile: Path, linkTo: Path, tosecRomMatch: TosecGameRom):
if destFile.is_symlink():
destFile.unlink()
if destFile.exists():
self.handleDestFound(scanFile, destFile, tosecRomMatch, False)
else:
logging.info("softlink file %s to %s", cDim(destFile.as_posix()), cDim(linkTo.as_posix()))
destFile.symlink_to(linkTo)
def renameOrDeleteFoundFile(self, scanFile: ScanFile, destFile: Path, tosecRomMatch: TosecGameRom) -> bool:
if destFile.is_symlink():
destFile.unlink()
if destFile.exists():
return self.handleDestFound(scanFile, destFile, tosecRomMatch, self.__delDupes)
logging.info("rename file %s to %s", cDim(scanFile.fileName.as_posix()), cDim(destFile.as_posix()))
scanFile.fileName.rename(destFile)
if self.__noWritePermission:
self.removeWritePermission(destFile)
return True
def handleDestFound(self, scanFile: ScanFile, destFile: Path, tosecRomMatch: TosecGameRom, deleteDups: bool):
scanDest = ScanFile(PlainFileReader(destFile))
matchDests = self.__matcher.findMatch(scanDest)
if matchDests is None:
logging.error("in destination directory file %s was found but does not match ROM it should have. File %s ignored",
cDim(destFile.as_posix()), cDim(scanFile.fileName.as_posix()))
return False
if deleteDups:
for matchDest in matchDests:
logging.warning("delete Duplicate file %s for matching ROM %s",
cDim(scanFile.fileName.as_posix()), cDim(matchDest.name))
scanFile.fileName.unlink()
else:
for matchDest in matchDests:
logging.warning("duplicate file found %s for matching ROM %s. Source file %s ignored",
cDim(destFile.as_posix()), cDim(matchDest.name), cDim(scanFile.fileName.as_posix()))
return True
def removeWritePermission(self, destFile: Path):
currentPermission = stat.S_IMODE(os.lstat(destFile).st_mode)
os.chmod(destFile, currentPermission & (~stat.S_IWUSR) & (~stat.S_IWGRP) & (~stat.S_IWOTH))