# Path: muninn/struct.py
# class Struct(object):
#     def __init__(self, data=None):
#         super(Struct, self).__init__()
#         if data is not None:
#             for key in data:
#                 if type(data[key]) == dict:
#                     self[key] = Struct(data[key])
#                 else:
#                     self[key] = data[key]
# 
#     def __getitem__(self, key):
#         try:
#             return getattr(self, key)
#         except AttributeError:
#             raise KeyError(key)
# 
#     def __setitem__(self, key, value):
#         setattr(self, key, value)
# 
#     def __delitem__(self, key):
#         try:
#             return delattr(self, key)
#         except AttributeError:
#             raise KeyError(key)
# 
#     def __contains__(self, key):
#         return hasattr(self, key)
# 
#     def __len__(self):
#         return len(vars(self))
# 
#     def __iter__(self):
#         return iter(vars(self))
# 
#     def __repr__(self):
#         return "Struct(%r)" % vars(self)
# 
#     def update(self, other):
#         '''update a struct, using the same semantics as dict.update()'''
#         for key in other:
#             other_item = other[key]
#             if isinstance(other_item, Struct):
#                 if key not in self:
#                     self[key] = Struct()
#                 else:
#                     if not isinstance(self[key], Struct):
#                         raise Error('Incompatible structs: %s vs %s' % (self, other))
#                 self[key].update(other_item)
#             else:
#                 self[key] = other_item
# 
# Path: muninn/tools/utils.py
# class Processor(object):
# 
#     def __init__(self, archive_name):
#         self._archive_name = archive_name
#         self._archive = None
# 
#     def perform_operation(self, archive, item):
#         pass
# 
#     def __call__(self, item):
#         try:
#             if self._archive is None:
#                 self._archive = muninn.open(self._archive_name)
#             return self.perform_operation(self._archive, item)
#         except KeyboardInterrupt:
#             # don't capture keyboard interrupts inside sub-processes (only the main process should handle it)
#             pass
# 
# def create_parser(*args, **kwargs):
#     parser = argparse.ArgumentParser(*args, parents=[version_parser], **kwargs)
#     parser.add_argument("--verbose", action="store_true", help="display debug information")
#     return parser
# 
# def parse_args_and_run(parser, func):
#     args, unused_args = version_parser.parse_known_args()
#     if args.version:
#         version(os.path.basename(sys.argv[0]))
#         sys.exit(0)
# 
#     args = parser.parse_args(unused_args)
# 
#     log_level = logging.DEBUG if args.verbose else logging.INFO
#     logging.basicConfig(level=log_level, format="%(levelname)s: %(message)s")
# 
#     try:
#         return func(args)
#     except SystemExit:
#         raise
#     except KeyboardInterrupt:
#         sys.exit(1)
#     except muninn.Error as error:
#         logging.error(error)
#         sys.exit(1)
#     except Exception:
#         log_internal_error()
#         sys.exit(1)
#     finally:
#         logging.shutdown()


import logging
import multiprocessing
import sys
import muninn
    from tqdm import tqdm as bar
from muninn.struct import Struct
from .utils import Processor, create_parser, parse_args_and_run
        # only get products with a remote_url
        if expression:
            expression = "is_defined(remote_url) and (%s)" % expression
        else:
            expression = "is_defined(remote_url)"

    processor = UpdateProcessor(args)
    with muninn.open(args.archive) as archive:
        if args.action in ['ingest', 'pull']:
            # we only need the uuid and the product_name
            products = archive.search(expression, property_names=['uuid', 'product_name'])
        else:
            products = archive.search(expression, namespaces=archive.namespaces())
        if args.parallel:
            if args.processes is not None:
                pool = multiprocessing.Pool(args.processes)
            else:
                pool = multiprocessing.Pool()
            list(bar(pool.imap(processor, products), total=len(products)))
            pool.close()
            pool.join()
        else:
            for product in bar(products):
                processor.perform_operation(archive, product)

    return 0


