Commits

Ronny Pfannschmidt committed 9ce7805

rename pu to kij

  • Participants
  • Parent commits 3505f1e

Comments (0)

Files changed (32)

File kij/__init__.py

Empty file added.

File kij/commands/__init__.py

Empty file added.

File kij/commands/install.py

+"""
+
+    :license: MIT/PSF
+    :copyright: 2010 by Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
+"""
+from kij.tasks.install import LinkPTH
+
+
+def link_command(config, queue):
+    #XXX: handle fscked paths?
+    #XXX: scripts
+    queue.add(LinkPTH(
+                   source=config.source,
+                   site=config.site,
+                   ))

File kij/files/__init__.py

Empty file added.

File kij/files/dist.py

+"""
+    pu.files.dist
+    ~~~~~~~~~~~~~
+
+    Read and write pu distribution files.
+
+    :license: MIT/PSF (see LICENSE.txt file)
+    :copyright: pu Authors (see AUTHORS.txt file)
+
+    This is the primary configuration file for any Python distribution. It
+    aims to capture all the data required for distribution. The dist file is
+    presented as a Yaml file, with a number of keys, each corresponding to a
+    configuration directive for the distribution.
+
+    A very simple example can be seen::
+
+    name:    Blogatron
+    version: 1.0
+    author:  Ali Afshar
+    packages:
+        - blogatron
+
+    Although the specification will grow, certain fields are recognised, some
+    are required, and some optional. Other when present need to be of a
+    certain type. The recognised attributes are desribed:
+
+    name
+        The distribution name, usually the name of the project. *required*
+
+    version
+        The version of the distribution, should be a string of the numerical
+        version number.
+
+    summary
+        A short one-line summary of the distribution.
+
+    packages
+        A list of package descriptions to add to the distribution
+
+
+    Being Yaml, there is a certain degree of type expressivity over ini-based
+    systems. Addiitonally, the Yaml loading layer can be easily swapped out
+    for anything else.
+"""
+
+import yaml
+
+
+from py.path import local
+
+
+DIST_FILE_KEYS = set((
+    'packages', 'summary', 'scripts'
+))
+
+
+class DistFileError(ValueError):
+    """Error with Dist File"""
+
+
+class DistFile(object):
+
+    def __init__(self, path):
+        self.path = local(path)
+        self._load()
+
+    def _load(self):
+        # XXX Handle exceptions
+        try:
+            conf = yaml.load(self.path.open())
+        except Exception, e:
+            raise DistFileError('Error loading file %s %s' % (self.path, e))
+        self.name = conf.get('name')
+        if self.name is None:
+            raise DistFileError('Missing "name" key %s' % self.path)
+        # now the optional keys
+        for k in DIST_FILE_KEYS:
+            setattr(self, k, conf.get(k))
+        # now some validation
+        if self.packages and not isinstance(self.packages, list):
+            raise DistFileError('packages must be a list')
+        self._model = conf
+
+    def __str__(self):
+        return "<DistFile: %s>" % self.path

File kij/files/pth.py

+'''
+    kid.files.pth
+    ~~~~~~~~~~~~~
+
+    deals with reading, editing and writing pth files
+
+    :license: GNU GPL3
+    :copyright: 2010 by Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
+'''
+from py.path import local
+
+
+class PthFile(object):
+    def __init__(self, path):
+        self.path = local(path)
+        self.entries = []
+        if not self.path.check():
+            return
+        with self.path.open() as f:
+            for entry in f:
+                entry = entry.strip()
+                if entry[0] == '.':
+                    self.append(self.path.dirpath().join(entry))
+                else:
+                    self.append(local(entry))
+
+    def append(self, path):
+        if path not in self.entries:
+            self.entries.append(path)
+
+    def remove(self, path):
+        self.entries.remove(path)
+
+    def save(self):
+        with self.path.open('w') as f:
+            for path in self.entries:
+                rel = path.relto(self.path.dirpath())
+                if rel:
+                    f.write('./%s\n' % rel)
+                else:
+                    f.write('%s\n' % path)

