Ejemplo n.º 1
0
 def update_worksheet(self, worksheet_info, new_items):
     '''
     Set the worksheet to have items |new_items|.
     '''
     worksheet_uuid = worksheet_info['uuid']
     last_item_id = worksheet_info['last_item_id']
     length = len(worksheet_info['items'])
     worksheet = self.model.get_worksheet(worksheet_uuid, fetch_items=False)
     check_has_all_permission(self.model, self._current_user(), worksheet)
     try:
         new_items = [worksheet_util.convert_item_to_db(item) for item in new_items]
         self.model.update_worksheet(worksheet_uuid, last_item_id, length, new_items)
     except UsageError:
         # Turn the model error into a more readable one using the object.
         raise UsageError('%s was updated concurrently!' % (worksheet,))
Ejemplo n.º 2
0
def update_worksheet_items(worksheet_info, new_items, convert_items=True):
    """
    Set the worksheet to have items |new_items|.
    """
    worksheet_uuid = worksheet_info['uuid']
    last_item_id = worksheet_info['last_item_id']
    length = len(worksheet_info['items'])
    worksheet = local.model.get_worksheet(worksheet_uuid, fetch_items=False)
    check_worksheet_has_all_permission(local.model, request.user, worksheet)
    worksheet_util.check_worksheet_not_frozen(worksheet)
    try:
        if convert_items:
            new_items = [worksheet_util.convert_item_to_db(item) for item in new_items]
        local.model.update_worksheet_items(worksheet_uuid, last_item_id, length, new_items)
    except UsageError:
        # Turn the model error into a more readable one using the object.
        raise UsageError('%s was updated concurrently!' % (worksheet,))
Ejemplo n.º 3
0
def update_worksheet_items(worksheet_info, new_items, convert_items=True):
    """
    Set the worksheet to have items |new_items|.
    """
    worksheet_uuid = worksheet_info['uuid']
    last_item_id = worksheet_info['last_item_id']
    length = len(worksheet_info['items'])
    worksheet = local.model.get_worksheet(worksheet_uuid, fetch_items=False)
    check_worksheet_has_all_permission(local.model, request.user, worksheet)
    worksheet_util.check_worksheet_not_frozen(worksheet)
    try:
        if convert_items:
            new_items = [worksheet_util.convert_item_to_db(item) for item in new_items]
        local.model.update_worksheet_items(worksheet_uuid, last_item_id, length, new_items)
    except UsageError:
        # Turn the model error into a more readable one using the object.
        raise UsageError('%s was updated concurrently!' % (worksheet,))
