# Path: datapackage_pipelines/utilities/extended_json.py
# class json(object):
#     dumps = _dumps
#     loads = _loads
#     dumpl = _dumpl
#     loadl = _loadl
#     dump = _dump
#     load = _load
#     JSONDecodeError = _json.JSONDecodeError
# 
# Path: datapackage_pipelines/specs/parsers/base_parser.py
# class PipelineSpec(object):
#     def __init__(self,
#                  path=None,
#                  pipeline_id=None,
#                  pipeline_details=None,
#                  source_details=None,
#                  validation_errors=None,
#                  dependencies=None,
#                  cache_hash='',
#                  schedule=None,
#                  environment=None):
#         self.path = path
#         self.pipeline_id = pipeline_id
#         self.pipeline_details = pipeline_details
#         self.source_details = source_details
#         self.validation_errors = [] if validation_errors is None else validation_errors
#         self.dependencies = [] if dependencies is None else dependencies
#         self.cache_hash = cache_hash
#         self.schedule = schedule
#         self.environment = environment
# 
#     def __str__(self):
#         return 'PipelineSpec({}, validation_errors={}, ' \
#                'dependencies={}, cache_hash={})'\
#             .format(self.pipeline_id, self.validation_errors,
#                     self.dependencies, self.cache_hash)
# 
#     def __repr__(self):
#         return str(self)
# 
# Path: datapackage_pipelines/specs/errors.py
# class SpecError(NamedTuple):
#     short_msg: str
#     long_msg: str
# 
#     def __str__(self):
#         return '{}: {}'.format(self.short_msg, self.long_msg)
# 
# Path: datapackage_pipelines/specs/hashers/dependency_resolver.py
# def resolve_dependencies(spec: PipelineSpec, all_pipeline_ids, status_mgr):
# 
#     cache_hash = ''
#     dependencies = spec.pipeline_details.get('dependencies', ())
#     for dependency in dependencies:
#         if 'pipeline' in dependency:
#             pipeline_id = dependency['pipeline']
#             if pipeline_id not in all_pipeline_ids:
#                 raise DependencyMissingException(spec, pipeline_id)
# 
#     for dependency in dependencies:
#         if 'pipeline' in dependency:
#             pipeline_id = dependency['pipeline']
#             ps = status_mgr.get(pipeline_id)
#             if not ps.runnable():
#                 spec.validation_errors.append(
#                     SpecError('Invalid dependency',
#                               'Cannot run until dependency passes validation: {}'.format(pipeline_id))
#                 )
#             elif ps.dirty():
#                 spec.validation_errors.append(
#                     SpecError('Dirty dependency',
#                               'Cannot run until dependency is executed: {}'.format(pipeline_id))
#                 )
#             elif ps.get_last_execution() is not None and not ps.get_last_execution().success:
#                 spec.validation_errors.append(
#                     SpecError('Dependency unsuccessful',
#                               'Cannot run until dependency "{}" is successfully '
#                               'executed'.format(pipeline_id))
#                 )
# 
#             for dep_err in ps.validation_errors:
#                 spec.validation_errors.append(
#                     SpecError('From {}'.format(pipeline_id), dep_err)
#                 )
# 
#             pipeline_hash = all_pipeline_ids.get(pipeline_id).cache_hash
#             assert pipeline_hash is not None
#             cache_hash += pipeline_hash
# 
#             spec.dependencies.append(pipeline_id)
# 
#         elif 'datapackage' in dependency:
#             dp_id = dependency['datapackage']
#             try:
#                 dp = datapackage.DataPackage(dp_id)
#                 if 'hash' in dp.descriptor:
#                     cache_hash += dp.descriptor['hash']
#                 else:
#                     spec.validation_errors.append(
#                         SpecError('Missing dependency',
#                                   "Couldn't get data from datapackage %s"
#                                   % dp_id))
#             except DataPackageException:
#                 spec.validation_errors.append(
#                     SpecError('Missing dependency',
#                               "Couldn't open datapackage %s"
#                               % dp_id))
# 
#         else:
#             spec.validation_errors.append(
#                 SpecError('Missing dependency',
#                           'Unknown dependency provided (%r)' % dependency))
# 
#     return cache_hash


import hashlib
from ...utilities.extended_json import json
from ..parsers.base_parser import PipelineSpec
from ..errors import SpecError
from .dependency_resolver import resolve_dependencies




class HashCalculator(object):

    def __init__(self):
        self.all_pipeline_ids = {}

    def calculate_hash(self, spec: PipelineSpec, status_mgr, ignore_missing_deps=False):

        cache_hash = None
        if spec.pipeline_id in self.all_pipeline_ids:
            message = 'Duplicate key {0} in {1}' \
                .format(spec.pipeline_id, spec.path)
            spec.validation_errors.append(SpecError('Duplicate Pipeline Id', message))

        else:
            if ignore_missing_deps:
                cache_hash = ''
            else:

