| <?php |
| /******************************************************************************* |
| * Copyright (c) 2010, 2012 Eclipse Foundation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Wayne Beaton (Eclipse Foundation) - initial API and implementation |
| * Wayne Beaton (Eclipse Foundation) - Bug 369905 |
| *******************************************************************************/ |
| |
| /* |
| * This script assumes that it is being included by another script. We |
| * assume that the $App variable has already been defined. |
| */ |
| |
| require_once(dirname(__FILE__) . "/ProjectRoot.class.php"); |
| require_once(dirname(__FILE__) . "/debug.php"); |
| require_once(dirname(__FILE__) . "/common.php"); |
| trace_file_info(__FILE__); |
| |
| /** |
| * Get a project from the PMI instead of the foundation database. |
| * |
| * @param string $id a project id of the form 'technology.egit' |
| * @return PMIProject |
| */ |
| function get_project_from_pmi($id) { |
| if (!isValidProjectId($id)) return null; |
| if (preg_match('/^polarsys\.(.*)$/',$id, $matches)) { |
| $id = $matches[1]; |
| $url = "https://polarsys.org/json/project/$id"; |
| } else { |
| $url = "http://projects.eclipse.org/json/project/$id"; |
| } |
| if (!$json = file_get_contents($url)) return null; |
| |
| $all = json_decode($json, true); |
| return new PMIProject($all['projects'][$id]); |
| } |
| |
| /** |
| * PMI stand-in for Project class. The intent is that this |
| * is a valid subtype. The current reality is that I'm implementing |
| * only those bits of functionality that I'm actually using as I |
| * need it. |
| * |
| * @see Project |
| * @see get_project_from_pmi |
| */ |
| class PMIProject { |
| var $data; |
| |
| function __construct($data) { |
| $this->data = $data; |
| } |
| |
| function getId() { |
| // TODO Get the name (when it's available) |
| return $this->data['id'][0]['value']; |
| } |
| |
| /** |
| * @return string |
| */ |
| function getShortId() { |
| preg_match("/([^\.]+)$/", $this->getId(), $matches); |
| return $matches[1]; |
| } |
| |
| function getName() { |
| // TODO Get the name (when it's available) |
| return $this->data['title']; |
| } |
| |
| function getDescription() { |
| if (!$field = @$this->data['description'][0]) return null; |
| if (!empty($field['summary'])) return $field['summary']; |
| return $field['safe_value']; |
| } |
| |
| function getDevListUrl() { |
| return $this->data['dev_list']['url']; |
| } |
| |
| function getPlanUrl() { |
| return $this->data['plan_url'][0]['url']; |
| } |
| |
| function getSourceRepositories() { |
| $repositories = array(); |
| foreach($this->data['source_repo'] as $repo) { |
| if ($local = getSourceRepository($repo['path'], $this)) |
| $repositories[] = $local; |
| } |
| return $repositories; |
| } |
| |
| function getBugzillaProduct() { |
| foreach($this->data['bugzilla'] as $record) { |
| if (strlen($record['product']) > 0) |
| return $record['product']; |
| } |
| return null; |
| } |
| |
| function getBugzillaComponents() { |
| $components = array(); |
| foreach($this->data['bugzilla'] as $record) { |
| if (strlen($record['component']) > 0) |
| $components[] = $record['component']; |
| } |
| return $components; |
| } |
| |
| /** |
| * Return the parent of the project. Note that this does |
| * not cache. Subsequent calls will result in an additional |
| * query. |
| */ |
| function getParent() { |
| if (!$id = @$this->data['parent_project'][0]['id']) return; |
| return get_project_from_pmi($id); |
| } |
| |
| function getTopLevelProject() { |
| if (!$parent = $this->getParent()) return $this; |
| return $this->getParent()->getTopLevelProject(); |
| } |
| } |
| |
| /** |
| * @deprecated use #getProjectRoot() |
| */ |
| function get_project_root() { |
| return getProjectRoot(); |
| } |
| /** |
| * Lazily create an instance of ProjectRoot; this instance will read in and hold onto |
| * the project information. This way, we only read it once. |
| * |
| * PRIVATE: THIS IS NOT API |
| */ |
| function getProjectRoot() { |
| global $_project_root; |
| |
| if (!$_project_root) $_project_root = new ProjectRoot(); |
| |
| return $_project_root; |
| } |
| |
| /** |
| * Clear the project cache. Call this method if you need to reload the |
| * projects for any reason, or if you just want to try and reclaim some |
| * space (though I remain skeptical about PHP's garbage collection). |
| */ |
| function clear_project_cache() { |
| global $_project_root; |
| |
| unset($_project_root); |
| } |
| |
| /** |
| * Force projects to be preloaded. You might use this behaviour |
| * to override the default lazy behaviour (which is to load only |
| * the active projects) thereby including inactive projects in |
| * later queries. |
| * |
| * This function is no longer required. Projects load on demand; |
| * there is only one way to load. |
| * |
| * @deprecated |
| * @param bool $activeOnly Load only the active projects (default) |
| */ |
| function preloadProjects($activeOnly = true) { |
| _loadAllProjects($activeOnly); |
| } |
| |
| /** |
| * Do the actual load of the projects. Projects are cached. |
| * |
| * PRIVATE: THIS IS NOT API |
| * |
| * @deprecated This function is unnecessary. |
| * @internal |
| * @param bool $activeOnly Load only the active projects (default) |
| */ |
| function _loadAllProjects($activeOnly = true) { |
| global $_project_root; |
| $_project_root = new ProjectRoot($activeOnly); |
| } |
| |
| /** |
| * Answers an array containing all top-level projects. Only |
| * active projects are included. |
| * |
| * @return Project[] |
| */ |
| function getTopLevelProjects() { |
| return getProjectRoot()->getTopLevelProjects(); |
| } |
| |
| /** |
| * @deprecated |
| * @see #getTopLevelProjects() |
| */ |
| function get_project_hierarchy() { |
| return getTopLevelProjects(); |
| } |
| |
| /** |
| * This function returns an instance of Project representing the project |
| * with the provided $id. Note that this function preserves object |
| * identity: if called twice with the same value, it will return the |
| * exact same object. |
| * |
| * @return Project |
| */ |
| function getProject($id) { |
| return getProjectRoot()->getProject($id); |
| } |
| |
| /** |
| * @deprecated use #getProject($id) |
| * @return Project |
| */ |
| function get_project($id) { |
| return getProjectRoot()->get_project($id); |
| } |
| |
| /** |
| * This function returns all the active projects. |
| * @return Project[] |
| */ |
| function getActiveProjects() { |
| return getProjectRoot()->getActiveProjects(); |
| } |
| |
| /** |
| * @deprecated use #getActiveProjects() |
| * @return Project[] |
| */ |
| function get_all_projects() { |
| return getActiveProjects(); |
| } |
| |
| /** |
| * This function returns an array containing those projects that have |
| * declared participation in the simultaneous release with the provided |
| * name. |
| * |
| * @param string $name |
| */ |
| function getAllProjectsInSimultaneousRelease($name) { |
| $all = get_all_projects(); |
| $projects = array(); |
| foreach($all as $project) { |
| /* @var $project Project */ |
| if (in_array($name, $project->getSimultaneousReleaseNames())) $projects[] = $project; |
| } |
| return $projects; |
| } |
| |
| /* |
| * List of field names in the database. |
| * |
| * PRIVATE: THIS FIELD IS NOT API. |
| */ |
| $project_fields = array('ProjectId', 'Name','Level','ParentProjectID','Description', |
| 'UrlDownload','UrlIndex','DateActive','SortOrder','IsActive', |
| 'BugsName','ProjectPhase','DiskQuotaGB','IsComponent','IsStandard'); |
| $project_fields_string = implode(',', $project_fields); |
| |
| define('PROJECT_LIVELINESS_ACTIVE', 1); |
| define('PROJECT_LIVELINESS_STALE', 2); |
| define('PROJECT_LIVELINESS_DEAD', 3); |
| |
| define('PROJECT_REPO_ALL_GIT', 1); |
| define('PROJECT_REPO_SOME_GIT', 2); |
| define('PROJECT_REPO_NO_GIT', 3); |
| define('PROJECT_REPO_NONE', 4); |
| |
| class Project { |
| /** |
| * @internal |
| * @var ProjectRoot |
| */ |
| var $root; |
| |
| /** |
| * Project information from the 'Foundation' database |
| * @internal |
| */ |
| var $data; |
| |
| /** |
| * Values from the Eclipse database |
| * @internal |
| */ |
| var $values = array(); |
| |
| /** |
| * @internal |
| * @var Project |
| */ |
| var $parent; |
| |
| /** |
| * @internal |
| * @var Project[] |
| */ |
| var $children = array(); |
| |
| /** |
| * Keep track of the people associated with the project. This |
| * field is lazy-initialized; use the getPeople() method to access. |
| * |
| * @internal |
| */ |
| var $people = null; |
| |
| /** |
| * An array containing the the projects that the receiver has |
| * been moved from (e.g., if the project moved from a->b->c, then |
| * project c would list (a,b) in this field). |
| * |
| * @internal |
| * @var Project[] |
| */ |
| var $movedFrom = array(); |
| |
| /** |
| * @param Project $root |
| * @param mixed $data |
| */ |
| function __construct($root, $data) { |
| $this->root = $root; |
| $this->data = $data; |
| } |
| |
| /** |
| * @return string |
| */ |
| function getId() { |
| return $this->data['ProjectId']; |
| } |
| |
| /** |
| * @return Project |
| */ |
| function getParent() { |
| return $this->parent; |
| } |
| |
| function getUrl() { |
| return "http://projects.eclipse.org/projects/" . $this->getId(); |
| } |
| |
| /** |
| * @return string |
| */ |
| function getShortId() { |
| preg_match("/([^\.]+)$/", $this->getId(), $matches); |
| return $matches[1]; |
| } |
| |
| /** |
| * Answer the project's name as it appears in the Project metadata. |
| * If the project metadata has not been specified, get the value |
| * from the Eclipse Foundation Database. If the name has not been |
| * specified, the ID is answered instead. |
| * |
| * @return string |
| */ |
| function getName() { |
| if ($name = $this->findFirstValue('projectname')) return $name; |
| if ($name = $this->findFirstValue('projectshortname')) return $name; |
| return $this->data['Name'] ? $this->data['Name'] : $this->getId(); |
| } |
| |
| function getTopLevelProject() { |
| if (!$this->parent) return $this; |
| return $this->parent->getTopLevelProject(); |
| } |
| |
| function getSiblings() { |
| return $this->parent ? $this->parent->getChildren() : getTopLevelProjects(); |
| } |
| |
| /** |
| * Answer the project's name as it appears in the developer portal |
| * (this value is set by the project's commmitters). If the projectname |
| * field has not been specified, the project's name as it appears |
| * in the Eclipse Foundation Database is answered instead. |
| * |
| * @return string |
| */ |
| function getProjectName() { |
| $name = $this->findFirstValue('projectname'); |
| if ($name) return $name; |
| return $this->getName(); |
| } |
| |
| /** |
| * Answer the short name of the project as entered in the |
| * 'projectshortname' field in the portal. If the value is |
| * not set in the portal, the receiver's name is returned instead. |
| * |
| * @return string |
| */ |
| function getShortName() { |
| $name = $this->findFirstValue('projectshortname'); |
| return $name ? $name : $this->getName(); |
| } |
| |
| /** |
| * Note that this is a fairly expensive operation. We assume that |
| * this function will be called at most once in any session. The current |
| * implementation does not cache the results, so the caller should |
| * be careful to avoid subsequent calls (or change this implementation). |
| * |
| * @return string |
| */ |
| function getDescription() { |
| $id = $this->getId(); |
| $raw = $this->getDescriptionUrl(); |
| $url = normalizeFilePathUrl($raw); |
| |
| if (!$url) { |
| trace("Description URL for $id not provided."); |
| return null; |
| } |
| |
| if (preg_match('/\.php$/', $url)) { |
| trace("Ignoring PHP description URL for $id."); |
| return null; |
| } |
| |
| trace("Description URL for $id is $raw, normalizes to $url."); |
| |
| $description = @file_get_contents($url); |
| if (!$description) { |
| trace("Description for $id not found."); |
| return null; |
| } |
| |
| $description = $this->cleanDescription($description); |
| |
| if(!trim($description)) { |
| trace("Description for $id is empty."); |
| return null; |
| } |
| |
| return $description; |
| } |
| |
| /** |
| * The short description is an abridged version of the description. We first |
| * try to obtain the description using the #getParagraph method; if this does |
| * not return a value, we grab the description (assuming that it is available). |
| * Whatever value we start from, we strip out any HTML tags and limit the size |
| * to 100 words. Results vary based on the quality of the input :-( |
| * |
| * Note that this is a fairly expensive operation. We assume that |
| * this function will be called at most once in any session. The current |
| * implementation does not cache the results, so the caller should |
| * be careful to avoid subsequent calls (or change this implementation). |
| * |
| * @return string |
| */ |
| function getShortDescription() { |
| $description = $this->getParagraph(); |
| if (!$description) $description = $this->getDescription(); |
| return $this->extractShortDescription($description); |
| } |
| |
| /** |
| * Answer a paragraph describing the receiver, extracted from |
| * the file referenced in the 'paragraphurl' field in the portal, |
| * or <code>null</code> if the field is not specified. |
| * |
| * @return string|null |
| */ |
| function getParagraph() { |
| $id = $this->getId(); |
| $raw = $this->getParagraphUrl(); |
| $url = normalizeFilePathUrl($raw); |
| |
| if (!$url) { |
| trace("Paragraph URL for $id not provided."); |
| return null; |
| } |
| |
| trace("Paragraph URL for $id is $raw, normalizes to $url."); |
| |
| $paragraph = @file_get_contents($url); |
| |
| if (!$paragraph) { |
| trace("Paragraph for $id not found."); |
| return null; |
| } |
| |
| if(!trim($paragraph)) { |
| trace("Paragraph for $id is empty."); |
| return null; |
| } |
| |
| return $paragraph; |
| } |
| |
| /** |
| * Return the URL for the project. This information is |
| * represented in both the portal and the Foundation database. |
| * The value provided by a project committer in the metadata |
| * (portal) overrides any value that exists in the Foundation |
| * Database. |
| * |
| * @string |
| */ |
| function getProjectUrl() { |
| $url = $this->findFirstValue('projecturl'); |
| if ($url) return $url; |
| |
| return $this->data['UrlIndex']; |
| } |
| |
| function getPlanUrl() { |
| $plan = $this->findFirstValue('projectplanurl'); |
| if (preg_match('/^http:\/\/(www\.)?eclipse\.org\/projects\/project-plan\.php\?planurl=(.+\.xml)$/', $plan, $matches)) { |
| return $matches[2]; |
| } |
| |
| return $plan; |
| } |
| |
| function getWikiUrl() { |
| return $this->findFirstValue('wikiurl'); |
| } |
| |
| function getIpLogUrl() { |
| return $this->findFirstValue('iplogurl'); |
| } |
| |
| function getLogoUrl() { |
| return $this->findFirstValue('logourl'); |
| } |
| |
| function getDocumentationUrl() { |
| return $this->findFirstValue('documentationurl'); |
| } |
| |
| function getDescriptionUrl() { |
| if ($url = $this->findFirstValue('descriptionurl')) return $url; |
| |
| if ($root = $this->getWebRoot()) return "$root/description.html"; |
| |
| return null; |
| } |
| |
| /** |
| * Answers the root directory for the website of the project. |
| */ |
| function getWebRoot() { |
| $short = end(preg_split('/\./', $this->getId())); |
| if (file_exists(normalizeFilePathUrl($short))) return $short; |
| return null; |
| } |
| |
| function getParagraphUrl() { |
| return $this->findFirstValue('paragraphurl'); |
| } |
| |
| function getDownloadsUrl() { |
| return $this->findFirstValue('downloadsurl'); |
| } |
| |
| function getGettingStartedUrl() { |
| return $this->findFirstValue('gettingstartedurl'); |
| } |
| /** |
| * @return String |
| */ |
| function getBugzillaProduct() { |
| return $this->findFirstValue('bugzilla', 'productname'); |
| } |
| |
| /** |
| * Return an array containing the component names for the project. |
| * If no components are specified for this project, then the |
| * result is an empty array. |
| * |
| * Components are stored in an single string. Each component is |
| * separated from the next using a comma. We try to be as forgiving |
| * as possible here and trim out leading or trailing spaces. |
| * Since I'm not sure exactly what limitations are placed on |
| * component names, this is probably the best we can do. |
| * |
| * @return String[] |
| */ |
| function getBugzillaComponents() { |
| $value = $this->findFirstValue('bugzilla', 'components'); |
| if (!$value) return array(); |
| $components = array(); |
| $values = split(',', $value); |
| foreach($values as $component) { |
| $components[] = trim($component); |
| } |
| return $components; |
| } |
| |
| function getBugzillaUrl() { |
| return $this->findFirstValue('bugzilla', 'url'); |
| } |
| |
| /** |
| * |
| * @return Review[] |
| */ |
| function getReviews() { |
| require_once(dirname(__FILE__) . "/Review.class.php"); |
| return getReviewsForProject($this->getId()); |
| } |
| |
| function getProposal() { |
| require_once(dirname(__FILE__) . "/Proposal.class.php"); |
| return getProposalForProject($this->getId()); |
| } |
| |
| function getScope() { |
| $proposal = $this->getProposal(); |
| if (!$proposal) return; |
| return $proposal->getScope(); |
| } |
| |
| /** |
| * Answer the creation review of the receiver or null if |
| * the creation review cannot be found. If $checkParent |
| * (optional) is true (default), then we assume that--if |
| * the receiver does not have its own creation review--it |
| * shares creation with its parent. |
| * |
| * @return Review|null |
| */ |
| function getCreationReview($checkParent = true) { |
| foreach($this->getReviews() as $review) { |
| if ($review->isCreation()) return $review; |
| } |
| if (!$checkParent) return null; |
| if (!$this->parent) return null; |
| return $this->parent->getCreationReview(); |
| } |
| |
| /** |
| * Answer the termination review of the receiver or null if |
| * the creation review cannot be found. |
| * |
| * @return Review|null |
| */ |
| function getTerminationReview() { |
| foreach($this->getReviews() as $review) { |
| if ($review->isTermination()) return $review; |
| } |
| return null; |
| } |
| |
| // At some point, we may consider an approach along these lines. |
| // For now, it's better to separate methods for each getter to |
| // better allow for code completion to work. |
| // |
| // function __call($name, $parameters) { |
| // global $projectAPI; |
| // |
| // $matches = array(); |
| // if (preg_match('/^get([_\d\w]*)$/')) { |
| // $metadata = $projectAPI->findMetaDataForProjectInfo($matches[1]); |
| // $value = $this->findFirstValue($metadata['mainkey']); |
| // |
| // } |
| // |
| // return parent::__call($name, $description); |
| // } |
| |
| /** |
| * |
| * @return Newsgroup[] |
| */ |
| function getNewsgroups() { |
| return $this->getProjectInfoValues('newsgroup'); |
| } |
| |
| function getMailingLists() { |
| return $this->getProjectInfoValues('mailinglist'); |
| } |
| |
| /** |
| * A project has releases if (a) there is at least one |
| * release documented in the metadata, and (b) there is no |
| * documented release with 'noreleases' as its name. |
| * |
| * @return bool |
| */ |
| function hasReleases() { |
| return $this->getReleases() ? true : false; |
| } |
| |
| /** |
| * Answers the collection of releases made by the project sorted |
| * in ascending order (i.e. the oldest release is first). |
| * |
| * @return Release[] |
| */ |
| function getReleases() { |
| $releases = array(); |
| foreach ($this->getProjectInfoValues('release') as $data) { |
| $release = new Release($this, $data); |
| if (!$release->isValid()) continue; |
| $releases[$release->getName()] = $release; |
| } |
| |
| foreach($this->movedFrom as $project) { |
| $trace = trace("Adding releases from " . $project->getId()); |
| foreach($project->getReleases() as $release) { |
| //if (!isset($releases[$release->getName()])) |
| $releases[$release->getName()] = $release; |
| //else |
| $trace->trace("Adding " . $release->getName()); |
| } |
| } |
| |
| usort($releases, array($this, 'sortReleases')); |
| |
| return $releases; |
| } |
| |
| /** |
| * This function is used by #renderReleases. |
| * |
| * @internal |
| * @param Release $release1 |
| * @param Release $release2 |
| */ |
| function sortReleases($release1, $release2) { |
| $date1 = $release1->getDate(); |
| $date2 = $release2->getDate(); |
| if ($date1 == $date2) return 0; |
| return $date1 < $date2 ? -1 : 1; |
| } |
| |
| /** |
| * @param $date timestamp |
| * @return Release|null |
| */ |
| function getReleaseOnDate($date) { |
| $string = date('Y-m-d', $date); |
| $releases = $this->getReleases(); |
| foreach ($releases as $release) { |
| /* @var $release Release */ |
| if ($release->getDate() == $string) return $release; |
| } |
| return null; |
| } |
| |
| /** |
| * @return Release |
| */ |
| function getGraduationRelease() { |
| $releases = array(); |
| foreach($this->getReleases() as $release) { |
| if (preg_match('/(\d+)(\.\d+){1,2}/', $release->getName(), $matches)) { |
| $major = $matches[1]; |
| if ((int)$major > 0) return $release; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * @param $name string |
| * @return Release|null |
| */ |
| function getReleaseNamed($name) { |
| $releases = $this->getReleases(); |
| foreach ($releases as $release) { |
| /* @var $release Release */ |
| if (strcasecmp($release->getName(), $name) == 0) return $release; |
| } |
| return null; |
| } |
| |
| function hasCommitActivity() { |
| foreach($this->getSourceRepositories() as $repository) { |
| if ($repository->providesCommitActivity()) return true; |
| } |
| return false; |
| } |
| |
| /** |
| * This function answers true if the receiver has at least |
| * one source repository specified; it returns false otherwise. |
| * |
| * @return boolean |
| */ |
| function hasSourceRepositories() { |
| return $this->getSourceRepositories() ? true : false; |
| } |
| |
| function getGitStatus() { |
| $types = $this->getSourceRepositoryTypes(); |
| if (count($types) == 1 && isset($types['git'])) return PROJECT_REPO_ALL_GIT; |
| if (isset($types['git']) && count($types) > 1) return PROJECT_REPO_SOME_GIT; |
| if (count($types)) return PROJECT_REPO_NO_GIT; |
| return PROJECT_REPO_NONE; |
| } |
| |
| /** |
| * This function answers an array of source repository types, |
| * e.g. array('git'=>'git', 'cvs'=>'cvs'). |
| * |
| * @return multitype:string |
| */ |
| function getSourceRepositoryTypes() { |
| $types = array(); |
| |
| foreach($this->getSourceRepositories() as $repository) { |
| $type = $repository->getType(); |
| $types[$type] = $type; |
| } |
| |
| return $types; |
| } |
| |
| /** |
| * This function returns a collection of SourceRepository instances, |
| * each representing one of the source repositories associated with |
| * the project. |
| * |
| * @return SourceRepository[] |
| */ |
| function getSourceRepositories() { |
| // TODO Cache these results. |
| $values = $this->findValues('sourcerepository'); |
| $repositories = array(); |
| foreach($values as $repository) { |
| if ($sourceRepository = getSourceRepository($repository, $this)) { |
| $repositories[$sourceRepository->getName()] = $sourceRepository; |
| } |
| } |
| return $repositories; |
| } |
| |
| function getUniqueSourceRepositories() { |
| $repositories = $this->getSourceRepositories(); |
| $this->removeRedundantRepositories($repositories); |
| return $repositories; |
| } |
| |
| /** |
| * @internal |
| * @param SourceRepository[] $repositories |
| */ |
| function removeRedundantRepositories(&$repositories) { |
| foreach($this->getChildren() as $subproject) { |
| foreach($subproject->getUniqueSourceRepositories() as $subrepo) { |
| unset($repositories[$subrepo->getName()]); |
| } |
| $subproject->removeRedundantRepositories($repositories); |
| } |
| } |
| |
| function getUpdateSiteUrl() { |
| return $this->findFirstValue('updatesiteurl'); |
| } |
| |
| function getProjectPhase() { |
| return $this->data['ProjectPhase']; |
| } |
| |
| /** |
| * This function answers true if the receiver is marked as |
| * a "Component" in the Eclipse Foundation database. |
| * This is a relatively old concept that predates the 2007 version |
| * of the EDP. Components tend to have their own UNIX groups, |
| * but are considered fully part of the parent project. |
| */ |
| function isComponent() { |
| return $this->data['IsComponent']; |
| } |
| |
| function isActive() { |
| return $this->data['IsActive'] == 1; |
| } |
| |
| function isInIncubationPhase() { |
| return in_array($this->getProjectPhase(), array('Incubation', 'Incubation.nc')); |
| } |
| |
| function isArchived() { |
| return $this->getProjectPhase() == 'Archived'; |
| } |
| |
| function isInIncubationConformingPhase() { |
| return $this->getProjectPhase() == 'Incubation'; |
| } |
| |
| function isInIncubationNonConformingPhase() { |
| return $this->getProjectPhase() == 'Incubation.nc'; |
| } |
| |
| function isTopLevel() { |
| return !$this->parent; |
| } |
| |
| /** |
| * This function returns an array containing the names of the |
| * simultaneous releases that the receiver participates in. |
| * |
| * @return string[] |
| */ |
| function getSimultaneousReleaseNames() { |
| $rows = $this->findRows('simultaneousrelease'); |
| $releases = array(); |
| foreach ($rows as $row) { |
| if ($row['Value']) |
| $releases[$row['SubKey']] = true; |
| } |
| return array_keys($releases); |
| } |
| |
| /** |
| * Returns an instance of SimultaneousReleaseInfo for the receiver, |
| * or <code>null</code> if no information has been provided. |
| * |
| * @return SimultaneousReleaseInfo |
| */ |
| function getSimultaneousReleaseInfo($releaseName = null) { |
| return getSimultaneousReleaseInfo($this->getId(), $releaseName); |
| } |
| |
| function getLiveliness() { |
| $liveliness = PROJECT_LIVELINESS_DEAD; |
| foreach($this->getChildren() as $child) { |
| $liveliness = min($liveliness, $child->getLiveliness()); |
| } |
| if ($liveliness == PROJECT_LIVELINESS_ACTIVE) return PROJECT_LIVELINESS_ACTIVE; |
| if ($this->hasRecentCommitActivity(3)) return PROJECT_LIVELINESS_ACTIVE; |
| |
| if ($liveliness == PROJECT_LIVELINESS_STALE) return PROJECT_LIVELINESS_STALE; |
| if ($this->hasRecentCommitActivity(6)) return PROJECT_LIVELINESS_STALE; |
| |
| return PROJECT_LIVELINESS_DEAD; |
| } |
| |
| /**
|
| * @return int
|
| */
|
| function getActiveCommittersCount() {
|
| global $App;
|
|
|
| $id = $this->getId();
|
| $result = $App->dashboard_sql("select count(distinct login) as count from ProjectCommitterActivity where project='$id'");
|
|
|
| while($row = mysql_fetch_assoc($result)) {
|
| return (int)$row['count'];
|
| }
|
| return 0;
|
| } |
| |
| /** |
| * @return int |
| */ |
| function getActiveOrganizationsCount() {
|
| global $App;
|
|
|
| $id = $this->getId();
|
| $result = $App->dashboard_sql("select count(distinct company) as count from ProjectCompanyActivity where project='$id'");
|
|
|
| while($row = mysql_fetch_assoc($result)) {
|
| return (int)$row['count'];
|
| }
|
| return 0; |
| } |
| |
| /** |
| * Answers whether or not the receiver has recent commit activity. |
| * |
| * @param int $months (Optional) how many months in the past to check. |
| * @return boolean |
| */ |
| function hasRecentCommitActivity($months = 6) { |
| $activity = $this->getCommitActivity(); |
| $date = strtotime('now'); |
| while ($months) { |
| if ($activity[date('Ym',$date)]) return true; |
| $date = strtotime("-1 month", $date); |
| $months--; |
| } |
| return false; |
| } |
| |
| /** |
| * Returns the commit activity for the receiver in the form of an |
| * array mapping period to commit count. |
| * |
| * e.g., |
| * |
| * array('201001' => 52, '201002' => 33, ...) |
| * |
| * Note that this information is cached. The first time this method |
| * is called (on any instance), the cache is created. |
| * |
| * @returns [] array mapping period to commit count. |
| */ |
| function getCommitActivity() { |
| if (isset($this->_commitActivity)) return $this->_commitActivity; |
| |
| global $App; |
| |
| $id = $this->getId(); |
| $result = $App->dashboard_sql("select period, count from ProjectCommitActivity where project='$id'"); |
| |
| $this->_commitActivity = array(); |
| while($row = mysql_fetch_assoc($result)) { |
| $this->_commitActivity[$row['period']] = $row['count']; |
| } |
| return $this->_commitActivity; |
| } |
| |
| /** |
| * Returns the last three month's worth of company commit activity |
| * for the receiver in the form of an array mapping company name to |
| * commit count. |
| * |
| * e.g., |
| * |
| * array('IBM' => 52, 'Actuate Corporation' => 33) |
| * |
| * Note that this information is cached. The first time this method |
| * is called (on any instance), the cache is created. |
| * |
| * @returns [] array mapping company name to commit count. |
| */ |
| function getCompanyCommitActivity() { |
| if (isset($this->_companyActivity)) return $this->_companyActivity; |
| |
| global $App; |
| |
| $id = $this->getId(); |
| $result = $App->dashboard_sql("select company, count from ProjectCompanyActivity where project='$id'"); |
| |
| $this->_companyActivity = array(); |
| while($row = mysql_fetch_assoc($result)) { |
| $this->_companyActivity[$row['company']] = $row['count']; |
| } |
| return $this->_companyActivity; |
| } |
| |
| /** |
| * Returns the last three month's worth of committer commit activity |
| * for the receiver in the form of an array mapping committer name to |
| * commit count. |
| * |
| * e.g., |
| * |
| * array('Wayne Beaton' => 52, 'Doug Schaefer' => 33) |
| * |
| * Note that this information is cached. The first time this method |
| * is called (on any instance), the cache is created. |
| * |
| * @returns [] array mapping company name to commit count. |
| */ |
| function getCommitterCommitActivity() { |
| if (isset($this->_committerActivity)) return $this->_committerActivity; |
| |
| global $App; |
| |
| $id = $this->getId(); |
| $result = $App->dashboard_sql("select login, count from ProjectCommitterActivity where project='$id'"); |
| |
| $this->_committerActivity = array(); |
| while($row = mysql_fetch_assoc($result)) { |
| $this->_committerActivity[$row['login']] = $row['count']; |
| } |
| return $this->_committerActivity; |
| } |
| |
| function getLicenses() { |
| global $App; |
| |
| $id = $this->getId(); |
| |
| $sql = "select distinct LicenseId from ProjectLicenses where ProjectId='$id'"; |
| $result = $App->foundation_sql($sql); |
| |
| $licenses = array(); |
| while ($row = mysql_fetch_assoc($result)) { |
| $licenses[] = $row['LicenseId']; |
| } |
| return $licenses; |
| } |
| |
| /* |
| * This function assembles a collection of ProjectInfoValue instances |
| * for the given $key. Essentially, this is an object that represents |
| * a group of values in the receiver and presents a higher-level of |
| * abstraction for accessing those values. |
| * |
| * Values are stored in the DB in a table like this: |
| * |
| * +---------------+---------+-----------+----------------------------+ |
| * | ProjectInfoID | MainKey | SubKey | Value | |
| * +---------------+---------+-----------+----------------------------+ |
| * |... | | | | |
| * |8512 |newsgroup|name |eclipse.examples.users | |
| * |8512 |newsgroup|type |main | |
| * |8512 |newsgroup|description|A useful newsgroup | |
| * |9765 |newsgroup|name |eclipse.examples.dev | |
| * |9765 |newsgroup|type |standard | |
| * |... | | | | |
| * +---------------+---------+-----------+----------------------------+ |
| * |
| * These values are associated with the technology.examples project. |
| * |
| * If we ask the Project instance to getNewsgroups(), this function will |
| * be invoked and find these five rows. It would, from these rows, create |
| * two instances of ProjectInfoValues: one representing the values for |
| * ProjectInfoID=8512, and a second representing the values for |
| * ProjectInfoID=9765. These instances can then be sent relatively |
| * high-level messages like getName(), getType(), and getDescription() |
| * to obtain useful information. |
| * |
| * PRIVATE: THIS FUNCTION IS NOT API. |
| */ |
| /* private */ function getProjectInfoValues($key) { |
| $this->root->load_project_info(); |
| $infoValues = array(); |
| foreach($this->values as $value) { |
| if ($value['MainKey'] == $key) { |
| $id = $value['ProjectInfoID']; |
| if (!isset($infoValues[$id])) $infoValues[$id] = new ProjectInfoValue($id, $key, $this); |
| } |
| } |
| return $infoValues; |
| } |
| |
| /* private */ function findRows($mainkey) { |
| $this->root->load_project_info(); |
| $rows = array(); |
| foreach($this->values as $row) { |
| if ($row['MainKey'] == $mainkey) $rows[] = $row; |
| } |
| return $rows; |
| } |
| |
| /* private */ function findFirstValue($mainkey, $subkey = '') { |
| $this->root->load_project_info(); |
| foreach($this->values as $row) { |
| if ($row['MainKey'] != $mainkey) continue; |
| if ($row['SubKey'] != $subkey) continue; |
| return trim($row['Value']); |
| } |
| return null; |
| } |
| |
| /* private */ function findValues($mainkey, $subkey = '') { |
| $values = array(); |
| $this->root->load_project_info(); |
| foreach($this->values as $row) { |
| if ($row['MainKey'] != $mainkey) continue; |
| if ($row['SubKey'] != $subkey) continue; |
| $values[] = trim($row['Value']); |
| } |
| return $values; |
| } |
| |
| function isCommitterEmail($address) { |
| return true; |
| } |
| |
| function hasChildren() { |
| return $this->children ? true : false; |
| } |
| |
| function getChildren() { |
| return $this->children; |
| } |
| |
| /** |
| * Return the people associated with this project. Note that |
| * the value is cached so that subsequent calls return the |
| * same objects. |
| * |
| * @return Committer[] |
| */ |
| function getPeople() { |
| require_once dirname(__FILE__) . '/Committer.class.php'; |
| |
| if ($this->people === null) |
| $this->people = getCommittersForProject($this->getId()); |
| |
| return $this->people; |
| } |
| |
| /** |
| * Answers <code>true</code> if the receiver's |
| * inherit flag is set (meaning that metadata from the |
| * parent should be inherited), or <code>false</code> |
| * otherwise. |
| */ |
| function inheritsFromParent() { |
| return $this->findFirstValue('inherit', 'inherit'); |
| } |
| |
| /** |
| * This function will make sure that the given URL is likely valid by |
| * converting it (if necessary) into an absolute URL. It further checks |
| * to ensure that the URL is from an 'eclipse.org' property. |
| * |
| * @deprecated Use normalizeFilePathUrl or normalizeHttpUrl |
| * @param A string value representing an absolute or relative URL. |
| * @return A likely valid absolute URL that references an eclipse.org page |
| */ |
| function normalizeProjectDescriptionUrl($url) { |
| return $this->normalizeUrlAsHTTP($url); |
| } |
| |
| /** |
| * This function normalizes the provided URL to an HTTP form. Input |
| * should be a valid eclipse.org URL or a relative URL (with or without |
| * a leading slash). |
| * |
| * e.g. The following URLs will all normalize to |
| * http://eclipse.org/woolsey/para.html |
| * |
| * - http://www.eclipse.org/woolsey/para.html |
| * - http://eclipse.org/woolsey/para.html |
| * - http://localhost/woolsey/para.html |
| * - woolsey/para.html |
| * - /woolsey/para.html) |
| * |
| * Note that URLs that do not correspond to eclipse.org addresses, will |
| * result in a <code>null</code> result. |
| * |
| * Usage: |
| * |
| * Project::normalizeHttpUrl('http://www.eclipse.org/woolsey/para.html'); |
| * |
| * @param String $url |
| * @deprecated Use normalizeHttpUrl($url) from common.php |
| */ |
| public function normalizeHttpUrl($url) { |
| return normalizeHttpUrl($url); |
| } |
| |
| /** |
| * This function normalizes the provided URL to valid file path on the |
| * eclipse.org web directory. Input should be a valid eclipse.org URL |
| * or a relative URL (with or without a leading slash). |
| * |
| * e.g. The following URLs will all normalize to |
| * /home/local/data/httpd/www.eclipse.org/html/woolsey/para.html |
| * |
| * - http://www.eclipse.org/woolsey/para.html |
| * - http://eclipse.org/woolsey/para.html |
| * - http://localhost/woolsey/para.html |
| * - woolsey/para.html |
| * - /woolsey/para.html) |
| * |
| * Note that URLs that do not correspond to eclipse.org addresses, will |
| * result in a <code>null</code> result. |
| * |
| * Usage: |
| * |
| * Project::normalizeFilePathUrl('http://www.eclipse.org/woolsey/para.html'); |
| * |
| * @param String $url |
| * @deprecated Use normalizeFilePathUrl($url) from common.php |
| */ |
| public function normalizeFilePathUrl($url) { |
| return normalizeFilePathUrl($url); |
| } |
| |
| /** |
| * This function normalizes the provided URL to a relative path. |
| * Input should be a valid eclipse.org URL or a relative URL |
| * (with or without a leading slash). |
| * |
| * e.g. The following URLs will all normalize to |
| * /woolsey/para.html |
| * |
| * - http://www.eclipse.org/woolsey/para.html |
| * - http://eclipse.org/woolsey/para.html |
| * - http://localhost/woolsey/para.html |
| * - woolsey/para.html |
| * - /woolsey/para.html) |
| * |
| * Note that URLs that do not correspond to eclipse.org addresses, will |
| * result in a <code>null</code> result. |
| * |
| * Usage: |
| * |
| * Project::extractcRelativeUrl('http://www.eclipse.org/woolsey/para.html'); |
| * |
| * @param string $url |
| * @deprecated Use normalizeRelativeUrl($url) from common.php |
| */ |
| public function normalizeRelativeUrl($url) { |
| return normalizeRelativeUrl($url); |
| } |
| |
| /** |
| * PRIVATE - THIS IS NOT API. |
| * |
| * This method cleans up the description by removing potentially harmful tags. |
| * |
| * @param string $description |
| */ |
| function cleanDescription($description) { |
| // If we've been given a phoenix page, extract out the interesting bits. |
| if(preg_match('/\<div id="midcolumn"\>/s', $description)) { |
| $description = preg_replace('/((^.*\<div id="midcolumn"\>)|(\<\/div\>\<div id="footer"\>.*))/s', '', $description); |
| $description = substr($description, 0, strripos($description, '</div>')); |
| } |
| |
| return $description; |
| } |
| |
| /** |
| * This function extracts a short description from the provided (potentially) |
| * long one. We attempt to find the first paragraph in what we assume is HTML |
| * text. |
| * |
| * @param string $description The (potentially) long description, a string containing HTML. |
| * @param int $maxWords (optional) The maximum number of words in the result. |
| * @return string a string with limited HTML content (no surrounding 'p' tags). |
| */ |
| function extractShortDescription($description, $maxWords=100) { |
| // Match everything between the first <p> tag and the next </p> or <br> tag. |
| $matches = array(); |
| if (preg_match('/<p>(.*?)(?:(?:<\/p>)|(?:<br\s*\/?>))/s', $description, $matches)) { |
| //print_r($matches); |
| $description = $matches[1]; |
| } |
| |
| // Kill any tags that might occur in the text. |
| $description = preg_replace('/<[^>]*>/', '', $description); |
| |
| // Restrict the word count in the result. |
| $words = str_word_count($description, 2); |
| if (count($words) > $maxWords) { |
| $indices = array_keys($words); |
| $description = substr($description, 0, $indices[$maxWords]) . '...'; |
| } |
| |
| return $description; |
| } |
| } |
| |
| /* |
| * Each instance of this class represents a collection of values |
| * from the ProjectInfoValues table that share a common ProjectInfoID and MainKey. |
| * These values are actually stored in an array on the Project instance itself; |
| * instances of this class do not store the values themselves, but rather |
| * find the values on the Project instance. |
| * |
| * Instances can be queried for the values of the various SubKeys in the |
| * corresponding values using high-level function names. The function |
| * getName(), for example, would return the value in the row with SubKey |
| * 'name'. |
| * |
| * For more information, see the comment on Project#getProjectInfoValues($key). |
| * |
| * THIS CLASS IS NOT INTENDED TO BE INSTANTIATED BY CLIENTS. |
| */ |
| class ProjectInfoValue { |
| var $id; |
| var $key; |
| var $project; |
| |
| function __construct($id, $key, $project) { |
| $this->id = $id; |
| $this->key = $key; |
| $this->project = $project; |
| } |
| |
| function __call($name, $args) { |
| $match = array(); |
| if (preg_match('/^get(.*)$/', $name, $match)) { |
| return $this->getValue($match[1]); |
| } |
| } |
| |
| /* private */ function getValue($subkey) { |
| foreach ($this->project->values as $row) { |
| if ($row['MainKey'] != $this->key) continue; |
| if ($row['ProjectInfoID'] != $this->id) continue; |
| if (strcasecmp($row['SubKey'], $subkey) == 0) return $row['Value']; |
| } |
| return null; |
| } |
| } |
| |
| /** |
| * We never actually instantiate this class, it is provided to |
| * expose API for values returned by the Project#getNewsgroups |
| * method. Actual values are instances of ProjectInfoValue and |
| * the methods indicated below work through reflection. |
| */ |
| abstract class Newsgroup { |
| abstract function getId(); |
| abstract function getName(); |
| abstract function getType(); |
| abstract function getDescription(); |
| } |
| |
| |
| class Release { |
| var $project; |
| var $name; |
| var $date; |
| |
| function __construct($project, $data) { |
| $this->project = $project; |
| $this->data = $data; |
| $name = $data->getValue('name'); |
| if (preg_match('/(\d+)(\.\d+)?(\.\d+)?[\s\_\-\.]*((M|RC)\d+)?/', $name, $matches)) { |
| $name = $matches[1]; |
| $name .= isset($matches[2]) && $matches[2] ? $matches[2] : '.0'; |
| $name .= isset($matches[3]) && $matches[3] ? $matches[3] : '.0'; |
| if (isset($matches[4]) && $matches[4]) $name .= $matches[4]; |
| $this->name = $name; |
| } |
| $this->date = strtotime($data->getValue('date')); |
| } |
| |
| function getReview() { |
| foreach($this->project->getReviews() as $review) { |
| if (!$review->isRelease()) continue; |
| if ($review->getVersion() == $this->name) return $review; |
| } |
| return null; |
| } |
| |
| function getName() { |
| return $this->name; |
| } |
| |
| function isValid() { |
| if (!$this->name) return false; |
| if (!$this->date) return false; |
| if ($this->date < strtotime('2000-01-01')) return false; |
| return true; |
| } |
| |
| function isMilestone() { |
| return preg_match('/((M|RC)\d+)$/', $this->name); |
| } |
| |
| function getDate() { |
| return $this->date; |
| } |
| |
| /** |
| * Fetch the URL for the project plan for this release if it has |
| * been specified. Note that we try to be very forgiving about the format. |
| * |
| * The following values will all result in a plan URL of "project/plan.xml" |
| * - http://www.eclipse.org/project/plan.xml |
| * - http://eclipse.org/project/plan.xml |
| * - http://www.eclipse.org/projects/project-plan.php?planurl=http://eclipse.org/project/plan.xml |
| * - http://www.eclipse.org/projects/project-plan.php?planurl=/project/plan.xml |
| * - http://www.eclipse.org/projects/project-plan.php?planurl=project/plan.xml |
| * |
| * @return string |
| */ |
| function getPlan() { |
| $plan = $this->data->getValue('plan'); |
| if (preg_match('/^(http:\/\/(www\.)?eclipse\.org\/projects\/project-plan\.php\?planurl=)?(http:\/\/(www\.)?eclipse.org)?\/?(.+\.xml)$/', $plan, $matches)) { |
| return $matches[5]; |
| } |
| return $plan; |
| } |
| |
| function getStatus() { |
| return $this->data->getValue('status'); |
| } |
| |
| function getNoteworthyUrl() { |
| return $this->data->getValue('noteworthyurl'); |
| } |
| |
| function getDownload() { |
| return $this->data->getValue('download'); |
| } |
| } |
| |
| abstract class SourceRepository { |
| var $project; |
| var $path; |
| |
| function __construct($project, $path) { |
| $this->project = $project; |
| $this->path = $path; |
| } |
| |
| function getName() { |
| return $this->getPath(); |
| } |
| |
| function getPath() { |
| return $this->path; |
| } |
| |
| function providesCommitActivity() { |
| return true; |
| } |
| |
| function isReal() { |
| // TODO test to see if the receiver represents a real repository. |
| return true; |
| } |
| |
| /** |
| * Get the repository-technology specific URL for the repository. |
| * e.g. git://git.eclipse.org/gitroot/jgit/jgit.git |
| */ |
| abstract function getUrl(); |
| abstract function getType(); |
| |
| /** |
| * Return an HTTP link for the receiver. i.e. something that is suitable |
| * for a browser |
| */ |
| abstract function getLink(); |
| } |
| |
| class GitRepository extends SourceRepository { |
| function getName() { |
| if (preg_match('/org\.eclipse\.(.*)\.git$/', $this->path, $matches)) { |
| return $matches[1]; |
| } else if (preg_match('/org\.eclipse\.(.*)$/', $this->path, $matches)) { |
| return $matches[1]; |
| } else if (preg_match('/([^\/]*)\.git$/', $this->path, $matches)) { |
| return $matches[1]; |
| } else if (preg_match('/([^\/]*)$/', $this->path, $matches)) { |
| return $matches[1]; |
| } else { |
| return $this->path; |
| } |
| } |
| |
| function getPath() { |
| return "/gitroot$this->path"; |
| } |
| |
| function getType() { |
| return "git"; |
| } |
| |
| function getLink() { |
| return "http://git.eclipse.org/c$this->path"; |
| } |
| |
| function getGitUrl() { |
| return "git://git.eclipse.org/gitroot$this->path"; |
| } |
| |
| function getUrl() { |
| return $this->getGitUrl(); |
| } |
| } |
| |
| class EGitRepository extends GitRepository { |
| |
| function getName() { |
| return $this->getLink(); |
| } |
| |
| function getLink() { |
| if (preg_match('/^git:\/\/(egit\.eclipse\.org\/.*)$/', $this->path, $matches)) { |
| return 'http://' . $matches[1]; |
| } |
| return $this->path; |
| } |
| |
| function getPath() { |
| return $this->getLink(); |
| } |
| |
| function getGitUrl() { |
| return $this->path; |
| } |
| |
| function providesCommitActivity() { |
| return false; |
| } |
| } |
| |
| class CvsRepository extends SourceRepository { |
| function getType() { |
| return "cvs"; |
| } |
| |
| function getPath() { |
| return "/cvsroot$this->path"; |
| } |
| function getLink() { |
| preg_match('/^\/?\w+\/(.*)$/', $this->path, $matches); |
| $root = $this->project->getTopLevelProject()->getId(); |
| if (strlen($root) <= 4) { |
| $root = strtoupper($root); |
| } else { |
| $root = ucwords($root); |
| } |
| $path = $matches[1]; |
| return "http://dev.eclipse.org/viewcvs/viewvc.cgi/$path/?root=${root}_Project"; |
| } |
| |
| function getUrl() { |
| if (preg_match('/^(\/cvsroot\/[^\/]+)\/(.+)$/', $this->getPath(), $matches)) { |
| $repository = $matches[1]; |
| $path = $matches[2]; |
| |
| return ":pserver:anonymous@dev.eclipse.org:$repository:$path"; |
| } else return null; |
| } |
| } |
| |
| class SvnRepository extends SourceRepository { |
| function getType() { |
| return "svn"; |
| } |
| |
| /* private */ function isUppercaseRoot($root) { |
| if ($root == 'modeling') return false; |
| if ($root == 'technology') return false; |
| return true; |
| } |
| |
| function getLink() { |
| preg_match('/^[^\/]*\/(.*)$/', $this->path, $matches); |
| $root = $this->project->getTopLevelProject()->getId(); |
| if ($this->isUppercaseRoot($root)) { |
| $root = strtoupper($root); |
| } else { |
| $root = ucwords($root); |
| } |
| $project = $this->project->getShortId(); |
| |
| // Need to handle a few special cases... |
| if ($project == 'swtbot') $project = 'SWTBot'; |
| else if ($project == 'g-eclipse') $project = 'GEclipse'; |
| else if ($project == 'eclipselink') $project = 'PERSISTENCE'; |
| else if ($project == 'dbaccess') $project = 'GEMINI.DBACCESS'; // Bug 369905 |
| else if ($project == 'naming') $project = 'GEMINI.NAMING'; |
| else if ($project == 'blueprint') $project = 'GEMINI.BLUEPRINT'; |
| else if ($project == 'jpa') $project = 'GEMINI.JPA'; |
| else $project = strtoupper($project); |
| |
| return "http://dev.eclipse.org/viewcvs/viewvc.cgi/?root=${root}_${project}"; |
| } |
| |
| function getUrl() { |
| $path = $this->getPath(); |
| return "http://dev.eclipse.org$path"; |
| } |
| |
| function getPath() { |
| return "/svnroot/$this->path"; |
| } |
| } |
| |
| /** |
| * Sort the array of projects by the given key. Valid keys |
| * are 'name', or 'top' (top level project). |
| * |
| * @param Project[] $projects |
| * @param string $key |
| */ |
| function sortProjects(&$projects, $key = 'name') { |
| if (!in_array($key, array('name', 'top'))) $key = 'name'; |
| |
| return usort($projects, "_sortProjects_$key"); |
| } |
| |
| /* private */ function _sortProjects_name($a, $b) { |
| return strcasecmp($a->getName(), $b->getName()); |
| } |
| |
| /* private */ function _sortProjects_top($a, $b) { |
| return strcasecmp($a->getTopLevelProject()->getName(), $b->getTopLevelProject()->getName()); |
| } |
| |
| /** |
| * This function answers an instance of SourceRepository corresponding to the |
| * value of the parameter. |
| * |
| * Example: |
| * |
| * getSourceRepository('/gitroot/woolsey/org.eclipse.woolsey.iplog.git') |
| * returns an instance of GitRepository |
| * |
| * @see SourceRepository |
| * @see GitRepository |
| * @see EGitRepository |
| * @see CvsRepository |
| * @see SvnRepository |
| * |
| * @param string $repository |
| * @return SourceRepository |
| */ |
| function getSourceRepository($repository, $project=null) { |
| global $projectNamePattern; |
| |
| // We only care about source code repositories, skip websites. |
| if (preg_match('/org\.eclipse\/www/', $repository)) return null; |
| |
| // EGit is a special case. |
| if (preg_match('/^git:\/\/egit\.eclipse\.org(\/.*)$/', $repository)) return new EGitRepository($project, $repository); |
| |
| // Deal with Git. |
| if (preg_match('/\/gitroot((\/[\w\.\-]+)+)\/?$/', $repository, $matches)) return new GitRepository($project, $matches[1]); |
| if (preg_match('/^http:\/\/git\.eclipse\.org\/c(\/.*)$/', $repository)) return new GitRepository($project, $matches[1]); |
| |
| // Deal with CVS. |
| if (preg_match('/^\/cvsroot((\/[\w\-\.]+)+)\/?$/', $repository, $matches)) return new CvsRepository($project, $matches[1]); |
| |
| // Deal with SVN. |
| if (preg_match('/^(\/?svnroot)?\/?(\w+(\/[\w\-\.]+)+)\/?$/', $repository, $matches)) return new SvnRepository($project, $matches[2]); |
| return null; |
| } |
| |
| ?> |