File kij/task_queue.py

+from kij.tasks.util import task_failed
+from kij.tasks.util import task_succeeded
+
+
+
+class Queue(object):
+    def __init__(self):
+        self._key_to_identity = {}
+        self.depends = {}
+        self.completed = set()
+        self.runnable = set()
+        self.failed = set()
+        self.running = set()
+
+    def _run_canidates(self):
+        for k, v in self.depends.iteritems():
+            if k in self.completed:
+                continue
+            if k in self.running:
+                continue
+            if v - self.completed:
+                continue
+            yield k, v
+
+
+    def find_and_add_new_runnable(self):
+        for k, v in  self._run_canidates():
+            try:
+                new_item = next(k)
+                new_item = self.add(new_item, parent=k)
+                return True
+            except (TypeError, StopIteration):
+                self.runnable.add(k)
+                return False
+
+
+    def report_failure(self, task):
+        self.failed.add(task)
+        task_failed.send(task)
+        self.completed.add(task)
+        self.running.remove(task)
+
+    def report_success(self, task):
+        task_succeeded.send(task)
+        self.completed.add(task)
+        self.running.remove(task)
+
+    def next(self):
+        #XXX: expensive
+        if not self.runnable:
+            retry = True
+            while retry:
+                retry = self.find_and_add_new_runnable()
+
+
+        if not self.runnable:
+            raise StopIteration
+
+        result = self.runnable.pop()
+        self.running.add(result)
+        return result
+
+    def __iter__(self):
+        return self
+
+    def __len__(self):
+        return len(self.depends) - len(self.completed)
+
+    def add(self, task, parent=None):
+        """add a `task`
+        if `parent` is given this task is a new dependency for parent
+        """
+        if parent:
+            assert parent in self.depends
+
+        if task not in self.depends:
+            self.depends[task] = set()
+            self._key_to_identity[task] = task
+        else:
+            task = self._key_to_identity[task]
+
+        if parent:
+            self.depends[parent].add(task)
+            task_succeeded.connect(parent._requirement_succeeded, sender=task)
+            task_failed.connect(parent._requirement_failed, sender=task)
+
+            # directly resignal on already completed signals
+            if task in self.completed:
+                print 'completed, but reasked', task
+                if task in self.failed:
+                    task_failed.send(task)
+                else:
+                    task_succeeded.send(task)
+        return task
+
+    def run_all_possible(self):
+        """runs all tasks it can complete
+
+        leaves the queue in a state where
+        all completable tasks are completed
+        """
+        for item in self:
+            print 'trying to run', item
+            try:
+                item()
+                self.report_success(item)
+            except RuntimeError:
+                #reraise if report_failure tells us to do so
+                if self.report_failure(item):
+                    raise
+
+    def run_all(self):
+        """try to run all tasks
+
+        if some tasks are unaccessible
+        :raises: RuntimeError
+        """
+        self.run_all_possible()
+        if len(self.completed) < len(self.depends):
+
+            def sanestr(x):
+                for a in 'match package'.split():
+                    if hasattr(x, a):
+                        return '%s %s=%s' % (
+                                x.__class__.__name__,
+                                a,
+                                getattr(x, a))
+
+                return x.__class__.__name__
+
+            def depspec(x):
+                if not self.depends[x]:
+                    return sanestr(x)
+                return '%s -> %s' % (
+                        sanestr(x),
+                        ', '.join(sanestr(v)
+                                  for v in sorted(self.depends[x])),
+                        )
+
+            print 'completed: \n ', '\n  '.join(sanestr(x)
+                                                for x in sorted(self.completed))
+            print 'depends', '\n  '.join(depspec(x) 
+                                         for x in sorted(self.depends))
+            raise RuntimeError('not all tasks are executable')

File kij/tasks/__init__.py

Empty file added.

File kij/tasks/build.py

