51 'shortname'=>array(
'shortname',
'Short Name'),
52 'licensetype'=>array(
'licensetype',
'license_type',
'License Type'),
53 'fullname'=>array(
'fullname',
'Long Name'),
54 'spdx_id'=>array(
'spdx_id',
'SPDX ID'),
55 'text'=>array(
'text',
'Full Text'),
56 'parent_shortname'=>array(
'parent_shortname',
'Decider Short Name'),
57 'report_shortname'=>array(
'report_shortname',
'Regular License Text Short Name'),
58 'url'=>array(
'url',
'URL'),
59 'notes'=>array(
'notes'),
60 'source'=>array(
'source',
'Foreign ID'),
61 'risk'=>array(
'risk',
'risk_level'),
62 'group'=>array(
'group',
'License group'),
63 'obligations'=>array(
'obligations',
'License obligations'),
64 'external_id'=>array(
'id',
'LicenseDB Id'),
108 if (!is_file($filename) || ($handle = fopen($filename,
'r')) ===
false) {
109 return _(
'Internal error');
114 if ($fileExtension ==
'csv') {
115 while (($row = fgetcsv($handle,0,$this->delimiter,$this->enclosure)) !==
false) {
122 $msg .= _(
'Read csv').(
": $cnt ")._(
'licenses');
124 $jsonContent = fread($handle, filesize($filename));
125 $data = json_decode($jsonContent,
true);
126 if ($data ===
null && json_last_error() !== JSON_ERROR_NONE) {
127 $msg .=
"Error decoding JSON: " . json_last_error_msg() .
"\n";
130 $msg .= _(
'Read json').(
":". count($data) .
" ")._(
'licenses');
134 return $msg .= _(
'Error while parsing file').
': '.$e->getMessage();
148 $defaultValues = array(
149 'parent_shortname' =>
null,
150 'report_shortname' =>
null,
159 foreach ($row as $key => $value) {
161 foreach ($this->alias as $aliasKey => $aliasValues) {
162 if (in_array($key, $aliasValues)) {
167 $newArray[$newKey] = $value;
169 foreach ($defaultValues as $key => $defaultValue) {
170 if (!array_key_exists($key, $newArray)) {
171 $newArray[$key] = $defaultValue;
185 if ($this->headrow ===
null) {
191 foreach (array(
'shortname',
'fullname',
'text') as $needle) {
192 $mRow[$needle] = $row[$this->headrow[$needle]];
194 foreach (array(
'parent_shortname' =>
null,
'report_shortname' =>
null,
195 'url' =>
'',
'notes' =>
'',
'source' =>
'',
'risk' => 0,
196 'group' =>
null,
'spdx_id' =>
null,
'licensetype' =>
null
197 ) as $optNeedle=>$defaultValue) {
198 $mRow[$optNeedle] = $defaultValue;
199 if ($this->headrow[$optNeedle]!==
false && array_key_exists($this->headrow[$optNeedle], $row)) {
200 $mRow[$optNeedle] = $row[$this->headrow[$optNeedle]];
216 foreach (array(
'parent_shortname' =>
null,
'report_shortname' =>
null,
217 'url' =>
'',
'notes' =>
'',
'source' =>
'',
'risk' => 0,
'active' =>
true,
218 'group' =>
null,
'spdx_id' =>
null,
'licensetype' =>
null,
219 'obligation_ids' => array()
220 ) as $optNeedle => $defaultValue) {
221 if (!array_key_exists($optNeedle, $mRow)) {
222 $mRow[$optNeedle] = $defaultValue;
226 if (empty($mRow[
'external_id'])) {
242 $row[0] =
trim($row[0],
"\xEF\xBB\xBF");
243 foreach (array(
'shortname',
'fullname',
'text') as $needle) {
244 $col = ArrayOperation::multiSearch($this->alias[$needle], $row);
245 if (
false === $col) {
246 throw new \Exception(
"Undetermined position of $needle");
250 foreach (array(
'parent_shortname',
'report_shortname',
'url',
'notes',
251 'source',
'risk',
'group',
'spdx_id',
'licensetype') as $optNeedle) {
252 $headrow[$optNeedle] = ArrayOperation::multiSearch($this->alias[$optNeedle], $row);
265 $stmt = __METHOD__ .
'.getOldLicense';
266 $oldLicense = $this->
dbManager->getSingleRow(
'SELECT ' .
267 'rf_shortname, rf_fullname, rf_spdx_id, rf_text, rf_url, rf_notes, rf_source, rf_risk, rf_licensetype, rf_active ' .
268 'FROM license_ref WHERE rf_pk = $1', array($rfPk), $stmt);
270 $log =
"License '$row[shortname]' already exists in DB (id = $rfPk)";
271 $stmt = __METHOD__ .
'.updateLicense';
272 $sql =
"UPDATE license_ref SET ";
273 if (! empty($row[
'group'])) {
274 $sql =
"UPDATE license_candidate SET ";
276 $extraParams = array();
277 $param = array($rfPk);
278 if (isset($row[
'fullname']) && $row[
'fullname'] != $oldLicense[
'rf_fullname']) {
279 $param[] = $row[
'fullname'];
281 $extraParams[] =
"rf_fullname=$" . count($param);
282 $log .=
", updated fullname";
285 if (isset($row[
'external_id']) && isset($row[
'shortname']) && $row[
'shortname'] !== $oldLicense[
'rf_shortname']) {
286 $param[] = $row[
'shortname'];
288 $extraParams[] =
"rf_shortname=$" . count($param);
289 $log .=
", updated shortname";
291 if (isset($row[
'spdx_id']) && $row[
'spdx_id'] != $oldLicense[
'rf_spdx_id']) {
292 $param[] = $row[
'spdx_id'];
294 $extraParams[] =
"rf_spdx_id=$" . count($param);
295 $log .=
", updated SPDX ID";
297 if (isset($row[
'text']) && $row[
'text'] != $oldLicense[
'rf_text'] && $row[
'text'] != LicenseMap::TEXT_MAX_CHAR_LIMIT) {
298 $param[] = $row[
'text'];
300 $extraParams[] =
"rf_text=$" . count($param) .
",rf_md5=md5($" .
302 $log .=
", updated text";
304 if (isset($row[
'url']) && $row[
'url'] != $oldLicense[
'rf_url']) {
305 $param[] = $row[
'url'];
307 $extraParams[] =
"rf_url=$" . count($param);
308 $log .=
", updated URL";
310 if (isset($row[
'notes']) && $row[
'notes'] != $oldLicense[
'rf_notes']) {
311 $param[] = $row[
'notes'];
313 $extraParams[] =
"rf_notes=$" . count($param);
314 $log .=
", updated notes";
316 if (isset($row[
'source']) && $row[
'source'] != $oldLicense[
'rf_source']) {
317 $param[] = $row[
'source'];
318 $stmt .=
'.updSource';
319 $extraParams[] =
"rf_source=$".count($param);
320 $log .=
', updated the source';
322 if (isset($row[
'risk']) && $row[
'risk'] != $oldLicense[
'rf_risk']) {
323 $param[] = $row[
'risk'];
325 $extraParams[] =
"rf_risk=$".count($param);
326 $log .=
', updated the risk level';
328 if (isset($row[
'licensetype']) && $row[
'licensetype'] != $oldLicense[
'rf_licensetype']) {
329 $param[] = $row[
'licensetype'];
331 $extraParams[] =
"rf_licensetype=$".count($param);
332 $log .=
', updated the licensetype';
334 if (isset($row[
'active']) && $row[
'active'] !=
335 $this->
dbManager->booleanFromDb($oldLicense[
'rf_active'])) {
336 $param[] = $this->
dbManager->booleanToDb($row[
'active']);
338 $extraParams[] =
'rf_active=$' . count($param);
339 $log .=
', updated active';
341 if (count($param) > 1) {
342 $sql .= join(
",", $extraParams);
343 $sql .=
" WHERE rf_pk=$1;";
344 $this->
dbManager->getSingleRow($sql, $param, $stmt);
345 if (!isset($row[
'external_id'])) {
346 $this->mdkMap[md5($row[
'text'])] = $rfPk;
352 if ($row[
'external_id'] ===
null) {
353 $stmt = __METHOD__ .
'.getOldMapping';
354 $sql =
'SELECT rf_parent FROM license_map WHERE rf_fk = $1 AND usage = $2;';
356 $oldParentRow = $this->
dbManager->getSingleRow($sql, array($rfPk,
357 LicenseMap::CONCLUSION), $stmt);
358 if (!empty($oldParentRow)) {
359 $oldParent = $oldParentRow[
'rf_parent'];
362 $oldReportRow = $this->
dbManager->getSingleRow($sql, array($rfPk,
363 LicenseMap::REPORT), $stmt);
364 if (!empty($oldReportRow)) {
365 $oldReport = $oldReportRow[
'rf_parent'];
369 $newParent = ($row[
'parent_shortname'] ==
null) ?
null :
373 $newReport = ($row[
'report_shortname'] ==
null) ?
null :
376 if (($oldParent != $newParent) && $this->
setMap($newParent, $rfPk, LicenseMap::CONCLUSION)) {
377 $log .=
" with conclusion '$row[parent_shortname]'";
379 if (($oldReport != $newReport) && $this->
setMap($newReport, $rfPk, LicenseMap::REPORT)) {
380 $log .=
" reporting '$row[report_shortname]'";
396 if (empty($row[
'risk'])) {
399 if (empty($row[
'external_id'])) {
400 $row[
'external_id'] =
null;
407 if ($rfPk !==
false) {
408 if (! empty($row[
'group']) || ($md5Match == $rfPk || $md5Match ===
false)) {
411 return "Error: MD5 checksum of '" . $row[
'shortname'] .
412 "' collides with license id=$md5Match";
415 if ($md5Match !==
false && empty($row[
'group'])) {
416 return "Error: MD5 checksum of '" . $row[
'shortname'] .
417 "' collides with license id=$md5Match";
421 if (!empty($row[
'group'])) {
428 if (is_string($return)) {
431 return $return[
'log'];
448 if (empty($row[
"external_id"])) {
449 return "Error: external_id cannot be empty";
451 $stmt = __METHOD__ .
".getExistingLicense";
452 $rfPk = $this->
dbManager->getSingleRow(
"SELECT rf_pk FROM " .
453 "license_ref WHERE rf_external_id=$1", array($row[
"external_id"]), $stmt);
461 $stmt = __METHOD__ .
"getNewLicenseObligations";
463 foreach ($row[
'obligation_ids'] as $obExternalId) {
464 $obPk = $this->
dbManager->getSingleRow(
"SELECT ob_pk FROM obligation_ref WHERE ob_external_id = $1;",
465 array($obExternalId), $stmt);
467 $newObIds[] = $obPk[
'ob_pk'];
469 $log .= \sprintf(
'obligation with ob_external_id %s not found', $obExternalId);
474 $stmt = __METHOD__ .
"getOldObligationAssociations";
475 $oldObIdsDB = $this->
dbManager->getRows(
"SELECT ob_fk FROM obligation_map WHERE rf_fk = $1", array($rfPk[
'rf_pk']), $stmt);
477 foreach ($oldObIdsDB as $obId) {
478 $oldObIds[] = $obId[
'ob_fk'];
485 if (!empty($diff[
'remove'])) {
486 $log .=
' unlinked obligation ids [' . implode(
',', $diff[
'remove']) .
']';
488 if (!empty($diff[
'add'])) {
489 $log .=
' linked obligation ids [' . implode(
',', $diff[
'add']) .
']';
493 foreach ($diff[
'remove'] as $obid) {
494 $this->obligationMap->unassociateLicenseFromObligation($obid, $rfPk[
'rf_pk']);
498 foreach ($diff[
'add'] as $obid) {
499 $this->obligationMap->associateLicenseWithObligation($obid, $rfPk[
'rf_pk']);
504 $log .= $licRetVal[
'log'];
508 $stmt = __METHOD__ .
"getNewLicenseObligationsForInsert";
509 foreach ($row[
'obligation_ids'] as $obExternalId) {
510 $obPk = $this->
dbManager->getSingleRow(
"SELECT ob_pk FROM obligation_ref WHERE ob_external_id = $1;",
511 array($obExternalId), $stmt);
513 $newObIds[] = $obPk[
'ob_pk'];
515 $log .= \sprintf(
'obligation with ob_external_id %s not found', $obExternalId);
520 if (!empty($newObIds)) {
521 $log .=
' linked obligation ids [' . implode(
',', $newObIds) .
']';
523 foreach ($newObIds as $obid) {
524 $this->obligationMap->associateLicenseWithObligation($obid, $licRetVal[
'pkey']);
545 $isNontrivial = ($fromName!==
null && $fromName!=$toName && $this->
getKeyFromShortname($fromName)!==
false);
547 $this->
dbManager->insertTableRow(
'license_map',
552 return $isNontrivial;
562 $keyName = $shortname;
563 $tableName =
"license_ref";
564 $addCondition =
"AND rf_external_id IS NULL";
565 $statement = __METHOD__ .
".getId";
566 $params = array($shortname);
568 if ($groupFk !=
null) {
569 $keyName .= $groupFk;
570 $tableName =
"license_candidate";
571 $addCondition =
"AND group_fk = $2";
572 $statement .=
".candidate";
573 $params[] = $this->userDao->getGroupIdByName($groupFk);
575 $sql =
"SELECT rf_pk FROM ONLY $tableName WHERE rf_shortname = $1 $addCondition;";
577 if (array_key_exists($keyName, $this->nkMap)) {
578 return $this->nkMap[$keyName];
580 $row = $this->
dbManager->getSingleRow($sql, $params, $statement);
581 $this->nkMap[$keyName] = ($row===
false) ?
false : $row[
'rf_pk'];
582 return $this->nkMap[$keyName];
592 $md5 = md5($licenseText);
593 if (array_key_exists($md5, $this->mdkMap)) {
594 return $this->mdkMap[$md5];
596 $row = $this->
dbManager->getSingleRow(
"SELECT rf_pk " .
597 "FROM ONLY license_ref WHERE rf_md5=md5($1) AND rf_external_id IS NULL",
598 array($licenseText));
599 $this->mdkMap[$md5] = (empty($row)) ?
false : $row[
'rf_pk'];
600 return $this->mdkMap[$md5];
613 private function setMap($from, $to, $usage)
617 $sql =
"SELECT license_map_pk, rf_parent FROM license_map WHERE rf_fk = $1 AND usage = $2;";
618 $statement = __METHOD__ .
".getCurrentMapping";
619 $row = $this->
dbManager->getSingleRow($sql, array($to, $usage), $statement);
620 if (!empty($row) && $row[
'rf_parent'] != $from) {
621 $this->
dbManager->updateTableRow(
"license_map", array(
623 'rf_parent' => $from,
625 ),
'license_map_pk', $row[
'license_map_pk']);
627 } elseif (empty($row)) {
628 $this->
dbManager->insertTableRow(
'license_map', array(
630 'rf_parent' => $from,
650 $stmtInsert = __METHOD__ .
'.insert.' . $tableName;
652 "rf_shortname" => $row[
'shortname'],
653 "rf_licensetype" => $row[
'licensetype'] ?:
'Unknown',
654 "rf_fullname" => $row[
'fullname'],
655 "rf_spdx_id" => $row[
'spdx_id'],
656 "rf_text" => $row[
'text'],
657 "rf_md5" => md5($row[
'text']),
658 "rf_detector_type" => 1,
659 "rf_url" => $row[
'url'],
660 "rf_notes" => $row[
'notes'],
661 "rf_source" => $row[
'source'],
662 "rf_risk" => $row[
'risk'],
663 "rf_external_id" => $row[
'external_id'],
664 "rf_active" => $this->
dbManager->booleanToDb($row[
'active'] ?:
true),
668 if ($tableName ==
"license_candidate") {
669 $groupId = $this->userDao->getGroupIdByName($row[
'group']);
670 if (empty($groupId)) {
671 return "Error: Unable to insert candidate license " . $row[
'shortname'] .
672 " as group " . $row[
'group'] .
" does not exist";
674 $columns[
"group_fk"] = $groupId;
675 $columns[
"marydone"] = $this->
dbManager->booleanToDb(
true);
676 $as =
" as candidate license under group " . $row[
"group"];
679 $newPk = $this->
dbManager->insertTableRow($tableName, $columns, $stmtInsert,
'rf_pk');
682 $log =
"Inserted '$row[shortname]' in DB" . $as;
683 if ($row[
'external_id'] ===
null) {
684 if ($tableName ==
"license_candidate") {
685 $this->nkMap[$row[
'shortname'].$row[
'group']] = $newPk;
687 $this->nkMap[$row[
'shortname']] = $newPk;
689 $this->mdkMap[md5($row[
'text'])] = $newPk;
691 if ($this->
insertMapIfNontrivial($row[
'parent_shortname'], $row[
'shortname'], LicenseMap::CONCLUSION)) {
692 $log .=
" with conclusion '$row[parent_shortname]'";
695 $log .=
" reporting '$row[report_shortname]'";
700 $return[
'log'] = $log;
701 $return[
'pkey'] = $newPk;
712 foreach ($data as $row) {
Import licenses from CSV.
insertMapIfNontrivial($fromName, $toName, $usage)
Insert in license_map table if the license conclusion is non-trivial.
handleFile($filename, $fileExtension)
Read the CSV line by line and import it.
importJsonData($data, string $msg)
handleCsvLicense($row)
Handle a single row from CSV.
updateLicense($row, $rfPk)
Update the license info in the DB.
handleLicenseDBLicenseImport($row)
Handle a single row from csv import form LicenseDB.
setEnclosure($enclosure='"')
Update the enclosure.
getKeyFromShortname($shortname, $groupFk=null)
Get the license id using license shortname from DB or nkMap.
__construct(DbManager $dbManager, UserDao $userDao, $obligationMap=null)
handleHeadCsv($row)
Handle a row as head row.
insertNewLicense($row, $tableName="license_ref")
Insert a new license in DB.
setDelimiter($delimiter=',')
Update the delimiter.
setMap($from, $to, $usage)
Update license mappings.
getKeyFromMd5($licenseText)
Wrapper class for license map.
Wrapper class for obligation map.
static getArrayDiffs(array $oldArray, array $newArray)
Get list of additions/removals to make $oldArray equal to $newArray.
char * trim(char *ptext)
Trimming whitespace.
fo_dbManager * dbManager
fo_dbManager object
Utility functions for specific applications.