poikilos
3 years ago
2 changed files with 340 additions and 0 deletions
@ -0,0 +1,28 @@ |
|||
-rw-r--r-- 1 owner owner 9.3K Dec 14 2018 ./mods/coderfood/unified_foods/sounds/unified_hunger_eat_generic.ogg |
|||
-rw-r--r-- 1 owner owner 24K Dec 16 2018 ./mods/coderbuild/christmas_craft/sounds/snowball_splash.4.ogg |
|||
-rw-r--r-- 1 owner owner 19K Jun 22 2019 ./mods/coderbuild/travelnet/sounds/travelnet_bell.ogg |
|||
-rw-r--r-- 1 owner owner 15K Apr 21 2020 ./mods/coderbuild/castle/sounds/orbs_birds.ogg |
|||
-rw-r--r-- 1 owner owner 7.3K Apr 21 2020 ./mods/coderbuild/castle/sounds/castle_crossbow_click.ogg |
|||
-rw-r--r-- 1 owner owner 9.0K Apr 21 2020 ./mods/coderbuild/castle/sounds/ropes_creak.3.ogg |
|||
-rw-r--r-- 1 owner owner 50K Apr 21 2020 ./mods/coderbuild/castle/sounds/orbs_owl.ogg |
|||
-rw-r--r-- 1 owner owner 11K Apr 21 2020 ./mods/coderbuild/castle/sounds/ropes_creak.2.ogg |
|||
-rw-r--r-- 1 owner owner 17K Apr 21 2020 ./mods/coderbuild/castle/sounds/orbs_ding.ogg |
|||
-rw-r--r-- 1 owner owner 9.8K Nov 18 2016 ./mods/mtmachines/technic/sounds/item_drop_pickup.1.ogg |
|||
-rw-r--r-- 1 owner owner 15K Nov 18 2016 ./mods/mtmachines/technic/sounds/mining_drill.ogg |
|||
-rw-r--r-- 1 owner owner 9.5K Nov 18 2016 ./mods/mtmachines/technic/sounds/item_drop_pickup.4.ogg |
|||
-rw-r--r-- 1 owner owner 9.4K Nov 18 2016 ./mods/mtmachines/technic/sounds/item_drop_pickup.3.ogg |
|||
-rw-r--r-- 1 owner owner 11K Nov 18 2016 ./mods/mtmachines/technic/sounds/item_drop_pickup.2.ogg |
|||
-rw-r--r-- 1 owner owner 100K Jan 4 2016 ./mods/codercore/wiki/sounds/REALZulfikar.ogg |
|||
-rw-r--r-- 1 owner owner 26K Oct 20 2018 ./mods/codercore/tpr/sounds/whoosh.ogg |
|||
-rw-r--r-- 1 owner owner 15K Dec 22 2019 ./mods/codercore/unified_inventory/sounds/birds.ogg |
|||
-rw-r--r-- 1 owner owner 50K Dec 22 2019 ./mods/codercore/unified_inventory/sounds/owl.ogg |
|||
-rw-r--r-- 1 owner owner 9.8K Jun 21 13:50 ./mods/codercore/item_drop/sounds/item_drop_pickup.1.ogg |
|||
-rw-r--r-- 1 owner owner 9.5K Jun 21 13:50 ./mods/codercore/item_drop/sounds/item_drop_pickup.4.ogg |
|||
-rw-r--r-- 1 owner owner 9.4K Jun 21 13:50 ./mods/codercore/item_drop/sounds/item_drop_pickup.3.ogg |
|||
-rw-r--r-- 1 owner owner 11K Jun 21 13:50 ./mods/codercore/item_drop/sounds/item_drop_pickup.2.ogg |
|||
-rw-r--r-- 1 owner owner 6.8K Dec 19 2017 ./mods/codermobs/mobs/sounds/mobs_swing.ogg |
|||
-rw-r--r-- 1 owner owner 61K Jul 10 10:41 ./mods/codermobs/codermobs/sounds/codermobs_trex1.ogg |
|||
-rw-r--r-- 1 owner owner 50K Jul 10 10:41 ./mods/codermobs/codermobs/sounds/codermobs_trex2.ogg |
|||
-rw-r--r-- 1 owner owner 19K Jul 10 10:41 ./mods/codermobs/codermobs/sounds/codermobs_tiger.ogg |
|||
-rw-r--r-- 1 owner owner 11K Aug 24 2019 ./mods/codermobs/codermobs/sounds/codermobs_mdskeleton_war_cry.ogg |
|||
-rw-r--r-- 1 owner owner 8.0K Aug 24 2019 ./mods/codermobs/codermobs/sounds/codermobs_mdskeleton_attack.2.ogg |
@ -0,0 +1,312 @@ |
|||
#!/usr/bin/env python3 |
|||
''' |
|||
Remove the lines from the from the input file in Bucket_Game-base that are not in the matching list file in Bucket_Game-branches. |
|||
The resulting modified list is written to standard output. |
|||
|
|||
The provided filename must exist in both the Bucket_Game-base directory and the parallel Bucket_Game-branches directory. |
|||
|
|||
The file must contain output such as from ls or find executing ls. Examples: |
|||
find -type f -name "*.ogg" -exec ls -lh {} \; |
|||
find -type f -exec ls -lh {} \; |
|||
|
|||
Usage: |
|||
./trimpatchstats.py <filename> |
|||
''' |
|||
import sys |
|||
import os |
|||
import json |
|||
|
|||
def error(msg): |
|||
sys.stderr.write("{}\n".format(msg)) |
|||
sys.stderr.flush() |
|||
|
|||
def usage(): |
|||
error("") |
|||
error("trimpatchstats.py") |
|||
error("-----------------") |
|||
error(__doc__) |
|||
|
|||
|
|||
def splitFirst(line, delimiter): |
|||
''' |
|||
Only split once. Return a tuple of both parts excluding delimiter. |
|||
If delimiter isn't present, return the line, None |
|||
''' |
|||
delI = line.find(delimiter) |
|||
if delI < 0: |
|||
return line, None |
|||
return line[:delI], line[delI+1:] |
|||
|
|||
|
|||
def splitLast(line, delimiter): |
|||
''' |
|||
Only split once. Return a tuple of both parts excluding delimiter. |
|||
If delimiter isn't present, return the line, None |
|||
''' |
|||
delI = line.rfind(delimiter) |
|||
if delI < 0: |
|||
return line, None |
|||
return line[:delI], line[delI+1:] |
|||
|
|||
|
|||
def parse_ls(line): |
|||
''' |
|||
Parse the output from "ls -l" or "ls -lh" (human-readable size). |
|||
You can use 'n' instead of 'l' in either case, but the owner and |
|||
group will be numbers instead of names. |
|||
|
|||
Returns: a dictionary containing 'permissions', |
|||
'hardlinks' (count), 'owner', 'group', 'size', 'date', |
|||
'name' where each entry is a string. The format of size is |
|||
in bytes, unless the 'h' option was used with ls, in which |
|||
case it will be human-readable (such as "8.3K""). |
|||
The owner and group will be number strings rather than |
|||
name strings if the 'n' option was used with ls. |
|||
|
|||
Sequential arguments: |
|||
line -- The line must be like "perms hardlinks user group size date" |
|||
such as any of the following: |
|||
-rw-r--r-- 1 owner owner 8.3K Dec 14 2018 fire_extinguish.ogg |
|||
-rw-r--r-- 1 1000 1000 8.3K Dec 14 2018 'fire extinguish.ogg' |
|||
-rw-r--r-- 1 owner owner 8300 Dec 14 2018 "Poikilos' fire.ogg" |
|||
''' |
|||
if line.startswith("total "): |
|||
raise ValueError("Expected ls -l file lines but got the" |
|||
"ls -l total line: {}".format(line)) |
|||
results = {} |
|||
results['name'] = None |
|||
chopped = line |
|||
|
|||
# Gradually chop off parts of line until only the date |
|||
# remains, since that is the least predictable as far as |
|||
# delimiters. |
|||
|
|||
if chopped.endswith("'") or chopped.endswith('"'): |
|||
# the filename has spaces |
|||
# (or has "'" if has double quotes). |
|||
inQ = chopped[-1] |
|||
chopped = chopped[:-1] |
|||
firstQI = chopped.rfind(inQ) |
|||
if firstQI < 0: |
|||
raise ValueError("There is a missing '{}' before the" |
|||
" filename that ends with '{}'" |
|||
" in \"{}\"" |
|||
"".format(inQ, inQ, chopped + inQ)) |
|||
name = chopped[firstQI+1:] |
|||
chopped = chopped[:firstQI-1] # -1 to remove the space |
|||
else: |
|||
chopped, name = splitLast(chopped, " ") |
|||
results['permissions'], chopped = splitFirst(chopped, " ") |
|||
results['hardlinks'], chopped = splitFirst(chopped, " ") |
|||
results['owner'], chopped = splitFirst(chopped, " ") |
|||
results['group'], chopped = splitFirst(chopped, " ") |
|||
results['size'], chopped = splitFirst(chopped, " ") |
|||
results['date'] = chopped # Only the date should remain by now. |
|||
# results['name'] = os.path.split(path)[0] |
|||
# results['path'] = path |
|||
results['name'] = name |
|||
return results |
|||
|
|||
|
|||
def fill_file_dict_path(fileInfoDict, baseDir): |
|||
''' |
|||
Fill in the 'path' of the fileInfoDict with the baseDir, or if not |
|||
specified, the current working directory IF the file exists in it, |
|||
otherwise set 'path' to None if not set already. |
|||
''' |
|||
|
|||
name = fileInfoDict.get('name') |
|||
if name is None: |
|||
raise ValueError("The 'name' key must contain a filename" |
|||
" in the dictionary provided to" |
|||
" fill_file_dict_path.") |
|||
baseDirMsg = "specified baseDir" |
|||
if baseDir is None: |
|||
baseDirMsg = "current directory" |
|||
baseDir = os.getcwd() |
|||
path = os.path.join(baseDir, name) |
|||
|
|||
fileInfoDict['path'] = os.path.abspath(name) |
|||
if not os.path.exists(path): |
|||
if os.path.exists(fileInfoDict['path']): |
|||
print("WARNING: missing \"{}\" so using {} to form the path" |
|||
" \"{}\"" |
|||
"".format(path, baseDirMsg, fileInfoDict['path'])) |
|||
else: |
|||
print("WARNING: missing \"{}\" so using {} to form the path" |
|||
" \"{}\" which also doesn't exist" |
|||
"".format(path, baseDirMsg, fileInfoDict['path'])) |
|||
fileInfoDict['name'] = os.path.split(fileInfoDict['path'])[-1] |
|||
|
|||
|
|||
def key_matches_for_any(haystacks, key, needle): |
|||
''' |
|||
See if any dict in haystacks such as haystacks[0][key] is needle. |
|||
''' |
|||
for haystack in haystacks: |
|||
if haystack.get(key) == needle: |
|||
return True |
|||
else: |
|||
return False |
|||
|
|||
|
|||
class LSFileInfo: |
|||
|
|||
def __init__(self, line, baseDir): |
|||
''' |
|||
Parse the output from "ls -l" or "ls -lh" (human-readable size). |
|||
You can use 'n' instead of 'l' in either case, but the owner and |
|||
group will be numbers instead of names. |
|||
|
|||
Sequential arguments: |
|||
line -- The line must be like (ls -lh in this example): |
|||
-rw-r--r-- 1 owner owner 8.3K Dec 14 2018 fire_extinguish.ogg |
|||
perms hardlinks user group size date |
|||
baseDir -- Provide the directory from which the ls command was |
|||
originally run so the LSFileInfo can get the full path. |
|||
Otherwise, the current working directory will be tried. |
|||
''' |
|||
results = parse_ls(line) |
|||
# self.name = results['name'] |
|||
# self.path = None |
|||
self.permissions = results['permissions'] |
|||
self.hardlinks = results['hardlinks'] |
|||
self.owner = results['owner'] |
|||
self.group = results['group'] |
|||
self.size = results['size'] |
|||
self.date = results['date'] |
|||
fill_file_dict_path(results, baseDir) |
|||
self.name = results.get('name') |
|||
self.path = results.get('path') |
|||
|
|||
def to_dict(self): |
|||
results = {} |
|||
# result['name'] = self.name |
|||
results['path'] = self.path |
|||
results['permissions'] = self.permissions |
|||
results['hardlinks'] = self.hardlinks |
|||
results['owner'] = self.owner |
|||
results['group'] = self.group |
|||
results['date'] = self.date |
|||
return result |
|||
|
|||
def __repr__(self): |
|||
return json.dumps(self.to_dict()) |
|||
|
|||
def __str__(self): |
|||
return json.dumps(self.to_dict()) |
|||
|
|||
def getFileNumber(path, num): |
|||
''' |
|||
Get a file from a listfile that contains ls -l or ls -n output. |
|||
|
|||
Sequential arguments: |
|||
path -- The file must be output from 'ls -l' or 'ls -n' or other |
|||
ls commands with 'l' or 'n'. |
|||
num -- The file number, such as 1 for the first file, skipping a |
|||
line that is blank or starts with "total ", "#", or "$". |
|||
''' |
|||
lineN = 0 |
|||
with open(path, 'r') as ins: |
|||
for rawL in ins: |
|||
line = rawL.strip() |
|||
if len(line) == 0: |
|||
continue |
|||
if line.startswith("total "): |
|||
continue |
|||
if line.startswith("#"): |
|||
continue |
|||
if line.startswith("$"): |
|||
continue |
|||
lineN += 1 |
|||
if lineN == num: |
|||
return parse_ls(line) |
|||
return None |
|||
|
|||
|
|||
def printOnlyPatched(baseListPath): |
|||
baseListPath = os.path.abspath(baseListPath) |
|||
basePath, listName = os.path.split(baseListPath) |
|||
parentPath = os.path.split(basePath)[0] |
|||
patchedPath = os.path.join(parentPath, "Bucket_Game-branches") |
|||
patchedListPath = os.path.join(patchedPath, listName) |
|||
if not os.path.isfile(patchedListPath): |
|||
raise ValueError("{} is missing.".format(patchedListPath)) |
|||
|
|||
dotI = listName.find(".") |
|||
targetDirName = None |
|||
targetDirPath = None |
|||
if dotI > -1: |
|||
# See if the filename is named after the directory. |
|||
targetDirName = os.path.split(listName[:dotI])[1] |
|||
tryPath = os.path.join(patchedPath, targetDirName) |
|||
if os.path.isdir(tryPath): |
|||
targetDirPath = tryPath |
|||
else: |
|||
targetDirPath = os.getcwd() |
|||
print("WARNING: missing \"{}\" so trying current directory" |
|||
"".format(tryPath, None)) |
|||
|
|||
fid = getFileNumber(patchedListPath, 1) |
|||
if fid is None: |
|||
print("Error: \"{}\" contained no filenames." |
|||
"".format(patchedListPath)) |
|||
exit(1) |
|||
tryFilePath = os.path.join(targetDirPath, fid['name']) |
|||
if not os.path.isfile(tryFilePath): |
|||
print("Error: \"{}\" doesn't exist. Run again from the" |
|||
" directory containing \"{}\", otherwise name the patch" |
|||
" file so the part before the first dot matches a" |
|||
" directory name in the \"{}\" directory and run in a" |
|||
" directory parallel to that." |
|||
"".format(tryFilePath, fid['name'], patchedPath)) |
|||
exit(1) |
|||
|
|||
error("* analyzing \"{}\"".format(patchedListPath)) |
|||
patchedFIs = [] |
|||
rawNames = [] |
|||
with open(patchedListPath, 'r') as ins: |
|||
for rawL in ins: |
|||
line = rawL.strip() |
|||
if len(line) < 1: |
|||
continue |
|||
if line.startswith("total "): |
|||
continue |
|||
if line.startswith("$"): |
|||
continue |
|||
if line.startswith("#"): |
|||
continue |
|||
fid = parse_ls(line) |
|||
rawNames.append(fid['name']) |
|||
# fill_file_dict_path(fid, targetDirPath) |
|||
# error(fid) |
|||
|
|||
error("* analyzing \"{}\"".format(baseListPath)) |
|||
allCount = 0 |
|||
matchCount = 0 |
|||
with open(baseListPath, 'r') as ins: |
|||
for rawL in ins: |
|||
line = rawL.strip() |
|||
if len(line) < 1: |
|||
continue |
|||
if line.startswith("total "): |
|||
continue |
|||
if line.startswith("$"): |
|||
continue |
|||
if line.startswith("#"): |
|||
continue |
|||
fid = parse_ls(line) |
|||
allCount += 1 |
|||
if fid['name'] in rawNames: |
|||
print(line) |
|||
matchCount += 1 |
|||
error("{} of {} in {} were also in {}" |
|||
"".format(matchCount, allCount, baseListPath, |
|||
patchedListPath)) |
|||
|
|||
if __name__ == "__main__": |
|||
if len(sys.argv) < 2: |
|||
usage() |
|||
error("Error: You are missing the required list filename argument.\n") |
|||
exit(1) |
|||
printOnlyPatched(sys.argv[1]) |
Loading…
Reference in new issue