+from kij.tasks.util import TaskBase
+from kij.tasks.metadata import FindPackages, ReadYamlMetadata
+
+import logging
+log = logging.getLogger('kij.build')
+
+class CopySinglePackageToBuild(TaskBase):
+    keys = 'source', 'build_lib', 'package'
+
+    def __call__(self):
+        elem = self.package.split('.')
+        source_pkg = self.source.join(*elem)
+        build_pkg = self.build_lib.join(*elem).ensure(dir=1)
+        for src in source_pkg.listdir('*.py'):
+            src.copy(build_pkg.join(src.basename))
+
+
+class CopyPackagesToBuild(TaskBase):
+    keys = 'source', 'build_lib'
+    requirements = FindPackages,
+
+    def on_findpackages_success(self, task):
+        print 'found packages', task.result
+        for pkg in task.result:
+            task = CopySinglePackageToBuild(
+                    source=self.source,
+                    build_lib=self.build_lib,
+                    package=pkg,
+                    )
+            self.queue.append(task)
+
+    def __call__(self):
+        pass
+
+
+class CompileByteCode(TaskBase):
+    """
+    compiles all python files below the target directory
+    uses the optimizer settings of the current interpreter
+
+    .. warning::
+
+        ignores `sys.dont_write_bytecode`
+    """
+    keys = 'build_lib',
+    requirements = CopyPackagesToBuild,
+
+    def __call__(self):
+        from py_compile import compile
+        for x in self.build_lib.visit('*.py'):
+            compile(str(x))
+
+
+class CopyScripts(TaskBase):
+    #XXX: fix shebangs
+    keys = 'source', 'build_scripts'
+    scripts = None
+    requirements = ReadYamlMetadata,
+
+    def on_readyamlmetadata_success(self, item):
+        self.scripts = item.result.scripts or ()
+
+    def __call__(self):
+        self.build_scripts.ensure(dir=True)
+        for script in self.scripts:
+            script = self.source.join(script)
+            print script
+            #XXX: better error
+            assert script.check(file=1), 'script %s missing'%script
+            script.copy(target=self.build_scripts.join(script.basename))
+
+
+class Build(TaskBase):
+    keys = 'source', 'build_scripts', 'build_lib'
+    requirements = CopyScripts, CompileByteCode, CopyScripts
+
+    def __call__(self):
+        pass

File kij/tasks/install.py

+from kij.files.pth import PthFile
+
+
+class LinkTask(object):
+    pth_name = 'pu-links.pth'
+
+    def __init__(self, site, source):
+        self.site = site
+        self.source = source
+
+    def __call__(self):
+        self.run()
+
+
+class LinkPTH(LinkTask):
+
+    def run(self):
+        pth = PthFile(self.site.join(self.pth_name))
+        pth.append(self.source)
+        pth.save()
+
+
+class UnlinkPTH(LinkTask):
+
+    def run(self):
+        pth = PthFile(self.site.join(self.pth_name))
+        pth.remove(self.source)
+        pth.save()

File kij/tasks/metadata.py

+from .util import TaskBase, task_succeeded
+from kij.files.dist import DistFile
+
+
+def find_packages(base, start):
+    if start.join('__init__.py').check(file=1):
+        package = start.relto(base).replace('/', '.')
+        yield package
+        for path in start.listdir(lambda p: p.check(dir=1)):
+            for result in find_packages(base, path):
+                yield result
+
+
+class FindSubPackages(TaskBase):
+    keys = 'source', 'match',
+    result = None
+
+    def __call__(self):
+        deep = self.match[-2:] == '.*'
+        elements = self.match.split('.')
+        if deep:
+            elements.pop()
+
+        self.result = list(find_packages(self.source,
+                                         self.source.join(*elements)))
+        print 'found', self.result
+        if not self.result:
+            raise IOError('package %s not found below %s' % (
+                           self.match, self.source))
+
+
+class ReadYamlMetadata(TaskBase):
+    keys = 'source',
+    result = None
+    requirements = ()
+    def __call__(self):
+        self.result = DistFile(self.source.join('kij.yml'))
+
+
+class FindPackages(TaskBase):
+    keys = 'source',
+    requirements = ReadYamlMetadata,
+
+    def on_readyamlmetadata_success(self, item):
+        self.result = []
+        print 'got yaml for', self
+        print item.result.packages
+        for package in item.result.packages:
+            task = FindSubPackages(
+                match=package,
+                source=self.source)
+            self.queue.append(task)
+
+    def on_findsubpackages_success(self, item):
+        print item
+        self.result.extend(item.result)
+
+    def __call__(self):
+        assert self.result

