# Path: yawn/task/models.py
# class Template(models.Model):
#     workflow = models.ForeignKey('Workflow', models.PROTECT, editable=False, null=True)
#     queue = models.ForeignKey(Queue, models.PROTECT)
#     name = models.TextField()
# 
#     command = models.TextField()
#     max_retries = models.IntegerField(default=0)
#     timeout = models.IntegerField(null=True)  # seconds
# 
#     # self-reference for upstream tasks
#     upstream = models.ManyToManyField(
#         'Template', related_name='downstream', symmetrical=False, blank=True)
# 
#     class Meta:
#         unique_together = ('workflow', 'name')
# 
#     def __str__(self):
#         return self.name
# 
#     def save(self, *args, **kwargs):
#         # can't set the default above because the value isn't serializable for migrations
#         if not self.queue_id:
#             self.queue = Queue.get_default_queue()
#         super().save(*args, **kwargs)
# 
# Path: yawn/workflow/models.py
# class WorkflowName(models.Model):
#     name = models.TextField(unique=True)
#     current_version = models.OneToOneField('Workflow', on_delete=models.CASCADE,
#                                            null=True, related_name='is_current')
# 
#     def new_version(self, **kwargs):
#         """Create a new version of a workflow"""
#         version = 0
#         if self.current_version_id:
#             version = self.current_version.version
# 
#             # disable the past schedule
#             self.current_version.schedule_active = False
#             self.current_version.save()
# 
#         workflow = Workflow.objects.create(name=self, version=version + 1, **kwargs)
#         self.current_version = workflow
#         self.save()
#         return workflow
# 
# Path: yawn/workflow/serializers.py
# class WorkflowSerializer(serializers.ModelSerializer):
#     name = serializers.CharField(source='name.name')
#     name_id = serializers.IntegerField(read_only=True)
#     tasks = TemplateSerializer(many=True, allow_empty=False, source='template_set')
# 
#     class Meta:
#         model = Workflow
#         fields = '__all__'
#         read_only_fields = ('next_run', 'name_id')
# 
#     @transaction.atomic
#     def create(self, validated_data):
#         workflow_name = validated_data.pop('name')['name']
#         name, _ = WorkflowName.objects.get_or_create(name=workflow_name)
#         # get the current version and check for changes
#         if name.current_version and unchanged(name.current_version, validated_data):
#             # TODO return 302 found instead of 201 created
#             return name.current_version
# 
#         # changed or no existing version: create a new version
#         tasks = validated_data.pop('template_set')
#         workflow = name.new_version(**validated_data)
#         for task_kwargs in tasks:
#             # the awkward 'all' is so serialization gets related tasks through the manager method
#             upstream = workflow.template_set.filter(name__in=task_kwargs.pop('upstream')['all'])
#             task = Template.objects.create(workflow=workflow, **task_kwargs)
#             task.upstream.set(upstream)
# 
#         return workflow
# 
#     def validate_parameters(self, parameters):
#         """Validate variable name is a slug and value is a string"""
#         if not isinstance(parameters, dict):
#             raise serializers.ValidationError('Workflow parameters must be a dictionary')
#         key_regex = re.compile(r'[a-zA-Z_][a-zA-Z0-9_]*')
#         errors = []
#         for key, value in parameters.items():
#             if not key_regex.fullmatch(key):
#                 errors.append('Invalid parameter key: %s' % key)
#             if not isinstance(value, str):
#                 errors.append('Invalid parameter value: %s' % value)
#         if errors:
#             raise serializers.ValidationError(errors)
#         return parameters
# 
#     def validate_tasks(self, tasks):
#         """Validate tasks only reference already defined upstream tasks"""
#         seen_tasks = set()
#         errors = []
#         for task in tasks:
#             name = task['name']
#             if name in seen_tasks:
#                 errors.append('Task names must be unique. Tas %s is defined more than once' % name)
#             missing = set(task['upstream']['all']) - seen_tasks
#             if missing:
#                 errors.append(
#                     'Task {task} specifies upstream task(s) {upstream} but they do not exist. '
#                     'Hint: check the order of your tasks.'.format(
#                         task=name, upstream=', '.join(missing))
#                 )
#             seen_tasks.add(name)
# 
#         if errors:
#             raise serializers.ValidationError(errors)
#         return tasks
# 
# Path: yawn/workflow/tests/utils.py
# def load_sample_workflow():
#     filename = os.path.join(os.path.dirname(__file__), 'workflow.yaml')
#     return yaml.safe_load(open(filename).read())


