#!/usr/bin/env python # vim: ts=4 et sts=4 sw=4 autoindent """ Usage: configure_sndcs.py If type is passed it should be "client", "server" or "both". """ import os import getpass import ConfigParser import time import sys import imp def _(input): return input ### Helper Functions ### # We are redefining the function in TrueAndFalseMixin.py here because the sndcs module is not necessarily installed yet def true(value): return value in ["y", "Y", "yes", "Yes", "YES", "true", "True", "TRUE", "1", 1, True] # Redefining these two functions from Win32HelperMixin.py for the same reasons # as above def main_is_frozen(): return (hasattr(sys, "frozen") or # new py2exe hasattr(sys, "importers") # old py2exe or imp.is_frozen("__main__")) # tools/freeze def get_main_dir(): if main_is_frozen(): return os.path.dirname(sys.executable) return os.path.dirname(sys.argv[0]) def parameter_helper(config, section, parameter, prompt, default, just_accept_default = False, valid_map = {}, yes_and_no = 0): if not config.has_section(section): config.add_section(section) try: param_default = config.get(section, parameter) except ConfigParser.NoOptionError: param_default = default if yes_and_no: if true(param_default): prompt_default = "Y/n" else: prompt_default = "y/N" elif valid_map: prompt_default = valid_map[param_default] else: prompt_default = param_default valid = 0 while not valid: if just_accept_default: param_value = param_default break confirm = raw_input(" ".join([prompt, "[" + prompt_default + "]: "])) if confirm == "": param_value = param_default valid = 1 else: if yes_and_no: if true(confirm): param_value = True else: param_value = False valid = 1 elif valid_map: for k,v in valid_map.iteritems(): if confirm == v: param_value = k valid = 1 else: param_value = confirm valid = 1 if isinstance(param_value, str): # Gotta be a better way to do this param_value = param_value.strip() config.set(section, parameter, param_value) return param_value # Print introduction print "This is the configuration utility for SaberNet DCS." print "Please answer each of the questions, or press to accept the default." print ### Find out what we are going to install ### valid = 0 while not valid: if len(sys.argv) > 1: choices = {"client":"c", "server":"s", "both":"b"} if sys.argv[1].lower() in choices: install_components = choices[sys.argv[1].lower()] valid = 1 continue install_components = raw_input("Do you want to install the client, server, or both? [c/s/b]: ") if install_components.lower() in ["c", "s", "b"]: install_components = install_components.lower() valid = 1 if install_components in ["s", "b"]: if main_is_frozen(): filenames = [os.path.join(get_main_dir(), "config", "sndcsd.conf")] if os.name=="nt": filenames = [os.path.join(sys.prefix, "etc", "sndcs", "sndcsd.conf")] else: filenames = [os.path.join("/etc", "sndcs", "sndcsd.conf")] if not main_is_frozen(): filenames += ["sndcs/config/sndcsd.conf"] server_config = ConfigParser.RawConfigParser() # Use RawConfigParser because we don't want the magical interpolation behavior server_config.read(filenames) if install_components in ["c", "b"]: if main_is_frozen(): filenames = [os.path.join(get_main_dir(), "config", "sndcs2.conf")] elif os.name=="nt": filenames = [os.path.join(sys.prefix, "etc", "sndcs", "sndcs2.conf")] else: filenames = [os.path.join("/etc", "sndcs", "sndcs2.conf")] if not main_is_frozen(): filenames += ["sndcs/config/sndcs2.conf"] client_config = ConfigParser.RawConfigParser() # Use RawConfigParser because we don't want the magical interpolation behavior client_config.read(filenames) if not main_is_frozen(): documention = raw_input("Do you want to generate documentation? (NOTE: Doxygen must be installed)[y/N]") if true(documention): os.system("doxygen") print ### Server Configuration ### if install_components in ["s", "b"]: print "*** Server Configuration ***" print if not server_config.has_section("webware"): server_config.add_section("webware") valid = 0 while not valid: try: default = server_config.get("webware", "webware_path") except ConfigParser.NoOptionError: if os.name == "posix": default = "/usr/local/Webware" elif os.name == "nt": default = "c:\Program Files\Webware" else: default = "" webware_path = raw_input("""Webware path [%s]: """ % default) if not webware_path: webware_path = default else: webware_path = os.path.abspath(os.path.expanduser(webware_path)) if not os.path.isdir(webware_path): print "'%s' does not appear to be a valid directory. " % webware_path continue if not os.path.isfile(os.path.join(webware_path, "MiddleKit/Design/Generate.py")): print "'%s' does not appear to be a valid Webware installation. " % webware_path else: print "---> Using %s as your Webware directory." % (webware_path) print valid = 1 server_config.set("webware", "webware_path", webware_path) if not server_config.has_section("database"): server_config.add_section("database") valid = 0 engines = {1:"MySQL", 2:"PostgreSQL", 3:"MSSQL"} while not valid: try: default = server_config.get("database", "engine") except ConfigParser.NoOptionError: default = "MySQL" # Turn the string value back into the numerical key for key, value in engines.iteritems(): if default == value: default = key break print "Select your RDBMS Engine" for key, value in engines.iteritems(): print str(key) + ": " + value tmp = raw_input("Enter number [%s]: " % default) if not tmp: tmp = default try: db_engine = int(tmp) except ValueError: print "Not a valid RDBMS" continue if not engines.has_key(db_engine): print "Not a valid RDBMS" else: print "---> Using %s as your RDBMS." % (engines[db_engine]) print valid = 1 server_config.set("database", "engine", engines[db_engine]) try: default = server_config.get("database", "host") except ConfigParser.NoOptionError: default = "localhost" if db_engine==3: nametype="DSN" else: nametype="host" tmp = raw_input("Database %s [%s]: " % (nametype,default)) if not tmp: tmp = default db_host = tmp server_config.set("database", "host", db_host) try: default = server_config.get("database", "user") except ConfigParser.NoOptionError: default = "root" tmp = raw_input("Database user [%s]: " % default) if not tmp: tmp = default db_user = tmp server_config.set("database", "user", db_user) valid = 0 while not valid: valid = 1 try: default = server_config.get("database", "passwd") except ConfigParser.NoOptionError: default = "" tmp = getpass.getpass("Database password: ") if not tmp: confirm = raw_input("Do you really want a blank password? [y/N]: ") if confirm.lower() <> "y": valid = 0 continue db_passwd = tmp server_config.set("database", "passwd", db_passwd) try: default = server_config.get("database", "name") except ConfigParser.NoOptionError: default = "sndcs2" tmp = raw_input("Database name [%s]: " % default) if not tmp: tmp = default db_name = tmp server_config.set("database", "name", db_name) # Test if the proper module for the selected RDMS is installed if db_engine is 1: try: import MySQLdb except ImportError: print print "****************************************************" print "You do not have the MySQLdb python module installed." print "Please install it after this installation finishes." print "****************************************************" print raw_input("Please press any key after reading the above message.") print elif db_engine is 2: try: import psycopg except ImportError: print print "****************************************************" print "You do not have the psycopg python module installed." print "Please install it after this installation finishes." print "****************************************************" print raw_input("Please press any key after reading the above message.") print elif db_engine is 3: try: import mx.ODBC.Windows mx.ODBC.Windows.Test = "testIfReal" # mx.ODBC doesn't load a module until called except: print print "************************************************************" print "You do not have the mx.ODBC.Windows python module installed." print "Please install it after this installation finishes." print "************************************************************" print raw_input("Please press any key after reading the above message.") print if os.name=="nt": pythonGenerate="MiddleKit\\Design\\Generate.py" else: pythonGenerate="MiddleKit/Design/Generate.py" if os.name=="nt": try: from win32api import GetShortPathName as _ except ImportError: print "*****************************************************" print "You do not have the win32api python module installed." print "Please install it and restart the installation." print "*****************************************************" print sys.exit(1) os.chdir("sndcs") # Generate.py will only read the database name from the config file so this # is a hack to rewrite the database name in the Settings.config with whatever # we specify write_file=open("sndcs.mkmodel/Settings.config","w") write_file.write("""{ "Database": "%s", "SQLConnectionPoolSize": 20, "Package": "sndcs", #"SQLLog": {'File': 'middlekit.sql'}, } """ % db_name ) write_file.close() os.system("""%s "%s" --db %s --model sndcs""" % (_(sys.executable),os.path.join(webware_path, pythonGenerate), engines[db_engine])) os.chdir(os.pardir) print print "You can safely ignore any warnings printed above." print confirm = raw_input("Do you want to create the database? [y/N]: ") if os.name <> "nt" and confirm.lower() == "y": if db_engine <> 3: confirm = raw_input("Are you sure you want to do this? This will wipe out any data in the database if it exists. Type 'yesido' to confirm or press Enter to cancel: ") else: confirm = "yesido" if confirm =="yesido": if db_engine is 1: os.chdir("sndcs") if db_passwd <> "": os.system("mysql -h %s -u %s --password=%s < GeneratedSQL/Create.sql" % (db_host, db_user, db_passwd)) else: os.system("mysql -h %s -u %s < GeneratedSQL/Create.sql" % (db_host, db_user)) os.chdir(os.pardir) elif db_engine is 2: os.chdir("sndcs") os.system("dropdb sndcs") os.system("createdb sndcs") # TODO: use proper host, etc... print "Re-enter your PostgreSQL password below..." try: import pexpect child = pexpect.spawn("psql sndcs -U %s -d sndcs -h %s -p -f GeneratedSQL/Create.sql" % (db_user,db_host)) child.expect("Password for user %s:" % db_user) child.sendline(db_passwd) child.interact() except ImportError: os.system("psql sndcs -U %s -d sndcs -h %s -p -f GeneratedSQL/Create.sql" % (db_user,db_host)) os.chdir(os.pardir) elif db_engine is 3: print print "GeneratedSQL/Create.sql has to be manually installed with MSSQL Query Analyzer" print time.sleep(2) print "---> Database created." print if db_engine is 1: os.chdir("sndcs") if db_passwd <> "": os.system("mysql -h %s -u %s --password=%s < GeneratedSQL/InsertSamples.sql" % (db_host, db_user, db_passwd)) else: os.system("mysql -h %s -u %s < GeneratedSQL/InsertSamples.sql" % (db_host, db_user)) os.chdir(os.pardir) elif db_engine is 2: os.chdir("sndcs") # TODO: use proper host, etc... try: import pexpect child = pexpect.spawn("psql -U %s -d sndcs -h %s -p -f GeneratedSQL/InsertSamples.sql" % (db_user,db_host)) child.expect("Password for user %s:" % db_user) child.sendline(db_passwd) child.interact() except ImportError: os.system("psql -U %s -d sndcs -h %s -p -f GeneratedSQL/InsertSamples.sql" % (db_user,db_host)) os.chdir(os.pardir) elif db_engine is 3: print "GeneratedSQL/InsertSamples.sql has to be manually installed with MSSQL Query Analyzer" print time.sleep(2) print "---> Base data inserted." print else: print "---> Database creation canceled." print else: print "---> Skipping database creation." print # Find out what IP address to bind to valid = 0 while not valid: valid = 1 host = parameter_helper(server_config, "pyro", "hostname", "What host should the server bind to (empty string or whitespace will try to guess what host to bind to)?", "").strip() if not host: import socket print "Will bind to host '", socket.gethostname(), "' with IP address of '", socket.gethostbyname(socket.gethostname()), "'" if socket.gethostbyname(socket.gethostname()) == "127.0.0.1": print "*** WARNING: binding to '127.0.0.1' is probably not what you want. ***" confirm = raw_input("Do you want to change the host to bind to? [Y/n]: ") if confirm == "" or true(confirm): valid = 0 # Find out if we should automatically start the Name and Event servers start_name_server = parameter_helper(server_config, "pyro", "start_name_server", "Do you want to automatically start the pyro Name Server?", True, yes_and_no = 1) # If we are not starting the Name Server we need to find out where it is at if not true(start_name_server): parameter_helper(server_config, "pyro", "ns_hostname", "What host is the Pyro Name Server running on (empty string means use broadcast only)?", "") # Find out what host the HTTP Server should bind to (should this default to th pyro host???) parameter_helper(server_config, "web", "host", "What host should the HTTP server bind to?", "127.0.0.1") # Find out if we just want to accept the rest of the server defaults confirm = raw_input("Would you like to accept the rest of the server defaults? [Y/n]: ") if confirm == "" or true(confirm): accept_default = True else: accept_default = False parameter_helper(server_config, "web", "terminal_id", "What terminal ID would you like to give to the web frontend?", "sndcs_web", accept_default) parameter_helper(server_config, "web", "http_port", "What port should the HTTP server use?", "8080", accept_default) parameter_helper(server_config, "web", "appserver_port", "What port should the AppServer use?", "8086", accept_default) parameter_helper(server_config, "operation", "description_format", "What format should operation descriptions be in?", "%(customer_name)s - %(item_description)s - %(assembly_description)s - %(operation_description)s", accept_default) parameter_helper(server_config, "operation", "cascade", "Would you like to cascade completed operations?", False, accept_default) parameter_helper(server_config, "pyro", "namespace", "What namespace should the sndcs server register to the Pyro name server under? (If you change this make sure to make it same in the client config)", "sndcs", accept_default) parameter_helper(server_config, "pyro", "max_connections", "How many simultaneous connections to the server should be allowed?", "200", accept_default) if main_is_frozen(): filename = os.path.join(get_main_dir(), "config", "sndcsd.conf") else: # Create the config directory if it doesn't exist if not os.path.isdir("sndcs/config"): os.mkdir("sndcs/config") filename = "sndcs/config/sndcsd.conf" fp = open(filename, "w") server_config.write(fp) fp.close() print "---> Server configuration writen to '%s'" % os.path.abspath(filename) print ### Client Configuration ### if install_components in ["c", "b"]: print "*** Client Configuration ***" print parameter_helper(client_config, "gtk", "terminal_id", "What terminal ID would you like to give to the GTK+ frontend?", "") parameter_helper(client_config, "pyro", "ns_hostname", "What host is the Pyro Name Server running on (empty string means use broadcast only)?", "") # Find out if we just want to accept all defaults confirm = raw_input("Would you like to accept the rest of the client defaults? [Y/n]: ") if confirm == "" or true(confirm): accept_default = True else: accept_default = False parameter_helper(client_config, "gtk", "fullscreen", "Do you want the GTK+ frontend to run fullscreen?", False, accept_default, yes_and_no = 1) parameter_helper(client_config, "gtk", "osd_keyboard", "Do you want the GTK+ frontend to have OSD keyboard?", False, accept_default, yes_and_no = 1) parameter_helper(client_config, "gtk", "search_dialog", "Do you want the GTK+ frontend to have the search dialog?", True, accept_default, yes_and_no = 1) parameter_helper(client_config, "gtk", "menu_bar", "Do you want the GTK+ frontend to show the menu bar?", True, accept_default, yes_and_no = 1) parameter_helper(client_config, "gtk", "show_clocked_out_employees", "Do you want to show clocked out employees in the employee list?", True, accept_default, yes_and_no = 1) parameter_helper(client_config, "gtk", "show_notes", "Do you want to be able to enter LaborDtl notes?", True, accept_default, yes_and_no = 1) parameter_helper(client_config, "gtk", "scrap_codes", "Do you want to use Scrap Codes?", False, accept_default, yes_and_no = 1) parameter_helper(client_config, "gtk", "department_jobs", "Do you want to only show jobs where the employee is a member of that department?", False, accept_default, yes_and_no = 1) parameter_helper(client_config, "gtk", "qty_complete_warning", "Do you want to show a warning if quantity completed would be more than quantity required?", False, accept_default, yes_and_no = 1) parameter_helper(client_config, "gtk", "persistent_search", "Do you want to enable 'persistent search data'?", False, True, yes_and_no = 1) parameter_helper(client_config, "gtk", "search_criteria", None, "", True, yes_and_no = 1) # Prompt not displayed parameter_helper(client_config, "gtk", "recent_activity", "Do you want to display recent job activities?", True, accept_default, yes_and_no=1) parameter_helper(client_config, "gtk", "easy_employee_selection", "Do you want to allow easy employee selection?", True, accept_default, yes_and_no=1) parameter_helper(client_config, "gtk", "force_end_activity", "Do you want to force users to fill out the end activity screen?", False, accept_default, yes_and_no=1) parameter_helper(client_config, "gtk", "clock_format", "What format should the statusbar clock be displayed in? (Empty string means no clock.)", "%I:%M %p", accept_default) parameter_helper(client_config, "pyro", "namespace", "What Pyro namespace is the sndcs server registered under?", "sndcs", accept_default) if main_is_frozen(): filename = os.path.join(get_main_dir(), "config", "sndcs2.conf") else: # Create the config directory if it doesn't exist if not os.path.isdir("sndcs/config"): os.mkdir("sndcs/config") filename = "sndcs/config/sndcs2.conf" fp = open(filename, "w") client_config.write(fp) fp.close() print "---> Client configuration writen to '%s'" % os.path.abspath(filename) print ### Installation ### if os.name == "nt": print """*************************************************************************""" print """Run "python setup.py install" as administrator to finish the installation.""" print """*************************************************************************""" print sys.exit(0) if os.getuid() <> 0: print """************************************************************************""" print """Run "python setup.py install" as root to finish the installation.""" print """************************************************************************""" print else: confirm = raw_input("Would you like to install? [y/N]: ") if confirm.lower() == "y": os.system("python setup.py install") print print "---> ***********************" print "---> Installation completed!" print "---> ***********************" print else: print print """************************************************************************""" print """Run "python setup.py install" as root to finish the installation.""" print """************************************************************************""" print