File kij/tasks/util.py

+"""
+    pu.tasks.util
+    ~~~~~~~~~~~~~
+
+    utility base classes and functions
+"""
+
+from collections import deque
+from blinker import Namespace
+
+ns = Namespace()
+task_failed = ns.signal('task_failed')
+task_succeeded = ns.signal('task_succeeded')
+task_finished = ns.signal('task_finished')
+
+
+class TaskBase(object):
+    """
+    utility base class for implementing Tasks
+
+    """
+    keys = ()
+    requirements = ()
+    queue = None
+
+    def __init__(self, **kw):
+        for key in self.keys:
+            setattr(self, key, kw[key])
+
+        self._kw = kw
+
+    # hashing and equality
+    def _key(self):
+        return tuple((key, getattr(self, key)) for key in self.keys)
+
+    def __hash__(self):
+        return hash(self._key())
+
+    def __eq__(self, other):
+        return (type(self) == type(other)
+                and self._key() == other._key())
+
+    def __repr__(self):
+        return '<%s %s>' % (
+                type(self).__name__,
+                ' '.join('%s=%r' % k
+                    for k in self._key()))
+
+    # reporting dispatch
+    def _dispatch(self, base, item):
+        name = getattr(item, 'category', item.__class__.__name__.lower())
+        method = 'on_%s_%s' % (name, base)
+        default_method = 'on_' + name
+        if hasattr(self, method):
+            return getattr(self, method)(item)
+        elif hasattr(self, default_method):
+            return getattr(self, default_method)(item)
+
+    def _requirement_succeeded(self, requirement):
+        self._enqueue_next_requirement()
+        return self._dispatch('success', requirement)
+
+    def _requirement_failed(self, requirement):
+        #XXX: how to deal with failure
+        return self._dispatch('failure', requirement)
+
+    def _enqueue_next_requirement(self):
+        if self.requirements:
+            print 'equeue next for', self
+            req = self.requirements.popleft()
+            task = req(**self._kw)
+            print 'made', task
+            self.queue.append(task)
+
+    def __iter__(self):
+        return self
+
+    def next(self):
+        if self.queue is None:
+            self.queue = deque()
+            #XXX: we need to re-suffle the connections inside of queue
+            #     that is absolutely required since
+            #     the returned requirement might already be in the queue
+            #     but with different identity
+            if self.requirements:
+                print self, 'needs', self.requirements
+                self.requirements = deque(self.requirements)
+                self._enqueue_next_requirement()
+        if self.queue:
+            return self.queue.popleft()
+        else:
+            raise StopIteration

File pu/__init__.py

Empty file removed.

File pu/commands/__init__.py

Empty file removed.

File pu/commands/install.py

-"""
-
-    :license: MIT/PSF
-    :copyright: 2010 by Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
-"""
-from pu.tasks.install import LinkPTH
-
-
-def link_command(config, queue):
-    #XXX: handle fscked paths?
-    #XXX: scripts
-    queue.add(LinkPTH(
-                   source=config.source,
-                   site=config.site,
-                   ))

File pu/files/__init__.py

Empty file removed.

File pu/files/dist.py

