documentation full transformation
This commit is contained in:
		| @@ -1,10 +1,15 @@ | |||||||
| #!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||||
|  | ''' | ||||||
|  | ''' | ||||||
| from .core import node,nodes | from .core import node,nodes | ||||||
| from .configfile import configfile | from .configfile import configfile | ||||||
| from .connapp import connapp | from .connapp import connapp | ||||||
| from pkg_resources import get_distribution | from pkg_resources import get_distribution | ||||||
|  |  | ||||||
| __all__ = ["node", "nodes", "configfile", "connapp"] | __all__ = ["node", "nodes", "configfile"] | ||||||
| __version__ = "2.0.9" | __version__ = "2.0.10" | ||||||
| __author__ = "Federico Luzzi" | __author__ = "Federico Luzzi" | ||||||
|  | __pdoc__ = { | ||||||
|  |     'core': False, | ||||||
|  |     'connapp': False, | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								conn/app.py
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								conn/app.py
									
									
									
									
									
								
							| @@ -1,10 +0,0 @@ | |||||||
| #!/usr/bin/env python3 |  | ||||||
| import sys |  | ||||||
| from conn import * |  | ||||||
|  |  | ||||||
| def main(): |  | ||||||
|     conf = configfile() |  | ||||||
|     connapp(conf, node) |  | ||||||
|  |  | ||||||
| if __name__ == '__main__': |  | ||||||
|     sys.exit(main()) |  | ||||||
| @@ -96,6 +96,9 @@ class configfile: | |||||||
|                     folder = self.connections[uniques["folder"]] |                     folder = self.connections[uniques["folder"]] | ||||||
|                 newfolder = folder.copy() |                 newfolder = folder.copy() | ||||||
|                 newfolder.pop("type") |                 newfolder.pop("type") | ||||||
|  |                 for node in newfolder.keys(): | ||||||
|  |                     if "type" in newfolder[node].keys(): | ||||||
|  |                         newfolder[node].pop("type") | ||||||
|                 if keys == None: |                 if keys == None: | ||||||
|                     return newfolder |                     return newfolder | ||||||
|                 else: |                 else: | ||||||
| @@ -109,6 +112,7 @@ class configfile: | |||||||
|                 else: |                 else: | ||||||
|                     node = self.connections[uniques["id"]] |                     node = self.connections[uniques["id"]] | ||||||
|                 newnode = node.copy() |                 newnode = node.copy() | ||||||
|  |                 newnode.pop("type") | ||||||
|                 return newnode |                 return newnode | ||||||
|  |  | ||||||
|     def _connections_add(self,*, id, host, folder='', subfolder='', options='', logs='', password='', port='', protocol='', user='', type = "connection" ): |     def _connections_add(self,*, id, host, folder='', subfolder='', options='', logs='', password='', port='', protocol='', user='', type = "connection" ): | ||||||
|   | |||||||
| @@ -9,11 +9,12 @@ import argparse | |||||||
| import sys | import sys | ||||||
| import inquirer | import inquirer | ||||||
| import json | import json | ||||||
|  | from conn import * | ||||||
|  |  | ||||||
|  |  | ||||||
| #functions and classes | #functions and classes | ||||||
|  |  | ||||||
| class connapp: | class connapp: | ||||||
|  |  | ||||||
|     def __init__(self, config, node): |     def __init__(self, config, node): | ||||||
|         self.node = node |         self.node = node | ||||||
|         self.config = config |         self.config = config | ||||||
| @@ -27,7 +28,7 @@ class connapp: | |||||||
|         #NODEPARSER |         #NODEPARSER | ||||||
|         nodeparser = subparsers.add_parser("node",usage=self._help("usage"), help=self._help("node"),epilog=self._help("end"), formatter_class=argparse.RawTextHelpFormatter)  |         nodeparser = subparsers.add_parser("node",usage=self._help("usage"), help=self._help("node"),epilog=self._help("end"), formatter_class=argparse.RawTextHelpFormatter)  | ||||||
|         nodecrud = nodeparser.add_mutually_exclusive_group() |         nodecrud = nodeparser.add_mutually_exclusive_group() | ||||||
|         nodeparser.add_argument("node", metavar="node|folder", nargs='?', default=None, action=self.store_type, type=self._type_node, help=self._help("node")) |         nodeparser.add_argument("node", metavar="node|folder", nargs='?', default=None, action=self._store_type, type=self._type_node, help=self._help("node")) | ||||||
|         nodecrud.add_argument("--add", dest="action", action="store_const", help="Add new node[@subfolder][@folder] or [@subfolder]@folder", const="add", default="connect") |         nodecrud.add_argument("--add", dest="action", action="store_const", help="Add new node[@subfolder][@folder] or [@subfolder]@folder", const="add", default="connect") | ||||||
|         nodecrud.add_argument("--del", "--rm", dest="action", action="store_const", help="Delete node[@subfolder][@folder] or [@subfolder]@folder", const="del", default="connect") |         nodecrud.add_argument("--del", "--rm", dest="action", action="store_const", help="Delete node[@subfolder][@folder] or [@subfolder]@folder", const="del", default="connect") | ||||||
|         nodecrud.add_argument("--mod", "--edit", dest="action", action="store_const", help="Modify node[@subfolder][@folder]", const="mod", default="connect") |         nodecrud.add_argument("--mod", "--edit", dest="action", action="store_const", help="Modify node[@subfolder][@folder]", const="mod", default="connect") | ||||||
| @@ -36,7 +37,7 @@ class connapp: | |||||||
|         nodeparser.set_defaults(func=self._func_node) |         nodeparser.set_defaults(func=self._func_node) | ||||||
|         #PROFILEPARSER |         #PROFILEPARSER | ||||||
|         profileparser = subparsers.add_parser("profile", help="Manage profiles")  |         profileparser = subparsers.add_parser("profile", help="Manage profiles")  | ||||||
|         profileparser.add_argument("profile", nargs=1, action=self.store_type, type=self._type_profile, help="Name of profile to manage") |         profileparser.add_argument("profile", nargs=1, action=self._store_type, type=self._type_profile, help="Name of profile to manage") | ||||||
|         profilecrud = profileparser.add_mutually_exclusive_group(required=True) |         profilecrud = profileparser.add_mutually_exclusive_group(required=True) | ||||||
|         profilecrud.add_argument("--add", dest="action", action="store_const", help="Add new profile", const="add") |         profilecrud.add_argument("--add", dest="action", action="store_const", help="Add new profile", const="add") | ||||||
|         profilecrud.add_argument("--del", "--rm", dest="action", action="store_const", help="Delete profile", const="del") |         profilecrud.add_argument("--del", "--rm", dest="action", action="store_const", help="Delete profile", const="del") | ||||||
| @@ -45,25 +46,25 @@ class connapp: | |||||||
|         profileparser.set_defaults(func=self._func_profile) |         profileparser.set_defaults(func=self._func_profile) | ||||||
|         #MOVEPARSER |         #MOVEPARSER | ||||||
|         moveparser = subparsers.add_parser("move", aliases=["mv"], help="Move node")  |         moveparser = subparsers.add_parser("move", aliases=["mv"], help="Move node")  | ||||||
|         moveparser.add_argument("move", nargs=2, action=self.store_type, help="Move node[@subfolder][@folder] dest_node[@subfolder][@folder]", default="move", type=self._type_node) |         moveparser.add_argument("move", nargs=2, action=self._store_type, help="Move node[@subfolder][@folder] dest_node[@subfolder][@folder]", default="move", type=self._type_node) | ||||||
|         moveparser.set_defaults(func=self._func_others) |         moveparser.set_defaults(func=self._func_others) | ||||||
|         #COPYPARSER |         #COPYPARSER | ||||||
|         copyparser = subparsers.add_parser("copy", aliases=["cp"], help="Copy node")  |         copyparser = subparsers.add_parser("copy", aliases=["cp"], help="Copy node")  | ||||||
|         copyparser.add_argument("cp", nargs=2, action=self.store_type, help="Copy node[@subfolder][@folder] new_node[@subfolder][@folder]", default="cp", type=self._type_node) |         copyparser.add_argument("cp", nargs=2, action=self._store_type, help="Copy node[@subfolder][@folder] new_node[@subfolder][@folder]", default="cp", type=self._type_node) | ||||||
|         copyparser.set_defaults(func=self._func_others) |         copyparser.set_defaults(func=self._func_others) | ||||||
|         #LISTPARSER |         #LISTPARSER | ||||||
|         lsparser = subparsers.add_parser("list", aliases=["ls"], help="List profiles, nodes or folders")  |         lsparser = subparsers.add_parser("list", aliases=["ls"], help="List profiles, nodes or folders")  | ||||||
|         lsparser.add_argument("ls", action=self.store_type, choices=["profiles","nodes","folders"], help="List profiles, nodes or folders", default=False) |         lsparser.add_argument("ls", action=self._store_type, choices=["profiles","nodes","folders"], help="List profiles, nodes or folders", default=False) | ||||||
|         lsparser.set_defaults(func=self._func_others) |         lsparser.set_defaults(func=self._func_others) | ||||||
|         #BULKPARSER |         #BULKPARSER | ||||||
|         bulkparser = subparsers.add_parser("bulk", help="Add nodes in bulk")  |         bulkparser = subparsers.add_parser("bulk", help="Add nodes in bulk")  | ||||||
|         bulkparser.add_argument("bulk", const="bulk", nargs=0, action=self.store_type, help="Add nodes in bulk") |         bulkparser.add_argument("bulk", const="bulk", nargs=0, action=self._store_type, help="Add nodes in bulk") | ||||||
|         bulkparser.set_defaults(func=self._func_others) |         bulkparser.set_defaults(func=self._func_others) | ||||||
|         #CONFIGPARSER |         #CONFIGPARSER | ||||||
|         configparser = subparsers.add_parser("config", help="Manage app config")  |         configparser = subparsers.add_parser("config", help="Manage app config")  | ||||||
|         configparser.add_argument("--allow-uppercase", dest="case", nargs=1, action=self.store_type, help="Allow case sensitive names", choices=["true","false"]) |         configparser.add_argument("--allow-uppercase", dest="case", nargs=1, action=self._store_type, help="Allow case sensitive names", choices=["true","false"]) | ||||||
|         configparser.add_argument("--keepalive", dest="idletime", nargs=1, action=self.store_type, help="Set keepalive time in seconds, 0 to disable", type=int, metavar="INT") |         configparser.add_argument("--keepalive", dest="idletime", nargs=1, action=self._store_type, help="Set keepalive time in seconds, 0 to disable", type=int, metavar="INT") | ||||||
|         configparser.add_argument("--completion", dest="completion", nargs=0, action=self.store_type, help="Get bash completion configuration for conn") |         configparser.add_argument("--completion", dest="completion", nargs=0, action=self._store_type, help="Get bash completion configuration for conn") | ||||||
|         configparser.set_defaults(func=self._func_others) |         configparser.set_defaults(func=self._func_others) | ||||||
|         #Set default subparser and tune arguments |         #Set default subparser and tune arguments | ||||||
|         commands = ["node", "profile", "mv", "move","copy", "cp", "bulk", "ls", "list", "config"] |         commands = ["node", "profile", "mv", "move","copy", "cp", "bulk", "ls", "list", "config"] | ||||||
| @@ -76,7 +77,7 @@ class connapp: | |||||||
|         args = defaultparser.parse_args() |         args = defaultparser.parse_args() | ||||||
|         args.func(args) |         args.func(args) | ||||||
|  |  | ||||||
|     class store_type(argparse.Action): |     class _store_type(argparse.Action): | ||||||
|         def __call__(self, parser, args, values, option_string=None): |         def __call__(self, parser, args, values, option_string=None): | ||||||
|             setattr(args, "data", values) |             setattr(args, "data", values) | ||||||
|             delattr(args,self.dest) |             delattr(args,self.dest) | ||||||
| @@ -740,3 +741,10 @@ complete -o nosort -F _conn conn | |||||||
|         encryptor = PKCS1_OAEP.new(publickey) |         encryptor = PKCS1_OAEP.new(publickey) | ||||||
|         password = encryptor.encrypt(password.encode("utf-8")) |         password = encryptor.encrypt(password.encode("utf-8")) | ||||||
|         return str(password) |         return str(password) | ||||||
|  |  | ||||||
|  | def main(): | ||||||
|  |     conf = configfile() | ||||||
|  |     connapp(conf, node) | ||||||
|  |  | ||||||
|  | if __name__ == '__main__': | ||||||
|  |     sys.exit(main()) | ||||||
|   | |||||||
							
								
								
									
										189
									
								
								conn/core.py
									
									
									
									
									
								
							
							
						
						
									
										189
									
								
								conn/core.py
									
									
									
									
									
								
							| @@ -14,7 +14,40 @@ import threading | |||||||
| #functions and classes | #functions and classes | ||||||
|  |  | ||||||
| class node: | class node: | ||||||
|     def __init__(self, unique, host, options='', logs='', password='', port='', protocol='', type='', user='', config=''): |     ''' This class generates a node object. Containts all the information and methods to connect and interact with a device using ssh or telnet. | ||||||
|  |  | ||||||
|  |     Attributes:   | ||||||
|  |  | ||||||
|  |         - output (str) -- Output of the commands you ran with run or test  | ||||||
|  |                        -- method.   | ||||||
|  |         - result(bool) -- True if expected value is found after running  | ||||||
|  |                        -- the commands using test method. | ||||||
|  |         ''' | ||||||
|  |      | ||||||
|  |     def __init__(self, unique, host, options='', logs='', password='', port='', protocol='', user='', config=''): | ||||||
|  |         '''  | ||||||
|  |              | ||||||
|  |         Parameters:   | ||||||
|  |  | ||||||
|  |             - unique   (str) -- Unique name to assign to the node.   | ||||||
|  |             - host     (str) -- IP address or hostname of the node.   | ||||||
|  |  | ||||||
|  |         Optional Parameters:   | ||||||
|  |  | ||||||
|  |             - options  (str) -- Additional options to pass the ssh/telnet for | ||||||
|  |                              -- connection.   | ||||||
|  |             - logs     (str) -- Path/file for storing the logs. You can use  | ||||||
|  |                              -- ${unique},${host}, ${port}, ${user}, ${protocol}  | ||||||
|  |                              -- as variables.   | ||||||
|  |             - password (str) -- Encrypted or plaintext password.   | ||||||
|  |             - port     (str) -- Port to connect to node, default 22 for ssh and 23  | ||||||
|  |                              -- for telnet.   | ||||||
|  |             - protocol (str) -- Select ssh or telnet. Default is ssh.   | ||||||
|  |             - user     (str) -- Username to of the node.   | ||||||
|  |             - config   (obj) -- Pass the object created with class configfile with  | ||||||
|  |                              -- key for decryption and extra configuration if you  | ||||||
|  |                              -- are using connection manager.   | ||||||
|  |         ''' | ||||||
|         if config == '': |         if config == '': | ||||||
|             self.idletime = 0 |             self.idletime = 0 | ||||||
|             self.key = None |             self.key = None | ||||||
| @@ -22,7 +55,6 @@ class node: | |||||||
|             self.idletime = config.config["idletime"] |             self.idletime = config.config["idletime"] | ||||||
|             self.key = config.key |             self.key = config.key | ||||||
|         self.unique = unique |         self.unique = unique | ||||||
|         self.id = self.unique.split("@")[0] |  | ||||||
|         attr = {"host": host, "logs": logs, "options":options, "port": port, "protocol": protocol, "user": user} |         attr = {"host": host, "logs": logs, "options":options, "port": port, "protocol": protocol, "user": user} | ||||||
|         for key in attr: |         for key in attr: | ||||||
|             profile = re.search("^@(.*)", attr[key]) |             profile = re.search("^@(.*)", attr[key]) | ||||||
| @@ -45,6 +77,7 @@ class node: | |||||||
|             self.password = [password] |             self.password = [password] | ||||||
|  |  | ||||||
|     def __passtx(self, passwords, *, keyfile=None): |     def __passtx(self, passwords, *, keyfile=None): | ||||||
|  |         # decrypts passwords, used by other methdos. | ||||||
|         dpass = [] |         dpass = [] | ||||||
|         if keyfile is None: |         if keyfile is None: | ||||||
|             keyfile = self.key |             keyfile = self.key | ||||||
| @@ -65,9 +98,9 @@ class node: | |||||||
|      |      | ||||||
|  |  | ||||||
|     def _logfile(self, logfile = None): |     def _logfile(self, logfile = None): | ||||||
|  |         # translate logs variables and generate logs path. | ||||||
|         if logfile == None: |         if logfile == None: | ||||||
|             logfile = self.logs |             logfile = self.logs | ||||||
|         logfile = logfile.replace("${id}", self.id) |  | ||||||
|         logfile = logfile.replace("${unique}", self.unique) |         logfile = logfile.replace("${unique}", self.unique) | ||||||
|         logfile = logfile.replace("${host}", self.host) |         logfile = logfile.replace("${host}", self.host) | ||||||
|         logfile = logfile.replace("${port}", self.port) |         logfile = logfile.replace("${port}", self.port) | ||||||
| @@ -80,13 +113,14 @@ class node: | |||||||
|         return logfile |         return logfile | ||||||
|  |  | ||||||
|     def _logclean(self, logfile, var = False): |     def _logclean(self, logfile, var = False): | ||||||
|  |         #Remove special ascii characters and other stuff from logfile. | ||||||
|         if var == False: |         if var == False: | ||||||
|             t = open(logfile, "r").read() |             t = open(logfile, "r").read() | ||||||
|         else: |         else: | ||||||
|             t = logfile |             t = logfile | ||||||
|         t = t.replace("\n","",1).replace("\a","") |         t = t.replace("\n","",1).replace("\a","") | ||||||
|         t = t.replace('\n\n', '\n') |         t = t.replace('\n\n', '\n') | ||||||
|         t = re.sub('.\[K', '', t) |         t = re.sub(r'.\[K', '', t) | ||||||
|         while True: |         while True: | ||||||
|             tb = re.sub('.\b', '', t, count=1) |             tb = re.sub('.\b', '', t, count=1) | ||||||
|             if len(t) == len(tb): |             if len(t) == len(tb): | ||||||
| @@ -103,6 +137,14 @@ class node: | |||||||
|             return t |             return t | ||||||
|  |  | ||||||
|     def interact(self, debug = False): |     def interact(self, debug = False): | ||||||
|  |         ''' | ||||||
|  |         Allow user to interact with the node directly, mostly used by connection manager. | ||||||
|  |  | ||||||
|  |         Optional Parameters:   | ||||||
|  |  | ||||||
|  |             - debug (bool) -- If True, display all the connecting information  | ||||||
|  |                            -- before interact. Default False.   | ||||||
|  |         ''' | ||||||
|         connect = self._connect(debug = debug) |         connect = self._connect(debug = debug) | ||||||
|         if connect == True: |         if connect == True: | ||||||
|             size = re.search('columns=([0-9]+).*lines=([0-9]+)',str(os.get_terminal_size())) |             size = re.search('columns=([0-9]+).*lines=([0-9]+)',str(os.get_terminal_size())) | ||||||
| @@ -121,7 +163,32 @@ class node: | |||||||
|             print(connect) |             print(connect) | ||||||
|             exit(1) |             exit(1) | ||||||
|  |  | ||||||
|     def run(self, commands,*, folder = '', prompt = '>$|#$|\$$|>.$|#.$|\$.$', stdout = False): |     def run(self, commands,*, folder = '', prompt = r'>$|#$|\$$|>.$|#.$|\$.$', stdout = False): | ||||||
|  |         ''' | ||||||
|  |         Run a command or list of commands on the node and return the output. | ||||||
|  |  | ||||||
|  |         Parameters:   | ||||||
|  |  | ||||||
|  |             - commands (str/list) -- Commands to run on the node. Should be  | ||||||
|  |                                   -- str or a list of str. | ||||||
|  |  | ||||||
|  |         Optional Named Parameters:   | ||||||
|  |  | ||||||
|  |             - folder (str)  -- Path where output log should be stored, leave  | ||||||
|  |                             -- empty to disable logging.   | ||||||
|  |             - prompt (str)  -- Prompt to be expected after a command is finished  | ||||||
|  |                             -- running. Usually linux uses  ">" or EOF while  | ||||||
|  |                             -- routers use ">" or "#". The default value should  | ||||||
|  |                             -- work for most nodes. Change it if your connection  | ||||||
|  |                             -- need some special symbol.   | ||||||
|  |             - stdout (bool) -- Set True to send the command output to stdout.  | ||||||
|  |                             -- default False. | ||||||
|  |  | ||||||
|  |         Returns:   | ||||||
|  |  | ||||||
|  |             str -> Output of the commands you ran on the node. | ||||||
|  |  | ||||||
|  |         ''' | ||||||
|         connect = self._connect() |         connect = self._connect() | ||||||
|         if connect == True: |         if connect == True: | ||||||
|             expects = [prompt, pexpect.EOF] |             expects = [prompt, pexpect.EOF] | ||||||
| @@ -161,7 +228,31 @@ class node: | |||||||
|             self.output = connect |             self.output = connect | ||||||
|             return connect |             return connect | ||||||
|  |  | ||||||
|     def test(self, commands, expected, *, prompt = '>$|#$|\$$|>.$|#.$|\$.$'): |     def test(self, commands, expected, *, prompt = r'>$|#$|\$$|>.$|#.$|\$.$'): | ||||||
|  |         ''' | ||||||
|  |         Run a command or list of commands on the node, then check if expected value appears on the output after the last command. | ||||||
|  |  | ||||||
|  |         Parameters:   | ||||||
|  |  | ||||||
|  |             - commands (str/list) -- Commands to run on the node. Should be | ||||||
|  |                                   -- str or list of str.   | ||||||
|  |             - expected (str)      -- Expected text to appear after running  | ||||||
|  |                                   -- all the commands on the node. | ||||||
|  |  | ||||||
|  |         Optional Named Parameters:  | ||||||
|  |  | ||||||
|  |             - prompt (str) -- Prompt to be expected after a command is finished | ||||||
|  |                            -- running. Usually linux uses  ">" or EOF while  | ||||||
|  |                            -- routers use ">" or "#". The default value should  | ||||||
|  |                            -- work for most nodes. Change it if your connection  | ||||||
|  |                            -- need some special symbol. | ||||||
|  |  | ||||||
|  |         Returns:  | ||||||
|  |  | ||||||
|  |             bool -> true if expected value is found after running the commands  | ||||||
|  |                     false if prompt is found before. | ||||||
|  |  | ||||||
|  |         ''' | ||||||
|         connect = self._connect() |         connect = self._connect() | ||||||
|         if connect == True: |         if connect == True: | ||||||
|             expects = [prompt, pexpect.EOF] |             expects = [prompt, pexpect.EOF] | ||||||
| @@ -203,6 +294,7 @@ class node: | |||||||
|             return connect |             return connect | ||||||
|  |  | ||||||
|     def _connect(self, debug = False): |     def _connect(self, debug = False): | ||||||
|  |         # Method to connect to the node, it parse all the information, create the ssh/telnet command and login to the node. | ||||||
|         if self.protocol == "ssh": |         if self.protocol == "ssh": | ||||||
|             cmd = "ssh" |             cmd = "ssh" | ||||||
|             if self.idletime > 0: |             if self.idletime > 0: | ||||||
| @@ -221,7 +313,7 @@ class node: | |||||||
|                 passwords = self.__passtx(self.password) |                 passwords = self.__passtx(self.password) | ||||||
|             else: |             else: | ||||||
|                 passwords = [] |                 passwords = [] | ||||||
|             expects = ['yes/no', 'refused', 'supported', 'cipher', 'sage', 'timeout', 'unavailable', 'closed', '[p|P]assword:|[u|U]sername:', '>$|#$|\$$|>.$|#.$|\$.$', 'suspend', pexpect.EOF, "No route to host", "resolve hostname"] |             expects = ['yes/no', 'refused', 'supported', 'cipher', 'sage', 'timeout', 'unavailable', 'closed', '[p|P]assword:|[u|U]sername:', r'>$|#$|\$$|>.$|#.$|\$.$', 'suspend', pexpect.EOF, "No route to host", "resolve hostname", "no matching host key"] | ||||||
|         elif self.protocol == "telnet": |         elif self.protocol == "telnet": | ||||||
|             cmd = "telnet " + self.host |             cmd = "telnet " + self.host | ||||||
|             if self.port != '': |             if self.port != '': | ||||||
| @@ -234,7 +326,7 @@ class node: | |||||||
|                 passwords = self.__passtx(self.password) |                 passwords = self.__passtx(self.password) | ||||||
|             else: |             else: | ||||||
|                 passwords = [] |                 passwords = [] | ||||||
|             expects = ['[u|U]sername:', 'refused', 'supported', 'cipher', 'sage', 'timeout', 'unavailable', 'closed', '[p|P]assword:', '>$|#$|\$$|>.$|#.$|\$.$', 'suspend', pexpect.EOF, "No route to host", "resolve hostname"] |             expects = ['[u|U]sername:', 'refused', 'supported', 'cipher', 'sage', 'timeout', 'unavailable', 'closed', '[p|P]assword:', r'>$|#$|\$$|>.$|#.$|\$.$', 'suspend', pexpect.EOF, "No route to host", "resolve hostname", "no matching host key"] | ||||||
|         else: |         else: | ||||||
|             raise ValueError("Invalid protocol: " + self.protocol) |             raise ValueError("Invalid protocol: " + self.protocol) | ||||||
|         child = pexpect.spawn(cmd) |         child = pexpect.spawn(cmd) | ||||||
| @@ -257,7 +349,7 @@ class node: | |||||||
|                         else: |                         else: | ||||||
|                             self.missingtext = True |                             self.missingtext = True | ||||||
|                             break |                             break | ||||||
|                 if results in  [1, 2, 3, 4, 5, 6, 7, 12, 13]: |                 if results in  [1, 2, 3, 4, 5, 6, 7, 12, 13, 14]: | ||||||
|                     child.close() |                     child.close() | ||||||
|                     return "Connection failed code:" + str(results) |                     return "Connection failed code:" + str(results) | ||||||
|                 if results == 8: |                 if results == 8: | ||||||
| @@ -280,7 +372,43 @@ class node: | |||||||
|         return True |         return True | ||||||
|  |  | ||||||
| class nodes: | class nodes: | ||||||
|  |     ''' This class generates a nodes object. Contains a list of node class objects and methods to run multiple tasks on nodes simultaneously. | ||||||
|  |  | ||||||
|  |     ### Attributes:   | ||||||
|  |  | ||||||
|  |         - nodelist (list): List of node class objects passed to the init  | ||||||
|  |                            function.   | ||||||
|  |  | ||||||
|  |         - output   (dict): Dictionary formed by nodes unique as keys,  | ||||||
|  |                            output of the commands you ran on the node as  | ||||||
|  |                            value. Created after running methods run or test.   | ||||||
|  |  | ||||||
|  |         - result   (dict): Dictionary formed by nodes unique as keys, value  | ||||||
|  |                            is True if expected value is found after running  | ||||||
|  |                            the commands, False if prompt is found before.  | ||||||
|  |                            Created after running method test.   | ||||||
|  |  | ||||||
|  |         - <unique> (obj):  For each item in nodelist, there is an attribute | ||||||
|  |                            generated with the node unique. | ||||||
|  |         ''' | ||||||
|  |  | ||||||
|     def __init__(self, nodes: dict, config = ''): |     def __init__(self, nodes: dict, config = ''): | ||||||
|  |         '''  | ||||||
|  |         ### Parameters:   | ||||||
|  |  | ||||||
|  |             - nodes (dict): Dictionary formed by node information:   | ||||||
|  |                             Keys: Unique name for each node.   | ||||||
|  |                             Mandatory Subkeys: host(str).   | ||||||
|  |                             Optional Subkeys: options(str), logs(str), password(str), | ||||||
|  |                             port(str), protocol(str), user(str).   | ||||||
|  |                             For reference on subkeys check node class. | ||||||
|  |  | ||||||
|  |         Optional Parameters:   | ||||||
|  |  | ||||||
|  |             - config (obj): Pass the object created with class configfile with key  | ||||||
|  |                             for decryption and extra configuration if you are using  | ||||||
|  |                             connection manager. | ||||||
|  |         ''' | ||||||
|         self.nodelist = [] |         self.nodelist = [] | ||||||
|         self.config = config |         self.config = config | ||||||
|         for n in nodes: |         for n in nodes: | ||||||
| @@ -289,12 +417,29 @@ class nodes: | |||||||
|             setattr(self,n,this) |             setattr(self,n,this) | ||||||
|  |  | ||||||
|      |      | ||||||
|     def splitlist(self, lst, n): |     def _splitlist(self, lst, n): | ||||||
|  |         #split a list in lists of n members. | ||||||
|         for i in range(0, len(lst), n): |         for i in range(0, len(lst), n): | ||||||
|             yield lst[i:i + n] |             yield lst[i:i + n] | ||||||
|  |  | ||||||
|  |  | ||||||
|     def run(self, commands,*, folder = None, prompt = None, stdout = None, parallel = 10): |     def run(self, commands,*, folder = None, prompt = None, stdout = None, parallel = 10): | ||||||
|  |         ''' | ||||||
|  |         Run a command or list of commands on all the nodes in nodelist. | ||||||
|  |  | ||||||
|  |         Parameters:   | ||||||
|  |             commands (str/list): Commands to run on the node. Should be a str or a list of str. | ||||||
|  |  | ||||||
|  |         Optional Named Parameters:   | ||||||
|  |             folder   (str): Path where output log should be stored, leave empty to disable logging.   | ||||||
|  |             prompt   (str): Prompt to be expected after a command is finished running. Usually linux uses  ">" or EOF while routers use ">" or "#". The default value should work for most nodes. Change it if your connection need some special symbol.   | ||||||
|  |             stdout   (bool): Set True to send the command output to stdout. default False.   | ||||||
|  |             parallel (int): Number of nodes to run the commands simultaneously. Default is 10, if there are more nodes that this value, nodes are groups in groups with max this number of members. | ||||||
|  |  | ||||||
|  |         Returns:   | ||||||
|  |             dict: Dictionary formed by nodes unique as keys, Output of the commands you ran on the node as value. | ||||||
|  |  | ||||||
|  |         ''' | ||||||
|         args = {} |         args = {} | ||||||
|         args["commands"] = commands |         args["commands"] = commands | ||||||
|         if folder != None: |         if folder != None: | ||||||
| @@ -307,18 +452,32 @@ class nodes: | |||||||
|         tasks = [] |         tasks = [] | ||||||
|         for n in self.nodelist: |         for n in self.nodelist: | ||||||
|             tasks.append(threading.Thread(target=n.run, kwargs=args)) |             tasks.append(threading.Thread(target=n.run, kwargs=args)) | ||||||
|         taskslist = list(self.splitlist(tasks, parallel)) |         taskslist = list(self._splitlist(tasks, parallel)) | ||||||
|         for t in taskslist: |         for t in taskslist: | ||||||
|             for i in t: |             for i in t: | ||||||
|                 i.start() |                 i.start() | ||||||
|             for i in t: |             for i in t: | ||||||
|                 i.join() |                 i.join() | ||||||
|         for i in self.nodelist: |         for i in self.nodelist: | ||||||
|             output[i.id] = i.output |             output[i.unique] = i.output | ||||||
|         self.output = output |         self.output = output | ||||||
|         return output |         return output | ||||||
|  |  | ||||||
|     def test(self, commands, expected, *, prompt = None, parallel = 10): |     def test(self, commands, expected, *, prompt = None, parallel = 10): | ||||||
|  |         ''' | ||||||
|  |         Run a command or list of commands on all the nodes in nodelist, then check if expected value appears on the output after the last command. | ||||||
|  |  | ||||||
|  |         Parameters:   | ||||||
|  |             commands (str/list): Commands to run on the node. Should be a str or a list of str.   | ||||||
|  |             commands (str): Expected text to appear after running all the commands on the node. | ||||||
|  |  | ||||||
|  |         Optional Named Parameters:   | ||||||
|  |             prompt   (str): Prompt to be expected after a command is finished running. Usually linux uses  ">" or EOF while routers use ">" or "#". The default value should work for most nodes. Change it if your connection need some special symbol. | ||||||
|  |  | ||||||
|  |         Returns:   | ||||||
|  |             dict: Dictionary formed by nodes unique as keys, value is True if expected value is found after running the commands, False if prompt is found before. | ||||||
|  |  | ||||||
|  |         ''' | ||||||
|         args = {} |         args = {} | ||||||
|         args["commands"] = commands |         args["commands"] = commands | ||||||
|         args["expected"] = expected |         args["expected"] = expected | ||||||
| @@ -329,15 +488,15 @@ class nodes: | |||||||
|         tasks = [] |         tasks = [] | ||||||
|         for n in self.nodelist: |         for n in self.nodelist: | ||||||
|             tasks.append(threading.Thread(target=n.test, kwargs=args)) |             tasks.append(threading.Thread(target=n.test, kwargs=args)) | ||||||
|         taskslist = list(self.splitlist(tasks, parallel)) |         taskslist = list(self._splitlist(tasks, parallel)) | ||||||
|         for t in taskslist: |         for t in taskslist: | ||||||
|             for i in t: |             for i in t: | ||||||
|                 i.start() |                 i.start() | ||||||
|             for i in t: |             for i in t: | ||||||
|                 i.join() |                 i.join() | ||||||
|         for i in self.nodelist: |         for i in self.nodelist: | ||||||
|             result[i.id] = i.result |             result[i.unique] = i.result | ||||||
|             output[i.id] = i.output |             output[i.unique] = i.output | ||||||
|         self.output = output |         self.output = output | ||||||
|         self.result = result |         self.result = result | ||||||
|         return result |         return result | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								docs/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								docs/Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | # Minimal makefile for Sphinx documentation | ||||||
|  | # | ||||||
|  |  | ||||||
|  | # You can set these variables from the command line, and also | ||||||
|  | # from the environment for the first two. | ||||||
|  | SPHINXOPTS    ?= | ||||||
|  | SPHINXBUILD   ?= sphinx-build | ||||||
|  | SOURCEDIR     = . | ||||||
|  | BUILDDIR      = _build | ||||||
|  |  | ||||||
|  | # Put it first so that "make" without argument is like "make help". | ||||||
|  | help: | ||||||
|  | 	@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) | ||||||
|  |  | ||||||
|  | .PHONY: help Makefile | ||||||
|  |  | ||||||
|  | # Catch-all target: route all unknown targets to Sphinx using the new | ||||||
|  | # "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS). | ||||||
|  | %: Makefile | ||||||
|  | 	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) | ||||||
							
								
								
									
										54
									
								
								docs/conf.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								docs/conf.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | |||||||
