1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 """
22 CLI results display class
23 """
24
25 import difflib
26 import sys
27
28 from ClusterShell.NodeSet import NodeSet
29
30
31 VERB_QUIET = 0
32 VERB_STD = 1
33 VERB_VERB = 2
34 VERB_DEBUG = 3
35 THREE_CHOICES = ["never", "always", "auto"]
36 WHENCOLOR_CHOICES = THREE_CHOICES
37
38
40 """
41 Output display class for command line scripts.
42 """
43 COLOR_RESULT_FMT = "\033[32m%s\033[0m"
44 COLOR_STDOUT_FMT = "\033[34m%s\033[0m"
45 COLOR_STDERR_FMT = "\033[31m%s\033[0m"
46 COLOR_DIFFHDR_FMT = "\033[1m%s\033[0m"
47 COLOR_DIFFHNK_FMT = "\033[36m%s\033[0m"
48 COLOR_DIFFADD_FMT = "\033[32m%s\033[0m"
49 COLOR_DIFFDEL_FMT = "\033[31m%s\033[0m"
50 SEP = "-" * 15
51
53 """Private NodeSet substition to display raw keys"""
56
57 - def __init__(self, options, config=None, color=None):
58 """Initialize a Display object from CLI.OptionParser options
59 and optional CLI.ClushConfig.
60
61 If `color' boolean flag is not specified, it is auto detected
62 according to options.whencolor.
63 """
64 if options.diff:
65 self._print_buffer = self._print_diff
66 else:
67 self._print_buffer = self._print_content
68 self._display = self._print_buffer
69 self._diffref = None
70
71 self.gather = options.gatherall or options.gather or options.diff
72 self.progress = getattr(options, 'progress', False)
73
74 if options.diff and options.line_mode:
75 raise ValueError("diff not supported in line_mode")
76 self.line_mode = options.line_mode
77 self.label = options.label
78 self.regroup = options.regroup
79 self.groupsource = options.groupsource
80 self.noprefix = options.groupbase
81
82 self.maxrc = getattr(options, 'maxrc', False)
83
84 if color is None:
85
86 color = False
87 if not options.whencolor or options.whencolor == "auto":
88 color = sys.stdout.isatty()
89 elif options.whencolor == "always":
90 color = True
91
92 self._color = color
93
94 self.out = sys.stdout
95 self.err = sys.stderr
96 if self._color:
97 self.color_stdout_fmt = self.COLOR_STDOUT_FMT
98 self.color_stderr_fmt = self.COLOR_STDERR_FMT
99 self.color_diffhdr_fmt = self.COLOR_DIFFHDR_FMT
100 self.color_diffctx_fmt = self.COLOR_DIFFHNK_FMT
101 self.color_diffadd_fmt = self.COLOR_DIFFADD_FMT
102 self.color_diffdel_fmt = self.COLOR_DIFFDEL_FMT
103 else:
104 self.color_stdout_fmt = self.color_stderr_fmt = \
105 self.color_diffhdr_fmt = self.color_diffctx_fmt = \
106 self.color_diffadd_fmt = self.color_diffdel_fmt = "%s"
107
108
109 if config:
110
111 self.node_count = config.node_count
112 self.verbosity = config.verbosity
113 else:
114 self.node_count = True
115 self.verbosity = VERB_STD
116 if hasattr(options, 'quiet') and options.quiet:
117 self.verbosity = VERB_QUIET
118 if hasattr(options, 'verbose') and options.verbose:
119 self.verbosity = VERB_VERB
120 if hasattr(options, 'debug') and options.debug:
121 self.verbosity = VERB_DEBUG
122
124 """flush display object buffers"""
125
126 self._diffref = None
127
129 """line_mode getter"""
130 return self._display == self._print_lines
131
133 """line_mode setter"""
134 if value:
135 self._display = self._print_lines
136 else:
137 self._display = self._print_buffer
138 line_mode = property(_getlmode, _setlmode)
139
145
158
160 """Display a line with optional label."""
161 if self.label:
162 prefix = self.color_stdout_fmt % ("%s: " % nodeset)
163 self.out.write("%s%s\n" % (prefix, line))
164 else:
165 self.out.write("%s\n" % line)
166
168 """Display an error line with optional label."""
169 if self.label:
170 prefix = self.color_stderr_fmt % ("%s: " % nodeset)
171 self.err.write("%s%s\n" % (prefix, line))
172 else:
173 self.err.write("%s\n" % line)
174
176 """Generic method for displaying nodeset/content according to current
177 object settings."""
178 return self._display(NodeSet(nodeset), obj)
179
181 """Finalize display of diff-like gathered contents."""
182 if self._display == self._print_diff and self._diffref:
183 return self._display(nodeset, '')
184
186 """Generic method for displaying raw keys/content according to current
187 object settings (used by clubak)."""
188 return self._display(self.__class__._KeySet(keys), obj)
189
190 - def _print_content(self, nodeset, content):
191 """Display a dshbak-like header block and content."""
192 self.out.write("%s\n%s\n" % (self.format_header(nodeset), content))
193
195 """Display unified diff between remote gathered outputs."""
196 if self._diffref is None:
197 self._diffref = (nodeset, content)
198 else:
199 nodeset_ref, content_ref = self._diffref
200 nsstr_ref = self._format_nodeset(nodeset_ref)
201 nsstr = self._format_nodeset(nodeset)
202 if self.verbosity >= VERB_STD and self.node_count:
203 if len(nodeset_ref) > 1:
204 nsstr_ref += " (%d)" % len(nodeset_ref)
205 if len(nodeset) > 1:
206 nsstr += " (%d)" % len(nodeset)
207
208 udiff = difflib.unified_diff(list(content_ref), list(content), \
209 fromfile=nsstr_ref, tofile=nsstr, \
210 lineterm='')
211 output = ""
212 for line in udiff:
213 if line.startswith('---') or line.startswith('+++'):
214 output += self.color_diffhdr_fmt % line.rstrip()
215 elif line.startswith('@@'):
216 output += self.color_diffctx_fmt % line
217 elif line.startswith('+'):
218 output += self.color_diffadd_fmt % line
219 elif line.startswith('-'):
220 output += self.color_diffdel_fmt % line
221 else:
222 output += line
223 output += '\n'
224 self.out.write(output)
225
227 """Display a MsgTree buffer by line with prefixed header."""
228 out = self.out
229 if self.label:
230 header = self.color_stdout_fmt % \
231 ("%s: " % self._format_nodeset(nodeset))
232 for line in msg:
233 out.write("%s%s\n" % (header, line))
234 else:
235 for line in msg:
236 out.write(line + '\n')
237
238 - def vprint(self, level, message):
239 """Utility method to print a message if verbose level is high
240 enough."""
241 if self.verbosity >= level:
242 print message
243
245 """Utility method to print a message on stderr if verbose level
246 is high enough."""
247 if self.verbosity >= level:
248 print >> sys.stderr, message
249