-"""
-    pu.files.dist
-    ~~~~~~~~~~~~~
-
-    Read and write pu distribution files.
-
-    :license: MIT/PSF (see LICENSE.txt file)
-    :copyright: pu Authors (see AUTHORS.txt file)
-
-    This is the primary configuration file for any Python distribution. It
-    aims to capture all the data required for distribution. The dist file is
-    presented as a Yaml file, with a number of keys, each corresponding to a
-    configuration directive for the distribution.
-
-    A very simple example can be seen::
-
-    name:    Blogatron
-    version: 1.0
-    author:  Ali Afshar
-    packages:
-        - blogatron
-
-    Although the specification will grow, certain fields are recognised, some
-    are required, and some optional. Other when present need to be of a
-    certain type. The recognised attributes are desribed:
-
-    name
-        The distribution name, usually the name of the project. *required*
-
-    version
-        The version of the distribution, should be a string of the numerical
-        version number.
-
-    summary
-        A short one-line summary of the distribution.
-
-    packages
-        A list of package descriptions to add to the distribution
-
-
-    Being Yaml, there is a certain degree of type expressivity over ini-based
-    systems. Addiitonally, the Yaml loading layer can be easily swapped out
-    for anything else.
-"""
-
-import yaml
-
-
-from py.path import local
-
-
-DIST_FILE_KEYS = set((
-    'packages', 'summary', 'scripts'
-))
-
-
-class DistFileError(ValueError):
-    """Error with Dist File"""
-
-
-class DistFile(object):
-
-    def __init__(self, path):
-        self.path = local(path)
-        self._load()
-
-    def _load(self):
-        # XXX Handle exceptions
-        try:
-            conf = yaml.load(self.path.open())
-        except Exception, e:
-            raise DistFileError('Error loading file %s %s' % (self.path, e))
-        self.name = conf.get('name')
-        if self.name is None:
-            raise DistFileError('Missing "name" key %s' % self.path)
-        # now the optional keys
-        for k in DIST_FILE_KEYS:
-            setattr(self, k, conf.get(k))
-        # now some validation
-        if self.packages and not isinstance(self.packages, list):
-            raise DistFileError('packages must be a list')
-        self._model = conf
-
-    def __str__(self):
-        return "<DistFile: %s>" % self.path

File pu/files/pth.py

-'''
-    kid.files.pth
-    ~~~~~~~~~~~~~
-
-    deals with reading, editing and writing pth files
-
-    :license: GNU GPL3
-    :copyright: 2010 by Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
-'''
-from py.path import local
-
-
-class PthFile(object):
-    def __init__(self, path):
-        self.path = local(path)
-        self.entries = []
-        if not self.path.check():
-            return
-        with self.path.open() as f:
-            for entry in f:
-                entry = entry.strip()
-                if entry[0] == '.':
-                    self.append(self.path.dirpath().join(entry))
-                else:
-                    self.append(local(entry))
-
-    def append(self, path):
-        if path not in self.entries:
-            self.entries.append(path)
-
-    def remove(self, path):
-        self.entries.remove(path)
-
-    def save(self):
-        with self.path.open('w') as f:
-            for path in self.entries:
-                rel = path.relto(self.path.dirpath())
-                if rel:
-                    f.write('./%s\n' % rel)
-                else:
-                    f.write('%s\n' % path)

File pu/task_queue.py

