#!/usr/bin/env python

# Author: Forest Bond <forest@alittletooquiet.net>
# This file is in the public domain.

import os, sys, commands, glob
from distutils.command.build import build as _build
from distutils.command.clean import clean as _clean
from distutils.command.build_py import build_py
from distutils.core import setup, Command
from distutils.spawn import spawn
from distutils import log
from distutils.dir_util import remove_tree
from distutils.dist import Distribution

project_dir = os.path.dirname(__file__)
sys.path.insert(0, project_dir)

from tests.common import TEST_DIR

################################################################################

class test(Command):
    description = 'run tests'
    user_options = [('tests=', None, 'names of tests to run')]

    def initialize_options(self):
        self.tests = None

    def finalize_options(self):
        if self.tests is not None:
            self.tests = self.tests.split(',')

    def run(self):
        from tests import load, main
        load()
        main(self.tests)

################################################################################

class clean(_clean):
    temporary_files = []
    nontemporary_files = []

    temporary_dirs = []
    nontemporary_dirs = []

    def clean_file(self, filename):
        if not os.path.exists(filename):
            log.info("'%s' does not exist -- can't clean it", filename)
            return

        log.info("removing '%s'" % filename)
        if not self.dry_run:
            try:
                os.unlink(filename)
            except (IOError, OSError):
                log.warn("failed to remove '%s'" % filename)

    def clean_dir(self, dirname):
        if not os.path.exists(dirname):
            log.info("'%s' does not exist -- can't clean it", dirname)
            return

        log.info("removing '%s' (and everything under it)" % dirname)
        if not self.dry_run:
            try:
                remove_tree(dirname)
            except (IOError, OSError):
                log.warn("failed to remove '%s'" % dirname)

    def run(self):
        remove_files = list(self.temporary_files)
        if self.all:
            remove_files = remove_files + self.nontemporary_files

        for filename in remove_files:
            if callable(filename):
                filename = filename(self.distribution)
            self.clean_file(filename)

        remove_dirs = list(self.temporary_dirs)
        if self.all:
            remove_dirs = remove_dirs + self.nontemporary_dirs

        for dirname in remove_dirs:
            if callable(dirname):
                dirname = dirname(self.distribution)
            self.clean_dir(dirname)

        _clean.run(self)

################################################################################

class build_version_file(build_py):
    def initialize_options(self):
        build_py.initialize_options(self)

        self.version = None
        self.version_file = None

    def finalize_options(self):
        build_py.finalize_options(self)

        self.packages = self.distribution.packages
        self.py_modules = [self.distribution.version_module]

        self.version = self.distribution.get_version()
        self.version_file = self.distribution.version_file

    def check_module(self, *args, **kwargs):
        pass

    def build_modules(self, *args, **kwargs):
        log.info("creating version file '%s'" % self.version_file)
        if not self.dry_run:
            f = open(self.version_file, 'w')
            f.write('version = %s' % repr(self.version))
            f.close()
        build_py.build_modules(self, *args, **kwargs)

clean.temporary_files.append(lambda distribution: distribution.version_file)
Distribution.version_module = None
Distribution.release_file = None

def get_bzr_version():
    status, output = commands.getstatusoutput('bzr revno')
    return 'bzr%s' % output.strip()

def get_version(release_file):
    try:
        f = open(release_file, 'r')
        try:
            version = f.read().strip()
        finally:
            f.close()
    except (IOError, OSError):
        version = get_bzr_version()
    return version

def get_version_file(version_module):
    return '%s.py' % os.path.join(*(version_module.split('.')))

def wrap_init(fn):
    def __init__(self, *args, **kwargs):
        fn(self, *args, **kwargs)
        self.version_file = get_version_file(self.version_module)
        self.metadata.version = get_version(self.release_file)
    return __init__

Distribution.__init__ = wrap_init(Distribution.__init__)

################################################################################

class build(_build):
    sub_commands = _build.sub_commands + [
      ('build_version_file', (lambda self: True)),
    ]

################################################################################

setup(
  cmdclass = {
    'test': test,
    'build': build,
    'build_version_file': build_version_file,
    'clean': clean,
  },
  name = 'sclapp',
  version_module = 'sclapp.version',
  packages = ['sclapp'],
  release_file = 'release',

  author = 'Forest Bond',
  author_email = 'forest@alittletooquiet.net',
  url = 'http://www.alittletooquiet.net/software/sclapp/',
  license = 'GPLV2',
  description = 'A framework for python command-line applications.',
)
