#!/usr/bin/env python #!/usr/bin/python #!/usr/local/bin/python #Try this or some other first line if above doesn't work #Copyright Olaf Kayser 2006-8 (Open Source/GNU Affero General Public License) # This is a CGI-program (install.py) in the QuizComposer system # to be executed from a companion HTML-page (install.htm). These # two pieces of software can, when properly placed on your Web # server and properly modified, be used to install the QuizComposer system. # The introductory comments in install.htm should be read before these # comments. # The file install.htm must be placed into your DocumentRoot directory, # where the primary pages of your Web server, e.g. the file index.html, # are normally placed. # Having placed install.htm set its access rights, check that # it is accessible by pointing your browser to # http://your-domain/install.htm, where your-domain normally might # be localhost or have the format www.abc.xy or www.abc.xy/~def, # depending on the configuration of your server. # Secondly, make the change of the ACTION parameter in the
tag so that it equals the first element in the # ScriptAlias directive in the server configuration. # Check again that this file (install.py) is accessible from install.htm # by clicking any button in the latter. # You should get a message about a missing password. # If you still get an error mesage from the web server, you should probably # consider chaning the first line of this file. If you have the possibility # of executing a shell command on the computer write the # command: which python # If the answer starts with a slash insert that answer preceeded by #! # as the first line of this file. # If you are still stuck consult the administrator of your web server or # somebody else with experience in such matters. # Be carefull when you submit the form the first time WITH A NON-EMPTY # PASSWORD. Next time you must write the same password. # Your password (in its encrypted form) will be stored in a new # version of this install.py program. A copy of this program with the # name org-install.py is created at the same place. (If you forget your # password - or wish to change it - you must replace your install.py # program with org-install.py (or another copy in which the variable # correct_crypt is set to an empty value). # Before submitting the form (install.htm) the first time # with a non-empty password field, you will normally have to alter # one or more of the export statements in the entry field for defining # install variables to suit your Web server and your preferences. # At least you should set your own values for ADMINMAILADDRESS, # ADMINPASSWORD and TESTPASSWORD (unless you are working on an # intranet with trustworthy participants only). # This install.py program will always try to set the variables to # reasonable values by examining the environment in which it is executed. # Clicking a certain button displays the Web servers environment. # Another button results in the display of the the install variables # with the values which will be used at installation. # You might consider copying this output to a file for editing and subsequent # replacement of the contents of the entry field. For example, you # could add your own comments. # At the beginning of the installation process the contents of the large # entry field with the install variables is copied to an install # sub-directory as a file install.var and the files install.tgz and # install.sh are copied to the same sub-directory from www.quizcomposer.dk # (unless the sub-directory already contains files with these names). # Then the script install.sh is executed with messages being directed # to files install.log and install.err. # Any re-installation can be caried out from the same install sub-directory # possibly after any editing of the install.var file (or the install.sh # file, if you wish to use your own version of that script). # This may be practical when an external program is used to evaluate quiz # answers. Then an interface program corresponding to the external # program must have been placed in the directory containing the install # sub-directory prior to the execution of the install process. # Examples of such interface programs can be found on www.quizcomposer.dk. # Most often an interface program must be modified to suit the # environment in which it is used. # You can also carry out a re-installation process via the install button # in the the install.htm file as described in that file. # QuizComposer (Open Source/GNU General Public License). correct_crypt = '\067\362\053\307\175\245\060\031\303\100\156\307\327\356\062\306' print "Content-type: text/plain\n" import cgi, sys, os, re def encrypt( w ) : import md5 return md5.new(w).digest() form = cgi.FieldStorage() #print 'form:', form # if correct_crypt == '' : if not ( form.has_key('password') and form['password'].value.strip() ) : print "You must carefully enter a password for using the page you" print "submitted and its associated script - and memorize the password!" print "The script will be modified to run with that password only." print print "If the password for the script is forgotten replace the script" print "with its original version which has correct_crypt = ''." sys.exit(1) c = form['password'].value.strip().strip() if len(c) < 8 : print "The password must have at least 8 characters." sys.exit(1) c = encrypt( c ) l = list( c ) o = [] for ch in l : o.append( '\%03o' % ord(ch) ) s = ''.join( o ) # print "correct_crypt = '" + s + "'" # S = open( 'install.py' ).read().replace( "correct_crypt = ''", "correct_crypt = '"+s+"'", 1 ) open( 'install.py', 'w' ).write( S ) print 'Re-submitting the install page now requires the password you entered.' # print "correct_crypt = '" + s + "'" # sys.exit(0) password = form.getvalue("password", "").strip() if encrypt( password ) != correct_crypt : print "Content-type: text/plain\n" print 'Bad password.' sys.exit(1) try : install_var_txt = form['install_var'].value.strip() except : print "install_var field missing or empty in install.htm" sys.exit(1) pos1 = install_var_txt.find( 'export QUIZCOMPOSERPARENT=' ) pos2 = install_var_txt.find( '=', pos1 ) pos3 = install_var_txt.find( '\n', pos2 ) QUIZCOMPOSERPARENT = install_var_txt[ pos2 + 1: pos3 ].strip() # Checking for useful value of QUIZCOMPOSERPARENT in install.var file: replace_QUIZCOMPOSERPARENT = False if QUIZCOMPOSERPARENT == '$HOME' or QUIZCOMPOSERPARENT == '' : cmd = 'echo ~ > fil' status = os.system( cmd ) QUIZCOMPOSERPARENT = open( 'fil' ).read()[:-1] replace_QUIZCOMPOSERPARENT = True elif re.compile( r'[^\w\.\-/]' ).search( QUIZCOMPOSERPARENT ) : print 'QUIZCOMPOSERPARENT: bad string' sys.exit(1) #20070214+ QUIZCOMPOSERPARENT = QUIZCOMPOSERPARENT.strip() # Searhing install.htm for setting CGINAME: set_HTMLDIR = False DOCUMENT_ROOT = os.environ['DOCUMENT_ROOT'] install_htm = DOCUMENT_ROOT + '/install.htm' if not os.path.exists( install_htm ) : print 'DOCUMENT_ROOT determined from environment variables is:', DOCUMENT_ROOT print 'DOCUMENT_ROOT does not contain install.htm' print 'Attempting to find DOCUMENT_ROOT public_html under HOME directory' os.system( 'echo ~ > fil' ) #20070214~ # QUIZCOMPOSERPARENT = open( 'fil' ).read()[:-1] QUIZCOMPOSERPARENT = open( 'fil' ).read()[:-1].strip() print 'HOME directory:', QUIZCOMPOSERPARENT DOCUMENT_ROOT = QUIZCOMPOSERPARENT + '/public_html' if os.path.exists( DOCUMENT_ROOT ) : print 'DOCUMENT_ROOT found:', DOCUMENT_ROOT HTMLDIR = DOCUMENT_ROOT set_HTMLDIR = True else : sys.exit(1) install_htm = DOCUMENT_ROOT + '/install.htm' if os.path.exists( install_htm ) : print 'Found install page:', install_htm else : print 'DOCUMENT_ROOT directory and install page install.htm not found' sys.exit(1) CGIBINDIR = os.getcwd() install_var_lst = install_var_txt.replace( '\r', '' ).split( '\n' ) re_ = re.compile( r'^export (?P[\w]+)=(?P.*)$' ) n = 0 for line in install_var_lst : if line.find( 'export ' ) == 0 : xx = re_.match( line ) name = xx.group('name') if name == 'CGINAME' : cginame = xx.group('xpr') if cginame : CGINAME = cginame else : # Determining CGINAME from in install.htm file f = open( install_htm ) while 1 : line = f.readline() if not line : print 'ACTION attribute missing in ' + install_htm sys.exit(1) if line.find( 'ACTION=' ) >= 0 or line.find( 'action=' ) >= 0 : break l = re.compile( r'(?i).*ACTION="' ).sub( '', line ) CGINAME = re.compile( r'install\.py.*' ).sub( '', l )[:-1] f.close() install_var_lst[n] = ''.join(['export ', name, "='", CGINAME, "'"]) elif name == 'QUIZCOMPOSERPARENT' : install_var_lst[n] = ''.join(['export ', name, "='", QUIZCOMPOSERPARENT, "'"]) elif name == 'HTMLDIR' and set_HTMLDIR : install_var_lst[n] = ''.join(['export ', name, "='", HTMLDIR, "'"]) elif name == 'CGIBINDIR' : install_var_lst[n] = ''.join(['export ', name, "='", CGIBINDIR, "'"]) elif name == 'PYTHON' : val = xx.group('xpr') if not val : val = open( 'install.py' ).readline()[2:-1] install_var_lst[n] = ''.join(['export ', name, "='", val, "'"]) print 'Setting ', name, '=', val else : os.system( ''.join([ 'echo ', xx.group('xpr'), ' > tmpfile' ]) ) val = open( 'tmpfile' ).read()[:-1] install_var_lst[n] = ''.join(['export ', name, "='", val, "'"]) print 'Setting ', name, '=', val n = n + 1 if form.has_key('list_install_var') : print 'Install configuration with variables evaluated:\n' for line in install_var_lst : print line sys.exit(0) import time today = time.strftime('%Y%m%d') quizcomposerinstall_d = QUIZCOMPOSERPARENT + '/quizcomposerinstall.d/' if not os.path.exists( quizcomposerinstall_d ) : print 'Attempting to create ', quizcomposerinstall_d os.mkdir( quizcomposerinstall_d ) if not os.path.exists( quizcomposerinstall_d ) : print 'Cannot create ', quizcomposerinstall_d sys.exit(1) INSTALLDIR = quizcomposerinstall_d + today + '/' def printinstalllog( log, txt ) : # log = 'log' or 'err' os.chdir( quizcomposerinstall_d ) import glob lst = glob.glob( '[0-9]*' ) lst.sort() os.chdir( lst[-1] ) try : f = open( 'install.' + log ) except : print 'There is no ' + txt + ' in sub-directory for last installation' sys.exit(1) lst = f.readlines() if not lst : print ''.join([ 'File ', 'install.' + log, ' is empty' ]) sys.exit(1) for line in lst : print line, if form.has_key('install_sh') : print 'Attempting to install' if not os.path.exists( INSTALLDIR ) : print 'Attempting to create ', INSTALLDIR os.mkdir( INSTALLDIR ) if not os.path.exists( INSTALLDIR ) : print 'Cannot create directory ', INSTALLDIR sys.exit(1) INSTALLDIRinstall_var = INSTALLDIR + 'install.var' install_var = '\n'.join( install_var_lst ) try : open( INSTALLDIRinstall_var, 'w' ).write( install_var ) print 'Install variables (file install.var) written into ', INSTALLDIR except : print 'Cannot write file', INSTALLDIRinstall_var import urllib rqstinst_d = 'http://www.quizcomposer.dk/html.d/../rqstinst.d/' INSTALLDIR_install_sh = INSTALLDIR + 'install.sh' if not os.path.exists( INSTALLDIR_install_sh ) : install_sh_location = rqstinst_d + 'install.sh.txt' try : fi = urllib.urlopen( install_sh_location ) except : print 'Cannot open install script install.sh at ', install_sh_location sys.exit(1) install_sh = fi.read() if not install_sh : print 'Cannot read install script install.sh from ', install_sh_location sys.exit(1) fi.close() fo = open( INSTALLDIR_install_sh, 'w' ) fo.write( install_sh ) fo.close() print 'Install script install.sh written into ', INSTALLDIR INSTALLDIR_install_tgz = INSTALLDIR + 'install.tgz' if not os.path.exists( INSTALLDIR_install_tgz ) : install_tgz_location = rqstinst_d + 'install.tgz' try : fi = urllib.urlopen( install_tgz_location ) except : print 'Cannot open install file install.tgz at ', install_tgz_location sys.exit(1) install_tgz = fi.read() if not install_tgz : print 'Cannot read install file install.tgz from ', install_tgz_location sys.exit(1) fi.close() fo = open( INSTALLDIR_install_tgz, 'w' ) fo.write( install_tgz ) fo.close() print 'Install file install.tgz written into ', INSTALLDIR # Make local copy of interface programs: for prog in [ 'maple', 'mathematica' ] : local_prog = quizcomposerinstall_d + prog + '.py' if not os.path.exists( local_prog ) : try : prog_at_url = rqstinst_d + prog + '.txt' fi = urllib.urlopen( prog_at_url ) prg = fi.read() if not prg : print prog_at_url, ': cannot read Web file' sys.exit(1) fi.close() fo = open( local_prog, 'w' ) fo.write( prg ) fo.close() print 'Interface program ', prog, ' copied into ', INSTALLDIR except : pass os.chdir( INSTALLDIR ) print 'In directory ', os.getcwd(), print 'executing command:\n', ' bash install.sh > install.log 2> install.err' os.system( 'bash install.sh > install.log 2> install.err' ) printinstalllog( 'log', 'installation log' ) sys.exit(0) if form.has_key('install_log') : printinstalllog( 'log', 'installation log' ) sys.exit(0) if form.has_key('install_err') : printinstalllog( 'err', 'error log file' ) sys.exit(0) if form.has_key('list') : os.chdir( quizcomposerinstall_d ) import glob lst = glob.glob( '*' ) lst.sort() print print 'Files and directories in install directory: ', os.getcwd() print """Dates (YMD) are names of install sub-directories (date of installation proces). Other names (if any) represent interface programs to external programs used by QuizComposer to evaluate answers (or for other purposes).""" for i in lst : print print i, ':' cmd = 'ls -l ' + i + ' > fil' status = os.system( cmd ) print open( 'fil' ). read() os.remove( 'fil' ) sys.exit(0) if form.has_key('deldir') : try : first = form['first'].value.strip() except : first = '' try : last = form['last'].value.strip() except : last = '' os.chdir( quizcomposerinstall_d ) import glob, shutil lst = glob.glob( '*' ) lst.sort() n = 0 for i in lst : if i < first : continue elif i > last : continue else : shutil.rmtree( i ) print 'delete', i sys.exit(0) if form.has_key('lstenv') : print 'List of environment variables for execution of CGI-programs:\n' for i in os.environ.keys() : print ''.join([ i, '=', os.environ[i] ]) sys.exit(0) print 'Something went wrong!' cwd = os.getcwd() print 'Current working directory (cwd):', cwd listdir = os.listdir( cwd ) print 'Contents of cwd:', listdir for name in listdir : print name os.chdir( '..' ) cwd = os.getcwd() print 'Parent directory:', cwd listdir = os.listdir( cwd ) print 'Contents of parent directory:', listdir for name in listdir : print name print 'Goodbye'