FOSSology  4.6.0
Open Source License Compliance by Open Source Software
ReuserAgent.php
Go to the documentation of this file.
1 <?php
2 /*
3  SPDX-FileCopyrightText: © 2014-2018 Siemens AG
4 Author: Daniele Fognini, Andreas Würl
5 
6  SPDX-License-Identifier: GPL-2.0-only
7 */
8 
9 namespace Fossology\Reuser;
10 
27 
28 include_once(__DIR__ . "/version.php");
29 
36 class ReuserAgent extends Agent
37 {
41  private $uploadDao;
61  private $clearingDao;
65  private $copyrightDao;
69  private $aagentDao;
73  private $decisionTypes;
74 
75  function __construct()
76  {
77  parent::__construct(REUSER_AGENT_NAME, AGENT_VERSION, AGENT_REV);
78  $this->aagentDao = $this->container->get('dao.agent');
79  $this->uploadDao = $this->container->get('dao.upload');
80  $this->clearingDao = $this->container->get('dao.clearing');
81  $this->copyrightDao = $this->container->get('dao.copyright');
82  $this->decisionTypes = $this->container->get('decision.types');
83  $this->clearingEventProcessor = $this->container->get('businessrules.clearing_event_processor');
84  $this->clearingDecisionFilter = $this->container->get('businessrules.clearing_decision_filter');
85  $this->clearingDecisionProcessor = $this->container->get('businessrules.clearing_decision_processor');
86  $this->agentLicenseEventProcessor = $this->container->get('businessrules.agent_license_event_processor');
87  }
88 
94  function processUploadId($uploadId)
95  {
96  $itemTreeBounds = $this->uploadDao->getParentItemBounds($uploadId);
97  foreach ($this->uploadDao->getReusedUpload($uploadId, $this->groupId) as $reuseTriple) {
98  // Get the reuse upload id
99  $reusedUploadId = $reuseTriple['reused_upload_fk'];
100  // Get the group id
101  $reusedGroupId = $reuseTriple['reused_group_fk'];
102  // Get the reuse mode
103  $reuseMode = $reuseTriple['reuse_mode'];
104  // Get the ItemTreeBounds for the upload
105  $itemTreeBoundsReused = $this->uploadDao->getParentItemBounds($reusedUploadId);
106  if (false === $itemTreeBoundsReused) {
107  continue;
108  }
109 
110  if ($reuseMode & UploadDao::REUSE_ENHANCED) {
111  $this->processEnhancedUploadReuse($itemTreeBounds, $itemTreeBoundsReused, $reusedGroupId);
112  } else {
113  $this->processUploadReuse($itemTreeBounds, $itemTreeBoundsReused, $reusedGroupId);
114  }
115 
116  if ($reuseMode & UploadDao::REUSE_MAIN) {
117  $this->reuseMainLicense($uploadId, $this->groupId, $reusedUploadId, $reusedGroupId);
118  }
119 
120  if ($reuseMode & UploadDao::REUSE_CONF) {
121  $this->reuseConfSettings($uploadId, $reusedUploadId);
122  }
123 
124  if ($reuseMode & UploadDao::REUSE_COPYRIGHT) {
125  $this->reuseCopyrights($uploadId, $reusedUploadId);
126  }
127  }
128  return true;
129  }
130  protected function reuseConfSettings($uploadId, $reusedUploadId)
131  {
132  if (!$this->uploadDao->insertReportConfReuse($uploadId, $reusedUploadId)) {
133  echo "INFO :: Report configuration for select upload doesn't exists. Unable to copy!!!";
134  }
135  $this->heartbeat(1);
136  return true;
137  }
138 
149  protected function reuseMainLicense($uploadId, $groupId, $reusedUploadId, $reusedGroupId)
150  {
151  $mainLicenseIds = $this->clearingDao->getMainLicenseIds($reusedUploadId, $reusedGroupId);
152  if (!empty($mainLicenseIds)) {
153  $existingMainLicenseIds = $this->clearingDao->getMainLicenseIds($uploadId, $groupId);
154  foreach ($mainLicenseIds as $mainLicenseId) {
155  if (in_array($mainLicenseId, $existingMainLicenseIds)) {
156  continue;
157  } else {
158  $this->clearingDao->makeMainLicense($uploadId, $groupId, $mainLicenseId);
159  }
160  }
161  }
162  return true;
163  }
164 
172  protected function getAgentId($uploadId)
173  {
174  $agentName = 'copyright';
175 
177  $scanJobProxy = new ScanJobProxy($this->aagentDao, $uploadId);
178 
179  $scanJobProxy->createAgentStatus(array($agentName));
180  $selectedScanners = $scanJobProxy->getLatestSuccessfulAgentIds();
181  if (!array_key_exists($agentName, $selectedScanners)) {
182  return;
183  }
184  return $selectedScanners[$agentName];
185  }
186 
187 
196  protected function reuseCopyrights($uploadId, $reusedUploadId)
197  {
198  $agentId = $this->getAgentId($uploadId);
199  $reusedAgentId = $this->getAgentId($reusedUploadId);
200  if ($agentId == null || $reusedAgentId == null) {
201  return true;
202  }
203  $uploadTreeTableName = $this->uploadDao->getUploadtreeTableName($uploadId);
204  $extrawhere = ' agent_fk='.$agentId;
205  $allCopyrights = $this->copyrightDao->getScannerEntries('copyright',
206  $uploadTreeTableName, $uploadId, null, $extrawhere);
207 
208  $reusedCopyrights = $this->copyrightDao->getAllEventEntriesForUpload(
209  $reusedUploadId, $reusedAgentId);
210 
211  if (!empty($reusedCopyrights) && !empty($allCopyrights)) {
212  // Pre-index $allCopyrights by hash to avoid nested loop O(N*M)
213  $copyrightsByHash = [];
214  foreach ($allCopyrights as $copyrightKey => $copyright) {
215  $hash = $copyright['hash'];
216  if (!isset($copyrightsByHash[$hash])) {
217  $copyrightsByHash[$hash] = [];
218  }
219  $copyrightsByHash[$hash][] = $copyrightKey;
220  }
221 
222  foreach ($reusedCopyrights as $reusedCopyright) {
223  $reusedHash = $reusedCopyright['hash'];
224  if (isset($copyrightsByHash[$reusedHash]) && !empty($copyrightsByHash[$reusedHash])) {
225  // Take the first matching entry
226  $copyrightKey = array_shift($copyrightsByHash[$reusedHash]);
227  $copyright = $allCopyrights[$copyrightKey];
228 
229  if ($this->dbManager->booleanFromDb($reusedCopyright['is_enabled'])) {
230  $action = "update";
231  $content = $reusedCopyright["contentedited"];
232  } else {
233  $action = "delete";
234  $content = "";
235  }
236  $hash = $copyright['hash'];
237  $item = new ItemTreeBounds(
238  intval($copyright['uploadtree_pk']), $uploadTreeTableName,
239  $copyright['upload_fk'], $copyright['lft'], $copyright['rgt']);
240  $this->copyrightDao->updateTable($item, $hash, $content,
241  $this->userId, 'copyright', $action);
242  $this->heartbeat(1);
243  }
244  }
245  }
246  return true;
247  }
248 
257  protected function processUploadReuse($itemTreeBounds, $itemTreeBoundsReused, $reusedGroupId)
258  {
261 
262  $clearingDecisions = $this->clearingDao->getFileClearingsFolder($itemTreeBoundsReused, $reusedGroupId);
263  $currenlyVisibleClearingDecisions = $this->clearingDao->getFileClearingsFolder($itemTreeBounds, $groupId);
264 
265  $currenlyVisibleClearingDecisionsById = $this->mapByClearingId($currenlyVisibleClearingDecisions);
266  $clearingDecisionsById = $this->mapByClearingId($clearingDecisions);
267 
268  $clearingDecisionsToImport = array_diff_key($clearingDecisionsById,$currenlyVisibleClearingDecisionsById);
269 
270  $clearingDecisionToImportByFileId = $this->mapByFileId($clearingDecisionsToImport);
271 
274  $containedItems = ArrayOperation::callChunked(
275  function ($fileIds) use ($itemTreeBounds, $uploadDao)
276  {
277  return $uploadDao->getContainedItems(
278  $itemTreeBounds,
279  "pfile_fk = ANY($1)",
280  array('{' . implode(', ', $fileIds) . '}')
281  );
282  }, array_keys($clearingDecisionToImportByFileId), 100);
283 
284  foreach ($containedItems as $item) {
285  $fileId = $item->getFileId();
286  if (empty($fileId)) {
287  continue;
288  }
289  if (array_key_exists($fileId, $clearingDecisionToImportByFileId)) {
290  $this->createCopyOfClearingDecision($item->getId(), $userId, $groupId,
291  $clearingDecisionToImportByFileId[$fileId]);
292  } else {
293  throw new \Exception("bad internal state");
294  }
295 
296  $this->heartbeat(1);
297  }
298 
299  return true;
300  }
301 
309  protected function processEnhancedUploadReuse($itemTreeBounds, $itemTreeBoundsReused, $reusedGroupId)
310  {
311  $clearingDecisions = $this->clearingDao->getFileClearingsFolder($itemTreeBoundsReused, $reusedGroupId);
312  $currenlyVisibleClearingDecisions = $this->clearingDao->getFileClearingsFolder($itemTreeBounds, $this->groupId);
313 
314  $currenlyVisibleClearingDecisionsById = $this->mapByClearingId($currenlyVisibleClearingDecisions);
315  $clearingDecisionsById = $this->mapByClearingId($clearingDecisions);
316 
317  $clearingDecisionsToImport = array_diff_key($clearingDecisionsById,$currenlyVisibleClearingDecisionsById);
318 
319  $sql = "SELECT ut.* FROM uploadtree ur, uploadtree ut WHERE ur.upload_fk=$2"
320  . " AND ur.pfile_fk=$3 AND ut.upload_fk=$1 AND ut.ufile_name=ur.ufile_name";
321  $stmt = __METHOD__.'.reuseByName';
322  $this->dbManager->prepare($stmt, $sql);
323  $treeDao = $this->container->get('dao.tree');
324 
325  foreach ($clearingDecisionsToImport as $clearingDecision) {
326  $reusedPath = $treeDao->getRepoPathOfPfile($clearingDecision->getPfileId());
327  if (empty($reusedPath)) {
328  // File missing from repo
329  continue;
330  }
331 
332  $res = $this->dbManager->execute($stmt,array($itemTreeBounds->getUploadId(),
333  $itemTreeBoundsReused->getUploadId(),$clearingDecision->getPfileId()));
334  while ($row = $this->dbManager->fetchArray($res)) {
335  $newPath = $treeDao->getRepoPathOfPfile($row['pfile_fk']);
336  if (empty($newPath)) {
337  // File missing from repo
338  continue;
339  }
340  $this->copyClearingDecisionIfDifferenceIsSmall($reusedPath, $newPath, $clearingDecision, $row['uploadtree_pk']);
341  }
342  $this->dbManager->freeResult($res);
343  }
344  }
345 
357  protected function copyClearingDecisionIfDifferenceIsSmall($reusedPath,$newPath,$clearingDecision,$itemId)
358  {
359  $diffLevel = exec("diff $reusedPath $newPath | wc -l");
360  if ($diffLevel === false) {
361  throw new \Exception('cannot use diff tool');
362  }
363  if ($diffLevel < 5) {
364  $this->createCopyOfClearingDecision($itemId, $this->userId, $this->groupId, $clearingDecision);
365  $this->heartbeat(1);
366  }
367  }
368 
376  protected function mapByFileId($clearingDecisions)
377  {
378  $clearingDecisionByFileId = array();
379  foreach ($clearingDecisions as $clearingDecision) {
380  $fileId = $clearingDecision->getPfileId();
381  if (!array_key_exists($fileId, $clearingDecisionByFileId)) {
382  $clearingDecisionByFileId[$fileId] = $clearingDecision;
383  }
384  }
385  return $clearingDecisionByFileId;
386  }
387 
395  protected function createCopyOfClearingDecision($itemId, $userId, $groupId, $clearingDecisionToCopy)
396  {
397  $clearingEventIdsToCopy = array();
399  foreach ($clearingDecisionToCopy->getClearingEvents() as $clearingEvent) {
400  $licenseId = $clearingEvent->getLicenseId();
401  $uploadTreeId = $itemId;
402  $isRemoved = $clearingEvent->isRemoved();
403  $type = ClearingEventTypes::USER;
404  $reportInfo = $clearingEvent->getReportinfo();
405  $comment = $clearingEvent->getComment();
406  $acknowledgement = $clearingEvent->getAcknowledgement();
408  $clearingEventIdsToCopy[] = $this->clearingDao->insertClearingEvent(
409  $uploadTreeId, $userId, $groupId, $licenseId, $isRemoved,
410  $type, $reportInfo, $comment, $acknowledgement, $jobId);
411  }
412 
413  $this->clearingDao->createDecisionFromEvents(
414  $itemId,
415  $userId,
416  $groupId,
417  $clearingDecisionToCopy->getType(),
418  $clearingDecisionToCopy->getScope(),
419  $clearingEventIdsToCopy
420  );
421  }
422 
431  public function mapByClearingId($clearingDecisions)
432  {
433  $mapped = array();
434 
435  foreach ($clearingDecisions as $clearingDecision) {
436  $mapped[$clearingDecision->getClearingId()] = $clearingDecision;
437  }
438 
439  return $mapped;
440  }
441 }
Structure of an Agent with all required parameters.
Definition: Agent.php:41
heartbeat($newProcessed)
Send hear beat to the scheduler.
Definition: Agent.php:203
Various utility functions to filter ClearingDecision.
Utility functions to process ClearingDecision.
processEnhancedUploadReuse($itemTreeBounds, $itemTreeBoundsReused, $reusedGroupId)
Get clearing decisions and use copyClearingDecisionIfDifferenceIsSmall()
processUploadId($uploadId)
Get the upload items and reuse based on reuse mode.
Definition: ReuserAgent.php:94
reuseMainLicense($uploadId, $groupId, $reusedUploadId, $reusedGroupId)
Reuse main license from previous upload.
mapByClearingId($clearingDecisions)
Map clearing decisions by clearing id.
copyClearingDecisionIfDifferenceIsSmall($reusedPath, $newPath, $clearingDecision, $itemId)
Use diff tool to compare files.
mapByFileId($clearingDecisions)
Maps clearing decisions by file id.
reuseCopyrights($uploadId, $reusedUploadId)
Reuse deactivated Copyrights from previous upload.
fo_dbManager * dbManager
fo_dbManager object
Definition: process.c:16