From 797a5819e43b1fe35a7ef21afb9810d37e496069 Mon Sep 17 00:00:00 2001 From: Six Date: Sat, 11 Dec 2010 18:09:41 -0500 Subject: added build code --- .hgignore | 6 +- lib/dodai/build/__init__.py | 216 +++++++++++++++++++++++++++++++++++++++ lib/dodai/build/after_install.py | 84 +++++++++++++++ 3 files changed, 302 insertions(+), 4 deletions(-) create mode 100644 lib/dodai/build/__init__.py create mode 100644 lib/dodai/build/after_install.py diff --git a/.hgignore b/.hgignore index b3dab9e..b4caba7 100644 --- a/.hgignore +++ b/.hgignore @@ -1,9 +1,7 @@ syntax: glob *.pyc +*.pyo *~ -*.kpf -bin -include -lib .coverage examples/config/example.log +lib/dodai.egg-info diff --git a/lib/dodai/build/__init__.py b/lib/dodai/build/__init__.py new file mode 100644 index 0000000..c4989be --- /dev/null +++ b/lib/dodai/build/__init__.py @@ -0,0 +1,216 @@ +from setuptools.command.easy_install import easy_install +from distutils.util import convert_path +from pkg_resources import Distribution, PathMetadata, normalize_path +from distutils import log +from distutils.errors import * +import sys, os, setuptools, glob +import virtualenv +import textwrap +import tempfile +import subprocess +import stat +import pprint + + + +class Filler(object): + + TAB_WIDTH = 4 + TAB_CHAR = ' ' + LINE_LEN = 79 + + def __init__(self, indent): + self._obj = None + self.initial_indent = self.TAB_CHAR*self.TAB_WIDTH*indent + indent+=1 + self.subsequent_indent = self.TAB_CHAR*self.TAB_WIDTH*indent + + def __call__(self, text): + text = text.rstrip() + return self.process(text) + + @property + def obj(self): + if not self._obj: + self._obj = textwrap.TextWrapper( + width=self.LINE_LEN, + initial_indent=self.initial_indent, + subsequent_indent=self.subsequent_indent, + ) + return self._obj.fill + + def process(self, text): + out = [] + text = textwrap.dedent(text) + obj = self.obj + lines = text.split('\n') + for line in lines: + out.append(self.obj(line)) + return '\n'.join(out) + + +class AfterInstallActionBase(object): + + def _quote_list(self, data): + if isinstance(data, basestring): + out = ["'{0}'".format(data)] + else: + out = ["'{0}'".format(d) for d in data] + return ', '.join(out) + +class EasyInstall(AfterInstallActionBase): + + CODE = """ + for package in [{packages}]: + easy_install(package) + """ + + def __init__(self, packages): + self.packages = self._quote_list(packages) + self.fill = Filler(1) + + def __call__(self): + code = self.CODE.format(packages=self.packages) + return self.fill(code) + + +class HgClone(AfterInstallActionBase): + + CODE = """ + hg_clone('{url}', '{dest}') + """ + + def __init__(self, url, dest): + self.url = url + self.dest = dest + self.fill = Filler(1) + + def __call__(self): + code = self.CODE.format(url=self.url, dest=self.dest) + return self.fill(code) + + +class RunSetupCommand(AfterInstallActionBase): + + CODE = """ + for dir in [{dirs}]: + setup_py(dir, {command}) + """ + + def __init__(self, dirs, command): + self.dirs = self._quote_list(dirs) + self.command = repr(command).strip('[]()') + self.fill = Filler(1) + + def __call__(self): + code = self.CODE.format(dirs=self.dirs, command=self.command) + return self.fill(code) + + +class RunPythonPrograms(AfterInstallActionBase): + + CODE = """ + for program in [{programs}]: + run_program(program) + """ + + def __init__(self, programs): + self.programs = self._quote_list(programs) + self.fill = Filler(1) + + def __call__(self): + code = self.CODE.format(programs=self.programs) + return self.fill(code) + + +class AfterInstall(object): + + FILE = 'after_install.py' + + CODE = ''' + def after_install(options, home_dir): + paths = build_paths(home_dir) + easy_install = EasyInstall(paths) + hg_clone = HgClone(paths) + setup_py = SetupPy(paths) + run_program = RunPythonProgram(paths) + ''' + def __init__(self): + self.fill = Filler(0) + self._code_from_file_ = None + + @property + def _code_from_file(self): + if not self._code_from_file_: + path = os.path.dirname(os.path.realpath(__file__)) + path = os.path.join(path, self.FILE) + fp = open(path, 'r') + self._code_from_file_ = fp.read() + fp.close() + return self._code_from_file_ + + def __call__(self, chain): + out = [self._code_from_file, self.fill(self.CODE)] + for obj in chain: + out.append(obj()) + out = ''.join(out) + return out + + +class VirtualEnvDev(object): + + NAME = 'devstrap.py' + PACKAGES = ['nose', 'virtualenv', 'ipython', 'mercurial', 'pylint'] + HG_URL = 'hg clone https://dodai.googlecode.com/hg' + HG_DEST = 'src' + AFTER_BUILD = [] + + def __init__(self, path, name): + self.name = '{0}-{1}'.format(name, self.NAME) + self.path = os.path.join(path, self.name) + + def __call__(self): + self._write() + print "File Built: {0}".format(self.path) + + def _write(self): + with open(self.path, 'w') as f: + f.write(self._data) + + @property + def _after_install(self): + chain = [ + EasyInstall(self.PACKAGES), + HgClone(self.HG_URL, self.HG_DEST), + RunSetupCommand(self.HG_DEST, 'develop'), + RunPythonPrograms(self.AFTER_BUILD) + ] + obj = AfterInstall() + return obj(chain) + + @property + def _data(self): + return virtualenv.create_bootstrap_script(self._after_install) + + +class devstrap(easy_install): + + description = 'create a devstrap file used for installing a dev env' + + user_options = easy_install.user_options + boolean_options = easy_install.boolean_options + command_consumes_arguments = False + + def run(self): + virtual_env = VirtualEnvDev(self.prefix, self.distribution.get_name()) + virtual_env() + + def initialize_options(self): + easy_install.initialize_options(self) + + def finalize_options(self): + if self.prefix: + if not os.path.exists(self.prefix): + os.makedirs(self.prefix) + else: + self.prefix = os.getcwd() diff --git a/lib/dodai/build/after_install.py b/lib/dodai/build/after_install.py new file mode 100644 index 0000000..16c1ec6 --- /dev/null +++ b/lib/dodai/build/after_install.py @@ -0,0 +1,84 @@ +import os +from collections import namedtuple +from subprocess import Popen +from subprocess import call +from subprocess import PIPE + +def build_paths(home_dir): + + obj = namedtuple('Paths', 'wd, home, bin, src, python') + + wd = os.getcwd() + if home_dir.startswith(os.sep): + home = home_dir + else: + home = os.path.realpath(os.path.join(wd, home_dir)) + bin = os.path.join(home, 'bin') + src = os.path.join(home, 'src') + python = os.path.join(bin, 'python') + + return obj(wd, home, bin, src, python) + + +class EasyInstall(object): + + def __init__(self, paths): + self._easy_install = os.path.join(paths.bin, 'easy_install') + + def __call__(self, package): + cmd = [self._easy_install, '-Uv', package] + call(cmd) + + +class HgClone(object): + + def __init__(self, paths, easy_install=EasyInstall): + self._easy_install = easy_install(paths) + self._paths = paths + self._hg_ = None + + @property + def _hg(self): + if not self._hg_: + cmd = ['which', 'hg'] + self._hg_ = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate()[0]\ + .strip() + if not self._hg_: + self._hg_ = os.path.join(self._paths.bin, 'hg') + if not os.path.exists(self._hg_): + self._easy_install('mercurial') + return self._hg_ + + def __call__(self, url, dest): + if not dest.startswith(os.sep): + dest = os.path.join(self._paths.home, dest) + cmd = [self._hg, 'clone', url, dest] + call(cmd) + + +class SetupPy(object): + + FILE = 'setup.py' + + def __init__(self, paths): + self._paths = paths + + def __call__(self, dir, command): + path = os.path.join(self._paths.home, dir) + name = os.path.join(path, self.FILE) + if os.path.exists(name): + os.chdir(path) + cmd = [self._paths.python, name, command] + call(cmd) + +class RunPythonProgram(object): + + def __init__(self, paths): + self._paths = paths + + def __call__(self, program): + path = os.path.join(self._paths.bin, program) + if os.path.exists(path): + cmd = [self._paths.python, path] + call(cmd) + -- cgit v1.2.3