-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathslash2dot.py
executable file
·147 lines (133 loc) · 3.55 KB
/
slash2dot.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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#!/usr/bin/python3
import argparse
import glob
import logging
import logging.handlers
import pathlib
from cetools import (
to_title_case,
)
prog = "slash2dot"
version = "0.1"
author = "Carl Edman ([email protected])"
desc = "Rename files."
parser = None
args = None
log = logging.getLogger()
def doit(p: pathlib.Path):
dir = pathlib.Path.cwd().resolve()
try:
r = p.resolve().relative_to(dir)
except ValueError:
log.error(f"Path {p} cannot be rendered relative to {dir}, skipping")
return
if args.flatten:
s = dir / r.name
else:
s = pathlib.Path(args.separator.join(r.parts))
if args.titlecase:
s = s.with_stem(to_title_case(s.stem))
if s.exists():
log.error(f"Path {r} cannot be moved to {s} because the target exists, skipping")
return
log.info(f'mv "{r}" "{s}"')
if not args.dryrun:
r.rename(s)
if args.empty:
t = r.parent
while all(False for _ in t.iterdir()):
log.info(f"rmdir {t}")
if not args.dryrun:
t.rmdir()
t = t.parent
if __name__ == "__main__":
parser = argparse.ArgumentParser(
fromfile_prefix_chars="@", prog=prog, epilog="Written by: " + author
)
parser.add_argument("--version", action="version", version="%(prog)s " + version)
parser.add_argument(
"--verbose",
dest="loglevel",
action="store_const",
const=logging.INFO,
help="print informational (or higher) log messages.",
)
parser.add_argument(
"--debug",
dest="loglevel",
action="store_const",
const=logging.DEBUG,
help="print debugging (or higher) log messages.",
)
parser.add_argument(
"--taciturn",
dest="loglevel",
action="store_const",
const=logging.ERROR,
help="only print error level (or higher) log messages.",
)
parser.add_argument(
"--log", dest="logfile", action="store", help="location of alternate log file."
)
parser.add_argument(
"--dryrun",
dest="dryrun",
action="store_true",
help="do not perform operations, but only print them.",
)
parser.add_argument(
"--separator",
dest="separator",
action="store",
default=".",
help="separator to replace slashes",
)
parser.add_argument(
"--flatten",
dest="flatten",
action="store_true",
help="ignore all but final path element",
)
parser.add_argument(
"--empty",
dest="empty",
action="store_true",
help="remove directories left empty by action",
)
parser.add_argument(
"--title-case",
dest="titlecase",
action="store_true",
help="rename files to proper title case.",
)
parser.add_argument(
"paths", nargs="+", help="paths to be operated on; may include wildcards"
)
parser.set_defaults(loglevel=logging.WARN)
args = parser.parse_args()
if args.dryrun and args.loglevel > logging.INFO:
args.loglevel = logging.INFO
log.setLevel(0)
logformat = logging.Formatter("%(asctime)s [%(levelname)s]: %(message)s")
if args.logfile:
flogger = logging.handlers.WatchedFileHandler(args.logfile, "a", "utf-8")
flogger.setLevel(logging.DEBUG)
flogger.setFormatter(logformat)
log.addHandler(flogger)
slogger = logging.StreamHandler()
slogger.setLevel(args.loglevel)
slogger.setFormatter(logformat)
log.addHandler(slogger)
errand = False
for f in (pathlib.Path(fd) for a in args.paths for fd in glob.iglob(a)):
errand = True
if f.is_dir():
for f2 in f.iterdir():
if f2.is_file():
doit(f2)
errand = True
elif f.is_file():
doit(f)
errand = True
if not errand:
log.warning(f'No proper files matching {args.paths}.')