# Path: datapackage_pipelines/utilities/extended_json.py
# class json(object):
#     dumps = _dumps
#     loads = _loads
#     dumpl = _dumpl
#     loadl = _loadl
#     dump = _dump
#     load = _load
#     JSONDecodeError = _json.JSONDecodeError
# 
# Path: datapackage_pipelines/specs/parsers/base_parser.py
# class PipelineSpec(object):
#     def __init__(self,
#                  path=None,
#                  pipeline_id=None,
#                  pipeline_details=None,
#                  source_details=None,
#                  validation_errors=None,
#                  dependencies=None,
#                  cache_hash='',
#                  schedule=None,
#                  environment=None):
#         self.path = path
#         self.pipeline_id = pipeline_id
#         self.pipeline_details = pipeline_details
#         self.source_details = source_details
#         self.validation_errors = [] if validation_errors is None else validation_errors
#         self.dependencies = [] if dependencies is None else dependencies
#         self.cache_hash = cache_hash
#         self.schedule = schedule
#         self.environment = environment
# 
#     def __str__(self):
#         return 'PipelineSpec({}, validation_errors={}, ' \
#                'dependencies={}, cache_hash={})'\
#             .format(self.pipeline_id, self.validation_errors,
#                     self.dependencies, self.cache_hash)
# 
#     def __repr__(self):
#         return str(self)
# 
# Path: datapackage_pipelines/specs/errors.py
# class SpecError(NamedTuple):
#     short_msg: str
#     long_msg: str
# 
#     def __str__(self):
#         return '{}: {}'.format(self.short_msg, self.long_msg)
# 
# Path: datapackage_pipelines/specs/hashers/dependency_resolver.py
# def resolve_dependencies(spec: PipelineSpec, all_pipeline_ids, status_mgr):
# 
#     cache_hash = ''
#     dependencies = spec.pipeline_details.get('dependencies', ())
#     for dependency in dependencies:
#         if 'pipeline' in dependency:
#             pipeline_id = dependency['pipeline']
#             if pipeline_id not in all_pipeline_ids:
#                 raise DependencyMissingException(spec, pipeline_id)
# 
#     for dependency in dependencies:
#         if 'pipeline' in dependency:
#             pipeline_id = dependency['pipeline']
#             ps = status_mgr.get(pipeline_id)
#             if not ps.runnable():
#                 spec.validation_errors.append(
#                     SpecError('Invalid dependency',
#                               'Cannot run until dependency passes validation: {}'.format(pipeline_id))
#                 )
#             elif ps.dirty():
#                 spec.validation_errors.append(
#                     SpecError('Dirty dependency',
#                               'Cannot run until dependency is executed: {}'.format(pipeline_id))
#                 )
#             elif ps.get_last_execution() is not None and not ps.get_last_execution().success:
#                 spec.validation_errors.append(
#                     SpecError('Dependency unsuccessful',
#                               'Cannot run until dependency "{}" is successfully '
#                               'executed'.format(pipeline_id))
#                 )
# 
#             for dep_err in ps.validation_errors:
#                 spec.validation_errors.append(
#                     SpecError('From {}'.format(pipeline_id), dep_err)
#                 )
# 
#             pipeline_hash = all_pipeline_ids.get(pipeline_id).cache_hash
#             assert pipeline_hash is not None
#             cache_hash += pipeline_hash
# 
#             spec.dependencies.append(pipeline_id)
# 
#         elif 'datapackage' in dependency:
#             dp_id = dependency['datapackage']
#             try:
#                 dp = datapackage.DataPackage(dp_id)
#                 if 'hash' in dp.descriptor:
#                     cache_hash += dp.descriptor['hash']
#                 else:
#                     spec.validation_errors.append(
#                         SpecError('Missing dependency',
#                                   "Couldn't get data from datapackage %s"
#                                   % dp_id))
#             except DataPackageException:
#                 spec.validation_errors.append(
#                     SpecError('Missing dependency',
#                               "Couldn't open datapackage %s"
#                               % dp_id))
# 
#         else:
#             spec.validation_errors.append(
#                 SpecError('Missing dependency',
#                           'Unknown dependency provided (%r)' % dependency))
# 
#     return cache_hash


# Path: datapackage_pipelines/specs/hashers/hash_calculator.py
import hashlib
from ...utilities.extended_json import json
from ..parsers.base_parser import PipelineSpec
from ..errors import SpecError
from .dependency_resolver import resolve_dependencies





class HashCalculator(object):

    def __init__(self):
        self.all_pipeline_ids = {}

    def calculate_hash(self, spec: PipelineSpec, status_mgr, ignore_missing_deps=False):

        cache_hash = None
        if spec.pipeline_id in self.all_pipeline_ids:
            message = 'Duplicate key {0} in {1}' \
                .format(spec.pipeline_id, spec.path)
            spec.validation_errors.append(SpecError('Duplicate Pipeline Id', message))

        else:
            if ignore_missing_deps:
                cache_hash = ''
            else:

                cache_hash = resolve_dependencies(spec, self.all_pipeline_ids, status_mgr)