Ejemplo n.º 4
0
        def add_with_prelude_items(old_bundle_uuid, new_bundle_uuid):
            '''
            Add new_bundle_uuid to the current worksheet (along with the occurrences on the worksheet).
            Also add the prelude (items that occur right before old_bundle_uuid on a worksheet).
            Note that new_bundle_uuid might get multiple times.
            '''
            host_worksheet_uuids = self.model.get_host_worksheet_uuids([old_bundle_uuid])[old_bundle_uuid]
            if len(host_worksheet_uuids) > 0:
                # Choose a single worksheet.
                if worksheet_uuid in host_worksheet_uuids:
                    # If current worksheet is one of them, favor that one.
                    host_worksheet_uuid = worksheet_uuid
                else:
                    # Choose an arbitrary one
                    host_worksheet_uuid = host_worksheet_uuids[0]

                if host_worksheet_uuid in worksheet_cache:
                    worksheet_info = worksheet_cache[host_worksheet_uuid]
                else:
                    worksheet_info = worksheet_cache[host_worksheet_uuid] = \
                        self.get_worksheet_info(host_worksheet_uuid, fetch_items=True)

                # Look for items that appear right before the old_bundle_uuid
                collect_items = []
                for item in worksheet_info['items']:
                    (bundle_info, subworkheet_info, value_obj, type) = item
                    if type == worksheet_util.TYPE_BUNDLE and bundle_info['uuid'] == old_bundle_uuid:
                        # Ended in the target old_bundle_uuid, flush the prelude gathered so far.
                        for item2 in collect_items:
                            self.add_worksheet_item(worksheet_uuid, worksheet_util.convert_item_to_db(item2))
                        self.add_worksheet_item(worksheet_uuid, worksheet_util.bundle_item(new_bundle_uuid))
                        collect_items = []
                    elif type == worksheet_util.TYPE_MARKUP and value_obj == '':
                        collect_items = []
                    elif type == worksheet_util.TYPE_BUNDLE:
                        collect_items = []
                    else:
                        collect_items.append(item)
    def mimic(self, old_inputs, old_output, new_inputs, new_output_name, worksheet_uuid, depth, shadow, dry_run):
        '''
        old_inputs: list of bundle uuids
        old_output: bundle uuid that we produced
        new_inputs: list of bundle uuids that are analogous to old_inputs
        new_output_name: name of the bundle to create to be analogous to old_output (possibly None)
        worksheet_uuid: add newly created bundles to this worksheet
        depth: how far to do a BFS up from old_output.
        shadow: whether to add the new inputs right after all occurrences of the old inputs in worksheets.
        '''
        check_worksheet_has_all_permission(self.model, self._current_user(), self.model.get_worksheet(worksheet_uuid, fetch_items=False))
        #print 'old_inputs: %s, new_inputs: %s, old_output: %s, new_output_name: %s' % (old_inputs, new_inputs, old_output, new_output_name)

        # Build the graph (get all the infos).
        # If old_output is given, look at ancestors of old_output until we
        # reached some depth.  If it's not given, we first get all the
        # descendants first, and then get their ancestors.
        infos = {}  # uuid -> bundle info
        if old_output:
            bundle_uuids = [old_output]
        else:
            bundle_uuids = self.model.get_self_and_descendants(old_inputs, depth=depth)
        all_bundle_uuids = list(bundle_uuids) # should be infos.keys() in order
        for _ in range(depth):
            new_bundle_uuids = []
            for bundle_uuid in bundle_uuids:
                if bundle_uuid in infos: continue  # Already visited
                info = infos[bundle_uuid] = self.get_bundle_info(bundle_uuid)
                for dep in info['dependencies']:
                    parent_uuid = dep['parent_uuid']
                    if parent_uuid not in infos:
                        new_bundle_uuids.append(parent_uuid)
            all_bundle_uuids = new_bundle_uuids + all_bundle_uuids
            bundle_uuids = new_bundle_uuids

        # Make sure we have read access to all the bundles involved here.
        check_bundles_have_read_permission(self.model, self._current_user(), list(infos.keys()))

        # Now go recursively create the bundles.
        old_to_new = {}  # old_uuid -> new_uuid
        downstream = set()  # old_uuid -> whether we're downstream of an input (and actually needs to be mapped onto a new uuid)
        created_uuids = set()  # set of uuids which were newly created
        plan = []  # sequence of (old, new) bundle infos to make
        for old, new in zip(old_inputs, new_inputs):
            old_to_new[old] = new
            downstream.add(old)

        # Return corresponding new_bundle_uuid
        def recurse(old_bundle_uuid):
            if old_bundle_uuid in old_to_new:
                #print old_bundle_uuid, 'cached'
                return old_to_new[old_bundle_uuid]

            # Don't have any more information (because we probably hit the maximum depth)
            if old_bundle_uuid not in infos:
                #print old_bundle_uuid, 'no information'
                return old_bundle_uuid

            # Get information about the old bundle.
            info = infos[old_bundle_uuid]
            new_dependencies = [{
                'parent_uuid': recurse(dep['parent_uuid']),
                'parent_path': dep['parent_path'],
                'child_uuid': dep['child_uuid'],  # This is just a placeholder to do the equality test
                'child_path': dep['child_path']
            } for dep in info['dependencies']]

            # If there are no inputs or if we're downstream of any inputs, we need to make a new bundle.
            lone_output = (len(old_inputs) == 0 and old_bundle_uuid == old_output)
            downstream_of_inputs = any(dep['parent_uuid'] in downstream for dep in info['dependencies'])
            if lone_output or downstream_of_inputs:
                # Now create a new bundle that mimics the old bundle.
                # Only change the name if the output name is supplied.
                old_bundle_name = info['metadata']['name']
                new_info = copy.deepcopy(info)
                new_metadata = new_info['metadata']
                if new_output_name:
                    if old_bundle_uuid == old_output:
                        new_metadata['name'] = new_output_name
                    else:
                        # Just make up a name heuristically
                        new_metadata['name'] = new_output_name + '-' + info['metadata']['name']

                # Remove all the automatically generated keys
                cls = get_bundle_subclass(new_info['bundle_type'])
                for spec in cls.METADATA_SPECS:
                    if spec.generated and spec.key in new_metadata:
                        new_metadata.pop(spec.key)

                # Set the targets
                targets = [(dep['child_path'], (dep['parent_uuid'], dep['parent_path'])) for dep in new_dependencies]

                if dry_run:
                    new_bundle_uuid = None
                else:
                    if new_info['bundle_type'] not in ('make', 'run'):
                        raise UsageError('Can\'t mimic %s since it is not make or run' % old_bundle_uuid)
                    new_bundle_uuid = self._derive_bundle(new_info['bundle_type'], \
                        targets, new_info['command'], new_metadata, worksheet_uuid)

                new_info['uuid'] = new_bundle_uuid
                plan.append((info, new_info))
                downstream.add(old_bundle_uuid)
                created_uuids.add(new_bundle_uuid)
            else:
                new_bundle_uuid = old_bundle_uuid

            old_to_new[old_bundle_uuid] = new_bundle_uuid  # Cache it
            return new_bundle_uuid

        if old_output:
            recurse(old_output)
        else:
            # Don't have a particular output we're targetting, so just create
            # new versions of all the uuids.
            for uuid in all_bundle_uuids:
                recurse(uuid)

        # Add to worksheet
        if not dry_run:
            if shadow:
                # Add each new bundle in the "shadow" of the old_bundle (right after it).
                for old_bundle_uuid, new_bundle_uuid in old_to_new.items():
                    if new_bundle_uuid in created_uuids:  # Only add novel bundles
                        self.model.add_shadow_worksheet_items(old_bundle_uuid, new_bundle_uuid)
            else:
                def newline():
                    self.model.add_worksheet_item(worksheet_uuid, worksheet_util.markup_item(''))
                # A prelude of a bundle on a worksheet is the set of items that occur right before it (markup, directives, etc.)
                # Let W be the first worksheet containing the old_inputs[0].
                # Add all items on that worksheet that appear in old_to_new along with their preludes.
                # For items not on this worksheet, add them at the end (instead of making them floating).
                if old_output:
                    anchor_uuid = old_output
                elif len(old_inputs) > 0:
                    anchor_uuid = old_inputs[0]
                host_worksheet_uuids = self.model.get_host_worksheet_uuids([anchor_uuid])[anchor_uuid]
                new_bundle_uuids_added = set()
                skipped = True  # Whether there were items that we didn't include in the prelude (in which case we want to put '')
                if len(host_worksheet_uuids) > 0:
                    # Choose a single worksheet.
                    if worksheet_uuid in host_worksheet_uuids:
                        # If current worksheet is one of them, favor that one.
                        host_worksheet_uuid = worksheet_uuid
                    else:
                        # Choose an arbitrary one (in the future, have a better way of canonicalizing).
                        host_worksheet_uuid = host_worksheet_uuids[0]

                    # Fetch the worksheet
                    worksheet_info = self.get_worksheet_info(host_worksheet_uuid, fetch_items=True)

                    prelude_items = []  # The prelude that we're building up
                    for item in worksheet_info['items']:
                        (bundle_info, subworkheet_info, value_obj, item_type) = item
                        just_added = False

                        if item_type == worksheet_util.TYPE_BUNDLE:
                            old_bundle_uuid = bundle_info['uuid']
                            if old_bundle_uuid in old_to_new:
                                # Flush the prelude gathered so far.
                                new_bundle_uuid = old_to_new[old_bundle_uuid]
                                if new_bundle_uuid in created_uuids:  # Only add novel bundles
                                    # Stand in for things skipped (this is important so directives have proper extent).
                                    if skipped:
                                        newline()

                                    # Add prelude and items
                                    for item2 in prelude_items:
                                        self.add_worksheet_item(worksheet_uuid, worksheet_util.convert_item_to_db(item2))
                                    self.add_worksheet_item(worksheet_uuid, worksheet_util.bundle_item(new_bundle_uuid))
                                    new_bundle_uuids_added.add(new_bundle_uuid)
                                    just_added = True

                        if (item_type == worksheet_util.TYPE_MARKUP and value_obj != '') or item_type == worksheet_util.TYPE_DIRECTIVE:
                            prelude_items.append(item)  # Include in prelude
                            skipped = False
                        else:
                            prelude_items = [] # Reset
                            skipped = not just_added

                # Add the bundles that haven't been added yet
                for info, new_info in plan:
                    new_bundle_uuid = new_info['uuid']
                    if new_bundle_uuid not in new_bundle_uuids_added:
                        if skipped:
                            newline()
                            skipped = False
                        self.add_worksheet_item(worksheet_uuid, worksheet_util.bundle_item(new_bundle_uuid))

        return plan