skilleter-thingy 0.0.40__py3-none-any.whl → 0.0.41__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of skilleter-thingy might be problematic. Click here for more details.

Files changed (68) hide show
  1. skilleter_thingy/__init__.py +6 -0
  2. skilleter_thingy/addpath.py +107 -0
  3. skilleter_thingy/borger.py +269 -0
  4. skilleter_thingy/console_colours.py +63 -0
  5. skilleter_thingy/diskspacecheck.py +67 -0
  6. skilleter_thingy/docker_purge.py +113 -0
  7. skilleter_thingy/ffind.py +536 -0
  8. skilleter_thingy/ggit.py +90 -0
  9. skilleter_thingy/ggrep.py +154 -0
  10. skilleter_thingy/git_br.py +180 -0
  11. skilleter_thingy/git_ca.py +142 -0
  12. skilleter_thingy/git_cleanup.py +287 -0
  13. skilleter_thingy/git_co.py +220 -0
  14. skilleter_thingy/git_common.py +61 -0
  15. skilleter_thingy/git_hold.py +154 -0
  16. skilleter_thingy/git_mr.py +92 -0
  17. skilleter_thingy/git_parent.py +77 -0
  18. skilleter_thingy/git_review.py +1428 -0
  19. skilleter_thingy/git_update.py +385 -0
  20. skilleter_thingy/git_wt.py +96 -0
  21. skilleter_thingy/gitcmp_helper.py +322 -0
  22. skilleter_thingy/gitprompt.py +274 -0
  23. skilleter_thingy/gl.py +174 -0
  24. skilleter_thingy/gphotosync.py +610 -0
  25. skilleter_thingy/linecount.py +155 -0
  26. skilleter_thingy/moviemover.py +133 -0
  27. skilleter_thingy/photodupe.py +136 -0
  28. skilleter_thingy/phototidier.py +248 -0
  29. skilleter_thingy/py_audit.py +131 -0
  30. skilleter_thingy/readable.py +270 -0
  31. skilleter_thingy/remdir.py +126 -0
  32. skilleter_thingy/rmdupe.py +550 -0
  33. skilleter_thingy/rpylint.py +91 -0
  34. skilleter_thingy/splitpics.py +99 -0
  35. skilleter_thingy/strreplace.py +82 -0
  36. skilleter_thingy/sysmon.py +435 -0
  37. skilleter_thingy/tfm.py +920 -0
  38. skilleter_thingy/tfparse.py +101 -0
  39. skilleter_thingy/thingy/__init__.py +6 -0
  40. skilleter_thingy/thingy/colour.py +213 -0
  41. skilleter_thingy/thingy/dc_curses.py +278 -0
  42. skilleter_thingy/thingy/dc_defaults.py +221 -0
  43. skilleter_thingy/thingy/dc_util.py +50 -0
  44. skilleter_thingy/thingy/dircolors.py +308 -0
  45. skilleter_thingy/thingy/docker.py +95 -0
  46. skilleter_thingy/thingy/files.py +142 -0
  47. skilleter_thingy/thingy/git.py +1371 -0
  48. skilleter_thingy/thingy/git2.py +1307 -0
  49. skilleter_thingy/thingy/gitlab.py +193 -0
  50. skilleter_thingy/thingy/logger.py +112 -0
  51. skilleter_thingy/thingy/path.py +156 -0
  52. skilleter_thingy/thingy/popup.py +87 -0
  53. skilleter_thingy/thingy/process.py +112 -0
  54. skilleter_thingy/thingy/run.py +334 -0
  55. skilleter_thingy/thingy/tfm_pane.py +595 -0
  56. skilleter_thingy/thingy/tidy.py +160 -0
  57. skilleter_thingy/trimpath.py +84 -0
  58. skilleter_thingy/window_rename.py +92 -0
  59. skilleter_thingy/xchmod.py +125 -0
  60. skilleter_thingy/yamlcheck.py +89 -0
  61. {skilleter_thingy-0.0.40.dist-info → skilleter_thingy-0.0.41.dist-info}/METADATA +1 -1
  62. skilleter_thingy-0.0.41.dist-info/RECORD +66 -0
  63. skilleter_thingy-0.0.41.dist-info/top_level.txt +1 -0
  64. skilleter_thingy-0.0.40.dist-info/RECORD +0 -6
  65. skilleter_thingy-0.0.40.dist-info/top_level.txt +0 -1
  66. {skilleter_thingy-0.0.40.dist-info → skilleter_thingy-0.0.41.dist-info}/LICENSE +0 -0
  67. {skilleter_thingy-0.0.40.dist-info → skilleter_thingy-0.0.41.dist-info}/WHEEL +0 -0
  68. {skilleter_thingy-0.0.40.dist-info → skilleter_thingy-0.0.41.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,221 @@
1
+ """ Default dircolors data, and the reference .dircolors file.
2
+ Generated from dircolors in GNU coreutils version 8.31 """
3
+
4
+ __all__ = ['DEFAULT_DIRCOLORS', 'DEFAULT_LS_COLORS']
5
+
6
+ # the output of `dircolors -p`
7
+ DEFAULT_DIRCOLORS = r"""
8
+ # Configuration file for dircolors, a utility to help you set the
9
+ # LS_COLORS environment variable used by GNU ls with the --color option.
10
+ # Copyright (C) 1996-2019 Free Software Foundation, Inc.
11
+ # Copying and distribution of this file, with or without modification,
12
+ # are permitted provided the copyright notice and this notice are preserved.
13
+ # The keywords COLOR, OPTIONS, and EIGHTBIT (honored by the
14
+ # slackware version of dircolors) are recognized but ignored.
15
+ # Below are TERM entries, which can be a glob patterns, to match
16
+ # against the TERM environment variable to determine if it is colorizable.
17
+ TERM Eterm
18
+ TERM ansi
19
+ TERM *color*
20
+ TERM con[0-9]*x[0-9]*
21
+ TERM cons25
22
+ TERM console
23
+ TERM cygwin
24
+ TERM dtterm
25
+ TERM gnome
26
+ TERM hurd
27
+ TERM jfbterm
28
+ TERM konsole
29
+ TERM kterm
30
+ TERM linux
31
+ TERM linux-c
32
+ TERM mlterm
33
+ TERM putty
34
+ TERM rxvt*
35
+ TERM screen*
36
+ TERM st
37
+ TERM terminator
38
+ TERM tmux*
39
+ TERM vt100
40
+ TERM xterm*
41
+ # Below are the color init strings for the basic file types.
42
+ # One can use codes for 256 or more colors supported by modern terminals.
43
+ # The default color codes use the capabilities of an 8 color terminal
44
+ # with some additional attributes as per the following codes:
45
+ # Attribute codes:
46
+ # 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed
47
+ # Text color codes:
48
+ # 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white
49
+ # Background color codes:
50
+ # 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white
51
+ #NORMAL 00 # no color code at all
52
+ #FILE 00 # regular file: use no color at all
53
+ RESET 0 # reset to "normal" color
54
+ DIR 01;34 # directory
55
+ LINK 01;36 # symbolic link. (If you set this to 'target' instead of a
56
+ # numerical value, the color is as for the file pointed to.)
57
+ MULTIHARDLINK 00 # regular file with more than one link
58
+ FIFO 40;33 # pipe
59
+ SOCK 01;35 # socket
60
+ DOOR 01;35 # door
61
+ BLK 40;33;01 # block device driver
62
+ CHR 40;33;01 # character device driver
63
+ ORPHAN 40;31;01 # symlink to nonexistent file, or non-stat'able file ...
64
+ MISSING 00 # ... and the files they point to
65
+ SETUID 37;41 # file that is setuid (u+s)
66
+ SETGID 30;43 # file that is setgid (g+s)
67
+ CAPABILITY 30;41 # file with capability
68
+ STICKY_OTHER_WRITABLE 30;42 # dir that is sticky and other-writable (+t,o+w)
69
+ OTHER_WRITABLE 34;42 # dir that is other-writable (o+w) and not sticky
70
+ STICKY 37;44 # dir with the sticky bit set (+t) and not other-writable
71
+ # This is for files with execute permission:
72
+ EXEC 01;32
73
+ # List any file extensions like '.gz' or '.tar' that you would like ls
74
+ # to colorize below. Put the extension, a space, and the color init string.
75
+ # (and any comments you want to add after a '#')
76
+ # If you use DOS-style suffixes, you may want to uncomment the following:
77
+ #.cmd 01;32 # executables (bright green)
78
+ #.exe 01;32
79
+ #.com 01;32
80
+ #.btm 01;32
81
+ #.bat 01;32
82
+ # Or if you want to colorize scripts even if they do not have the
83
+ # executable bit actually set.
84
+ #.sh 01;32
85
+ #.csh 01;32
86
+ # archives or compressed (bright red)
87
+ .tar 01;31
88
+ .tgz 01;31
89
+ .arc 01;31
90
+ .arj 01;31
91
+ .taz 01;31
92
+ .lha 01;31
93
+ .lz4 01;31
94
+ .lzh 01;31
95
+ .lzma 01;31
96
+ .tlz 01;31
97
+ .txz 01;31
98
+ .tzo 01;31
99
+ .t7z 01;31
100
+ .zip 01;31
101
+ .z 01;31
102
+ .dz 01;31
103
+ .gz 01;31
104
+ .lrz 01;31
105
+ .lz 01;31
106
+ .lzo 01;31
107
+ .xz 01;31
108
+ .zst 01;31
109
+ .tzst 01;31
110
+ .bz2 01;31
111
+ .bz 01;31
112
+ .tbz 01;31
113
+ .tbz2 01;31
114
+ .tz 01;31
115
+ .deb 01;31
116
+ .rpm 01;31
117
+ .jar 01;31
118
+ .war 01;31
119
+ .ear 01;31
120
+ .sar 01;31
121
+ .rar 01;31
122
+ .alz 01;31
123
+ .ace 01;31
124
+ .zoo 01;31
125
+ .cpio 01;31
126
+ .7z 01;31
127
+ .rz 01;31
128
+ .cab 01;31
129
+ .wim 01;31
130
+ .swm 01;31
131
+ .dwm 01;31
132
+ .esd 01;31
133
+ # image formats
134
+ .jpg 01;35
135
+ .jpeg 01;35
136
+ .mjpg 01;35
137
+ .mjpeg 01;35
138
+ .gif 01;35
139
+ .bmp 01;35
140
+ .pbm 01;35
141
+ .pgm 01;35
142
+ .ppm 01;35
143
+ .tga 01;35
144
+ .xbm 01;35
145
+ .xpm 01;35
146
+ .tif 01;35
147
+ .tiff 01;35
148
+ .png 01;35
149
+ .svg 01;35
150
+ .svgz 01;35
151
+ .mng 01;35
152
+ .pcx 01;35
153
+ .mov 01;35
154
+ .mpg 01;35
155
+ .mpeg 01;35
156
+ .m2v 01;35
157
+ .mkv 01;35
158
+ .webm 01;35
159
+ .ogm 01;35
160
+ .mp4 01;35
161
+ .m4v 01;35
162
+ .mp4v 01;35
163
+ .vob 01;35
164
+ .qt 01;35
165
+ .nuv 01;35
166
+ .wmv 01;35
167
+ .asf 01;35
168
+ .rm 01;35
169
+ .rmvb 01;35
170
+ .flc 01;35
171
+ .avi 01;35
172
+ .fli 01;35
173
+ .flv 01;35
174
+ .gl 01;35
175
+ .dl 01;35
176
+ .xcf 01;35
177
+ .xwd 01;35
178
+ .yuv 01;35
179
+ .cgm 01;35
180
+ .emf 01;35
181
+ # https://wiki.xiph.org/MIME_Types_and_File_Extensions
182
+ .ogv 01;35
183
+ .ogx 01;35
184
+ # audio formats
185
+ .aac 00;36
186
+ .au 00;36
187
+ .flac 00;36
188
+ .m4a 00;36
189
+ .mid 00;36
190
+ .midi 00;36
191
+ .mka 00;36
192
+ .mp3 00;36
193
+ .mpc 00;36
194
+ .ogg 00;36
195
+ .ra 00;36
196
+ .wav 00;36
197
+ # https://wiki.xiph.org/MIME_Types_and_File_Extensions
198
+ .oga 00;36
199
+ .opus 00;36
200
+ .spx 00;36
201
+ .xspf 00;36
202
+ """
203
+
204
+ # the above converted to LS_COLORS by dircolors, but with the trailing ':' stripped
205
+ DEFAULT_LS_COLORS = r"""
206
+ rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:
207
+ mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:
208
+ *.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:
209
+ *.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:
210
+ *.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:
211
+ *.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:
212
+ *.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:
213
+ *.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:
214
+ *.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:
215
+ *.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:
216
+ *.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:
217
+ *.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:
218
+ *.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:
219
+ *.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:
220
+ *.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:
221
+ *.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36""".replace('\n', '')
@@ -0,0 +1,50 @@
1
+ # private utility functions for pydircolors
2
+ #
3
+ # Copyright 2019 Allen Wild <allenwild93@gmail.com>
4
+ # SPDX-License-Identifier: Apache-2.0
5
+
6
+ """ private/internal utility functions for pydircolors """
7
+
8
+ import os
9
+
10
+ __all__ = ['stat_at', 'readlink_at']
11
+
12
+ def stat_at(file, cwd=None, follow_symlinks=False):
13
+ """ helper function to call os.stat on a file relative to a given directory.
14
+ cwd should be a string, and will be opened as read-only (then closed), or an integer
15
+ for an already-open directory file descriptor (which won't be closed).
16
+ os.open or os.stat may raise various errors, which are passed on. """
17
+ if isinstance(cwd, str):
18
+ dirfd = os.open(cwd, os.O_RDONLY)
19
+ need_to_close = True
20
+ elif cwd is None or isinstance(cwd, int):
21
+ dirfd = cwd
22
+ need_to_close = False
23
+ else:
24
+ raise ValueError('cwd must be str, int, or None')
25
+
26
+ try:
27
+ return os.stat(file, dir_fd=dirfd, follow_symlinks=follow_symlinks)
28
+ finally:
29
+ if need_to_close:
30
+ os.close(dirfd)
31
+
32
+ def readlink_at(file, cwd=None):
33
+ """ helper function to call os.readlink on a file relative to a given directory.
34
+ cwd should be a string, and will be opened as read-only (then closed), or an integer
35
+ for an already-open directory file descriptor (which won't be closed).
36
+ os.open or os.readlink may raise various errors, which are passed on. """
37
+ if isinstance(cwd, str):
38
+ dirfd = os.open(cwd, os.O_RDONLY)
39
+ need_to_close = True
40
+ elif cwd is None or isinstance(cwd, int):
41
+ dirfd = cwd
42
+ need_to_close = False
43
+ else:
44
+ raise ValueError('cwd must be str, int, or None')
45
+
46
+ try:
47
+ return os.readlink(file, dir_fd=dirfd)
48
+ finally:
49
+ if need_to_close:
50
+ os.close(dirfd)
@@ -0,0 +1,308 @@
1
+ # Dircolors, a Python library for colorizing and formatting filenames like GNU Coreutils'
2
+ # ls and dircolors programs.
3
+ # Requires python 3.3 or later
4
+ #
5
+ # Copyright 2019 Allen Wild <allenwild93@gmail.com>
6
+ # Modifications copyright 2020 John Skilleter <john@skilleter.org.uk>
7
+ # SPDX-License-Identifier: Apache-2.0
8
+
9
+ """ dircolors, a Python library to colorize filenames based on their type
10
+ for terminal use, like GNU ls and dircolors. """
11
+
12
+ from collections import OrderedDict
13
+ from io import StringIO, TextIOBase
14
+ import os
15
+ import stat
16
+
17
+ import thingy.dc_defaults as dc_defaults
18
+ import thingy.dc_util as dc_util
19
+
20
+ __all__ = ['Dircolors']
21
+
22
+ _CODE_MAP = OrderedDict()
23
+ def _init_code_map():
24
+ """ mapping between the key name in the .dircolors file and the two letter
25
+ code found in the LS_COLORS environment variable.
26
+ Used for parsing .dircolors files. """
27
+ # This code is wrapped in a function so we can disable pylint's whitespace check
28
+ # on a limited scope.
29
+ # pylint: disable=bad-whitespace
30
+ _CODE_MAP['RESET'] = 'rs'
31
+ _CODE_MAP['DIR'] = 'di'
32
+ _CODE_MAP['LINK'] = 'ln'
33
+ _CODE_MAP['MULTIHARDLINK'] = 'mh'
34
+ _CODE_MAP['FIFO'] = 'pi'
35
+ _CODE_MAP['SOCK'] = 'so'
36
+ _CODE_MAP['DOOR'] = 'do'
37
+ _CODE_MAP['BLK'] = 'bd'
38
+ _CODE_MAP['CHR'] = 'cd'
39
+ _CODE_MAP['ORPHAN'] = 'or'
40
+ _CODE_MAP['MISSING'] = 'mi'
41
+ _CODE_MAP['SETUID'] = 'su'
42
+ _CODE_MAP['SETGID'] = 'sg'
43
+ _CODE_MAP['CAPABILITY'] = 'ca'
44
+ _CODE_MAP['STICKY_OTHER_WRITABLE'] = 'tw'
45
+ _CODE_MAP['OTHER_WRITABLE'] = 'ow'
46
+ _CODE_MAP['STICKY'] = 'st'
47
+ _CODE_MAP['EXEC'] = 'ex'
48
+
49
+ _init_code_map()
50
+ del _init_code_map
51
+
52
+ class Dircolors:
53
+ """ Main dircolors class. Contains a database of formats corresponding to file types,
54
+ modes, and extensions. Use the format() method to check a file and color it appropriately.
55
+ """
56
+ def __init__(self, load=True):
57
+ """ Initialize a Dircolors object. If load=True (the default), then try
58
+ to load dircolors info from the LS_COLORS environment variable.
59
+ If no data is obtained from LS_COLORS, load the defaults.
60
+ If load=False, don't even load defaults. """
61
+ self._loaded = False
62
+ self._codes = OrderedDict()
63
+ self._extensions = OrderedDict()
64
+ if load:
65
+ if not self.load_from_environ():
66
+ self.load_defaults()
67
+
68
+ def __bool__(self):
69
+ """ convenience method for checking whether this Dircolors object has loaded a database.
70
+ Can be used like
71
+ d = Dircolors()
72
+ if d:
73
+ d.format(somefile)
74
+ """
75
+ return self._loaded
76
+
77
+ @property
78
+ def loaded(self):
79
+ """ return a boolean indicating whether some valid dircolors data has been loaded """
80
+ return self._loaded
81
+
82
+ def clear(self):
83
+ """ Clear the loaded data """
84
+ self._loaded = False
85
+ self._codes.clear()
86
+ self._extensions.clear()
87
+
88
+ def load_from_lscolors(self, lscolors):
89
+ """ Load the dircolors database from a string in the same format as the LS_COLORS
90
+ environment variable.
91
+ Returns True if data was successfully loaded, False otherwise (e.g. if
92
+ envvar is unset). Regardless, the current database will be cleared """
93
+ self.clear()
94
+ if not lscolors:
95
+ return False
96
+
97
+ for item in lscolors.split(':'):
98
+ try:
99
+ code, color = item.split('=', 1)
100
+ except ValueError:
101
+ continue # no key=value, just ignore
102
+ if code.startswith('*.'):
103
+ self._extensions[code[1:]] = color
104
+ else:
105
+ self._codes[code] = color
106
+
107
+ if self._codes or self._extensions:
108
+ self._loaded = True
109
+ return self._loaded
110
+
111
+ def load_from_environ(self, envvar='LS_COLORS'):
112
+ """ Load the dircolors database from an environment variable. By default,
113
+ use LS_COLORS like the GNU Coreutils `ls` program.
114
+ Returns True if data was successfully loaded, False otherwise (e.g. if
115
+ envvar is unset). Regardless, the current database will be cleared. """
116
+ return self.load_from_lscolors(os.environ.get(envvar))
117
+
118
+ def load_from_dircolors(self, database, strict=False):
119
+ """ Load the dircolors database from a GNU-compatible .dircolors file.
120
+ May raise any of the usual OSError exceptions if filename doesn't exist
121
+ or otherwise can't be read.
122
+
123
+ database can be a string representing a filename, or a file-like object
124
+ opened in text mode (i.e. a subclass of io.TextIOBase). To load from the
125
+ contents of a .dircolors file, wrap it in an io.StringIO object.
126
+
127
+ If strict is True, raise ValueError on the first unparsed line
128
+
129
+ Returns a boolean indicating whether any data was loaded.
130
+ The current database will always be cleared. """
131
+ self.clear()
132
+ if isinstance(database, str):
133
+ file = open(database, 'r')
134
+ elif isinstance(database, TextIOBase):
135
+ file = database
136
+ else:
137
+ raise ValueError('database must be str or io.TextIOBase, not %s'%type(database))
138
+
139
+ try:
140
+ for line in file:
141
+ # remove comments and skip empty lines
142
+ line = line.split('#')[0].strip()
143
+ if not line:
144
+ continue
145
+
146
+ # make sure there's two space-separated fields
147
+ split = line.split()
148
+ if len(split) != 2:
149
+ if strict:
150
+ raise ValueError('Warning: unable to parse dircolors line "%s"'%line)
151
+ continue
152
+
153
+ key, val = split
154
+ if key == 'TERM':
155
+ continue # ignore TERM directives
156
+ elif key in _CODE_MAP:
157
+ self._codes[_CODE_MAP[key]] = val
158
+ elif key.startswith('.'):
159
+ self._extensions[key] = val
160
+ elif strict:
161
+ raise ValueError('Warning: unable to parse dircolors line "%s"'%line)
162
+ # elif not strict, skip
163
+
164
+ if self._codes or self._extensions:
165
+ self._loaded = True
166
+ return self._loaded
167
+ finally:
168
+ file.close()
169
+
170
+ def load_defaults(self):
171
+ """ Load the default database. """
172
+ self.clear()
173
+ return self.load_from_dircolors(StringIO(dc_defaults.DEFAULT_DIRCOLORS), True)
174
+
175
+ def generate_lscolors(self):
176
+ """ Output the database in the format used by the LS_COLORS environment variable. """
177
+ if not self._loaded:
178
+ return ''
179
+
180
+ def gen_pairs():
181
+ for pair in self._codes.items():
182
+ yield pair
183
+ for pair in self._extensions.items():
184
+ # change .xyz to *.xyz
185
+ yield '*' + pair[0], pair[1]
186
+
187
+ return ':'.join('%s=%s'%pair for pair in gen_pairs())
188
+
189
+ def _format_code(self, text, code):
190
+ """ format text with an lscolors code. Return text unmodified if code
191
+ isn't found in the database """
192
+ val = self._codes.get(code, None)
193
+ if val:
194
+ return '\033[%sm%s\033[%sm'%(val, text, self._codes.get('rs', '0'))
195
+ return text
196
+
197
+ def _format_ext(self, text, ext):
198
+ """ Format text according to the given file extension.
199
+ ext must have a leading '.'
200
+ text need not actually end in '.ext' """
201
+ val = self._extensions.get(ext, '0')
202
+ if val:
203
+ return '\033[%sm%s\033[%sm'%(val, text, self._codes.get('rs', '0'))
204
+ return text
205
+
206
+ def format_mode(self, text, mode):
207
+ """ Format and color the given text based on the given file mode.
208
+
209
+ `mode` can be an integer, usually the st_mode field of an os.stat_result
210
+ object obtained from os.stat() or similar function. It can also be an os.stat_result
211
+ object, and the st_mode field will be extracted automatically.
212
+
213
+ If mode is zero then the formatting is performed only according to the filename.
214
+
215
+ `text` is an arbitrary string which will be colored according to the bits
216
+ set in `mode` and the colors database loaded in this Dircolors object.
217
+
218
+ If `mode` represents a symlink, it will be formatted as such with no dereferencing
219
+ (since this function doesn't know the file name) """
220
+ if not self._loaded:
221
+ return text
222
+
223
+ if isinstance(mode, int):
224
+ pass
225
+ elif isinstance(mode, os.stat_result):
226
+ mode = mode.st_mode
227
+ else:
228
+ raise ValueError('mode must be int or os.stat_result, not %s'%type(mode))
229
+
230
+ if mode:
231
+ if stat.S_ISDIR(mode):
232
+ if (mode & (stat.S_ISVTX | stat.S_IWOTH)) == (stat.S_ISVTX | stat.S_IWOTH):
233
+ # sticky and world-writable
234
+ return self._format_code(text, 'tw')
235
+ if mode & stat.S_ISVTX:
236
+ # sticky but not world-writable
237
+ return self._format_code(text, 'st')
238
+ if mode & stat.S_IWOTH:
239
+ # world-writable but not sticky
240
+ return self._format_code(text, 'ow')
241
+ # normal directory
242
+ return self._format_code(text, 'di')
243
+
244
+ # special file?
245
+ # pylint: disable=bad-whitespace
246
+ special_types = (
247
+ (stat.S_IFLNK, 'ln'), # symlink
248
+ (stat.S_IFIFO, 'pi'), # pipe (FIFO)
249
+ (stat.S_IFSOCK, 'so'), # socket
250
+ (stat.S_IFBLK, 'bd'), # block device
251
+ (stat.S_IFCHR, 'cd'), # character device
252
+ (stat.S_ISUID, 'su'), # setuid
253
+ (stat.S_ISGID, 'sg'), # setgid
254
+ )
255
+
256
+ for mask, code in special_types:
257
+ if (mode & mask) == mask:
258
+ return self._format_code(text, code)
259
+
260
+ # executable file?
261
+ if mode & (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH):
262
+ return self._format_code(text, 'ex')
263
+
264
+ # regular file, format according to its extension
265
+ _, ext = os.path.splitext(text)
266
+ if ext:
267
+ return self._format_ext(text, ext)
268
+ return text
269
+
270
+ def format(self, file, cwd=None, follow_symlinks=False, show_target=False):
271
+ """ Format and color the file given by the name `file`.
272
+
273
+ If `cwd` is not None, it should be a string for the directory relative
274
+ to which `file` is looked up, or an integer representing a directory
275
+ descriptor (usually from `os.open()`).
276
+
277
+ If the file does not exist, it is formatted according to the filename only.
278
+
279
+ Use follow_symlinks to dereference symlinks entirely.
280
+ Use show_target=True with follow_symlinks=False to format both the link name
281
+ and its target in the format:
282
+ linkname -> target
283
+ With linkname formatted as a link color, and the link target formatted as its respective
284
+ type. If the link target is another link, it will not be recursively dereferenced. """
285
+
286
+ if not self.loaded:
287
+ return file
288
+
289
+ if os.path.exists(file):
290
+ try:
291
+ statbuf = dc_util.stat_at(file, cwd, follow_symlinks)
292
+ except OSError as e:
293
+ return '%s [Error stat-ing: %s]'%(file, e.strerror)
294
+
295
+ mode = statbuf.st_mode
296
+ if (not follow_symlinks) and show_target and stat.S_ISLNK(mode):
297
+ target_path = dc_util.readlink_at(file, cwd)
298
+ try:
299
+ dc_util.stat_at(target_path, cwd) # check for broken link
300
+ target = self.format(target_path, cwd, False, False)
301
+ except OSError:
302
+ # format as "orphan"
303
+ target = self._format_code(target_path, 'or') + ' [broken link]'
304
+ return self._format_code(file, 'ln') + ' -> ' + target
305
+ else:
306
+ mode = 0
307
+
308
+ return self.format_mode(file, mode)
@@ -0,0 +1,95 @@
1
+ #! /usr/bin/env python3
2
+
3
+ ################################################################################
4
+ """ Docker interface for Thingy
5
+
6
+ Copyright (C) 2017 John Skilleter
7
+
8
+ Note that this:
9
+ * Only implements functions required by docker-purge
10
+ * Only has basic error checking, in that it raises DockerError
11
+ for any error returned by the external docker command.
12
+ """
13
+ ################################################################################
14
+
15
+ # TODO: Convert to use thingy.proc
16
+ import thingy.process as process
17
+
18
+ ################################################################################
19
+
20
+ class DockerError(Exception):
21
+ """ Exception for dockery things """
22
+
23
+ pass
24
+
25
+ ################################################################################
26
+
27
+ def instances(all=False):
28
+ """ Return a list of all current Docker instances """
29
+
30
+ cmd = ['docker', 'ps', '-q']
31
+
32
+ if all:
33
+ cmd.append('-a')
34
+
35
+ try:
36
+ for result in process.run(cmd):
37
+ yield result
38
+ except process.RunError as exc:
39
+ raise DockerError(exc)
40
+
41
+ ################################################################################
42
+
43
+ def stop(instance, force=False):
44
+ """ Stop the specified Docker instance """
45
+
46
+ # TODO: force option not implemented
47
+
48
+ try:
49
+ process.run(['docker', 'stop', instance])
50
+ except process.RunError as exc:
51
+ raise DockerError(exc)
52
+
53
+ ################################################################################
54
+
55
+ def rm(instance, force=False):
56
+ """ Remove the specified instance """
57
+
58
+ cmd = ['docker', 'rm']
59
+
60
+ if force:
61
+ cmd.append('--force')
62
+
63
+ cmd.append(instance)
64
+
65
+ try:
66
+ process.run(cmd)
67
+ except process.RunError as exc:
68
+ raise DockerError(exc)
69
+
70
+ ################################################################################
71
+
72
+ def images():
73
+ """ Return a list of all current Docker images """
74
+
75
+ try:
76
+ for result in process.run(['docker', 'images', '-q']):
77
+ yield result
78
+ except process.RunError as exc:
79
+ raise DockerError(exc)
80
+
81
+ ################################################################################
82
+
83
+ def rmi(image, force=False):
84
+ """ Remove the specified image """
85
+
86
+ cmd = ['docker', 'rmi']
87
+ if force:
88
+ cmd.append('--force')
89
+
90
+ cmd.append(image)
91
+
92
+ try:
93
+ process.run(cmd)
94
+ except process.RunError as exc:
95
+ raise DockerError(exc)