| <?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']; | |
| } | |
| function getName() { | |
| // TODO Get the name (when it's available) | |
| return $this->data['id'][0]['value']; | |
| } | |
| function getPlanUrl() { | |
| return $this->data['plan_url'][0]['url']; | |
| } | |
| function getSourceRepositories() { | |
| $repositories = array(); | |
| foreach($this->data['source_repo'] as $repo) { | |
| $repositories[] = getSourceRepository($repo['path'], $this); | |
| } | |
| 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; | |
| } | |
| } | |
| /** | |
| * @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; | |
| } | |
| ?> |