66 include_once(__DIR__ .
"/spdx2utils.php");
68 include_once(__DIR__ .
"/version.php");
69 include_once(__DIR__ .
"/services.php");
154 function __construct()
157 $args = getopt(
"", array(self::OUTPUT_FORMAT_KEY.
'::'));
159 if (array_key_exists(self::OUTPUT_FORMAT_KEY,
$args)) {
166 parent::__construct(
$agentName, AGENT_VERSION, AGENT_REV);
168 $this->uploadDao = $this->container->get(
'dao.upload');
169 $this->clearingDao = $this->container->get(
'dao.clearing');
170 $this->licenseDao = $this->container->get(
'dao.license');
171 $this->
dbManager = $this->container->get(
'db.manager');
172 $this->renderer = $this->container->get(
'twig.environment');
173 $this->renderer->setCache(
false);
175 $this->agentSpecifLongOptions[] = self::UPLOAD_ADDS.
':';
176 $this->agentSpecifLongOptions[] = self::OUTPUT_FORMAT_KEY.
':';
191 if ((!array_key_exists(self::OUTPUT_FORMAT_KEY,
$args)
192 ||
$args[self::OUTPUT_FORMAT_KEY] ===
"")
193 && array_key_exists(self::UPLOAD_ADDS,
$args)) {
196 if (!array_key_exists(self::UPLOAD_ADDS,
$args) ||
$args[self::UPLOAD_ADDS] ===
"") {
211 if (array_key_exists(self::OUTPUT_FORMAT_KEY,
$args)) {
212 $possibleOutputFormat =
trim(
$args[self::OUTPUT_FORMAT_KEY]);
213 if (in_array($possibleOutputFormat, explode(
',',self::AVAILABLE_OUTPUT_FORMATS))) {
214 $this->outputFormat = $possibleOutputFormat;
217 $this->licenseMap =
new LicenseMap($this->
dbManager, $this->groupId, LicenseMap::REPORT,
true);
220 $docLicense = $this->licenseDao->getLicenseByShortName(self::DATA_LICENSE);
221 $docLicenseId = $docLicense->getId() .
"-" . md5($docLicense->getText());
223 ->setLicenseObj($docLicense)
224 ->setListedLicense(
true)
225 ->setCustomText(
false)
226 ->setTextPrinted(
true);
229 $additionalUploadIds = array_key_exists(self::UPLOAD_ADDS,
$args) ? explode(
',',
$args[self::UPLOAD_ADDS]) : array();
230 $packageIds = array($uploadId);
231 foreach ($additionalUploadIds as $additionalId) {
233 $packageIds[] = $additionalId;
236 $this->
writeReport($packageNodes, $packageIds, $uploadId);
247 $prefix = $this->outputFormat .
"-";
249 switch ($this->outputFormat) {
251 $postfix =
".xml" . $postfix;
257 $prefix .=
"copyright-";
260 return $prefix . $partname . $postfix;
272 if ($this->filebasename ==
null) {
273 $fileName =
strtoupper($this->outputFormat).
"_".$packageName;
274 switch ($this->outputFormat) {
276 $fileName .=
".spdx.rdf";
279 $fileName .=
".spdx";
288 $this->filebasename = $fileName;
301 $fileBase = $SysConf[
'FOSSOLOGY'][
'path'].
"/report/";
313 $url=$SysConf[
'SYSCONFIG'][
'FOSSologyURL'];
314 if (substr( $url, 0, 4 ) !==
"http") {
328 $uploadTreeTableName = $this->uploadDao->getUploadtreeTableName($uploadId);
329 $itemTreeBounds = $this->uploadDao->getParentItemBounds($uploadId,$uploadTreeTableName);
332 $filesWithLicenses = $this->reportutils
333 ->getFilesWithLicensesFromClearings($itemTreeBounds, $this->groupId,
334 $this, $this->licensesInDocument);
337 $this->reportutils->addClearingStatus($filesWithLicenses,$itemTreeBounds, $this->groupId);
340 $scannerIDs = $this->reportutils->addScannerResults($filesWithLicenses, $itemTreeBounds, $this->groupId, $this->licensesInDocument);
341 $licenseComment =
"";
342 if (!empty($scannerIDs)) {
347 $this->reportutils->addCopyrightResults($filesWithLicenses, $uploadId);
350 $upload = $this->uploadDao->getUpload($uploadId);
351 $fileNodes = $this->
generateFileNodes($filesWithLicenses, $upload->getTreeTableName(), $uploadId);
353 $mainLicenseIds = $this->clearingDao->getMainLicenseIds($uploadId, $this->groupId);
354 $mainLicenses = array();
355 foreach ($mainLicenseIds as $licId) {
356 $reportedLicenseId = $this->licenseMap->getProjectedId($licId);
357 $mainLicense = $this->licenseDao->getLicenseById($reportedLicenseId, $this->groupId);
358 $reportLicId = $mainLicense->getId() .
"-" . md5($mainLicense->getText());
359 $mainLicenses[] = $reportLicId;
360 if (!array_key_exists($reportLicId, $this->licensesInDocument)) {
361 $listedLicense = stripos($mainLicense->getSpdxId(),
362 LicenseRef::SPDXREF_PREFIX) !== 0;
364 ->setLicenseObj($mainLicense)
365 ->setCustomText(
false)
366 ->setListedLicense($listedLicense);
369 $mainLicenseString = [];
370 if ($this->outputFormat ==
"spdx2tv" ||
371 $this->outputFormat ==
"spdx2csv") {
372 foreach ($mainLicenses as $mainLicense) {
373 $shortName = $this->licensesInDocument[$mainLicense]
374 ->getLicenseObj()->getShortName();
376 LicenseRef::SPDXREF_PREFIX)) {
377 $mainLicenseString[] = $shortName;
379 $mainLicenseString[] = $this->licensesInDocument[$mainLicense]
380 ->getLicenseObj()->getSpdxId();
387 $hashes = $this->uploadDao->getUploadHashes($uploadId);
389 $reportInfo = $this->uploadDao->getReportInfo($uploadId);
390 $componentId = $reportInfo[
'ri_component_id'];
391 $componentType = $reportInfo[
'ri_component_type'];
392 $componentVersion = $reportInfo[
'ri_version'];
393 $generalAssessment = $reportInfo[
'ri_general_assesment'];
394 $releaseDate = $reportInfo[
'ri_release_date'];
395 if ($componentId ==
"NA") {
398 if ($componentVersion ==
"NA") {
399 $componentVersion =
"";
401 if ($generalAssessment ==
"NA") {
402 $generalAssessment =
"";
404 if ($releaseDate ==
"NA") {
407 $timeStamp = strtotime($releaseDate);
408 if ($timeStamp != -1) {
409 $releaseDate = date(
"Y-m-d\\T00:00:00\\Z", $timeStamp);
415 $componentType =
"maven-central";
417 $componentType =
"purl";
419 if (!empty($componentType)) {
428 'packageId' => $uploadId,
430 'packageName' => $upload->getFilename(),
431 'packageVersion' => $componentVersion,
432 'releaseDate' => $releaseDate,
433 'generalAssessment' => $generalAssessment,
434 'uploadName' => $upload->getFilename(),
435 'componentType' => $componentType,
436 'componentId' => htmlspecialchars($componentId),
437 'sha1' => $hashes[
'sha1'],
438 'md5' => $hashes[
'md5'],
439 'sha256' => $hashes[
'sha256'],
441 'mainLicenses' => $mainLicenses,
442 'mainLicenseString' => $mainLicenseString,
443 'licenseComments' => $licenseComment,
444 'fileNodes' => $fileNodes,
445 'obligations' => $obligations,
446 'licenseList' => $this->licensesInDocument
457 $func =
function($scannerId) use (
$agentDao)
459 return $agentDao->getAgentName($scannerId).
" (".
$agentDao->getAgentRev($scannerId).
")";
461 $scannerNames = array_map($func, $scannerIds);
462 return "licenseInfoInFile determined by Scanners:\n - ".implode(
"\n - ",$scannerNames);
475 if (!array_key_exists($licenses, $filesWithLicenses)) {
476 $filesWithLicenses[$licenses][
'files']=array();
477 $filesWithLicenses[$licenses][
'copyrights']=array();
479 if (empty($copyrights)) {
480 $copyrights = array();
482 $filesWithLicenses[$licenses][
'files'][$file] = $fullPath;
483 foreach ($copyrights as $copyright) {
484 if (!in_array($copyright, $filesWithLicenses[$licenses][
'copyrights'])) {
485 $filesWithLicenses[$licenses][
'copyrights'][] = $copyright;
498 $licensesWithFiles = array();
499 $treeDao = $this->container->get(
'dao.tree');
501 foreach ($filesWithLicenses as $fileId => $fileNode) {
502 $filesProceeded += 1;
503 if (($filesProceeded&2047)==0) {
506 $fullPath = $treeDao->getFullPath($fileId, $treeTableName, 0);
507 if (! empty($fileNode->getConcludedLicenses())) {
509 foreach ($fileNode->getConcludedLicenses() as $license) {
510 $licenses[] = $this->licensesInDocument[$license]
511 ->getLicenseObj()->getSpdxId();
516 $licenses, $fileNode->getCopyrights(), $fileId, $fullPath);
518 if (! empty($fileNode->getScanners())) {
519 $implodedLicenses = [];
520 foreach ($fileNode->getScanners() as $license) {
521 $implodedLicenses[] = $this->licensesInDocument[$license]
522 ->getLicenseObj()->getSpdxId();
526 if ($fileNode->isCleared()) {
527 $msgLicense =
"None (scanners found: " . $implodedLicenses .
")";
529 $msgLicense =
"NoLicenseConcluded (scanners found: " . $implodedLicenses .
")";
532 if ($fileNode->isCleared()) {
533 $msgLicense =
"None";
535 $msgLicense =
"NoLicenseConcluded";
539 $fileNode->getCopyrights(), $fileId, $fullPath);
542 return $licensesWithFiles;
551 $upload = $this->uploadDao->getUpload($uploadId);
552 $packageName = $upload->getFilename();
554 $this->uri = $this->
getUri($packageName);
555 $this->filename = $this->
getFileName($packageName);
564 protected function writeReport(&$packageNodes, $packageIds, $uploadId)
568 $fileBase = dirname($this->filename);
570 if (!is_dir($fileBase)) {
571 mkdir($fileBase, 0777,
true);
575 $organizationName = $SysConf[
'SYSCONFIG'][
"ReportHeaderText"];
576 $version = $SysConf[
'BUILD'][
'VERSION'];
579 'documentName' => $fileBase,
581 'userName' => $this->container->get(
'dao.user')->getUserName($this->userId) .
" (" . $this->container->get(
'dao.user')->getUserEmail($this->userId) .
")",
582 'organisation' => $organizationName,
583 'toolVersion' =>
'fossology-' . $version,
584 'packageNodes' => $packageNodes,
585 'packageIds' => $packageIds,
586 'dataLicense' => $this->getSPDXDataLicense(),
587 'licenseList' => $this->licensesInDocument
593 $message = preg_replace(
'/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/',
'?',$message);
595 file_put_contents($this->filename, $message);
607 $this->reportutils->updateOrInsertReportgenEntry($uploadId,
$jobId, $fileName);
618 return $this->renderer->load($templateName)->render($vars);
631 if (strcmp($this->outputFormat,
"dep5") !== 0) {
648 $treeDao = $this->container->get(
'dao.tree');
653 $textToBePrinted = [];
654 foreach ($filesWithLicenses as $fileId => $fileData) {
655 $filesProceeded += 1;
656 if (($filesProceeded & 2047) == 0) {
657 $this->
heartbeat($filesProceeded - $lastValue);
658 $lastValue = $filesProceeded;
660 $hashes = $treeDao->getItemHashes($fileId);
661 $fileName = $treeDao->getFullPath($fileId, $treeTableName, 0);
664 foreach ($fileData->getConcludedLicenses() as $license) {
665 if (! $this->licensesInDocument[$license]->isTextPrinted()) {
666 $textToBePrinted[] = $license;
669 foreach ($fileData->getScanners() as $license) {
670 if (! $this->licensesInDocument[$license]->isTextPrinted()) {
671 $textToBePrinted[] = $license;
674 $concludedLicensesString = [];
675 if ($this->outputFormat ==
"spdx2tv" ||
676 $this->outputFormat ==
"spdx2csv") {
677 foreach ($fileData->getConcludedLicenses() as $license) {
678 $shortName = $this->licensesInDocument[$license]
679 ->getLicenseObj()->getShortName();
681 LicenseRef::SPDXREF_PREFIX)) {
682 $concludedLicensesString[] = $shortName;
684 $concludedLicensesString[] = $this->licensesInDocument[$license]
685 ->getLicenseObj()->getSpdxId();
691 if (!$stateWoInfos ||
692 ($stateWoInfos && (!empty($fileData->getConcludedLicenses()) ||
693 !empty($fileData->getScanners()) || !empty($fileData->getCopyrights())))) {
694 $fileData->setAcknowledgements(
696 $fileData->setComments(
698 $dataTemplate = array(
700 'sha1' => $hashes[
'sha1'],
701 'md5' => $hashes[
'md5'],
702 'sha256' => $hashes[
'sha256'],
704 'fileName' => $fileName,
705 'fileDirName' => dirname($fileName),
706 'fileBaseName' => basename($fileName),
707 'fileData' => $fileData,
708 'licenseList' => $this->licensesInDocument,
709 'concludedLicensesString' => $concludedLicensesString,
710 'licenseCommentState' => $stateComment
715 foreach ($textToBePrinted as $license) {
716 $this->licensesInDocument[$license]->setTextPrinted(
true);
719 $this->
heartbeat($filesProceeded - $lastValue);
737 foreach ($licensesWithFiles as $licenseId=>$entry) {
738 $filesProceeded += count($entry[
'files']);
739 if ($filesProceeded&(~2047) > $lastStep) {
740 $this->
heartbeat($filesProceeded - $lastValue);
741 $lastStep = $filesProceeded&(~2047) + 2048;
742 $lastValue = $filesProceeded;
746 if (strrpos($licenseId,
"NoLicenseConcluded (scanners found: ", -strlen($licenseId)) !==
false) {
747 $comment = substr($licenseId,20,strlen($licenseId)-21);
748 $licenseId =
"NoLicenseConcluded";
749 } elseif (strrpos($licenseId,
"None (scanners found: ", -strlen($licenseId)) !==
false) {
750 $comment = substr($licenseId,6,strlen($licenseId)-7);
755 'fileNames'=>$entry[
'files'],
756 'license'=>$licenseId,
757 'copyrights'=>$entry[
'copyrights'],
758 'comment'=>$comment));
760 $this->
heartbeat($filesProceeded - $lastValue);
776 if ($upload->getTreeTableName()==
'uploadtree_a') {
777 $sql = $upload->getTreeTableName().
' WHERE upload_fk=$1 AND';
778 $param[] = $upload->getId();
780 $sql = $upload->getTreeTableName().
' WHERE';
781 $stmt .=
'.'.$upload->getTreeTableName();
784 $sql =
"SELECT STRING_AGG(lower_sha1,'') concat_sha1 FROM
785 (SELECT LOWER(pfile_sha1) lower_sha1 FROM pfile, $sql pfile_fk=pfile_pk AND parent IS NOT NULL ORDER BY pfile_sha1) templist";
786 $filelistPack = $this->
dbManager->getSingleRow($sql,$param,$stmt);
788 return sha1($filelistPack[
'concat_sha1']);
799 $sql =
"SELECT ri_spdx_selection FROM report_info WHERE upload_fk = $1";
800 $getCommentState = $this->
dbManager->getSingleRow($sql, array($uploadId), __METHOD__.
'.SPDX_license_comment');
801 if (!empty($getCommentState[
'ri_spdx_selection'])) {
802 $getCommentStateSingle = explode(
',', $getCommentState[
'ri_spdx_selection']);
803 if ($getCommentStateSingle[$key] ===
"checked") {
818 $licenses = $this->licenseClearedGetter->getCleared($uploadId, $this,
821 $licensesMain = $this->licenseMainGetter->getCleared($uploadId, $this,
824 list($obligations, $_) = $this->obligationsGetter->getObligations(
825 $licenses[
'statements'], $licensesMain[
'statements'], $uploadId,
827 if (empty($obligations)) {
830 return array_column($obligations,
"text");
840 $dataLic = $this->licenseDao->getLicenseByShortName(self::DATA_LICENSE);
841 return $dataLic->getId() .
"-" . md5($dataLic->getText());
857 $localList = array_values($this->licensesInDocument);
865 for ($i = 0; $i < count($localList) - 1; $i++) {
866 if ((! $localList[$i]->isCustomText() && ! $localList[$i + 1]->isCustomText()) &&
867 $localList[$i]->getLicenseObj()->getSpdxId() ===
868 $localList[$i + 1]->getLicenseObj()->getSpdxId()) {
869 $newShortName = $localList[$i + 1]->getLicenseObj()->getShortName();
871 $localList[$i + 1]->getLicenseObj()->getShortName(),
872 LicenseRef::SPDXREF_PREFIX)) {
873 $newShortName = LicenseRef::SPDXREF_PREFIX .
874 $localList[$i + 1]->getLicenseObj()->getShortName();
875 $newShortName = preg_replace(
'/\+$/',
'-or-later', $newShortName);
877 $md5 = md5($localList[$i + 1]->getLicenseObj()->getText());
878 $reportedLicenseShortname =
"$newShortName-$md5";
879 $licIndex = $localList[$i + 1]->getLicenseObj()->getId() .
"-$md5";
880 $oldLicObj = $this->licensesInDocument[$licIndex]->getLicenseObj();
881 $this->licensesInDocument[$licIndex]->setLicenseObj(
882 new License($oldLicObj->getId(), $reportedLicenseShortname,
883 $oldLicObj->getFullName(), $oldLicObj->getRisk(),
884 $oldLicObj->getText(), $oldLicObj->getUrl(),
885 $oldLicObj->getDetectorType(), $oldLicObj->getSpdxId()));
891 $agent =
new SpdxTwoAgent();
892 $agent->scheduler_connect();
893 $agent->run_scheduler_event_loop();
894 $agent->scheduler_disconnect(0);
Structure of an Agent with all required parameters.
heartbeat($newProcessed)
Send hear beat to the scheduler.
Wrapper class for license map.
static stringStartsWith($haystack, $needle)
getVerificationCode(Upload $upload)
Get a unique identifier for a given upload.
getFileName($packageName)
Get absolute path for report.
getTemplateFile($partname)
Get TWIG template file based on output format.
updateReportTable($uploadId, $jobId, $fileName)
Update the reportgen table with new report path.
const DATA_LICENSE
Data license for SPDX reports.
computeUri($uploadId)
For a given upload, compute the URI and filename for the report.
const UPLOAD_ADDS
Argument for additional uploads.
getFileBasename($packageName)
Generate report basename based on upload name.
getLicenseComment($scannerIds)
processUploadId($uploadId)
Given an upload ID, process the items in it.
const DEFAULT_OUTPUT_FORMAT
Default output format.
preWorkOnArgs($args)
Parse arguments.
renderString($templateName, $vars)
Render a twig template.
generateFileNodesByFiles($filesWithLicenses, $treeTableName, $uploadId)
For each file, generate the nodes by files.
getObligations(int $uploadId, int $groupId)
renderPackage($uploadId)
Given an upload id, render the report string.
writeReport(&$packageNodes, $packageIds, $uploadId)
Write the report the file and update report table.
toLicensesWithFilesAdder(&$filesWithLicenses, $licenses, $copyrights, $file, $fullPath)
Map licenses, copyrights, files and full path to filesWithLicenses array.
getUri($packageName)
Get the URI for the given package.
getSPDXReportConf($uploadId, $key)
Get spdx license comment state for a given upload.
generateFileNodes($filesWithLicenses, $treeTableName, $uploadId)
Generate report nodes for files.
const AVAILABLE_OUTPUT_FORMATS
Output formats available.
deduplicateLicenseList()
De-duplicate license list by comparing licenses with the same SPDX ID.
const OUTPUT_FORMAT_KEY
Argument key for output format.
generateFileNodesByLicenses($filesWithLicenses, $treeTableName)
For each file, generate the nodes by licenses.
toLicensesWithFiles(&$filesWithLicenses, $treeTableName)
Map findings to the files.
static implodeLicenses($licenses)
Implode licenses with "AND" or "OR".
static preWorkOnArgsFlp($args, $key1, $key2)
For a given set of arguments assign $args[$key1] and $args[$key2].
static cleanTextArray($texts)
static removeEmptyLicenses($licenses)
char * trim(char *ptext)
Trimming whitespace.
int jobId
The id of the job.
fo_dbManager * dbManager
fo_dbManager object
FUNCTION char * strtoupper(char *s)
Helper function to upper case a string.
Namespace used by SPDX2 agent.
list_t type structure used to keep various lists. (e.g. there are multiple lists).