import random
from django.core.management.base import BaseCommand
from yawn.task.models import Template
from yawn.workflow.models import WorkflowName
from yawn.workflow.serializers import WorkflowSerializer
from yawn.workflow.tests.utils import load_sample_workflow




class Command(BaseCommand):
    help = 'Load sample data'

    def handle(self, *args, **options):
        self.stdout.write('Creating sample workflows!')

        self.stdout.write('First, a simple four task workflow...')
        name, _ = WorkflowName.objects.get_or_create(name='Simple Workflow Example')
        workflow = name.new_version(parameters={'MY_OBJECT_ID': '1', 'SOME_SETTING': 'false'})
        task1 = Template.objects.create(workflow=workflow, name='start', command='echo Starting...')
        task2 = Template.objects.create(workflow=workflow, name='task2', command='echo Working on $MY_OBJECT_ID')
        task2.upstream.add(task1)
        task3 = Template.objects.create(workflow=workflow, name='task3',
                                        command='yawn exec yawn.management.tests.test_exec '
                                                'ExampleClass "thing to log"')
        task3.upstream.add(task1)
        task4 = Template.objects.create(workflow=workflow, name='done', command='echo Finished!')
        task4.upstream.add(task2, task3)

        workflow.submit_run(parameters={'child': 'true'})
        workflow.submit_run(parameters={'child': 'true'})
        workflow.submit_run(parameters={'child': 'true'})

        self.stdout.write('Second, a big beast workflow...')


