blob: 2e820f0a215fbe11ea261a8e69844b5b379226ab [file] [log] [blame]
<?php
/*******************************************************************************
* Copyright (c) 2017 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
*******************************************************************************/
require_once(dirname(__FILE__) . '/../classes/Project.class.php');
require_once(dirname(__FILE__) . '/../classes/SPDX.class.inc');
require_once(dirname(__FILE__) . '/../classes/database.inc');
class IPZilla {
var $filePatternPath;
var $cqs = array();
public static function getInstance() {
$ipzilla = new IPZilla();
$ipzilla->filePatternPath = dirname(__FILE__) . '/../ip-check/cq-map.txt';
$ipzilla->load();
return $ipzilla;
}
public function getCq($id) {
return $this->cqs[$id];
}
public function rootCqsDo($function) {
foreach($this->cqs as $cq) {
if ($cq->isRoot()) $function($cq);
}
}
public function asArray() {
$data = array();
$this->rootCqsDo(function($cq) use (&$data) {
$data[$cq->getId()] = $cq->asArray();
});
return $data;
}
private function load() {
$sql = "
select
b.bug_id as id,
c.name as project,
b.short_desc as description,
b.bug_status as status,
b.resolution as resolution,
group_concat(kd.name) as keywords,
b.bug_severity as state,
b.cf_type as type,
b.cf_license as license
from bugs as b
join components as c on b.component_id = c.id
join keywords as k on b.bug_id=k.bug_id
join keyworddefs as kd on k.keywordid=kd.id
where b.bug_severity in ('approved', 'license_certified')
group by b.bug_id
";
query('ipzilla', $sql, array(), function($row) {
$this->cqs[$row['id']] = new CQ($this, $row);
});
$this->initialize();
$this->loadFilePatterns();
$this->loadMvnPatterns();
}
private function initialize() {
foreach($this->cqs as $cq) {
if ($cq->isRoot()) continue;
$cq->getRoot()->data['piggybacks'][$cq->getId()] = $cq->getProjectId() ;
}
}
private function loadFilePatterns() {
foreach($this->cqs as &$cq) {
if (preg_match('/([a-zA-Z0-9\.\-\_]+)[_-]((?:\d+\.){3})(.*\.)?jar/', $cq->getDescription(), $matches)) {
$cq->getRoot()->addFilePattern($matches[0]);
}
}
query('dashboard', 'select distinct cq, pattern from CQBundleMap', array(), function($row) {
if ($cq = $this->cqs[$row['cq']]) {
$cq->addFilePattern($row['pattern']);
$cq->data['bundle'][] = $row;
}
});
query('dashboard', 'select distinct cq, name, version, file from CQOrbit', array(), function($row) {
if ($cq = $this->cqs[$row['cq']]) {
$cq->addFilePattern($row['file']);
$cq->data['orbit'][] = $row;
}
});
}
private function loadMvnPatterns() {
$mvnRegex = '([\w\-\*\.]+):([\w\-\*\.]+):([\w\-\*\.]+):([\w\-\*\.]+)';
foreach($this->cqs as &$cq) {
if (preg_match("/$mvnRegex/", $cq->getDescription(), $matches)) {
$cq->getRoot()->addMvnPattern("{$matches[1]}:{$matches[2]}:*:{$matches[4]}");
}
}
query('dashboard', 'select distinct cq, pattern from CQMavenMap', array(), function($row) {
if ($cq = $this->cqs[$row['cq']]) {
$cq->addMvnPattern($row['pattern']);
$cq->data['maven'][] = $row;
}
});
}
}
class CQ {
var $ipzilla;
var $data;
var $root;
var $keywords;
public function __construct($ipzilla, $data) {
$this->ipzilla = $ipzilla;
$this->data = $data;
// Compute some values.
$this->data['name'] = $this->computeName();
$this->data['version'] = $this->computeVersion();
$this->data['spdx'] = SPDX::asSpdx($this->data['license']);
// Cache information
$this->keywords = preg_split('/\s*,\s*/',$this->data['keywords']);
}
public function getId() {
return $this->data['id'];
}
public function getName() {
return $this->data['name'];
}
public function getVersion() {
return $this->data['version'];
}
private function computeVersion() {
if (preg_match('/Version\:?\s+(\d+(\.\d+)*)/i', $this->getDescription(), $matches)) {
return $matches[1];
} else if (preg_match('/(\d+(\.\d+)*)/', $this->getDescription(), $matches)) {
return $matches[1];
}
return null;
}
private function computeName() {
$name = $this->getDescription();
$name = preg_replace('/Apache/i', '', $name);
$name = preg_replace('/Google/i', '', $name);
$name = preg_replace('/\[[^\]]*\]/', '', $name);
$name = preg_replace('/\([^\)]*\)/', '', $name);
$name = preg_replace('/\([^\)]*\)/', '', $name);
$name = preg_replace('/Version\:?.*$/i', '', $name);
$name = preg_replace('/\-?(\d+(\.\d+)*)/i', '', $name);
$name = preg_replace('/\.jar/i', '', $name);
$name = preg_replace('/\sjar/i', '', $name);
$name = preg_replace('/\sv(\s|$)/i', '', $name); // Remove a solitary 'v' (i.e. "version")
$name = preg_replace('/\W+/', ' ', $name); // Replace non-word characters with a single space.
$name = ucwords($name);
return trim($name);
}
public function getDescription() {
return $this->data['description'];
}
public function getLicense() {
return $this->data['license'];
}
public function getSPDX() {
return $this->data['spdx'];
}
public function getProject() {
return Project::getProject($this->getProjectId());
}
public function getProjectId() {
return $this->data['project'];
}
public function getState() {
return $this->data['state'];
}
public function getStatus() {
return $this->data['status'];
}
public function getResolution() {
return $this->data['resolution'];
}
public function getKeywords() {
return $this->data['keywords'];
}
public function getFilePatterns() {
return @$this->data['filePatterns'];
}
public function getMvnPatterns() {
return @$this->data['mvnPatterns'];
}
public function getDueDiligenceType() {
return $this->data['type'];
}
public function isRoot() {
return $this == $this->getRoot();
}
/**
* Answer the root CQ. The root is basically the first CQ
* created for a particular bit of content. A piggyback will,
* for example, refer to a root. It's possible that a piggyback
* may refer to another piggyback, so it's possible that we
* may be several layers deep.
*
* The parameter should not generally be provided by the sender.
* Because it is possible that there may be cycles in the dependency
* graph (there shouldn't be, but errors happen), we take an array
* with us through the recursion. It would be an exceptional state
* to find the receiver in recursion list; in this case, the only
* thing that we can do is to throw an exception.
*
* @param array $recursion_list
* @throws RecursiveAncestryException
* @return CQ
*/
public function getRoot($recursion_list = array()) {
if (!isset($this->root)) {
if (in_array($this, $recursion_list)) throw new RecursiveAncestryException();
if (!$parent = $this->getParent()) return $this;
if ($parent == $this) return $this;
$recursion_list[] = $this;
$this->root = $parent->getRoot($recursion_list);
}
return $this->root;
}
public function getParent() {
if ($id = $this->getParentId()) {
return $this->ipzilla->getCq($id);
}
return null;
}
private function getParentId() {
if (preg_match ( '/\W(?:\(ATO|PB|Orbit)[^\d\)]*([0-9]+)/i', $this->getDescription(), $matches)) {
return $matches [1];
}
return null;
}
public function isResolved() {
if (!$this->getStatus()) return false;
return in_array($this->getStatus(), array('RESOLVED', 'VERIFIED', 'CLOSED'));
}
public function isFixed() {
if (!$this->isResolved()) return false;
return $this->getResolution() == 'FIXED';
}
public function isApproved() {
if (!$this->isResolved()) return false;
return $this->getState() == 'approved';
}
public function isProjectCode() {
return in_array('projectcode', $this->keywords);
}
public function isThirdParty() {
return in_array('thirdparty', $this->keywords);
}
function asArray() {
return $this->data;
}
function addFilePattern($value) {
if (preg_match('/(\S*\/)?([\w\.\-]+)[_-]((?:\d+\.){3})(.*\.)?jar/', $value, $matches)) {
$pattern = $matches[1] . $matches[2] . '_' . $matches[3];
$regex = $matches[1] . $matches[2] . '[_-]' . $matches[3];
$regex = str_replace('.', '\.', $regex);
$regex = str_replace('/', '\/', $regex);
$regex = $regex . '(.*\.)?jar';
$pattern = "$pattern*.jar";
$this->data['filePatterns'][$pattern] = $regex;
// Only generate a source bundle mapping if this isn't a source bundle.
if (!preg_match('/\.source$/', $matches[2])) {
$sourcePattern = $matches[1] . $matches[2]. '.source_' . $matches[3];
$sourceRegex = $matches[1] . $matches[2] . '.source[_-]' . $matches[3];
$sourceRegex = str_replace('.', '\.', $sourceRegex);
$regex = str_replace('/', '\/', $regex);
$sourceRegex = $sourceRegex . '(.*\.)?jar';
$sourcePattern = "$sourcePattern*.jar";
$this->data['filePatterns'][$pattern] = $regex;
}
} else {
$pattern = $value;
$regex = str_replace('.', '\.', $pattern);
$regex = str_replace('/', '\/', $regex);
$this->data['filePatterns'][$pattern] = $regex;
}
}
function addMvnPattern($value) {
if (isset($this->data['mvnPatterns']) && in_array($value, $this->data['mvnPatterns'])) return;
$this->data['mvnPatterns'][] = $value;
}
}
class RecursiveAncestryException extends Exception {}
?>