예제 #1
0
    def handle(self, *args, **options):
        experiment_id = options.get('experiment_id', None)
        if not experiment_id:
            raise CommandError("Expected exactly 1 argument - Experiment ID")
        try:
            exp = Experiment.objects.get(pk=experiment_id)
        except Experiment.DoesNotExist:
            raise CommandError("Experiment ID %s not found" % args[0])

        # FIXME - we are fetch a bunch of stuff outside of any transaction, and then
        # doing the deletes in a transaction.  There is an obvious race condition here
        # that may result in components of an experiment not being deleted or being deleted
        # when they shouldn't be.

        # Fetch Datasets and Datafiles and work out which ones would be deleted
        datasets = Dataset.objects.filter(experiments__id=exp.id)
        datafiles = DataFile.objects.filter(
            dataset__id__in=map((lambda ds: ds.id), datasets))
        uniqueDatasets = filter((lambda ds: ds.experiments.count() == 1),
                                datasets)
        uniqueDatasetIds = map((lambda ds: ds.id), uniqueDatasets)
        uniqueDatafiles = filter(
            (lambda df: df.dataset.id in uniqueDatasetIds), datafiles)

        # Fetch other stuff to be printed and deleted.
        acls = ObjectACL.objects.filter(content_type=exp.get_ct(),
                                        object_id=exp.id)
        authors = ExperimentAuthor.objects.filter(experiment=exp)
        epsets = ExperimentParameterSet.objects.filter(experiment=exp)

        confirmed = options.get('confirmed', False)
        listOnly = options.get('list', False)
        if not listOnly and not confirmed:
            self.stdout.write("Delete the following experiment?\n\n")

        if listOnly or not confirmed:
            # Print basic experiment information
            self.stdout.write("Experiment\n    ID: {0}\n".format(exp.id))
            self.stdout.write("    Title: {0}\n".format(exp.title))
            self.stdout.write("    Locked: {0}\n".format(exp.locked))
            self.stdout.write("    Public Access: {0}\n".format(
                exp.public_access))

            # List experiment authors
            self.stdout.write("    Authors:\n")
            for author in authors:
                self.stdout.write("        {0}\n".format(author.author))

            # List experiment metadata
            for epset in epsets:
                self.stdout.write("    Param Set: {0} - {1}\n".format(
                    epset.schema.name, epset.schema.namespace))
                params = ExperimentParameter.objects.filter(parameterset=epset)
                for param in params:
                    self.stdout.write("        {0} = {1}\n".format(
                        param.name.full_name, param.get()))

            # List experiment ACLs
            self.stdout.write("    ACLs:\n")
            for acl in acls:
                self.stdout.write("        {0}-{1}, flags: ".format(
                    acl.pluginId, acl.entityId))
                if acl.canRead:
                    self.stdout.write("R")
                if acl.canWrite:
                    self.stdout.write("W")
                if acl.canDelete:
                    self.stdout.write("D")
                if acl.isOwner:
                    self.stdout.write("O")
                self.stdout.write("\n")

            # Basic Statistics
            self.stdout.write(
                "    {0} total dataset(s), containing {1} file(s)\n".format(
                    datasets.count(), datafiles.count()))
            self.stdout.write(
                "    {0} non-shared dataset(s), containing {1} file(s)\n".
                format(len(list(uniqueDatasets)), len(list(uniqueDatafiles))))
            if uniqueDatasets and not listOnly:
                self.stdout.write(
                    "        (The non-shared datasets and files will be deleted)\n"
                )

        # If the user has only requested a listing finish now
        if listOnly:
            return

        if not confirmed:
            # User must enter "yes" to proceed
            self.stdout.write("\n\nConfirm Deletion? (yes): ")
            ans = sys.stdin.readline().strip()
            if ans != "yes":
                self.stdout.write("'yes' not entered, aborting.\n")
                return

        # Consider the entire experiment deletion atomic
        using = options.get('database', DEFAULT_DB_ALIAS)

        try:
            with transaction.atomic(using=using):
                acls.delete()
                epsets.delete()
                for dataset in datasets:
                    dataset.experiments.remove(exp.id)
                    if dataset.experiments.count() == 0:
                        DatasetParameterSet.objects.filter(
                            dataset=dataset).delete()
                        for datafile in DataFile.objects.filter(
                                dataset=dataset):
                            DatafileParameterSet.objects.filter(
                                datafile=datafile).delete()
                            datafile.delete()
                        dataset.delete()
                authors.delete()
                exp.delete()
        except Exception:
            exc_class, exc, _ = sys.exc_info()
            new_exc = CommandError(
                "Exception %s has occurred: rolled back transaction" %
                (exc or exc_class))
            raise new_exc.__class__(new_exc)