-from pu.tasks.util import task_failed
-from pu.tasks.util import task_succeeded
-
-
-
-class Queue(object):
-    def __init__(self):
-        self._key_to_identity = {}
-        self.depends = {}
-        self.completed = set()
-        self.runnable = set()
-        self.failed = set()
-        self.running = set()
-
-    def _run_canidates(self):
-        for k, v in self.depends.iteritems():
-            if k in self.completed:
-                continue
-            if k in self.running:
-                continue
-            if v - self.completed:
-                continue
-            yield k, v
-
-
-    def find_and_add_new_runnable(self):
-        for k, v in  self._run_canidates():
-            try:
-                new_item = next(k)
-                new_item = self.add(new_item, parent=k)
-                return True
-            except (TypeError, StopIteration):
-                self.runnable.add(k)
-                return False
-
-
-    def report_failure(self, task):
-        self.failed.add(task)
-        task_failed.send(task)
-        self.completed.add(task)
-        self.running.remove(task)
-
-    def report_success(self, task):
-        task_succeeded.send(task)
-        self.completed.add(task)
-        self.running.remove(task)
-
-    def next(self):
-        #XXX: expensive
-        if not self.runnable:
-            retry = True
-            while retry:
-                retry = self.find_and_add_new_runnable()
-
-
-        if not self.runnable:
-            raise StopIteration
-
-        result = self.runnable.pop()
-        self.running.add(result)
-        return result
-
-    def __iter__(self):
-        return self
-
-    def __len__(self):
-        return len(self.depends) - len(self.completed)
-
-    def add(self, task, parent=None):
-        """add a `task`
-        if `parent` is given this task is a new dependency for parent
-        """
-        if parent:
-            assert parent in self.depends
-
-        if task not in self.depends:
-            self.depends[task] = set()
-            self._key_to_identity[task] = task
-        else:
-            task = self._key_to_identity[task]
-
-        if parent:
-            self.depends[parent].add(task)
-            task_succeeded.connect(parent._requirement_succeeded, sender=task)
-            task_failed.connect(parent._requirement_failed, sender=task)
-
-            # directly resignal on already completed signals
-            if task in self.completed:
-                print 'completed, but reasked', task
-                if task in self.failed:
-                    task_failed.send(task)
-                else:
-                    task_succeeded.send(task)
-        return task
-
-    def run_all_possible(self):
-        """runs all tasks it can complete
-
-        leaves the queue in a state where
-        all completable tasks are completed
-        """
-        for item in self:
-            print 'trying to run', item
-            try:
-                item()
-                self.report_success(item)
-            except RuntimeError:
-                #reraise if report_failure tells us to do so
-                if self.report_failure(item):
-                    raise
-
-    def run_all(self):
-        """try to run all tasks
-
-        if some tasks are unaccessible
-        :raises: RuntimeError
-        """
-        self.run_all_possible()
-        if len(self.completed) < len(self.depends):
-
-            def sanestr(x):
-                for a in 'match package'.split():
-                    if hasattr(x, a):
-                        return '%s %s=%s' % (
-                                x.__class__.__name__,
-                                a,
-                                getattr(x, a))
-
-                return x.__class__.__name__
-
-            def depspec(x):
-                if not self.depends[x]:
-                    return sanestr(x)
-                return '%s -> %s' % (
-                        sanestr(x),
-                        ', '.join(sanestr(v)
-                                  for v in sorted(self.depends[x])),
-                        )
-
-            print 'completed: \n ', '\n  '.join(sanestr(x)
-                                                for x in sorted(self.completed))
-            print 'depends', '\n  '.join(depspec(x) 
-                                         for x in sorted(self.depends))
-            raise RuntimeError('not all tasks are executable')

File pu/tasks/__init__.py

Empty file removed.

File pu/tasks/build.py

-from pu.tasks.util import TaskBase
-from pu.tasks.metadata import FindPackages, ReadYamlMetadata
-
-import logging
-log = logging.getLogger('kij.build')
-
-class CopySinglePackageToBuild(TaskBase):
-    keys = 'source', 'build_lib', 'package'
-
-    def __call__(self):
-        elem = self.package.split('.')
-        source_pkg = self.source.join(*elem)
-        build_pkg = self.build_lib.join(*elem).ensure(dir=1)
-        for src in source_pkg.listdir('*.py'):
-            src.copy(build_pkg.join(src.basename))
-
-
-class CopyPackagesToBuild(TaskBase):
-    keys = 'source', 'build_lib'
-    requirements = FindPackages,
-
-    def on_findpackages_success(self, task):
-        print 'found packages', task.result
-        for pkg in task.result:
-            task = CopySinglePackageToBuild(
-                    source=self.source,
-                    build_lib=self.build_lib,
-                    package=pkg,
-                    )
-            self.queue.append(task)
-
-    def __call__(self):
-        pass
-
-
-class CompileByteCode(TaskBase):
-    """
-    compiles all python files below the target directory
-    uses the optimizer settings of the current interpreter
-
-    .. warning::
-
-        ignores `sys.dont_write_bytecode`
-    """
-    keys = 'build_lib',
-    requirements = CopyPackagesToBuild,
-
-    def __call__(self):
-        from py_compile import compile
-        for x in self.build_lib.visit('*.py'):
-            compile(str(x))
-
-
-class CopyScripts(TaskBase):
-    #XXX: fix shebangs
-    keys = 'source', 'build_scripts'
-    scripts = None
-    requirements = ReadYamlMetadata,
-
-    def on_readyamlmetadata_success(self, item):
-        self.scripts = item.result.scripts or ()
-
-    def __call__(self):
-        self.build_scripts.ensure(dir=True)
-        for script in self.scripts:
-            script = self.source.join(script)
-            print script
-            #XXX: better error
-            assert script.check(file=1), 'script %s missing'%script
-            script.copy(target=self.build_scripts.join(script.basename))
-
-
-class Build(TaskBase):
-    keys = 'source', 'build_scripts', 'build_lib'
-    requirements = CopyScripts, CompileByteCode, CopyScripts
-
-    def __call__(self):
-        pass

