# Path: peru/async_helpers.py
# async def safe_communicate(process, input=None):
#     '''Asyncio's communicate method has a bug where `communicate(input=b"")` is
#     treated the same as `communicate(). That means that child processes can
#     hang waiting for input, when their stdin should be closed. See
#     https://bugs.python.org/issue26848. The issue is fixed upstream in
#     https://github.com/python/asyncio/commit/915b6eaa30e1e3744e6f8223f996e197c1c9b91d,
#     but we will probably always need this workaround for old versions.'''
#     if input is not None and len(input) == 0:
#         process.stdin.close()
#         return (await process.communicate())
#     else:
#         return (await process.communicate(input))
# 
# Path: peru/compat.py
# def makedirs(path):
#     '''os.makedirs() has an exist_ok param, but it still throws errors when the
#     path exists with non-default permissions. This isn't fixed until 3.4.
#     Pathlib won't be getting an exist_ok param until 3.5.'''
#     path = str(path)  # compatibility with pathlib
#     # Use isdir to avoid silently returning if the path exists but isn't a dir.
#     if not os.path.isdir(path):
#         os.makedirs(path)


import asyncio
import contextlib
import collections
import hashlib
import json
import os
import pathlib
import re
import textwrap
from .async_helpers import safe_communicate
from .compat import makedirs
from .error import PrintableError
from .keyval import KeyVal
        for line in output.strip('\x00').split('\x00'):
            mode, type, hash, name = re.match(entry_regex, line).groups()
            if (recursive and path is not None
                    and len(name) < len(canonical_path) and type == TREE_TYPE):
                # In recursive mode, leave out the parents of the target dir.
                continue
            entries[name] = TreeEntry(mode, type, hash)
        return entries

    async def make_tree_from_entries(self, entries):
        entry_format = '{} {} {}\t{}'
        input = '\x00'.join(
            entry_format.format(mode, type, hash, name)
            for name, (mode, type, hash) in entries.items())
        tree = await self.git('mktree', '-z', input=input)
        return tree


async def Cache(root):
    'This is the async constructor for the _Cache class.'
    cache = _Cache(root)
    await cache._init_trees()
    return cache


class _Cache:
    def __init__(self, root):
        "Don't instantiate this class directly. Use the Cache() constructor."
        self.root = root
        self.plugins_root = os.path.join(root, "plugins")

# Path: peru/async_helpers.py
# async def safe_communicate(process, input=None):
#     '''Asyncio's communicate method has a bug where `communicate(input=b"")` is
#     treated the same as `communicate(). That means that child processes can
#     hang waiting for input, when their stdin should be closed. See
#     https://bugs.python.org/issue26848. The issue is fixed upstream in
#     https://github.com/python/asyncio/commit/915b6eaa30e1e3744e6f8223f996e197c1c9b91d,
#     but we will probably always need this workaround for old versions.'''
#     if input is not None and len(input) == 0:
#         process.stdin.close()
#         return (await process.communicate())
#     else:
#         return (await process.communicate(input))
# 
# Path: peru/compat.py
# def makedirs(path):
#     '''os.makedirs() has an exist_ok param, but it still throws errors when the
#     path exists with non-default permissions. This isn't fixed until 3.4.
#     Pathlib won't be getting an exist_ok param until 3.5.'''
#     path = str(path)  # compatibility with pathlib
#     # Use isdir to avoid silently returning if the path exists but isn't a dir.
#     if not os.path.isdir(path):
#         os.makedirs(path)


# Path: peru/cache.py
import asyncio
import contextlib
import collections
import hashlib
import json
import os
import pathlib
import re
import textwrap
from .async_helpers import safe_communicate
from .compat import makedirs
from .error import PrintableError
from .keyval import KeyVal

        for line in output.strip('\x00').split('\x00'):
            mode, type, hash, name = re.match(entry_regex, line).groups()
            if (recursive and path is not None
                    and len(name) < len(canonical_path) and type == TREE_TYPE):
                # In recursive mode, leave out the parents of the target dir.
                continue
            entries[name] = TreeEntry(mode, type, hash)
        return entries

    async def make_tree_from_entries(self, entries):
        entry_format = '{} {} {}\t{}'
        input = '\x00'.join(
            entry_format.format(mode, type, hash, name)
            for name, (mode, type, hash) in entries.items())
        tree = await self.git('mktree', '-z', input=input)
        return tree


async def Cache(root):
    'This is the async constructor for the _Cache class.'
    cache = _Cache(root)
    await cache._init_trees()
    return cache


class _Cache:
    def __init__(self, root):
        "Don't instantiate this class directly. Use the Cache() constructor."
        self.root = root
        self.plugins_root = os.path.join(root, "plugins")

        makedirs(self.plugins_root)