Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# -*- coding: utf-8 -*- 

2# This file is part of Xpra. 

3# Copyright (C) 2015-2020 Antoine Martin <antoine@xpra.org> 

4# Xpra is released under the terms of the GNU GPL v2, or, at your option, any 

5# later version. See the file COPYING for details. 

6 

7from xpra.log import Logger 

8from xpra.util import csv, engs 

9 

10log = Logger("util", "command") 

11 

12 

13class ControlError(Exception): 

14 

15 def __init__(self, msg, help_text=None, code=127): 

16 super().__init__(msg) 

17 self.help = help_text 

18 self.code = code 

19 

20 

21class ControlCommand: 

22 """ Utility superclass for control commands """ 

23 

24 def __init__(self, name, help_text=None, run=None): 

25 self.name = name 

26 self.help = help_text 

27 if run: 

28 self.do_run = run 

29 

30 def run(self, *args): 

31 log("%s.run: calling %s%s", self, self.do_run, args) 

32 return self.do_run(*args) 

33 

34 def do_run(self, *args): 

35 raise NotImplementedError("control command %s undefined!" % self.name) 

36 

37 def raise_error(self, msg): 

38 raise ControlError(msg, self.help) 

39 

40 def __repr__(self): 

41 return "ControlCommand(%s)" % self.name 

42 

43 

44class ArgsControlCommand(ControlCommand): 

45 """ Adds very basic argument validation """ 

46 def __init__(self, name, help_text=None, run=None, validation=(), min_args=None, max_args=None): 

47 super().__init__(name, help_text, run) 

48 self.validation = validation 

49 self.min_args = min_args 

50 self.max_args = max_args 

51 

52 def run(self, *args): 

53 if self.min_args is not None and len(args)<self.min_args: 

54 self.raise_error("at least %i argument%s required" % (self.min_args, engs(self.min_args))) 

55 if self.max_args is not None and len(args)>self.max_args: 

56 self.raise_error("too many arguments, %i maximum" % self.max_args) 

57 args = list(args) 

58 for i,validation in enumerate(self.validation): 

59 if i>=len(args): 

60 #argument not supplied 

61 continue 

62 v = args[i] 

63 log("running '%s' validation for argument %i: %s (value=%s, type=%s)", self.name, i, validation, v, type(v)) 

64 if not validation: 

65 continue 

66 try: 

67 args[i] = validation(v) 

68 except ValueError as e: 

69 self.raise_error("argument %i failed validation: %s" % (i+1, e)) 

70 return super().run(*args) 

71 

72 def do_run(self): 

73 raise NotImplementedError() 

74 

75 

76class FixedMessageCommand(ControlCommand): 

77 """ A control command that returns a fixed message """ 

78 def __init__(self, name, message, help_text=None): 

79 super().__init__(name, help_text) 

80 self.message = message 

81 

82 def run(self, *_args): 

83 return self.message 

84 

85 

86class HelloCommand(FixedMessageCommand): 

87 """ Just says hello """ 

88 

89 def __init__(self): 

90 super().__init__("hello", "hello", "just says hello back") 

91 

92 

93class HelpCommand(ArgsControlCommand): 

94 """ The help command looks at the 'help' definition of other commands """ 

95 def __init__(self, control_commands): 

96 super().__init__("help", max_args=1) 

97 self.control_commands = control_commands 

98 

99 def run(self, *args): 

100 if len(args)==0: 

101 return "control supports: %s" % csv(self.control_commands) 

102 name = args[0] 

103 command = self.control_commands.get(name) 

104 if not command: 

105 self.raise_error("unknown command '%s'" % name) 

106 if not command.help: 

107 return "sorry, no help message available for '%s'" % name 

108 return "control command '%s': %s" % (name, command.help) 

109 

110 

111class DebugControl(ArgsControlCommand): 

112 def __init__(self): 

113 super().__init__("debug", 

114 "usage: 'debug enable category', 'debug disable category', 'debug status' or 'debug mark'", 

115 min_args=1) 

116 

117 def run(self, *args): 

118 if len(args)==1 and args[0]=="status": 

119 from xpra.log import get_all_loggers 

120 return "logging is enabled for: %s" % str(list([str(x) for x in get_all_loggers() if x.is_debug_enabled()])) 

121 log_cmd = args[0] 

122 if log_cmd=="mark": 

123 for _ in range(10): 

124 log.info("*"*80) 

125 if len(args)>1: 

126 log.info("mark: %s", " ".join(args[1:])) 

127 else: 

128 log.info("mark") 

129 for _ in range(10): 

130 log.info("*"*80) 

131 return "mark inserted into logfile" 

132 if len(args)<2: 

133 self.raise_error("not enough arguments") 

134 if log_cmd not in ("enable", "disable"): 

135 self.raise_error("only 'enable' and 'disable' verbs are supported") 

136 from xpra.log import add_debug_category, add_disabled_category, enable_debug_for, disable_debug_for 

137 #each argument is a group 

138 loggers = [] 

139 groups = args[1:] 

140 for group in groups: 

141 #and each group is a list of categories 

142 #preferably separated by "+", 

143 #but we support "," for backwards compatibility: 

144 categories = [v.strip() for v in group.replace("+", ",").split(",")] 

145 if log_cmd=="enable": 

146 add_debug_category(*categories) 

147 loggers += enable_debug_for(*categories) 

148 else: 

149 assert log_cmd=="disable" 

150 add_disabled_category(*categories) 

151 loggers += disable_debug_for(*categories) 

152 if not loggers: 

153 log.info("%s debugging, no new loggers matching: %s", log_cmd, csv(groups)) 

154 else: 

155 log.info("%sd debugging for:", log_cmd) 

156 for l in loggers: 

157 log.info(" - %s", l) 

158 return "logging %sd for %s" % (log_cmd, csv(loggers))