############################################################################ # Copyright (C) by gempa GmbH, GFZ Potsdam # # # # You can redistribute and/or modify this program under the # # terms of the SeisComP Public License. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # SeisComP Public License for more details. # ############################################################################ from __future__ import print_function import os import sys import glob # Python version depended string conversion if sys.version_info[0] < 3: py3input = raw_input #pylint: disable=E0602 else: py3input = input def split_tokens(line): return line.split() def convert_wildcard(s): wild = s.split(".") if len(wild) > 2: raise Exception("station selector: only one dot allowed") # Add station wildcard if only network is given if len(wild) == 1: wild.append('*') return '_'.join([x if x else '*' for x in wild]) def convert_stations(s): toks = s.split(".") if len(toks) != 2: raise Exception("station: expected format: NET.STA") return '_'.join(toks) class CLI: """ Simple console shell. """ def __init__(self, env = None): self.env = env def run(self, env): self.env = env sys.stdout.write('''\ %s SeisComP shell %s Welcome to the SeisComP interactive shell. You can get help about available commands with 'help'. 'exit' leaves the shell. ''' % (("="*80), ("="*80))) prompt = "$ " while True: line = py3input(prompt).strip() toks = split_tokens(line) if len(toks) == 0: continue if line in ("exit", "quit"): break self.handleCommand(toks[0], toks[1:]) def handleCommand(self, cmd, args): try: if cmd == "help": return self.commandHelp(args) if cmd == "list": return self.commandList(args) if cmd == "delete": return self.commandDelete(args) if cmd == "print": return self.commandPrint(args) if cmd == "set": return self.commandSet(args) if cmd == "remove": return self.commandRemove(args) raise Exception("Unknown command: %s" % cmd) except Exception as e: sys.stdout.write("%s\n" % str(e)) return False @staticmethod def commandHelp(args): if len(args) == 0: sys.stdout.write("""\ Commands: list stations Lists all available stations keys. list profiles {mod} Lists all available profiles of a module. list modules {sta} Lists all bound modules of a station incl. profiles (if used). delete profile {mod} {profile} Deletes the given profile of given module. If the profile does not exist an error is raised. The module is removed from all stations that are using this profile. delete binding {mod} {sta} Deletes the binding for given module and station. If the station is bound to module mod using a profile the binding is kept, removed otherwise. An existing binding file (etc/key/[mod]/station_[sta]) is deleted in any case. print station {sta} Dumps all set binding parameters for the given station. set profile {mod} {profile} {sta-sel} Sets for all selected stations a binding profile of a module. The resulting station file looks like this: ... mod:profile ... This command checks for the existence of the specified profile set module {mod} {sta-sel} Binds all selected stations to given module. No profiles are used and if any of the stations is already using a profile it is removed. The resulting station key file looks like this: ... mod ... remove profile {mod} {profile} {sta-sel} Removes the binding profile of given module for all selected stations if module is bound already to that station. As a result all selected stations that are bound to the given module already will use a station key file afterwards. mod:profile -> mod remove module {mod} {sta-sel} Unbinds given module from selected stations. The line that refers to the given module is completely removed from the station key files. exit Exit the shell. quit Alias for exit. """) def commandList(self, args): if len(args) == 0: raise Exception("Missing operand") if args[0] == "stations": if len(args) > 2: raise Exception("Too many arguments") if len(args) > 1: wild = convert_wildcard(args[1]) else: wild = "*" stas = [] for f in sorted(glob.glob(os.path.join(self.env.key_dir, "station_" + wild))): stas.append(os.path.basename(f)[8:].replace("_", ".")) for s in stas: print(s) return True if args[0] == "profiles": if len(args) > 2: raise Exception("Too many arguments") if len(args) < 2: raise Exception("Expected: mod") module = args[1] for f in sorted(glob.glob(os.path.join(self.env.key_dir, module, "profile_*"))): print(os.path.basename(f)[8:]) return True if args[0] == "modules": if len(args) > 2: raise Exception("Too many arguments") if len(args) < 2: raise Exception("Expected: sta") sta = convert_stations(args[1]) f = os.path.join(self.env.key_dir, "station_" + sta) if not os.path.exists(f): raise Exception("%s: station key does not exists" % args[1]) for l in [line.strip() for line in open(f, "r").readlines()]: if l.startswith("#"): continue if len(l) == 0: continue print(l) return True raise Exception("Invalid argument: %s" % args[0]) def commandDelete(self, args): if len(args) == 0: raise Exception("Missing operand") if args[0] == "profile": if len(args) > 3: raise Exception("Too many arguments") if len(args) < 3: raise Exception("Expected: mod profile") module = args[1] profile = args[2] if not os.path.exists(os.path.join(self.env.key_dir, module, "profile_" + profile)): raise Exception("%s/%s: profile not found" % (module, profile)) os.remove(os.path.join(self.env.key_dir, module, "profile_" + profile)) modified = 0 for f in glob.glob(os.path.join(self.env.key_dir, "station_*")): lines = [line.strip() for line in open(f, "r").readlines()] new_lines = [] is_modified = False for line in lines: # Comment line if line.startswith("#"): new_lines.append(line) continue # Empty line if not line: new_lines.append(line) continue toks = line.split(':') # Wrong module name if toks[0] != module: new_lines.append(line) continue # Profile found if len(toks) > 1 and toks[1] == profile: # Filter line is_modified = True continue new_lines.append(line) if is_modified: modified += 1 try: open(f, "w").write('\n'.join(new_lines)) except Exception as e: sys.stdout.write("%s: %s\n" % (f, str(e))) sys.stdout.write("OK, %d files modified\n" % modified) return True if args[0] == "binding": if len(args) > 3: raise Exception("Too many arguments") if len(args) < 3: raise Exception("Expected: mod profile") module = args[1] sta = convert_stations(args[2]) if not os.path.exists(os.path.join(self.env.key_dir, module, "station_" + sta)): raise Exception("%s/%s: binding not found" % (module, args[2])) os.remove(os.path.join(self.env.key_dir, module, "station_" + sta)) f = os.path.join(self.env.key_dir, "station_" + sta) try: lines = [line.strip() for line in open(f, "r").readlines()] except OSError: pass new_lines = [] is_modified = False for line in lines: # Comment line if line.startswith("#"): new_lines.append(line) continue # Empty line if len(line) == 0: new_lines.append(line) continue toks = line.split(':') # Wrong module name if toks[0] != module: new_lines.append(line) continue # Profile found if len(toks) == 1: # Filter line is_modified = True continue new_lines.append(line) if is_modified: try: open(f, "w").write('\n'.join(new_lines)) except Exception as e: sys.stdout.write("%s: %s\n" % (f, str(e))) return True raise Exception("Invalid argument: %s" % args[0]) def commandPrint(self, args): if len(args) == 0: raise Exception("Missing operand") if args[0] == "station": if len(args) != 2: raise Exception("missing argument, expected: sta") sta = convert_stations(args[1]) key = os.path.join(self.env.key_dir, "station_" + sta) try: lines = [line.strip() for line in open(key, "r").readlines()] except IOError as e: raise Exception("%s: station not configured" % sta) except Exception as e: raise Exception("%s: unexpected error: %s" % (sta, str(e))) first = True for line in lines: # Comment line if line.startswith("#"): continue # Empty line if len(line) == 0: continue toks = line.split(':') if len(toks) == 1: binding = os.path.join( self.env.key_dir, toks[0], "station_" + sta) else: binding = os.path.join( self.env.key_dir, toks[0], "profile_" + toks[1]) if not first: sys.stdout.write("\n") first = False sys.stdout.write("[%s]\n" % toks[0]) sys.stdout.write("%s\n" % binding) try: data = open(binding).read() sys.stdout.write("-"*80 + "\n") sys.stdout.write(data) sys.stdout.write("-"*80 + "\n") except IOError as e: sys.stdout.write("!binding not found\n") except Exception as e: sys.stdout.write("!unexpected error: %s\n" % str(e)) else: raise Exception("Invalid argument: %s" % args[0]) def commandSet(self, args): if len(args) == 0: raise Exception("Missing operand") if args[0] == "profile": if len(args) != 4: raise Exception( "missing arguments, expected: module profile station-selector") module = args[1] profile = args[2] wild = convert_wildcard(args[3]) if not os.path.exists(os.path.join(self.env.key_dir, module, "profile_" + profile)): raise Exception("%s/%s: profile not found" % (module, profile)) modified = 0 for f in glob.glob(os.path.join(self.env.key_dir, "station_" + wild)): lines = [line.strip() for line in open(f, "r").readlines()] module_found = False is_modified = False for i in range(len(lines)): #pylint: disable=C0200 line = lines[i] # Comment line if line.startswith("#"): continue # Empty line if len(line) == 0: continue toks = line.split(':') # Wrong module name if toks[0] != module: continue module_found = True # No profile if len(toks) == 1: toks.append("") # Profile already set elif toks[1] == profile: continue toks[1] = profile lines[i] = ':'.join(toks) is_modified = True if not module_found: lines.append("%s:%s\n" % (module, profile)) is_modified = True if is_modified: modified += 1 try: open(f, "w").write('\n'.join(lines)) except Exception as e: sys.stdout.write("%s: %s\n" % (f, str(e))) sys.stdout.write("OK, %d files modified\n" % modified) return True if args[0] == "module": if len(args) != 3: raise Exception( "missing arguments, expected: module station-selector") module = args[1] wild = convert_wildcard(args[2]) modified = 0 for f in glob.glob(os.path.join(self.env.key_dir, "station_" + wild)): lines = [line.strip() for line in open(f, "r").readlines()] module_found = False is_modified = False for i in range(len(lines)): #pylint: disable=C0200 line = lines[i] # Comment line if line.startswith("#"): continue # Empty line if len(line) == 0: continue toks = line.split(':') # Wrong module name if toks[0] != module: continue module_found = True lines[i] = module is_modified = True if not module_found: lines.append("%s\n" % module) is_modified = True if is_modified: modified += 1 try: open(f, "w").write('\n'.join(lines)) except Exception as e: sys.stdout.write("%s: %s\n" % (f, str(e))) sys.stdout.write("OK, %d files modified\n" % modified) return True raise Exception("Invalid argument: %s" % args[0]) def commandRemove(self, args): if len(args) == 0: raise Exception("Missing operand") if args[0] == "profile": if len(args) != 4: raise Exception( "Missing arguments, expected: module profile station-selector") module = args[1] profile = args[2] wild = convert_wildcard(args[3]) modified = 0 for f in glob.glob(os.path.join(self.env.key_dir, "station_" + wild)): lines = [line.strip() for line in open(f, "r").readlines()] is_modified = False for i in range(len(lines)): #pylint: disable=C0200 line = lines[i] # Comment line if line.startswith("#"): continue # Empty line if len(line) == 0: continue toks = line.split(':') # No profile if len(toks) == 1: continue # Wrong module name if toks[0] != module: continue # Wrong profile name if toks[1] != profile: continue lines[i] = module is_modified = True continue if is_modified: modified += 1 if (len(lines) > 0) and (len(lines[-1]) > 0): lines.append("") try: open(f, "w").write('\n'.join(lines)) except Exception as e: sys.stdout.write("%s: %s\n" % (f, str(e))) sys.stdout.write("OK, %d files modified\n" % modified) return True if args[0] == "module": if len(args) != 3: raise Exception( "Missing arguments, expected: module station-selector") module = args[1] wild = convert_wildcard(args[2]) modified = 0 for f in glob.glob(os.path.join(self.env.key_dir, "station_" + wild)): lines = [line.strip() for line in open(f, "r").readlines()] new_lines = [] is_modified = False for line in lines: # Comment line if line.startswith("#"): new_lines.append(line) continue # Empty line if len(line) == 0: new_lines.append(line) continue toks = line.split(':') # Wrong module name if toks[0] != module: new_lines.append(line) continue # Filter line is_modified = True if is_modified: modified += 1 if (len(new_lines) > 0) and (len(new_lines[-1]) > 0): new_lines.append("") try: open(f, "w").write('\n'.join(new_lines)) except Exception as e: sys.stdout.write("%s: %s\n" % (f, str(e))) try: os.remove(os.path.join(self.env.key_dir, module, os.path.basename(f))) except OSError: pass sys.stdout.write("OK, %d files modified\n" % modified) return True raise Exception("Invalid argument: %s" % args[0])