#!/usr/bin/env python
# Copyright  2001, 2002 Progiciels Bourbeau-Pinard inc.
# Franois Pinard <pinard@iro.umontreal.ca>, 2001.

"""\
Installer tool for Pymacs.

Usage: setup [OPTION]

  -H   Display this help, then exit.
  -V   Display package name and version, then exit.

  -i         Interactively check selected options with user.
  -n         Dry run: merely display selected options.
  -g GROUP   Install with write permissions for that user GROUP.
  -e         Load `.emacs' before checking Emacs `load-path'.

  -b BINDIR      Install `pymacs-services' in BINDIR.
  -l LISPDIR     Install `pymacs.el' in LISPDIR.
  -p PYTHONDIR   Install `pymacs.py' in PYTHONDIR.
  -x PYMACSDIR   Find Python extension for Emacs in PYMACSDIR.

  -E EMACS    Use that executable for EMACS, if not `emacs'.
  -P PYTHON   Use that executable for Python, if not `python'.

"""

import os, string, sys

class run:
    PACKAGE = 'pymacs'
    VERSION = '0.15'
    interactive = 0
    dry = 0
    group = None
    dot_emacs = 0
    bindir = None
    lispdir = None
    pythondir = None
    pymacsdir = None
    emacs = 'emacs'
    python = 'python'

def main(*arguments):
    import getopt
    options, arguments = getopt.getopt(arguments, 'E:HP:Vb:eg:il:np:x:')
    for option, value in options:
        if option == '-E' and value:
            run.emacs = value
        elif option == '-H':
            sys.stdout.write(__doc__)
            sys.exit(0)
        elif option == '-P' and value:
            run.python = value
        elif option == '-V':
            sys.stdout.write('%s-%s' % (run.PACKAGE, run.VERSION))
            sys.exit(0)
        elif option == '-b' and value:
            run.bindir = [value]
        elif option == '-e':
            run.dot_emacs = 1
        elif option == '-g' and value:
            run.group = value
        elif option == '-i':
            run.interactive = 1
        elif option == '-l' and value:
            run.lispdir = [value]
        elif option == '-p' and value:
            run.pythondir = [value]
        elif option == '-x' and value:
            run.pymacsdir = [value]
    study_possible()
    if run.interactive:
        check_with_user()
    check_choices()
    if not run.dry:
        complete_install()

def study_possible():
    if not run.bindir:
        run.bindir = []
        for path in string.split(os.environ['PATH'], ':'):
            if os.access(path, 7):
                run.bindir.append(path)
    if not run.lispdir:
        run.lispdir = []
        import tempfile
        script = tempfile.mktemp()
        try:
            open(script, 'w').write('(message "%S" load-path)')
            load_config = ''
            if run.dot_emacs:
                config = os.path.join(os.environ['HOME'], '.emacs')
                for name in config, config + '.el', config + '.elc':
                    if os.path.isfile(name):
                        load_config = ' -l %s' % name
                        break
            text = os.popen('%s -batch%s -l %s 2>&1'
                            % (run.emacs, load_config, script)).read()
        finally:
            os.remove(script)
        position = string.find(text, '("')
        if position >= 0:
            text = text[position:]
        if text[-1] == '\n':
            text = text[:-1]
        assert text[0] == '(' and text[-1] == ')', text
        for path in string.split(text[1:-1]):
            assert path[0] == '"' and path[-1] == '"', path
            path = path[1:-1]
            if os.access(path, 7):
                run.lispdir.append(path)
    if not run.pythondir:
        run.pythondir = []
        text = (os.popen('%s -c \'import sys; print sys.path\'' % run.python)
                .read())
        if text[-1] == '\n':
            text = text[:-1]
        assert text[:2] == '[\'' and text[-2:] == '\']', text
        for path in string.split(text[1:-1], ', '):
            assert path[0] == '\'' and path[-1] == '\'', path
            path = path[1:-1]
            if os.access(path, 7):
                run.pythondir.append(path)

def check_with_user():
    sys.stderr.write("""\
Installing tool for Pymacs version %s.
"""
                     % run.VERSION)
    run.bindir = user_select('bindir', run.bindir, """\
This is where `pymacs-services', the Python process starter, should go:
somewhere on your shell `PATH'.
""")
    run.lispdir = user_select('lispdir', run.lispdir, """\
This is where `pymacs.el', the Emacs side code of Pymacs, should go:
somewhere on your Emacs `load-path'.
""")
    run.pythondir = user_select('pythondir', run.pythondir, """\
This is where `pymacs.py', the Python side code of Pymacs, should go:
somewhere on your Python `sys.path'.
""")
    run.pymacsdir = user_select('pymacsdir', run.pymacsdir, """\
This is where you intend to keep your Python code to extend Emacs.
You should make sure this variable is empty if you do not want to use
a special directory for this purpose, as you might very well save your
Python extensions in any directory from your usual Python search path.
""")

