#!/usr/bin/env python2 # -*-python-*- # --------------------------------------------------------------------------- # # Copyright (C) 2003 Greg Stein. All Rights Reserved. # # By using this file, you agree to the terms and conditions set forth in # the LICENSE.html file which can be found at the top level of the SubWiki # distribution or at: # http://svn.webdav.org/repos/projects/subwiki/trunk/LICENSE.html # # Contact information: # Greg Stein, PO Box 760, Palo Alto, CA, 94302 # gstein@lyra.org, http://subwiki.tigris.org/ # # --------------------------------------------------------------------------- # # install-subwiki: installer program for SubWiki # import sys import os import ConfigParser import glob import shutil import compileall import py_compile # figure out the directory of the distribution dist_dir = os.path.dirname(sys.argv[0]) # get access to the subwiki package sys.path.insert(0, os.path.join(dist_dir, 'lib')) try: import subwiki.main import subwiki.util except ImportError: info = sys.exc_info() # dang. probably can't import the SVN modules. let's test for that case. try: import svn.fs except ImportError: print 'ERROR: the Subversion Python modules could not be loaded. Please fix the' print ' installation of those modules before installing SubWiki.' sys.exit(1) print 'ERROR: the SubWiki library modules could not be loaded.' print import traceback traceback.print_exception(*info) sys.exit(1) try: _unused = True except NameError: True = 1 False = 0 def main(): cfg = load_config() layout = select_layout(cfg) # get the basic prefix, and shove it into the selected layout's section # of the ConfigParser so that later lookups can use the value. prefix = prompt('Installation prefix?', cfg.get(layout, 'prefix')) cfg.set(layout, 'prefix', prefix) ### would be nice to add "long help" options bin_dir = prompt('Programs?', cfg.get(layout, 'bin-dir'), True) python_dir = prompt('Python files?', cfg.get(layout, 'python-dir'), True) content_dir = prompt('Content?', cfg.get(layout, 'content-dir'), True) plugin_dir = prompt('Plugin modules?', cfg.get(layout, 'plugin-dir'), True) scripts_dir = prompt('Supporting scripts?', cfg.get(layout, 'scripts-dir'), True) extra_dir = prompt('Extra files?', cfg.get(layout, 'extra-dir'), True) # the prompt() function has done an initial test of writability to the # directories, so we should generally be fine. subwiki_pkg = os.path.join(python_dir, 'subwiki') # create the directories and install all of the files copy_files('scripts/subwiki', bin_dir, package_dir=python_dir) copy_files('lib/subwiki', subwiki_pkg) ### copy over ezt.py (for now?) copy_files('lib/ezt.py', python_dir) copy_files('content', content_dir) copy_files('plugins', plugin_dir) copy_files('scripts/run-indexer.py', 'scripts/subwiki.cgi', scripts_dir, package_dir=python_dir) copy_files('LICENSE.html', 'conf/subwiki.conf.dist', extra_dir) # compile the modules in our package, then the plugins compileall.compile_dir(subwiki_pkg) compileall.compile_dir(plugin_dir) ### for now(?), byte-compile ezt.py ezt_py = os.path.join(python_dir, 'ezt.py') print 'Compiling', ezt_py, '...' py_compile.compile(ezt_py) # rewrite the install.conf file located in the subwiki package install_conf = os.path.join(subwiki_pkg, 'install.conf') lines = open(install_conf).readlines() idx1 = lines.index('#BEGIN\n') + 1 idx2 = lines.index('#END\n') data = [ '[install]\n', 'bin_dir = %s\n' % bin_dir, 'python_dir = %s\n' % python_dir, 'content_dir = %s\n' % content_dir, 'plugin_dir = %s\n' % plugin_dir, 'scripts_dir = %s\n' % scripts_dir, 'extra_dir = %s\n' % extra_dir, ] lines[idx1:idx2] = data open(install_conf, 'w').writelines(lines) print print 'Installation complete. To set up a new Wiki, please run:' print print ' ', os.path.join(bin_dir, 'subwiki'), 'create' print print 'You may also use "subwiki help" for more information. Enjoy.' def load_config(): fname = os.path.join(dist_dir, 'conf', 'layouts.conf') defaults = { 'version' : subwiki.main.__version__, } cfg = ConfigParser.ConfigParser(defaults) cfg.read(fname) return cfg def select_layout(cfg): print 'Welcome to the SubWiki installer program.' print print 'Please chose an installation layout. These merely set default' print 'paths for the SubWiki installation process. You will have an' print 'opportunity to alter every directory. If you are unfamiliar' print 'with these layouts, then just use the default layout.' print layouts = cfg.sections() layouts.sort() # special handling for the 'subwiki' layout, which we know is there. # we want it listed first. layouts.remove('subwiki') layouts.insert(0, 'subwiki') for name in layouts: print '%-12s %s' % (name, cfg.get(name, 'description')) return prompt('Layout choice?', 'subwiki', choices=layouts) def prompt(msg, default=None, is_dir=False, choices=[]): # make sure we have a trailing space if msg[-1:] != ' ': msg += ' ' # add default text, if a default exists if default: msg += '[%s] ' % default choice_map = { } for c in choices: choice_map[c.lower()] = c while 1: try: value = raw_input(msg) except EOFError: print '\nExiting.' sys.exit(0) if not value and default: value = default value = value.strip() if choices: value = value.lower() if choice_map.has_key(value): # normalize the case of the user input return choice_map[value] print 'Please select from the available set of choices:' print ' ', ', '.join(choices) print elif is_dir and not subwiki.util.dir_writeable(value): print 'Error: you do not have write access to that directory.' print else: return value def copy_files(*paths, **kw): "Copy each (globbed) path into the directory given as the last param." # we may have a subwiki package parent dir to edit into the files package_dir = kw.get('package_dir') dst_dir = paths[-1] # if we have a single source, and it is a directory, then the source # directory *becomes* the destination directory. pop up one level on # the destination because our algorithm copies source *into* dest. if len(paths) == 2 and os.path.isdir(paths[0]): dst_basename = os.path.basename(dst_dir) dst_dir = os.path.dirname(dst_dir) else: dst_basename = None # make sure the destination exists if not os.path.exists(dst_dir): print 'Creating:', dst_dir os.makedirs(dst_dir) sources = [ ] for path in paths[:-1]: sources.extend(glob.glob(path)) for src in sources: basename = os.path.basename(src) # if we're copying a single directory, then we will have a custom # destination directory name dst = os.path.join(dst_dir, dst_basename or basename) if os.path.exists(dst): print 'ERROR:', dst, 'already exists.' dst += '.new' if os.path.exists(dst): num = 2 dst += '2' while os.path.exists(dst): num += 1 idx = dst.rfind('w') dst = dst[:idx+1] + str(num) print ' ... will install as "%s".' % os.path.basename(dst) if os.path.isdir(src): copy_tree(src, dst, package_dir) else: print 'Installing:', dst copy_one_file(src, dst, package_dir) def copy_tree(src, dst, package_dir): "Copy an entire tree." print 'Creating:', dst os.mkdir(dst) for name in os.listdir(src): # in case we are testing this from a working copy, let's eliminate # some of the files we might find if ignore_file(name): continue src_path = os.path.join(src, name) dst_path = os.path.join(dst, name) if os.path.isdir(src_path): copy_tree(src_path, dst_path, package_dir) else: try: print 'Installing:', dst_path copy_one_file(src_path, dst_path, package_dir) except (IOError, os.error), why: print 'ERROR: cannot copy "%s" to "%s": %s' % (src_path, dst_path, why) def copy_one_file(src, dst, package_dir): if package_dir: lines = open(src).readlines() for i in xrange(len(lines)): if lines[i].startswith('SUBWIKI_PACKAGE_PARENT_DIR'): lines[i] = "SUBWIKI_PACKAGE_PARENT_DIR = '%s'\n" % package_dir break open(dst, 'w').writelines(lines) shutil.copymode(src, dst) else: shutil.copy(src, dst) def ignore_file(name): if name == '.svn': return True for suffix in ignore_suffixes: if name.endswith(suffix): return True return False ignore_suffixes = [ '~', '.pyc', ] if __name__ == '__main__': main()