File pu/tasks/install.py

-from pu.files.pth import PthFile
-
-
-class LinkTask(object):
-    pth_name = 'pu-links.pth'
-
-    def __init__(self, site, source):
-        self.site = site
-        self.source = source
-
-    def __call__(self):
-        self.run()
-
-
-class LinkPTH(LinkTask):
-
-    def run(self):
-        pth = PthFile(self.site.join(self.pth_name))
-        pth.append(self.source)
-        pth.save()
-
-
-class UnlinkPTH(LinkTask):
-
-    def run(self):
-        pth = PthFile(self.site.join(self.pth_name))
-        pth.remove(self.source)
-        pth.save()

File pu/tasks/metadata.py

-from .util import TaskBase, task_succeeded
-
-
-def find_packages(base, start):
-    if start.join('__init__.py').check(file=1):
-        package = start.relto(base).replace('/', '.')
-        yield package
-        for path in start.listdir(lambda p: p.check(dir=1)):
-            for result in find_packages(base, path):
-                yield result
-
-
-class FindSubPackages(TaskBase):
-    keys = 'source', 'match',
-    result = None
-
-    def __call__(self):
-        deep = self.match[-2:] == '.*'
-        elements = self.match.split('.')
-        if deep:
-            elements.pop()
-
-        self.result = list(find_packages(self.source,
-                                         self.source.join(*elements)))
-        print 'found', self.result
-        if not self.result:
-            raise IOError('package %s not found below %s' % (
-                           self.match, self.source))
-
-
-class ReadYamlMetadata(TaskBase):
-    keys = 'source',
-    result = None
-    requirements = ()
-    def __call__(self):
-        from pu.files.dist import DistFile
-        self.result = DistFile(self.source.join('kij.yml'))
-
-
-class FindPackages(TaskBase):
-    keys = 'source',
-    requirements = ReadYamlMetadata,
-
-    def on_readyamlmetadata_success(self, item):
-        self.result = []
-        print 'got yaml for', self
-        print item.result.packages
-        for package in item.result.packages:
-            task = FindSubPackages(
-                match=package,
-                source=self.source)
-            self.queue.append(task)
-
-    def on_findsubpackages_success(self, item):
-        print item
-        self.result.extend(item.result)
-
-    def __call__(self):
-        assert self.result

File pu/tasks/util.py