def user_select(name, values, message):
    write = sys.stderr.write
    readline = sys.stdin.readline
    if values is None:
        write("""\

Enter a value for `%s', or merely type `Enter' if you do not want any.
"""
              % name)
        write(message)
        while 1:
            write('%s? ' % name)
            text = string.strip(readline())
            if not text:
                return None
            if os.access(os.path.expanduser(text), 7):
                return [text]
            write("""\

This directory does not exist, or is not writable.  Please reenter it.
""")
    if len(values) == 1:
        return values
    if values == []:
        write("""\

Pymacs is not likely to install properly, as the installer may not currently
write in any directory for `%s'.  Running as `root' might help you.
Or else, you will most probably have to revise a bit your work setup.
"""
              % name)
        write(message)
        return values
    write("""\

There are many possibilities for `%s', please select one of them by
typing its number followed by `Enter'.  A mere `Enter' selects the first.
"""
          % name)
    write(message)
    write('\n')
    for counter in range(len(values)):
        write('%d. %s\n' % (counter + 1, values[counter]))
    while 1:
        write('[1-%d]? ' % len(values))
        text = string.strip(readline())
        if not text:
            return [values[0]]
        try:
            counter = int(text)
        except ValueError:
            pass
        else:
            if 1 <= counter <= len(values):
                return [values[counter-1]]
        write("""\
This is not a valid choice.  Please retry.
""")

def check_choices():
    write = sys.stderr.write
    error = 0
    if run.bindir and os.access(os.path.expanduser(run.bindir[0]), 7):
        run.bindir = os.path.expanduser(run.bindir[0])
    else:
        write("Use `-b BINDIR' to select where `pymacs-services' should go.\n")
        error = 1
    if run.lispdir and os.access(os.path.expanduser(run.lispdir[0]), 7):
        run.lispdir = run.lispdir[0]
    else:
        write("Use `-l LISPDIR' to select where `pymacs.el' should go.\n")
        error = 1
    if run.pythondir and os.access(os.path.expanduser(run.pythondir[0]), 7):
        run.pythondir = os.path.expanduser(run.pythondir[0])
    else:
        write("Use `-p PYTHONDIR' to select where `pymacs.py' should go.\n")
        error = 1
    if run.pymacsdir:
        if os.access(os.path.expanduser(run.pymacsdir[0]), 7):
            run.pymacsdir = os.path.expanduser(run.pymacsdir[0])
        else:
            write("Use `-x PYMACSDIR' to where Python extensions are kept.\n")
            error = 1
    else:
        run.pymacsdir = ''
    if error:
        write("ERROR: Installation aborted!\n"
              "       Try `%s -i'.\n" % sys.argv[0])
        sys.exit(1)
    write(
        '\n'
        "Directory selection for installing Pymacs:\n"
        "  bindir    = %(bindir)s\n"
        "  lispdir   = %(lispdir)s\n"
        "  pythondir = %(pythondir)s\n"
        "  pymacsdir = %(pymacsdir)s\n"
        '\n'
        % run.__dict__)

def complete_install():
    goal = os.path.join(run.bindir, 'pymacs-services')
    install('pymacs-services', goal, 0755)
    goal = os.path.join(run.lispdir, 'pymacs.el')
    install('pymacs.el', goal, 0644)
    compile_lisp(goal)
    goal = os.path.join(run.pythondir, 'pymacs.py')
    install('pymacs.py', goal, 0644)
    compile_python(goal)

def install(source, destination, permissions):
    sys.stderr.write('Installing %s\n' % destination)
    write = open(destination, 'w').write
    produce_at = 0
    for fragment in string.split(open(source).read(), '@'):
        if produce_at:
            replacement = run.__dict__.get(fragment)
            if replacement:
                write(replacement)
                produce_at = 0
            else:
                write('@')
                write(fragment)
        else:
            write(fragment)
            produce_at = 1
    write = None
    set_attributes(destination, permissions)

def compile_lisp(name):
    sys.stderr.write('Compiling %s\n' % name)
    os.system('%s -batch -f batch-byte-compile %s' % (run.emacs, name))
    set_attributes(name + 'c', 0644)

def compile_python(name):
    sys.stderr.write('Compiling %s\n' % name)
    import py_compile
    py_compile.compile(name)
    set_attributes(name + 'c', 0644)

def set_attributes(name, permissions):
    if run.group:
        os.chown(name, run.group)
        permissions = permissions | 0020
    os.chmod(name, permissions)

if __name__ == '__main__':
    apply(main, sys.argv[1:])