# Path: yawn/task/models.py
# class Template(models.Model):
#     workflow = models.ForeignKey('Workflow', models.PROTECT, editable=False, null=True)
#     queue = models.ForeignKey(Queue, models.PROTECT)
#     name = models.TextField()
# 
#     command = models.TextField()
#     max_retries = models.IntegerField(default=0)
#     timeout = models.IntegerField(null=True)  # seconds
# 
#     # self-reference for upstream tasks
#     upstream = models.ManyToManyField(
#         'Template', related_name='downstream', symmetrical=False, blank=True)
# 
#     class Meta:
#         unique_together = ('workflow', 'name')
# 
#     def __str__(self):
#         return self.name
# 
#     def save(self, *args, **kwargs):
#         # can't set the default above because the value isn't serializable for migrations
#         if not self.queue_id:
#             self.queue = Queue.get_default_queue()
#         super().save(*args, **kwargs)
# 
# Path: yawn/workflow/models.py
# class WorkflowName(models.Model):
#     name = models.TextField(unique=True)
#     current_version = models.OneToOneField('Workflow', on_delete=models.CASCADE,
#                                            null=True, related_name='is_current')
# 
#     def new_version(self, **kwargs):
#         """Create a new version of a workflow"""
#         version = 0
#         if self.current_version_id:
#             version = self.current_version.version
# 
#             # disable the past schedule
#             self.current_version.schedule_active = False
#             self.current_version.save()
# 
#         workflow = Workflow.objects.create(name=self, version=version + 1, **kwargs)
#         self.current_version = workflow
#         self.save()
#         return workflow
# 
# Path: yawn/workflow/serializers.py
# class WorkflowSerializer(serializers.ModelSerializer):
#     name = serializers.CharField(source='name.name')
#     name_id = serializers.IntegerField(read_only=True)
#     tasks = TemplateSerializer(many=True, allow_empty=False, source='template_set')
# 
#     class Meta:
#         model = Workflow
#         fields = '__all__'
#         read_only_fields = ('next_run', 'name_id')
# 
#     @transaction.atomic
#     def create(self, validated_data):
#         workflow_name = validated_data.pop('name')['name']
#         name, _ = WorkflowName.objects.get_or_create(name=workflow_name)
#         # get the current version and check for changes
#         if name.current_version and unchanged(name.current_version, validated_data):
#             # TODO return 302 found instead of 201 created
#             return name.current_version
# 
#         # changed or no existing version: create a new version
#         tasks = validated_data.pop('template_set')
#         workflow = name.new_version(**validated_data)
#         for task_kwargs in tasks:
#             # the awkward 'all' is so serialization gets related tasks through the manager method
#             upstream = workflow.template_set.filter(name__in=task_kwargs.pop('upstream')['all'])
#             task = Template.objects.create(workflow=workflow, **task_kwargs)
#             task.upstream.set(upstream)
# 
#         return workflow
# 
#     def validate_parameters(self, parameters):
#         """Validate variable name is a slug and value is a string"""
#         if not isinstance(parameters, dict):
#             raise serializers.ValidationError('Workflow parameters must be a dictionary')
#         key_regex = re.compile(r'[a-zA-Z_][a-zA-Z0-9_]*')
#         errors = []
#         for key, value in parameters.items():
#             if not key_regex.fullmatch(key):
#                 errors.append('Invalid parameter key: %s' % key)
#             if not isinstance(value, str):
#                 errors.append('Invalid parameter value: %s' % value)
#         if errors:
#             raise serializers.ValidationError(errors)
#         return parameters
# 
#     def validate_tasks(self, tasks):
#         """Validate tasks only reference already defined upstream tasks"""
#         seen_tasks = set()
#         errors = []
#         for task in tasks:
#             name = task['name']
#             if name in seen_tasks:
#                 errors.append('Task names must be unique. Tas %s is defined more than once' % name)
#             missing = set(task['upstream']['all']) - seen_tasks
#             if missing:
#                 errors.append(
#                     'Task {task} specifies upstream task(s) {upstream} but they do not exist. '
#                     'Hint: check the order of your tasks.'.format(
#                         task=name, upstream=', '.join(missing))
#                 )
#             seen_tasks.add(name)
# 
#         if errors:
#             raise serializers.ValidationError(errors)
#         return tasks
# 
# Path: yawn/workflow/tests/utils.py
# def load_sample_workflow():
#     filename = os.path.join(os.path.dirname(__file__), 'workflow.yaml')
#     return yaml.safe_load(open(filename).read())


# Path: yawn/management/commands/examples.py
import random
from django.core.management.base import BaseCommand
from yawn.task.models import Template
from yawn.workflow.models import WorkflowName
from yawn.workflow.serializers import WorkflowSerializer
from yawn.workflow.tests.utils import load_sample_workflow





class Command(BaseCommand):
    help = 'Load sample data'

    def handle(self, *args, **options):
        self.stdout.write('Creating sample workflows!')

        self.stdout.write('First, a simple four task workflow...')
        name, _ = WorkflowName.objects.get_or_create(name='Simple Workflow Example')
        workflow = name.new_version(parameters={'MY_OBJECT_ID': '1', 'SOME_SETTING': 'false'})
        task1 = Template.objects.create(workflow=workflow, name='start', command='echo Starting...')
        task2 = Template.objects.create(workflow=workflow, name='task2', command='echo Working on $MY_OBJECT_ID')
        task2.upstream.add(task1)
        task3 = Template.objects.create(workflow=workflow, name='task3',
                                        command='yawn exec yawn.management.tests.test_exec '
                                                'ExampleClass "thing to log"')
        task3.upstream.add(task1)
        task4 = Template.objects.create(workflow=workflow, name='done', command='echo Finished!')
        task4.upstream.add(task2, task3)

        workflow.submit_run(parameters={'child': 'true'})
        workflow.submit_run(parameters={'child': 'true'})
        workflow.submit_run(parameters={'child': 'true'})

        self.stdout.write('Second, a big beast workflow...')


        name, _ = WorkflowName.objects.get_or_create(name='Big Ol\' Workflow Example')