FOSSology  4.4.0
Open Source License Compliance by Open Source Software
cp2foss.php
Go to the documentation of this file.
1 <?php
2 /*
3  SPDX-FileCopyrightText: © 2008-2014 Hewlett-Packard Development Company, L.P.
4  SPDX-FileCopyrightText: © 2015 Siemens AG
5 
6  SPDX-License-Identifier: GPL-2.0-only
7 */
8 
20 require_once("$MODDIR/lib/php/common-cli.php");
21 cli_Init();
22 
23 global $Plugins;
24 error_reporting(E_NOTICE & E_STRICT);
25 
26 $Usage = "Usage: " . basename($argv[0]) . " [options] [archives]
27  Options:
28  -h = this help message
29  -v = enable verbose debugging
30  --username string = user name
31  --groupname string = group name
32  --password string = password
33  -c string = Specify the directory for the system configuration
34  -g number = set the global decisions from previous uploads or not. 1: yes; 0: no
35  -P number = set the permission to public on this upload or not. 1: yes; 0: no
36  -s = Run synchronously. Don't return until archive already in FOSSology repository.
37  If the archive is a file (see below), then the file can be safely removed.
38 
39  Upload from version control system options(you have to specify which type of vcs you are using):
40  -S = upload from subversion repo
41  -G = upload from git repo
42  --user string = user name
43  --pass string = password
44 
45  FOSSology storage options:
46  -f path = folder path for placing files (e.g., -f 'Fedora/ISOs/Disk 1')
47  You do not need to specify your top level folder.
48  All paths are under your top level folder.
49  -A = alphabet folders; organize uploads into folder a-c, d-f, etc.
50  -AA num = specify the number of letters per folder (default: 3); implies -A
51  -n name = (optional) name for the upload (default: name it after the file)
52  -d desc = (optional) description for the update
53 
54  FOSSology processing queue options:
55  -Q = list all available processing agents
56  -q = specify a comma-separated list of agents, or 'all'
57  NOTE: By default, no analysis agents are queued up.
58  -T = TEST. No database or repository updates are performed.
59  Test mode enables verbose mode.
60  -I = ignore scm data scanning
61 
62  FOSSology source options:
63  archive = file, directory, or URL to the archive.
64  If the archive is a URL, then it is retrieved and added.
65  If the archive is a file, then it is used as the source to add.
66  If the archive is a directory, then ALL files under it are
67  recursively added.
68  The archive support globbing - '*', all the matched files will be added.
69  Note: have to put it in single/double quotes, e.g. '*.php'
70  - = a single hyphen means the archive list will come from stdin.
71  -X path = item to exclude when archive is a directory
72  You can specify more than one -X. For example, to exclude
73  all svn and cvs directories, include the following before the
74  archive's directory path:
75  -X .svn -X .cvs
76  NOTES:
77  If you use -n, then -n must be set BEFORE each archive.
78  If you specify a directory, then -n and -d are ignored.
79  Multiple archives can be specified after each storage option.
80 
81  One example, to load a file into one path:
82  cp2foss \\
83  --username USER --password PASSWORD \\
84  -f path -d 'the file' /tmp/file
85  One example, to upload all the php files in /tmp:
86  cp2foss --username USER --password PASSWORD -f path -d 'the file' '/tmp/*.php'
87 
88  Deprecated options:
89  -a archive = (deprecated) see archive
90  -e addr = (deprecated and ignored)
91  -p path = (deprecated) see -f
92  -R = (deprecated and ignored)
93  -w = (deprecated and ignored)
94  -W = (deprecated and ignored)
95 ";
96 /* Load command-line options */
97 global $PG_CONN;
98 $Verbose = 0;
99 $Test = 0;
100 $fossjobs_command = "";
101 /************************************************************************/
102 /************************************************************************/
103 /************************************************************************/
104 
109 function GetBucketFolder($UploadName, $BucketGroupSize)
110 {
111  $Letters = "abcdefghijklmnopqrstuvwxyz";
112  $Numbers = "0123456789";
113  if (empty($UploadName)) {
114  return;
115  }
116  $Name = strtolower(substr($UploadName, 0, 1));
117  /* See if I can find the bucket */
118  if (empty($BucketGroupSize) || ($BucketGroupSize < 1)) {
119  $BucketGroupSize = 3;
120  }
121  for ($i = 0;$i < 26;$i+= $BucketGroupSize) {
122  $Range = substr($Letters, $i, $BucketGroupSize);
123  $Find = strpos($Range, $Name);
124  if ($Find !== false) {
125  if (($BucketGroupSize <= 1) || (strlen($Range) <= 1)) {
126  return ($Range);
127  }
128  return (substr($Range, 0, 1) . '-' . substr($Range, -1, 1));
129  }
130  }
131  /* Not a letter. Check for numbers */
132  $Find = strpos($Numbers, $Name);
133  if ($Find !== false) {
134  return ("0-9");
135  }
136  /* Not a letter. */
137  return ("Other");
138 } /* GetBucketFolder() */
139 
151 function GetFolder($FolderPath, $Parent = null)
152 {
153  $dbManager = $GLOBALS['container']->get('db.manager');
154  global $Verbose;
155  global $Test;
156  if (empty($Parent)) {
157  $Parent = FolderGetTop();
158  }
159  /*/ indicates it's the root folder. Empty folder path ends recursion. */
160  if ($FolderPath == '/') {
161  return ($Parent);
162  }
163  if (empty($FolderPath)) {
164  return ($Parent);
165  }
166  list($folderHead, $folderTail) = explode('/', $FolderPath, 2);
167  if (empty($folderHead)) {
168  return (GetFolder($folderTail, $Parent));
169  }
170  /* See if it exists */
171  $SQL = "SELECT folder_pk FROM folder
172  INNER JOIN foldercontents ON child_id = folder_pk
173  AND foldercontents_mode = '1'
174  WHERE foldercontents.parent_fk = $1 AND folder_name = $2";
175  if ($Verbose) {
176  print "SQL=\n$SQL\n$1=$Parent\n$2=$folderHead\n";
177  }
178 
179  $row = $dbManager->getSingleRow($SQL, array($Parent, $folderHead), __METHOD__.".GetFolder.exists");
180  if (empty($row)) {
181  /* Need to create folder */
182  global $Plugins;
183  $P = & $Plugins[plugin_find_id("folder_create") ];
184  if (empty($P)) {
185  print "FATAL: Unable to find folder_create plugin.\n";
186  exit(1);
187  }
188  if ($Verbose) {
189  print "Folder not found: Creating $folderHead\n";
190  }
191  if (!$Test) {
192  $P->create($Parent, $folderHead, "");
193  $row = $dbManager->getSingleRow($SQL, array($Parent, $folderHead), __METHOD__.".GetFolder.exists");
194  }
195  }
196  $Parent = $row['folder_pk'];
197  return (GetFolder($folderTail, $Parent));
198 } /* GetFolder() */
199 
210 function UploadOne($FolderPath, $UploadArchive, $UploadName, $UploadDescription, $TarSource = null)
211 {
212  $dbManager = $GLOBALS['container']->get('db.manager');
213  global $Verbose;
214  global $Test;
215  global $QueueList;
216  global $fossjobs_command;
217  global $global_flag;
218  global $public_flag;
219  global $SysConf;
220  global $VCS;
221  global $vcsuser;
222  global $vcspass;
223  global $TarExcludeList;
224  global $scmarg;
225  $jobqueuepk = 0;
226 
227  if (empty($UploadName)) {
228  $text = "UploadName is empty\n";
229  echo $text;
230  return 1;
231  }
232 
233  $user_pk = $SysConf['auth']['UserId'];
234  $group_pk = $SysConf['auth']['GroupId'];
235  /* Get the user record and check the PLUGIN_DB_ level to make sure they have at least write access */
236  $UsersRow = GetSingleRec("users", "where user_pk=$user_pk");
237  if ($UsersRow["user_perm"] < PLUGIN_DB_WRITE) {
238  print "You have no permission to upload files into FOSSology\n";
239  return 1;
240  }
241 
242  /* Get the folder's primary key */
243  $root_folder_fk = $UsersRow["root_folder_fk"];
244  global $OptionA; /* Should it use bucket names? */
245  if ($OptionA) {
246  global $bucket_size;
247  $FolderPath.= "/" . GetBucketFolder($UploadName, $bucket_size);
248  }
249  $FolderPk = GetFolder($FolderPath, $root_folder_fk);
250  if ($FolderPk == 1) {
251  print " Uploading to folder: 'Software Repository'\n";
252  } else {
253  print " Uploading to folder: '$FolderPath'\n";
254  }
255  print " Uploading as '$UploadName'\n";
256  if (!empty($UploadDescription)) {
257  print " Upload description: '$UploadDescription'\n";
258  }
259 
260  $Mode = (1 << 3); // code for "it came from web upload"
261 
262  /* Create the upload for the file */
263  if ($Verbose) {
264  print "JobAddUpload($user_pk, $group_pk, $UploadName,$UploadArchive,$UploadDescription,$Mode,$FolderPk, $public_flag, $global_flag);\n";
265  }
266  if (!$Test) {
267  $Src = $UploadArchive;
268  if (!empty($TarSource)) {
269  $Src = $TarSource;
270  }
271  $UploadPk = JobAddUpload($user_pk, $group_pk, $UploadName, $Src, $UploadDescription, $Mode, $FolderPk, $public_flag, $global_flag);
272  print " UploadPk is: '$UploadPk'\n";
273  print " FolderPk is: '$FolderPk'\n";
274  }
275 
276  /* Prepare the job: job "wget" */
277  if ($Verbose) {
278  print "JobAddJob($user_pk, $group_pk, wget, $UploadPk);\n";
279  }
280  if (!$Test) {
281  $jobpk = JobAddJob($user_pk, $group_pk, "wget", $UploadPk);
282  if (empty($jobpk) || ($jobpk < 0)) {
283  $text = _("Failed to insert job record");
284  echo $text;
285  return 1;
286  }
287  }
288 
289  $jq_args = "$UploadPk - $Src";
290  if ($TarExcludeList) {
291  $jq_args .= " " . $TarExcludeList;
292  }
293  if ($VCS) {
294  $jq_args .= " " . $VCS; // add flags when upload from version control system
295  }
296  if ($vcsuser && $vcspass) {
297  $jq_args .= " --username $vcsuser --password $vcspass ";
298  }
299  if ($Verbose) {
300  print "JobQueueAdd($jobpk, wget_agent, $jq_args, no, NULL);\n";
301  }
302  if (!$Test) {
303  $jobqueuepk = JobQueueAdd($jobpk, "wget_agent", $jq_args, "no", NULL);
304  if (empty($jobqueuepk)) {
305  $text = _("Failed to insert task 'wget' into job queue");
306  echo $text;
307  return 1;
308  }
309  }
310  /* schedule agents */
311  global $Plugins;
312  if ($Verbose) {
313  print "AgentAdd wget_agent and dj2nest.\n";
314  }
315  if (!$Test) {
316  $unpackplugin = &$Plugins[plugin_find_id("agent_unpack") ];
317  $ununpack_jq_pk = $unpackplugin->AgentAdd($jobpk, $UploadPk, $ErrorMsg, array("wget_agent"), $scmarg);
318  if ($ununpack_jq_pk < 0) {
319  echo $ErrorMsg;
320  return 1;
321  }
322 
323  $adj2nestplugin = &$Plugins[plugin_find_id("agent_adj2nest") ];
324  $adj2nest_jq_pk = $adj2nestplugin->AgentAdd($jobpk, $UploadPk, $ErrorMsg, array());
325  if ($adj2nest_jq_pk < 0) {
326  echo $ErrorMsg;
327  return 1;
328  }
329  }
330  if (!empty($QueueList)) {
331  switch ($QueueList) {
332  case 'ALL':
333  case 'all':
334  $Cmd = "$fossjobs_command -U '$UploadPk'";
335  break;
336  default:
337  $Cmd = "$fossjobs_command -U '$UploadPk' -A '$QueueList'";
338  break;
339  }
340  if ($Verbose) {
341  print "CMD=$Cmd\n";
342  }
343  if (!$Test) {
344  system($Cmd);
345  }
346  } else {
347  /* No other agents other than unpack scheduled, attach to unpack*/
348  }
349  global $OptionS; /* Should it run synchronously? */
350  if ($OptionS) {
351  $working = true;
352  $waitCount = 0;
353  while ($working && ($waitCount++ < 30)) {
354  sleep(3);
355  $SQL = "select 1 from jobqueue inner join job on job.job_pk = jobqueue.jq_job_fk where job_upload_fk = $1 and jq_end_bits = 0 and jq_type = 'wget_agent'";
356 
357  $row = $dbManager->getSingleRow($SQL, array($UploadPk), __METHOD__.".UploadOne");
358  if (empty($row)) {
359  $working = false;
360  }
361 
362  }
363  if ($working) {
364  echo "Gave up waiting for copy completion. Is the scheduler running?";
365  return 1;
366  }
367  }
368 } /* UploadOne() */
369 
370 
371 /************************************************************************/
372 /************************************************************************/
373 /************************************************************************/
374 /* Process each parameter */
375 $FolderPath = "/";
376 $UploadDescription = "";
377 $UploadName = "";
378 $QueueList = "";
379 $TarExcludeList = "";
380 $bucket_size = 3;
381 $global_flag = 0;
382 $public_flag = 0;
383 $scmarg = NULL;
384 $OptionS = "";
385 
386 $user = $passwd = "";
387 $group = "";
388 $vcsuser = $vcspass= "";
389 
390 for ($i = 1; $i < $argc; $i ++) {
391  switch ($argv[$i]) {
392  case '-c':
393  $i++;
394  break; /* handled in fo_wrapper */
395  case '-h':
396  case '-?':
397  print $Usage . "\n";
398  exit(0);
399  case '--username':
400  $i++;
401  $user = escapeshellarg($argv[$i]);
402  break;
403  case '--groupname':
404  $i++;
405  $group = escapeshellarg($argv[$i]);
406  break;
407  case '--password':
408  $i++;
409  $passwd = escapeshellarg($argv[$i]);
410  break;
411  case '--user':
412  $i++;
413  $vcsuser = $argv[$i];
414  break;
415  case '--pass':
416  $i++;
417  $vcspass = $argv[$i];
418  break;
419  case '-A': /* use alphabet buckets */
420  $OptionA = true;
421  break;
422  case '-AA': /* use alphabet buckets */
423  $OptionA = true;
424  $i++;
425  $bucket_size = intval($argv[$i]);
426  if ($bucket_size < 1) {
427  $bucket_size = 1;
428  }
429  break;
430  case '-f': /* folder path */
431  case '-p': /* deprecated 'path' to folder */
432  $i++;
433  $FolderPath = $argv[$i];
434  /* idiot check for absolute paths */
435  //print " Before Idiot Checks: '$FolderPath'\n";
436  /* remove starting and ending / */
437  $FolderPath = preg_replace('@^/*@', "", $FolderPath);
438  $FolderPath = preg_replace('@/*$@', "", $FolderPath);
439  /* Note: the pattern below should probably be generalized to remove everything
440  * up to and including the 1st /, This pattern works in what I've
441  * tested: @^.*\/@ ( I had to escape the / so the comment works!)
442  */
443  $FolderPath = preg_replace("@^S.*? Repository@", "", $FolderPath);
444  $FolderPath = preg_replace('@//*@', "/", $FolderPath);
445  $FolderPath = '/' . $FolderPath;
446  //print " AFTER Idiot Checks: '$FolderPath'\n";
447 
448  break;
449  case '-R': /* obsolete: recurse directories */
450  break;
451  case '-W': /* obsolete: webserver */
452  break;
453  case '-w': /* obsolete: URL switch to use wget */
454  break;
455  case '-d': /* specify upload description */
456  $i++;
457  $UploadDescription = escapeshellarg($argv[$i]);
458  break;
459  case '-n': /* specify upload name */
460  $i++;
461  $UploadName = escapeshellarg($argv[$i]);
462  break;
463  case '-Q':
464  $OptionQ = 1;
465  break;
466  case '-q':
467  $i++;
468  $QueueList = escapeshellarg($argv[$i]);
469  break;
470  case '-s':
471  $OptionS = true;
472  break;
473  case '-T': /* Test mode */
474  $Test = 1;
475  if (!$Verbose) {
476  $Verbose++;
477  }
478  break;
479  case '-v':
480  $Verbose++;
481  break;
482  case '-X':
483  if (!empty($TarExcludeList)) {
484  $TarExcludeList .= " ";
485  }
486  $i++;
487  $TarExcludeList .= "--exclude '" . $argv[$i] . "'";
488  break;
489  case '-a': /* it's an archive! */
490  /* ignore -a since the next name is a file. */
491  break;
492  case '-': /* it's an archive list from stdin! */
493  $stdin_flag = 1;
494  break;
495  case '-g': /* set the permission to public or not */
496  $i++;
497  if (1 == $argv[$i]) {
498  $global_flag = 1;
499  } else {
500  $global_flag = 0;
501  }
502  break;
503  case '-P': /* set the permission to public or not */
504  $i++;
505  if (1 == $argv[$i]) {
506  $public_flag = 1;
507  } else {
508  $public_flag = 0;
509  }
510  break;
511  case '-S': /* upload from subversion repo */
512  $VCS = 'SVN';
513  break;
514  case '-G': /* upload from git repo */
515  $VCS = 'Git';
516  break;
517  case '-I': /* ignore scm data when scanning */
518  $scmarg = '-I';
519  break;
520  default:
521  if (substr($argv[$i], 0, 1) == '-') {
522  print "Unknown parameter: '" . $argv[$i] . "'\n";
523  print $Usage . "\n";
524  exit(1);
525  }
526  /* No hyphen means it is a file! */
527  $UploadArchive = escapeshellarg($argv[$i]);
528  } /* switch */
529 } /* for each parameter */
530 
531 account_check($user, $passwd, $group); // check username/password
532 
534 if (!$Test && $OptionQ) {
535  $Cmd = "fossjobs --username $user --groupname $group --password $passwd -c $SYSCONFDIR -a";
536  system($Cmd);
537  exit(0);
538 }
539 
541 if ($stdin_flag) {
542  $Fin = fopen("php://stdin", "r");
543  if (!feof($Fin)) {
544  $UploadArchive = trim(fgets($Fin));
545  }
546  fclose($Fin);
547 }
548 
550 if ($Verbose) {
551  $fossjobs_command = "fossjobs --username $user --groupname $group --password $passwd -c $SYSCONFDIR -v ";
552 } else {
553  $fossjobs_command = "fossjobs --username $user --groupname $group --password $passwd -c $SYSCONFDIR ";
554 }
555 
556 //print "fossjobs_command is:$fossjobs_command\n";
557 
558 if (!$UploadArchive) { // upload is empty
559  print "FATAL: No files to upload were specified.\n";
560  exit(1);
561 }
562 
565 $UploadArchiveTmp = realpath($UploadArchive);
566 if (!$UploadArchiveTmp) {
567  // neither a file nor folder from server?
568  if (filter_var($UploadArchive, FILTER_VALIDATE_URL)) {
569  } else if (strchr($UploadArchive, '*')) {
570  $file_number_cmd = "ls $UploadArchive > /dev/null";
571  system($file_number_cmd, $return_val);
572  if ($return_val) {
573  exit(1); // not files matched
574  }
575  if ("/" != $UploadArchive[0]) { // it is a absolute path
576  $UploadArchive = getcwd()."/".$UploadArchive;
577  }
578  } else {
579  print "Note: it seems that what you want to upload '$UploadArchive' does not exist. \n";
580  exit(1);
581  }
582 } else { // is a file or folder from server
583  $UploadArchive = $UploadArchiveTmp;
584 }
585 
586 if (strlen($UploadArchive) > 0 && empty($UploadName)) {
587  $UploadName = basename($UploadArchive);
588 }
589 
590 if ($vcsuser && $vcspass) {
591  print "Warning: usernames and passwords on the command line are visible to system users with a shell account. To avoid this you can download your source, then upload.\n";
592 }
593 
594 print "Loading '$UploadArchive'\n";
595 print " Calling UploadOne in 'main': '$FolderPath'\n";
596 $res = UploadOne($FolderPath, $UploadArchive, $UploadName, $UploadDescription);
597 if ($res) {
598  exit(1); // fail to upload
599 }
600 exit(0);
account_check(&$user, &$passwd, &$group="")
check if this account is correct
Definition: common-auth.php:75
cli_Init()
Initialize the fossology environment for CLI use. This routine loads the plugins so they can be use b...
Definition: common-cli.php:25
GetSingleRec($Table, $Where="")
Retrieve a single database record.
Definition: common-db.php:91
FolderGetTop()
DEPRECATED! Find the top-of-tree folder_pk for the current user.
JobQueueAdd($job_pk, $jq_type, $jq_args, $jq_runonpfile, $Depends, $host=NULL, $jq_cmd_args=NULL)
Insert a jobqueue + jobdepends records.
Definition: common-job.php:157
JobAddUpload($userId, $groupId, $job_name, $filename, $desc, $UploadMode, $folder_pk, $public_perm=Auth::PERM_NONE, $setGlobal=0)
Insert a new upload record, and update the foldercontents table.
Definition: common-job.php:56
if(! $UploadArchive) $UploadArchiveTmp
Definition: cp2foss.php:564
GetFolder($FolderPath, $Parent=null)
Given a folder path, return the folder_pk.
Definition: cp2foss.php:151
UploadOne($FolderPath, $UploadArchive, $UploadName, $UploadDescription, $TarSource=null)
Given one object (file or URL), upload it.
Definition: cp2foss.php:210
GetBucketFolder($UploadName, $BucketGroupSize)
Given an upload name and the number of letters per bucket, return the bucket folder name.
Definition: cp2foss.php:109
char * trim(char *ptext)
Trimming whitespace.
Definition: fossconfig.c:690
#define PLUGIN_DB_WRITE
Plugin requires write permission on DB.
Definition: libfossology.h:38
foreach($Options as $Option=> $OptVal) if(0==$reference_flag &&0==$nomos_flag) $PG_CONN
list_t type structure used to keep various lists. (e.g. there are multiple lists).
Definition: nomos.h:308