|  | # Configuration file for the Sphinx documentation builder. | ||||||
|  | # | ||||||
|  | # This file only contains a selection of the most common options. For a full | ||||||
|  | # list see the documentation: | ||||||
|  | # https://www.sphinx-doc.org/en/master/usage/configuration.html | ||||||
|  |  | ||||||
|  | # -- Path setup -------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | # If extensions (or modules to document with autodoc) are in another directory, | ||||||
|  | # add these directories to sys.path here. If the directory is relative to the | ||||||
|  | # documentation root, use os.path.abspath to make it absolute, like shown here. | ||||||
|  | # | ||||||
|  | # import os | ||||||
|  | # import sys | ||||||
|  | # sys.path.insert(0, os.path.abspath('.')) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # -- Project information ----------------------------------------------------- | ||||||
|  |  | ||||||
|  | project = 'conn' | ||||||
|  | copyright = '2022, Federico Luzzi' | ||||||
|  | author = 'Federico Luzzi' | ||||||
|  |  | ||||||
|  | # The full version, including alpha/beta/rc tags | ||||||
|  | release = '2.0.10' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # -- General configuration --------------------------------------------------- | ||||||
|  |  | ||||||
|  | # Add any Sphinx extension module names here, as strings. They can be | ||||||
|  | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom | ||||||
|  | # ones. | ||||||
|  | extensions = ['myst_parser'] | ||||||
|  |  | ||||||
|  | # Add any paths that contain templates here, relative to this directory. | ||||||
|  | templates_path = ['_templates'] | ||||||
|  |  | ||||||
|  | # List of patterns, relative to source directory, that match files and | ||||||
|  | # directories to ignore when looking for source files. | ||||||
|  | # This pattern also affects html_static_path and html_extra_path. | ||||||
|  | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # -- Options for HTML output ------------------------------------------------- | ||||||
|  |  | ||||||
|  | # The theme to use for HTML and HTML Help pages.  See the documentation for | ||||||
|  | # a list of builtin themes. | ||||||
|  | # | ||||||
|  | html_theme = 'alabaster' | ||||||
|  |  | ||||||
|  | # Add any paths that contain custom static files (such as style sheets) here, | ||||||
|  | # relative to this directory. They are copied after the builtin static files, | ||||||
|  | # so a file named "default.css" will overwrite the builtin "default.css". | ||||||
|  | html_static_path = ['_static'] | ||||||
							
								
								
									
										180
									
								
								docs/doc.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										180
									
								
								docs/doc.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,180 @@ | |||||||