-"""
-    pu.tasks.util
-    ~~~~~~~~~~~~~
-
-    utility base classes and functions
-"""
-
-from collections import deque
-from blinker import Namespace
-
-ns = Namespace()
-task_failed = ns.signal('task_failed')
-task_succeeded = ns.signal('task_succeeded')
-task_finished = ns.signal('task_finished')
-
-
-class TaskBase(object):
-    """
-    utility base class for implementing Tasks
-
-    """
-    keys = ()
-    requirements = ()
-    queue = None
-
-    def __init__(self, **kw):
-        for key in self.keys:
-            setattr(self, key, kw[key])
-
-        self._kw = kw
-
-    # hashing and equality
-    def _key(self):
-        return tuple((key, getattr(self, key)) for key in self.keys)
-
-    def __hash__(self):
-        return hash(self._key())
-
-    def __eq__(self, other):
-        return (type(self) == type(other)
-                and self._key() == other._key())
-
-    def __repr__(self):
-        return '<%s %s>' % (
-                type(self).__name__,
-                ' '.join('%s=%r' % k
-                    for k in self._key()))
-
-    # reporting dispatch
-    def _dispatch(self, base, item):
-        name = getattr(item, 'category', item.__class__.__name__.lower())
-        method = 'on_%s_%s' % (name, base)
-        default_method = 'on_' + name
-        if hasattr(self, method):
-            return getattr(self, method)(item)
-        elif hasattr(self, default_method):
-            return getattr(self, default_method)(item)
-
-    def _requirement_succeeded(self, requirement):
-        self._enqueue_next_requirement()
-        return self._dispatch('success', requirement)
-
-    def _requirement_failed(self, requirement):
-        #XXX: how to deal with failure
-        return self._dispatch('failure', requirement)
-
-    def _enqueue_next_requirement(self):
-        if self.requirements:
-            print 'equeue next for', self
-            req = self.requirements.popleft()
-            task = req(**self._kw)
-            print 'made', task
-            self.queue.append(task)
-
-    def __iter__(self):
-        return self
-
-    def next(self):
-        if self.queue is None:
-            self.queue = deque()
-            #XXX: we need to re-suffle the connections inside of queue
-            #     that is absolutely required since
-            #     the returned requirement might already be in the queue
-            #     but with different identity
-            if self.requirements:
-                print self, 'needs', self.requirements
-                self.requirements = deque(self.requirements)
-                self._enqueue_next_requirement()
-        if self.queue:
-            return self.queue.popleft()
-        else:
-            raise StopIteration

File tests/cli/test_install.py

-from pu.commands.install import link_command
-from pu.task_queue import Queue
+from kij.commands.install import link_command
+from kij.task_queue import Queue
 
 
 def test_link_command(config, site):

File tests/files/test_dist.py

 import py
-from pu.files.dist import DistFile, DistFileError
+from kij.files.dist import DistFile, DistFileError
 
 
 def pytest_funcarg__distfile(request):

File tests/files/test_pth.py

 import py
-from pu.files.pth import PthFile
+from kij.files.pth import PthFile
 
 
 def pytest_funcarg__pthfile(request):

File tests/tasks/test_build.py

-from pu.tasks.build import CopyPackagesToBuild, CompileByteCode, \
+from kij.tasks.build import CopyPackagesToBuild, CompileByteCode, \
         CopyScripts, Build
-from pu.task_queue import Queue
+from kij.task_queue import Queue
 
 
 def test_copy_build(source, tmpdir):

File tests/tasks/test_develop.py

-from pu.tasks.install import LinkPTH, UnlinkPTH
-from pu.files.pth import PthFile
+from kij.tasks.install import LinkPTH, UnlinkPTH
+from kij.files.pth import PthFile
 
 
 def test_enable(site, source):

File tests/tasks/test_metadata.py

 import py
-from pu.tasks.metadata import FindSubPackages, find_packages as gen_find_packages
-from pu.tasks.metadata import ReadYamlMetadata, FindPackages
-from pu.task_queue import Queue
+from kij.tasks.metadata import FindSubPackages, find_packages as gen_find_packages
+from kij.tasks.metadata import ReadYamlMetadata, FindPackages
+from kij.task_queue import Queue
 
 def find_packages(source, pkg):
     return list(gen_find_packages(source, pkg))

File tests/tasks/test_util.py

 import py
-from pu.tasks.util import TaskBase, task_succeeded, task_failed
-from pu.task_queue import Queue
+from kij.tasks.util import TaskBase, task_succeeded, task_failed
+from kij.task_queue import Queue
 
 
 class Omg(TaskBase):

File tests/test_task_queue.py

 import py
-from pu.task_queue import Queue
-from pu.tasks.install import LinkPTH
-from pu.tasks.util import TaskBase
+from kij.task_queue import Queue
+from kij.tasks.install import LinkPTH
+from kij.tasks.util import TaskBase
 
 class SimpleTask(TaskBase):
     ndeps = None