git @ Cat's Eye Technologies tagfarm / 2beb0fb
Split tagfarm.utils off from tagfarm.main. Chris Pressey 5 years ago
3 changed file(s) with 124 addition(s) and 125 deletion(s). Raw diff Collapse all Expand all
00 # encoding: UTF-8
11
22 from argparse import ArgumentParser
3 import errno
43 import os
54 import sys
6 from subprocess import Popen, STDOUT, PIPE
75
8
9 # - - - -
10
11
12 def mkdir_p(path):
13 try:
14 os.makedirs(path)
15 except OSError as exc:
16 if exc.errno == errno.EEXIST and os.path.isdir(path):
17 pass
18 else:
19 raise
20
21
22 def find_media_root(path):
23 while path != '/':
24 if os.path.isdir(os.path.join(path, 'by-tag')):
25 return path
26 path = os.path.abspath(os.path.join(path, os.pardir))
27 raise ValueError("could not locate `by-tag` directory in curent directory or any parent directory thereof")
28
29
30 def index_files(media_root):
31 index = {}
32 for root, dirs, files in os.walk(media_root):
33 if os.path.normpath(root) == os.path.normpath(os.path.join(media_root, 'by-tag')):
34 dirs[:] = []
35 continue
36
37 for basename in files:
38 filename = os.path.normpath(os.path.join(root, basename))
39 if os.path.islink(filename):
40 continue
41
42 index.setdefault(basename, set()).add(filename)
43 return index
44
45
46 def is_broken_link(path):
47 return os.path.lexists(path) and not os.path.exists(path)
48
49
50 def is_absolute_link(path):
51 return os.path.lexists(path) and os.readlink(path).startswith('/')
52
53
54 def readlink_or_broken(path):
55 return '*BROKEN*' if is_broken_link(path) else os.readlink(path)
56
57
58 def relativize_target(media_root, path):
59 # Prepends `../..` because the link always resides in `by-tag/<tagname>`
60 return os.path.join('..', '..', os.path.relpath(path, media_root))
61
62
63 def tag_file(media_root, filename, tag):
64 mkdir_p(os.path.join(media_root, 'by-tag', tag))
65 linkname = os.path.join(media_root, 'by-tag', tag, os.path.basename(filename))
66 if not os.path.lexists(linkname):
67 srcname = relativize_target(media_root, filename)
68 os.symlink(srcname, linkname)
69
70
71 def perform_repair(media_root, verbose=False, force_relink=False, prune=False):
72 index = index_files(media_root)
73
74 by_tags_dir = os.path.join(media_root, 'by-tag')
75 for tag in os.listdir(by_tags_dir):
76 tagdir = os.path.join(by_tags_dir, tag)
77 if not os.path.isdir(tagdir):
78 continue
79 repairs_made = []
80 for basename in os.listdir(tagdir):
81
82 linkname = os.path.join(tagdir, basename)
83
84 if basename.startswith('Link to '):
85 new_basename = basename[8:]
86 new_linkname = os.path.join(tagdir, new_basename)
87 if os.path.lexists(new_linkname):
88 repairs_made.append(
89 "WARNING: not renaming '{}' (-> '{}') because '{}' (-> '{}') already exists".format(
90 linkname, readlink_or_broken(linkname), new_linkname, readlink_or_broken(new_linkname)
91 )
92 )
93 else:
94 repairs_made.append("RENAMING {} -> {}".format(linkname, new_linkname))
95 os.rename(linkname, new_linkname)
96 linkname = new_linkname
97
98 if not force_relink:
99 if not os.path.islink(linkname):
100 repairs_made.append("WARNING: skipping {} (is regular file, but --force-relink not given)".format(linkname))
101 continue
102 if not (is_broken_link(linkname) or is_absolute_link(linkname)):
103 if verbose:
104 repairs_made.append('kept {} -> {}'.format(linkname, os.readlink(linkname)))
105 continue
106
107 candidates = index.get(basename, set())
108 if len(candidates) == 0:
109 if prune:
110 repairs_made.append("NOTICE: no candidates for {}, DELETING".format(basename))
111 os.remove(linkname)
112 else:
113 repairs_made.append("WARNING: no candidates for {}".format(basename))
114 elif len(candidates) > 1:
115 repairs_made.append("WARNING: multiple candidates for {}: {}".format(basename, candidates))
116 else:
117 os.remove(linkname)
118 filename = list(candidates)[0]
119 srcname = relativize_target(media_root, filename)
120 os.symlink(srcname, linkname)
121 repairs_made.append('FIXED {} -> {}'.format(linkname, srcname))
122
123 if repairs_made:
124 print('*** {}'.format(tag))
125 for repair_made in repairs_made:
126 print(repair_made)
127
128
129 # - - - - commands - - - -
6 from tagfarm.utils import (
7 mkdir_p, find_media_root, tag_file, perform_repair
8 )
1309
13110
13211 def tag(media_root, args, verbose=False):
0 import json
10 import os
21 import sys
32 from tempfile import mkdtemp
0 # encoding: UTF-8
1
2 import errno
3 import os
4
5
6 def mkdir_p(path):
7 try:
8 os.makedirs(path)
9 except OSError as exc:
10 if exc.errno == errno.EEXIST and os.path.isdir(path):
11 pass
12 else:
13 raise
14
15
16 def find_media_root(path):
17 while path != '/':
18 if os.path.isdir(os.path.join(path, 'by-tag')):
19 return path
20 path = os.path.abspath(os.path.join(path, os.pardir))
21 raise ValueError("could not locate `by-tag` directory in curent directory or any parent directory thereof")
22
23
24 def index_files(media_root):
25 index = {}
26 for root, dirs, files in os.walk(media_root):
27 if os.path.normpath(root) == os.path.normpath(os.path.join(media_root, 'by-tag')):
28 dirs[:] = []
29 continue
30
31 for basename in files:
32 filename = os.path.normpath(os.path.join(root, basename))
33 if os.path.islink(filename):
34 continue
35
36 index.setdefault(basename, set()).add(filename)
37 return index
38
39
40 def is_broken_link(path):
41 return os.path.lexists(path) and not os.path.exists(path)
42
43
44 def is_absolute_link(path):
45 return os.path.lexists(path) and os.readlink(path).startswith('/')
46
47
48 def readlink_or_broken(path):
49 return '*BROKEN*' if is_broken_link(path) else os.readlink(path)
50
51
52 def relativize_target(media_root, path):
53 # Prepends `../..` because the link always resides in `by-tag/<tagname>`
54 return os.path.join('..', '..', os.path.relpath(path, media_root))
55
56
57 def tag_file(media_root, filename, tag):
58 mkdir_p(os.path.join(media_root, 'by-tag', tag))
59 linkname = os.path.join(media_root, 'by-tag', tag, os.path.basename(filename))
60 if not os.path.lexists(linkname):
61 srcname = relativize_target(media_root, filename)
62 os.symlink(srcname, linkname)
63
64
65 def perform_repair(media_root, verbose=False, force_relink=False, prune=False):
66 index = index_files(media_root)
67
68 by_tags_dir = os.path.join(media_root, 'by-tag')
69 for tag in os.listdir(by_tags_dir):
70 tagdir = os.path.join(by_tags_dir, tag)
71 if not os.path.isdir(tagdir):
72 continue
73 repairs_made = []
74 for basename in os.listdir(tagdir):
75
76 linkname = os.path.join(tagdir, basename)
77
78 if basename.startswith('Link to '):
79 new_basename = basename[8:]
80 new_linkname = os.path.join(tagdir, new_basename)
81 if os.path.lexists(new_linkname):
82 repairs_made.append(
83 "WARNING: not renaming '{}' (-> '{}') because '{}' (-> '{}') already exists".format(
84 linkname, readlink_or_broken(linkname), new_linkname, readlink_or_broken(new_linkname)
85 )
86 )
87 else:
88 repairs_made.append("RENAMING {} -> {}".format(linkname, new_linkname))
89 os.rename(linkname, new_linkname)
90 linkname = new_linkname
91
92 if not force_relink:
93 if not os.path.islink(linkname):
94 repairs_made.append("WARNING: skipping {} (is regular file, but --force-relink not given)".format(linkname))
95 continue
96 if not (is_broken_link(linkname) or is_absolute_link(linkname)):
97 if verbose:
98 repairs_made.append('kept {} -> {}'.format(linkname, os.readlink(linkname)))
99 continue
100
101 candidates = index.get(basename, set())
102 if len(candidates) == 0:
103 if prune:
104 repairs_made.append("NOTICE: no candidates for {}, DELETING".format(basename))
105 os.remove(linkname)
106 else:
107 repairs_made.append("WARNING: no candidates for {}".format(basename))
108 elif len(candidates) > 1:
109 repairs_made.append("WARNING: multiple candidates for {}: {}".format(basename, candidates))
110 else:
111 os.remove(linkname)
112 filename = list(candidates)[0]
113 srcname = relativize_target(media_root, filename)
114 os.symlink(srcname, linkname)
115 repairs_made.append('FIXED {} -> {}'.format(linkname, srcname))
116
117 if repairs_made:
118 print('*** {}'.format(tag))
119 for repair_made in repairs_made:
120 print(repair_made)