|  | Module conn | ||||||
|  | =========== | ||||||
|  |  | ||||||
|  | Classes | ||||||
|  | ------- | ||||||
|  |  | ||||||
|  | `configfile(conf=None, *, key=None)` | ||||||
|  | :    | ||||||
|  |  | ||||||
|  |     ### Methods | ||||||
|  |  | ||||||
|  |     `createconfig(self, conf)` | ||||||
|  |     : | ||||||
|  |  | ||||||
|  |     `createkey(self, keyfile)` | ||||||
|  |     : | ||||||
|  |  | ||||||
|  |     `getitem(self, unique, keys=None)` | ||||||
|  |     : | ||||||
|  |  | ||||||
|  |     `loadconfig(self, conf)` | ||||||
|  |     : | ||||||
|  |  | ||||||
|  |     `saveconfig(self, conf)` | ||||||
|  |     : | ||||||
|  |  | ||||||
|  | `node(unique, host, options='', logs='', password='', port='', protocol='', user='', config='')` | ||||||
|  | :   This class generates a node object. Containts all the information and methods to connect and interact with a device using ssh or telnet. | ||||||
|  |      | ||||||
|  |     Attributes:   | ||||||
|  |      | ||||||
|  |         - output (str) -- Output of the commands you ran with run or test  | ||||||
|  |                        -- method.   | ||||||
|  |         - result(bool) -- True if expected value is found after running  | ||||||
|  |                        -- the commands using test method. | ||||||
|  |          | ||||||
|  |      | ||||||
|  |          | ||||||
|  |     Parameters:   | ||||||
|  |      | ||||||
|  |         - unique   (str) -- Unique name to assign to the node.   | ||||||
|  |         - host     (str) -- IP address or hostname of the node.   | ||||||
|  |      | ||||||
|  |     Optional Parameters:   | ||||||
|  |      | ||||||
|  |         - options  (str) -- Additional options to pass the ssh/telnet for | ||||||
|  |                          -- connection.   | ||||||
|  |         - logs     (str) -- Path/file for storing the logs. You can use  | ||||||
|  |                          -- ${unique},${host}, ${port}, ${user}, ${protocol}  | ||||||
|  |                          -- as variables.   | ||||||
|  |         - password (str) -- Encrypted or plaintext password.   | ||||||
|  |         - port     (str) -- Port to connect to node, default 22 for ssh and 23  | ||||||
|  |                          -- for telnet.   | ||||||
|  |         - protocol (str) -- Select ssh or telnet. Default is ssh.   | ||||||
|  |         - user     (str) -- Username to of the node.   | ||||||
|  |         - config   (obj) -- Pass the object created with class configfile with  | ||||||
|  |                          -- key for decryption and extra configuration if you  | ||||||
|  |                          -- are using connection manager. | ||||||
|  |  | ||||||
|  |     ### Methods | ||||||
|  |  | ||||||
|  |     `interact(self, debug=False)` | ||||||
|  |     :   Allow user to interact with the node directly, mostly used by connection manager. | ||||||
|  |          | ||||||
|  |         Optional Parameters:   | ||||||
|  |          | ||||||
|  |             - debug (bool) -- If True, display all the connecting information  | ||||||
|  |                            -- before interact. Default False. | ||||||
|  |  | ||||||
|  |     `run(self, commands, *, folder='', prompt='>$|#$|\\$$|>.$|#.$|\\$.$', stdout=False)` | ||||||
|  |     :   Run a command or list of commands on the node and return the output. | ||||||
|  |          | ||||||
|  |         Parameters:   | ||||||
|  |          | ||||||
|  |             - commands (str/list) -- Commands to run on the node. Should be  | ||||||
|  |                                   -- str or a list of str. | ||||||
|  |          | ||||||
|  |         Optional Named Parameters:   | ||||||
|  |          | ||||||
|  |             - folder (str)  -- Path where output log should be stored, leave  | ||||||
|  |                             -- empty to disable logging.   | ||||||
|  |             - prompt (str)  -- Prompt to be expected after a command is finished  | ||||||
|  |                             -- running. Usually linux uses  ">" or EOF while  | ||||||
|  |                             -- routers use ">" or "#". The default value should  | ||||||
|  |                             -- work for most nodes. Change it if your connection  | ||||||
|  |                             -- need some special symbol.   | ||||||
|  |             - stdout (bool) -- Set True to send the command output to stdout.  | ||||||
|  |                             -- default False. | ||||||
|  |          | ||||||
|  |         Returns:   | ||||||
|  |          | ||||||
|  |             str -> Output of the commands you ran on the node. | ||||||
|  |  | ||||||
|  |     `test(self, commands, expected, *, prompt='>$|#$|\\$$|>.$|#.$|\\$.$')` | ||||||
|  |     :   Run a command or list of commands on the node, then check if expected value appears on the output after the last command. | ||||||
|  |          | ||||||
|  |         Parameters:   | ||||||
|  |          | ||||||
|  |             - commands (str/list) -- Commands to run on the node. Should be | ||||||
|  |                                   -- str or list of str.   | ||||||
|  |             - expected (str)      -- Expected text to appear after running  | ||||||
|  |                                   -- all the commands on the node. | ||||||
|  |          | ||||||
|  |         Optional Named Parameters:  | ||||||
|  |          | ||||||
|  |             - prompt (str) -- Prompt to be expected after a command is finished | ||||||
|  |                            -- running. Usually linux uses  ">" or EOF while  | ||||||
|  |                            -- routers use ">" or "#". The default value should  | ||||||
|  |                            -- work for most nodes. Change it if your connection  | ||||||
|  |                            -- need some special symbol. | ||||||
|  |          | ||||||
|  |         Returns:  | ||||||
|  |          | ||||||
|  |             bool -> true if expected value is found after running the commands  | ||||||
|  |                     false if prompt is found before. | ||||||
|  |  | ||||||
|  | `nodes(nodes: dict, config='')` | ||||||
|  | :   This class generates a nodes object. Contains a list of node class objects and methods to run multiple tasks on nodes simultaneously. | ||||||
|  |      | ||||||
|  |     ### Attributes:   | ||||||
|  |      | ||||||
|  |         - nodelist (list): List of node class objects passed to the init  | ||||||
|  |                            function.   | ||||||
|  |      | ||||||
|  |         - output   (dict): Dictionary formed by nodes unique as keys, output of the commands you ran on the node as  | ||||||
|  |                            value. Created after running methods run or test.   | ||||||
|  |      | ||||||
|  |         - result   (dict): Dictionary formed by nodes unique as keys, value  | ||||||
|  |                            is True if expected value is found after running  | ||||||
|  |                            the commands, False if prompt is found before.  | ||||||
|  |                            Created after running method test.   | ||||||
|  |      | ||||||
|  |         - <unique> (obj):  For each item in nodelist, there is an attribute | ||||||
|  |                            generated with the node unique. | ||||||
|  |          | ||||||
|  |      | ||||||
|  |     ### Parameters:   | ||||||
|  |      | ||||||
|  |         - nodes (dict): Dictionary formed by node information:   | ||||||
|  |                         Keys: Unique name for each node.   | ||||||
|  |                         Mandatory Subkeys: host(str).   | ||||||
|  |                         Optional Subkeys: options(str), logs(str), password(str), | ||||||
|  |                         port(str), protocol(str), user(str).   | ||||||
|  |                         For reference on subkeys check node class. | ||||||
|  |      | ||||||
|  |     Optional Parameters:   | ||||||
|  |      | ||||||
|  |         - config (obj): Pass the object created with class configfile with key  | ||||||
|  |                         for decryption and extra configuration if you are using  | ||||||
|  |                         connection manager. | ||||||
|  |  | ||||||
|  |     ### Methods | ||||||
|  |  | ||||||
|  |     `run(self, commands, *, folder=None, prompt=None, stdout=None, parallel=10)` | ||||||
|  |     :   Run a command or list of commands on all the nodes in nodelist. | ||||||
|  |          | ||||||
|  |         Parameters:   | ||||||
|  |             commands (str/list): Commands to run on the node. Should be a str or a list of str. | ||||||
|  |          | ||||||
|  |         Optional Named Parameters:   | ||||||
|  |             folder   (str): Path where output log should be stored, leave empty to disable logging.   | ||||||
|  |             prompt   (str): Prompt to be expected after a command is finished running. Usually linux uses  ">" or EOF while routers use ">" or "#". The default value should work for most nodes. Change it if your connection need some special symbol.   | ||||||
|  |             stdout   (bool): Set True to send the command output to stdout. default False.   | ||||||
|  |             parallel (int): Number of nodes to run the commands simultaneously. Default is 10, if there are more nodes that this value, nodes are groups in groups with max this number of members. | ||||||
|  |          | ||||||
|  |         Returns:   | ||||||
|  |             dict: Dictionary formed by nodes unique as keys, Output of the commands you ran on the node as value. | ||||||
|  |  | ||||||
|  |     `test(self, commands, expected, *, prompt=None, parallel=10)` | ||||||
|  |     :   Run a command or list of commands on all the nodes in nodelist, then check if expected value appears on the output after the last command. | ||||||
|  |          | ||||||
|  |         Parameters:   | ||||||
|  |             commands (str/list): Commands to run on the node. Should be a str or a list of str.   | ||||||
|  |             commands (str): Expected text to appear after running all the commands on the node. | ||||||
|  |          | ||||||
|  |         Optional Named Parameters:   | ||||||
|  |             prompt   (str): Prompt to be expected after a command is finished running. Usually linux uses  ">" or EOF while routers use ">" or "#". The default value should work for most nodes. Change it if your connection need some special symbol. | ||||||
|  |          | ||||||
|  |         Returns:   | ||||||
|  |             dict: Dictionary formed by nodes unique as keys, value is True if expected value is found after running the commands, False if prompt is found before. | ||||||
							
								
								
									
										22
									
								
								docs/index.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								docs/index.rst
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | .. conn documentation master file, created by | ||||||
|  |    sphinx-quickstart on Sat Apr  2 23:19:12 2022. | ||||||
|  |    You can adapt this file completely to your liking, but it should at least | ||||||
|  |    contain the root `toctree` directive. | ||||||
|  |  | ||||||
|  | Welcome to conn's documentation! | ||||||
|  | ================================ | ||||||
|  |  | ||||||
|  | .. toctree:: | ||||||
|  |  | ||||||
|  |    doc.md | ||||||
|  |    :maxdepth: 2 | ||||||
|  |    :caption: Contents: | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Indices and tables | ||||||
|  | ================== | ||||||
|  |  | ||||||
|  | * :ref:`genindex` | ||||||
|  | * :ref:`modindex` | ||||||
|  | * :ref:`search` | ||||||
							
								
								
									
										35
									
								
								docs/make.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								docs/make.bat
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | @ECHO OFF | ||||||
|  |  | ||||||
|  | pushd %~dp0 | ||||||
|  |  | ||||||
|  | REM Command file for Sphinx documentation | ||||||
|  |  | ||||||
|  | if "%SPHINXBUILD%" == "" ( | ||||||
|  | 	set SPHINXBUILD=sphinx-build | ||||||
|  | ) | ||||||
|  | set SOURCEDIR=. | ||||||
|  | set BUILDDIR=_build | ||||||
|  |  | ||||||
|  | %SPHINXBUILD% >NUL 2>NUL | ||||||
|  | if errorlevel 9009 ( | ||||||
|  | 	echo. | ||||||
|  | 	echo.The 'sphinx-build' command was not found. Make sure you have Sphinx | ||||||
|  | 	echo.installed, then set the SPHINXBUILD environment variable to point | ||||||
|  | 	echo.to the full path of the 'sphinx-build' executable. Alternatively you | ||||||
|  | 	echo.may add the Sphinx directory to PATH. | ||||||
|  | 	echo. | ||||||
|  | 	echo.If you don't have Sphinx installed, grab it from | ||||||
|  | 	echo.https://www.sphinx-doc.org/ | ||||||
|  | 	exit /b 1 | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | if "%1" == "" goto help | ||||||
|  |  | ||||||
|  | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% | ||||||
|  | goto end | ||||||
|  |  | ||||||
|  | :help | ||||||
|  | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% | ||||||
|  |  | ||||||
|  | :end | ||||||
|  | popd | ||||||
		Reference in New Issue
	
	Block a user