from __future__ import print_function import P4 import argparse import re class BufferedIterator: def __init__(self, it): self.it = iter(it) self.buf = [] def __iter__(self): return self def __next__(self): if self.buf: return self.buf.pop() return next(self.it) def push(self, item): self.buf.append(item) class Configurable: def __init__(self, name, default, description, undocumented = False): self.name = name self.default = default self.description = description self.undocumented = undocumented def __str__(self): return "{}: {}\t\t{}\t\t{}".format("undoc" if self.undocumented else " doc",self.name, self.default, self.description) class Configurables: def __init__(self, p4): self.server_configurables = [] self.client_configurables = [] # self.current_configurables = self.server_configurables self.p4 = p4 with self.p4.connect(): documented = self.p4.run_help('configurables') undoc = self.p4.run_help('undoc') print("".join(documented[0])) print("".join(undoc)) self.parse_help_output(documented[0], False) self.parse_help_output(undoc[0], True) print("Server:\n") for c in self.server_configurables: print(c) print("\n\nClient:\n") for c in self.client_configurables: print(c) def parse_help_output(self, documented, undocumented=False): header = re.compile("\tName\s+Default\s+Use") underline = re.compile("\t----\s+-------\s+---") lines = [x for x in documented.split('\n') if x] # strip out empty lines line_iter = BufferedIterator(lines) line = next(line_iter) self.current_configurables = self.server_configurables try: while (line): if header.match(line): line = next(line_iter) if underline.match(line): self.process_help(line_iter, undocumented) line = next(line_iter) except StopIteration: pass def process_help(self, line_iter, undocumented=False): pattern = re.compile("\t([^\s]+)\s+([^\s+]+)\s+(.+)") terminators = [ ' Perforce client configurables', ' P4CHARSET', ' Perforce client configuration (unsupported)' ] try: line = next(line_iter) while line: match = pattern.match(line) if match: conf = Configurable(match.group(1), match.group(2), match.group(3), undocumented) self.current_configurables.append(conf) # let's see if there is more description to be had # if it is the final end bit, exception will get us out of here line = next(line_iter) while line: match = pattern.match(line) if match: # seems like this is the next one configurable, push back line_iter.push(line) break elif line in terminators: # we found the next section, return and try again self.current_configurables = self.client_configurables return else: line = line.strip() conf.description += "\n" conf.description += line line = next(line_iter) line = next(line_iter) else: # check if it is the end of this help section if line in terminators: self.current_configurables = self.client_configurables return except StopIteration: pass if __name__ == '__main__': parser = argparse.ArgumentParser( description="P4Configure", epilog="Copyright (C) 2018 Sven Erik Knop, Perforce Software Ltd" ) parser.add_argument("-p", "--port", help="P4PORT") parser.add_argument("-u", "--user", help="P4USER") parser.add_argument("-P", "--password", help="P4PASSWD") args = parser.parse_args() p4 = P4.P4() if args.port: p4.port = args.port if args.user: p4.user = args.user if args.password: p4.password = args.password configurables = Configurables(p4)