# Path: badwolf/utils.py
# class ObjectDict(dict):
#     """Makes a dictionary behave like an object, with attribute-style access.
#     """
#     def __getattr__(self, key):
#         if key in self:
#             return self[key]
#         return None
# 
#     def __setattr__(self, key, value):
#         self[key] = value
# 
# def to_text(value, encoding='utf-8', errors='ignore'):
#     """Convert value to unicode, default encoding is utf-8
# 
#     :param value: Value to be converted
#     :param encoding: Desired encoding
#     """
#     if not value:
#         return ''
#     if isinstance(value, str):
#         return value
#     if isinstance(value, bytes):
#         return value.decode(encoding, errors)
#     return str(value)
# 
# def to_binary(value, encoding='utf-8'):
#     """Convert value to binary string, default encoding is utf-8
# 
#     :param value: Value to be converted
#     :param encoding: Desired encoding
#     """
#     if not value:
#         return b''
#     if isinstance(value, bytes):
#         return value
#     if isinstance(value, str):
#         return value.encode(encoding)
#     return bytes(value)
# 
# Path: badwolf/security.py
# class SecureToken(object):
# 
#     @staticmethod
#     def encrypt(text):
#         fernet = Fernet(to_binary(current_app.config['SECURE_TOKEN_KEY']))
#         return fernet.encrypt(to_binary(text))
# 
#     @staticmethod
#     def decrypt(encrypted):
#         fernet = Fernet(to_binary(current_app.config['SECURE_TOKEN_KEY']))
#         text = fernet.decrypt(to_binary(encrypted))
#         return to_text(text)
# 
# def parse_secretfile(fd):
#     env = []
#     for line in fd:
#         line = line.strip()
#         if not line:
#             continue
#         if line.startswith('#'):
#             continue
#         elif line.startswith('>'):
#             # Write to file not supported for now
#             continue
#         else:
#             env.append(line)
#     return env
# 
# Path: badwolf/exceptions.py
# class InvalidSpecification(BadwolfException):
#     pass


import io
import base64
import logging
import shlex
import yaml
    from yaml import CLoader as _Loader
    from yaml import Loader as _Loader
from flask import render_template
from marshmallow import Schema, fields, pre_load, post_load, ValidationError, validate
from marshmallow.utils import is_collection
from marshmallow_oneofschema import OneOfSchema
from badwolf.utils import ObjectDict, to_text, to_binary
from badwolf.security import SecureToken, parse_secretfile
from badwolf.exceptions import InvalidSpecification
        from cryptography.fernet import InvalidToken
    secretfile = fields.Boolean(missing=True)  # 是否自动从 Secretfile 加载 Vault 内容

    @post_load
    def _postprocess(self, data, **kwargs):
        # vault.envs format should be:
        # ENV_NAME secret/path:key
        env_map = ObjectDict()
        for env in data['env']:
            try:
                name, path_key = env.strip().split(' ', 1)
                path, key = path_key.strip().split(':', 1)
            except ValueError:
                raise ValidationError('Invalid vault env {}'.format(name), 'env')
            env_map[name] = (path, key)
        data['env'] = env_map
        return super()._postprocess(data, **kwargs)


class SpecificationSchema(Schema):
    class Meta:
        strict = True

    image = fields.String(missing=None)
    shell = fields.String(missing='bash')
    dockerfile = fields.String(missing='Dockerfile')
    docker = fields.Boolean(missing=False)
    privileged = fields.Boolean(missing=False)
    services = ListField(fields.String(), data_key='service', missing=list)
    branch = SetField(fields.String(), missing=set)
    environments = ListField(SecureField(), data_key='env', missing=list)

# Path: badwolf/utils.py
# class ObjectDict(dict):
#     """Makes a dictionary behave like an object, with attribute-style access.
#     """
#     def __getattr__(self, key):
#         if key in self:
#             return self[key]
#         return None
# 
#     def __setattr__(self, key, value):
#         self[key] = value
# 
# def to_text(value, encoding='utf-8', errors='ignore'):
#     """Convert value to unicode, default encoding is utf-8
# 
#     :param value: Value to be converted
#     :param encoding: Desired encoding
#     """
#     if not value:
#         return ''
#     if isinstance(value, str):
#         return value
#     if isinstance(value, bytes):
#         return value.decode(encoding, errors)
#     return str(value)
# 
# def to_binary(value, encoding='utf-8'):
#     """Convert value to binary string, default encoding is utf-8
# 
#     :param value: Value to be converted
#     :param encoding: Desired encoding
#     """
#     if not value:
#         return b''
#     if isinstance(value, bytes):
#         return value
#     if isinstance(value, str):
#         return value.encode(encoding)
#     return bytes(value)
# 
# Path: badwolf/security.py
# class SecureToken(object):
# 
#     @staticmethod
#     def encrypt(text):
#         fernet = Fernet(to_binary(current_app.config['SECURE_TOKEN_KEY']))
#         return fernet.encrypt(to_binary(text))
# 
#     @staticmethod
#     def decrypt(encrypted):
#         fernet = Fernet(to_binary(current_app.config['SECURE_TOKEN_KEY']))
#         text = fernet.decrypt(to_binary(encrypted))
#         return to_text(text)
# 
# def parse_secretfile(fd):
#     env = []
#     for line in fd:
#         line = line.strip()
#         if not line:
#             continue
#         if line.startswith('#'):
#             continue
#         elif line.startswith('>'):
#             # Write to file not supported for now
#             continue
#         else:
#             env.append(line)
#     return env
# 
# Path: badwolf/exceptions.py
# class InvalidSpecification(BadwolfException):
#     pass


# Path: badwolf/spec.py
import io
import base64
import logging
import shlex
import yaml
    from yaml import CLoader as _Loader
    from yaml import Loader as _Loader
from flask import render_template
from marshmallow import Schema, fields, pre_load, post_load, ValidationError, validate
from marshmallow.utils import is_collection
from marshmallow_oneofschema import OneOfSchema
from badwolf.utils import ObjectDict, to_text, to_binary
from badwolf.security import SecureToken, parse_secretfile
from badwolf.exceptions import InvalidSpecification
        from cryptography.fernet import InvalidToken

    secretfile = fields.Boolean(missing=True)  # 是否自动从 Secretfile 加载 Vault 内容

    @post_load
    def _postprocess(self, data, **kwargs):
        # vault.envs format should be:
        # ENV_NAME secret/path:key
        env_map = ObjectDict()
        for env in data['env']:
            try:
                name, path_key = env.strip().split(' ', 1)
                path, key = path_key.strip().split(':', 1)
            except ValueError:
                raise ValidationError('Invalid vault env {}'.format(name), 'env')
            env_map[name] = (path, key)
        data['env'] = env_map
        return super()._postprocess(data, **kwargs)


class SpecificationSchema(Schema):
    class Meta:
        strict = True

    image = fields.String(missing=None)
    shell = fields.String(missing='bash')
    dockerfile = fields.String(missing='Dockerfile')
    docker = fields.Boolean(missing=False)
    privileged = fields.Boolean(missing=False)
    services = ListField(fields.String(), data_key='service', missing=list)
    branch = SetField(fields.String(), missing=set)
    environments = ListField(SecureField(), data_key='env', missing=list)

    scripts = ListField(SecureField(), data_key='script', missing=list)