/**
  * Retrieve all items that were affected by an operation.
  *
  * @param $fetch_source_items
  *   If TRUE, source and replaced items will be retrieved as well,
  *   and stored as additional properties inside each item array.
  *   If FALSE, only current/new items will be retrieved.
  *   If NULL (default), source and replaced items will be retrieved for commits
  *   but not for branch or tag operations.
  *
  * @return
  *   A structured array containing all items that were affected by the given
  *   operation. Array keys are the current/new paths, even if the item doesn't
  *   exist anymore (as is the case with delete actions in commits).
  *   The associated array elements are structured item arrays and consist of
  *   the following elements:
  *
  *   - 'type': Specifies the item type, which is either
  *        VERSIONCONTROL_ITEM_FILE or VERSIONCONTROL_ITEM_DIRECTORY for items
  *        that still exist, or VERSIONCONTROL_ITEM_FILE_DELETED respectively
  *        VERSIONCONTROL_ITEM_DIRECTORY_DELETED for items that have been
  *        removed (by a commit's delete action).
  *   - 'path': The path of the item at the specific revision.
  *   - 'revision': The (file-level) revision when the item was changed.
  *        If there is no such revision (which may be the case for
  *        directory items) then the 'revision' element is an empty string.
  *   - 'item_revision_id': Identifier of this item revision in the database.
  *        Note that you can only rely on this element to exist for
  *        operation items - functions that interface directly with the VCS
  *        (such as VersioncontrolItem::getDirectoryContents() or
  *        VersioncontrolItem::getParallelItems()) might not include
  *        this identifier, for obvious reasons.
  *
  *   If the @p $fetch_source_items parameter is TRUE,
  *   versioncontrol_fetch_source_items() will be called on the list of items
  *   in order to retrieve additional information about their origin.
  *   The following elements will be set for each item in addition
  *   to the ones listed above:
  *
  *   - 'action': Specifies how the item was changed.
  *        One of the predefined VERSIONCONTROL_ACTION_* values.
  *   - 'source_items': An array with the previous revision(s) of the affected
  *        item. Empty if 'action' is VERSIONCONTROL_ACTION_ADDED. The key for
  *        all items in this array is the respective item path.
  *   - 'replaced_item': The previous but technically unrelated item at the
  *        same location as the current item. Only exists if this previous item
  *        was deleted and replaced by a different one that was just moved
  *        or copied to this location.
  *   - 'line_changes': Only exists if line changes have been recorded for this
  *        action - if so, this is an array containing the number of added lines
  *        in an element with key 'added', and the number of removed lines in
  *        the 'removed' key.
  * FIXME refactor me to oo
  */
 public function getItems($fetch_source_items = NULL)
 {
     $items = array();
     $result = db_query('SELECT ir.item_revision_id, ir.path, ir.revision, ir.type
   FROM {versioncontrol_operation_items} opitem
   INNER JOIN {versioncontrol_item_revisions} ir
   ON opitem.item_revision_id = ir.item_revision_id
   WHERE opitem.vc_op_id = %d AND opitem.type = %d', $this->vc_op_id, VERSIONCONTROL_OPERATION_MEMBER_ITEM);
     while ($item_revision = db_fetch_object($result)) {
         $items[$item_revision->path] = new $this->repository->backend->classes['item']($item_revision->type, $item_revision->path, $item_revision->revision, NULL, $this->repository, NULL, $item_revision->item_revision_id);
         $items[$item_revision->path]->selected_label = new stdClass();
         $items[$item_revision->path]->selected_label->get_from = 'operation';
         $items[$item_revision->path]->selected_label->operation =& $this;
         //TODO inherit from operation class insteadof types?
         if ($this->type == VERSIONCONTROL_OPERATION_COMMIT) {
             $items[$item_revision->path]->commit_operation = $this;
         }
     }
     if (!isset($fetch_source_items)) {
         // By default, fetch source items for commits but not for branch or tag ops.
         $fetch_source_items = $this->type == VERSIONCONTROL_OPERATION_COMMIT;
     }
     if ($fetch_source_items) {
         versioncontrol_fetch_source_items($this->repository, $items);
     }
     ksort($items);
     // similar paths should be next to each other
     return $items;
 }
Ejemplo n.º 2
0
 /**
  * Retrieve the revisions where the given item has been changed,
  * in reverse chronological order.
  *
  * Only one direct source or successor of each item will be retrieved,
  * which means that you won't get parallel history logs with a single
  * function call. In order to retrieve the log for this item in a
  * different branch, you need to switch the selected label of the item
  * by retrieving a different version of it with a call of
  * Item::getParallelItems() (if the backend supports this function).
  *
  * TODO: params doc
  *
  * @return
  *   An array containing a list of item arrays, each one specifying a
  *   revision of the same item that was given as argument. The array is
  *   sorted in reverse chronological order, so the newest revision
  *   comes first. Each element has its (file-level) item revision as
  *   key, and a standard item object (as the ones retrieved by
  *   VersioncontrolOperation::getItems()) as value. All items except
  *   for the oldest one will also have the 'action' and 'source_items'
  *   properties filled in, the oldest item might or might not have
  *   them. (If they exist for the oldest item, 'action' will be
  *   VERSIONCONTROL_ACTION_ADDED and 'source_items' an empty array.)
  *
  *   NULL is returned if the given item is not under version control,
  *   or was not under version control at the time of the given
  *   revision, or if no history could be retrieved for any other
  *   reason.
  */
 public function getHistory($successor_item_limit = NULL, $source_item_limit = NULL)
 {
     // Items without revision have no history, don't even try to fetch it.
     if (empty($this->revision)) {
         return NULL;
     }
     // If we don't yet know the item_revision_id (required for db
     // queries), try to retrieve it. If we don't find it, we can't go on
     // with this function.
     if (!$this->fetchItemRevisionId()) {
         return NULL;
     }
     // Make sure we don't run into infinite loops when passed bad
     // arguments.
     if (is_numeric($successor_item_limit) && $successor_item_limit < 0) {
         $successor_item_limit = 0;
     }
     if (is_numeric($source_item_limit) && $source_item_limit < 0) {
         $source_item_limit = 0;
     }
     // Naive implementation - can probably be improved by sticking to
     // the samerepo_id/path until an action other than "modified" or
     // "other" appears. (With the drawback that code will probably need
     // to be duplicated among this function and
     // versioncontrol_fetch_{source,successor}_items().
     // Find (recursively) all successor items within the successor item
     // limit.
     $history_successor_items = array();
     $source_item = $this;
     while (!isset($successor_item_limit) || $successor_item_limit > 0) {
         $source_items = array($source_item->path => $source_item);
         versioncontrol_fetch_successor_items($this->repository, $source_items);
         $source_item = $source_items[$source_item->path];
         // If there are no successor items, we are obviously at the end of
         // the log.
         if (empty($source_item->successor_items)) {
             break;
         }
         // There might be multiple successor items - in most cases, the
         // first one is the only one so that's ok except for "merged"
         // actions.
         $successor_item = NULL;
         $highest_priority_so_far = 0;
         foreach ($source_item->successor_items as $path => $succ_item) {
             if (!isset($successor_item) || self::$successor_action_priority[$succ_item->action] > $highest_priority_so_far) {
                 $successor_item = $succ_item;
                 $highest_priority_so_far = self::$successor_action_priority[$succ_item->action];
             }
         }
         $history_successor_items[$successor_item->revision] = $successor_item;
         $source_item = $successor_item;
         // Decrement the counter until the item limit is reached.
         if (isset($successor_item_limit)) {
             --$successor_item_limit;
         }
     }
     // We want the newest revisions first, so reverse the successor array.
     $history_successor_items = array_reverse($history_successor_items, TRUE);
     // Find (recursively) all source items within the source item limit.
     $history_source_items = array();
     $successor_item = $this;
     while (!isset($source_item_limit) || $source_item_limit > 0) {
         $successor_items = array($successor_item->path => $successor_item);
         versioncontrol_fetch_source_items($repository, $successor_items);
         $successor_item = $successor_items[$successor_item->path];
         // If there are no source items, we are obviously at the end of the log.
         if (empty($successor_item->source_items)) {
             break;
         }
         // There might be multiple source items - in most cases, the first one is
         // the only one so that's ok except for "merged" actions.
         $source_item = NULL;
         if ($successor_item->action == VERSIONCONTROL_ACTION_MERGED) {
             if (isset($successor_item->source_items[$successor_item->path])) {
                 $source_item = $successor_item->source_items[$successor_item->path];
             }
         }
         if (!isset($source_item)) {
             $source_item = reset($successor_item->source_items);
             // first item
         }
         $history_source_items[$source_item->revision] = $source_item;
         $successor_item = $source_item;
         // Decrement the counter until the item limit is reached.
         if (isset($source_item_limit)) {
             --$source_item_limit;
         }
     }
     return $history_successor_items + array($this->revision => $this) + $history_source_items;
 }