Let commandline registration group image versions
[joel/kofoto.git] / src / packages / kofoto / clientutils.py
1 """Kofoto client utility functions."""
2
3 ######################################################################
4 ### Public names.
5
6 __all__ = [
7     "DIRECTORIES_TO_IGNORE",
8     "expanduser",
9     "get_file_encoding",
10     "walk_files",
11     ]
12
13 ######################################################################
14 ### Libraries.
15
16 import locale
17 import os
18 import re
19 import sys
20
21 ######################################################################
22 ### Implementation.
23
24 DIRECTORIES_TO_IGNORE = [
25     ".jimageviewpics",
26     ".svn",
27     ".thumbnails",
28     ".xvpics",
29     "CVS",
30     "MT",
31     "_darcs",
32     "{arch}",
33     ]
34
35 def expanduser(path):
36     """Expand ~ and ~user constructions.
37
38     If user or $HOME is unknown, do nothing.
39
40     Unlike os.path.expanduser in Python 2.4.1, this function takes and
41     returns Unicode strings correctly.
42     """
43     fs_encoding = sys.getfilesystemencoding()
44     return os.path.expanduser(path.encode(fs_encoding)).decode(fs_encoding)
45
46 def get_file_encoding(f):
47     if hasattr(f, "encoding") and f.encoding:
48         return f.encoding
49     else:
50         return locale.getpreferredencoding()
51
52 def group_image_versions(paths):
53     original_extensions = [
54         ".cr2", ".crw", ".dcr", ".k25", ".kdc", ".mos", ".mrw", ".nef", ".orf",
55         ".pef", ".raf", ".raw", ".srf"]
56     def order_extension(ext):
57         try:
58             return original_extensions.index(ext.lower())
59         except ValueError:
60             # Not a known original extension. Sort it after originals.
61             return len(original_extensions)
62
63     def compare_paths(path1, path2):
64         (root1, ext1) = os.path.splitext(path1)
65         (root2, ext2) = os.path.splitext(path2)
66         extcmp = cmp(order_extension(ext1), order_extension(ext2))
67         if extcmp != 0:
68             return extcmp
69         # The extensions are equal. Sort shorter paths before longer,
70         # since originals probably have shorter names.
71         lencmp = cmp(len(root1), len(root2))
72         if lencmp != 0:
73             return lencmp
74         return cmp(root1, root2)
75
76     pat = re.compile(r"(\w+)", re.UNICODE)
77     bins = {}
78     for path in paths:
79         (head, tail) = os.path.split(path)
80         m = pat.match(tail)
81         if m:
82             key = os.path.join(head, m.group(1))
83         else:
84             key = path
85         bins.setdefault(key, []).append(path)
86     for key in sorted(bins):
87         vpaths = bins[key]
88         vpaths.sort(cmp=compare_paths)
89         yield vpaths
90
91 def walk_files(paths, directories_to_ignore=None):
92     """Traverse paths and return filename while ignoring some directories.
93
94     Arguments:
95
96         paths -- A list of files and directories to traverse.
97
98         directories_to_ignore -- A list of directory names to ignore.
99         If None, directories in DIRECTORIES_TO_IGNORE are ignored.
100
101     Returns:
102
103         An iterable returning paths to the found files.
104     """
105     if directories_to_ignore == None:
106         directories_to_ignore = DIRECTORIES_TO_IGNORE
107     for x in paths:
108         if os.path.isfile(x):
109             yield x
110         elif os.path.isdir(x):
111             if os.path.basename(x) in directories_to_ignore:
112                 continue
113             for dirpath, dirnames, filenames in os.walk(x):
114                 for igndir in directories_to_ignore:
115                     try:
116                         dirnames.remove(igndir)
117                     except ValueError:
118                         pass
119                 for filename in filenames:
120                     yield os.path.join(dirpath, filename)