def main():
    parser = create_parser(description="""Updates properties of existing products.

# Path: muninn/struct.py
# class Struct(object):
#     def __init__(self, data=None):
#         super(Struct, self).__init__()
#         if data is not None:
#             for key in data:
#                 if type(data[key]) == dict:
#                     self[key] = Struct(data[key])
#                 else:
#                     self[key] = data[key]
# 
#     def __getitem__(self, key):
#         try:
#             return getattr(self, key)
#         except AttributeError:
#             raise KeyError(key)
# 
#     def __setitem__(self, key, value):
#         setattr(self, key, value)
# 
#     def __delitem__(self, key):
#         try:
#             return delattr(self, key)
#         except AttributeError:
#             raise KeyError(key)
# 
#     def __contains__(self, key):
#         return hasattr(self, key)
# 
#     def __len__(self):
#         return len(vars(self))
# 
#     def __iter__(self):
#         return iter(vars(self))
# 
#     def __repr__(self):
#         return "Struct(%r)" % vars(self)
# 
#     def update(self, other):
#         '''update a struct, using the same semantics as dict.update()'''
#         for key in other:
#             other_item = other[key]
#             if isinstance(other_item, Struct):
#                 if key not in self:
#                     self[key] = Struct()
#                 else:
#                     if not isinstance(self[key], Struct):
#                         raise Error('Incompatible structs: %s vs %s' % (self, other))
#                 self[key].update(other_item)
#             else:
#                 self[key] = other_item
# 
# Path: muninn/tools/utils.py
# class Processor(object):
# 
#     def __init__(self, archive_name):
#         self._archive_name = archive_name
#         self._archive = None
# 
#     def perform_operation(self, archive, item):
#         pass
# 
#     def __call__(self, item):
#         try:
#             if self._archive is None:
#                 self._archive = muninn.open(self._archive_name)
#             return self.perform_operation(self._archive, item)
#         except KeyboardInterrupt:
#             # don't capture keyboard interrupts inside sub-processes (only the main process should handle it)
#             pass
# 
# def create_parser(*args, **kwargs):
#     parser = argparse.ArgumentParser(*args, parents=[version_parser], **kwargs)
#     parser.add_argument("--verbose", action="store_true", help="display debug information")
#     return parser
# 
# def parse_args_and_run(parser, func):
#     args, unused_args = version_parser.parse_known_args()
#     if args.version:
#         version(os.path.basename(sys.argv[0]))
#         sys.exit(0)
# 
#     args = parser.parse_args(unused_args)
# 
#     log_level = logging.DEBUG if args.verbose else logging.INFO
#     logging.basicConfig(level=log_level, format="%(levelname)s: %(message)s")
# 
#     try:
#         return func(args)
#     except SystemExit:
#         raise
#     except KeyboardInterrupt:
#         sys.exit(1)
#     except muninn.Error as error:
#         logging.error(error)
#         sys.exit(1)
#     except Exception:
#         log_internal_error()
#         sys.exit(1)
#     finally:
#         logging.shutdown()


# Path: muninn/tools/update.py
import logging
import multiprocessing
import sys
import muninn
    from tqdm import tqdm as bar
from muninn.struct import Struct
from .utils import Processor, create_parser, parse_args_and_run

        # only get products with a remote_url
        if expression:
            expression = "is_defined(remote_url) and (%s)" % expression
        else:
            expression = "is_defined(remote_url)"

    processor = UpdateProcessor(args)
    with muninn.open(args.archive) as archive:
        if args.action in ['ingest', 'pull']:
            # we only need the uuid and the product_name
            products = archive.search(expression, property_names=['uuid', 'product_name'])
        else:
            products = archive.search(expression, namespaces=archive.namespaces())
        if args.parallel:
            if args.processes is not None:
                pool = multiprocessing.Pool(args.processes)
            else:
                pool = multiprocessing.Pool()
            list(bar(pool.imap(processor, products), total=len(products)))
            pool.close()
            pool.join()
        else:
            for product in bar(products):
                processor.perform_operation(archive, product)

    return 0


def main():
    parser = create_parser(description="""Updates properties of existing products.

        This is an archive maintenance tool, meant to be used when the archive structure has changed.