示例#1
0
 /**
  * Verify that uninstalling packages passed in to command line is OK.
  *
  * @param PEAR_Installer $dl
  * @return PEAR_Error|true
  */
 function validatePackageUninstall(&$dl)
 {
     if (PEAR::isError($this->_dependencydb)) {
         return $this->_dependencydb;
     }
     $params = array();
     // construct an array of "downloaded" packages to fool the package dependency checker
     // into using these to validate uninstalls of circular dependencies
     $downloaded =& $dl->getUninstallPackages();
     foreach ($downloaded as $i => $pf) {
         if (!class_exists('PEAR_Downloader_Package')) {
             require_once 'PEAR/Downloader/Package.php';
         }
         $dp =& new PEAR_Downloader_Package($dl);
         $dp->setPackageFile($downloaded[$i]);
         $params[$i] =& $dp;
     }
     // check cache
     $memyselfandI = strtolower($this->_currentPackage['channel']) . '/' . strtolower($this->_currentPackage['package']);
     if (isset($dl->___uninstall_package_cache)) {
         $badpackages = $dl->___uninstall_package_cache;
         if (isset($badpackages[$memyselfandI]['warnings'])) {
             foreach ($badpackages[$memyselfandI]['warnings'] as $warning) {
                 $dl->log(0, $warning[0]);
             }
         }
         if (isset($badpackages[$memyselfandI]['errors'])) {
             foreach ($badpackages[$memyselfandI]['errors'] as $error) {
                 if (is_array($error)) {
                     $dl->log(0, $error[0]);
                 } else {
                     $dl->log(0, $error->getMessage());
                 }
             }
             if (isset($this->_options['nodeps']) || isset($this->_options['force'])) {
                 return $this->warning('warning: %s should not be uninstalled, other installed packages depend ' . 'on this package');
             }
             return $this->raiseError('%s cannot be uninstalled, other installed packages depend on this package');
         }
         return true;
     }
     // first, list the immediate parents of each package to be uninstalled
     $perpackagelist = array();
     $allparents = array();
     foreach ($params as $i => $param) {
         $a = array('channel' => strtolower($param->getChannel()), 'package' => strtolower($param->getPackage()));
         $deps = $this->_dependencydb->getDependentPackages($a);
         if ($deps) {
             foreach ($deps as $d) {
                 $pardeps = $this->_dependencydb->getDependencies($d);
                 foreach ($pardeps as $dep) {
                     if (strtolower($dep['dep']['channel']) == $a['channel'] && strtolower($dep['dep']['name']) == $a['package']) {
                         if (!isset($perpackagelist[$a['channel'] . '/' . $a['package']])) {
                             $perpackagelist[$a['channel'] . '/' . $a['package']] = array();
                         }
                         $perpackagelist[$a['channel'] . '/' . $a['package']][] = array($d['channel'] . '/' . $d['package'], $dep);
                         if (!isset($allparents[$d['channel'] . '/' . $d['package']])) {
                             $allparents[$d['channel'] . '/' . $d['package']] = array();
                         }
                         if (!isset($allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']])) {
                             $allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']] = array();
                         }
                         $allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']][] = array($d, $dep);
                     }
                 }
             }
         }
     }
     // next, remove any packages from the parents list that are not installed
     $remove = array();
     foreach ($allparents as $parent => $d1) {
         foreach ($d1 as $d) {
             if ($this->_registry->packageExists($d[0][0]['package'], $d[0][0]['channel'])) {
                 continue;
             }
             $remove[$parent] = true;
         }
     }
     // next remove any packages from the parents list that are not passed in for
     // uninstallation
     foreach ($allparents as $parent => $d1) {
         foreach ($d1 as $d) {
             foreach ($params as $param) {
                 if (strtolower($param->getChannel()) == $d[0][0]['channel'] && strtolower($param->getPackage()) == $d[0][0]['package']) {
                     // found it
                     continue 3;
                 }
             }
             $remove[$parent] = true;
         }
     }
     // remove all packages whose dependencies fail
     // save which ones failed for error reporting
     $badchildren = array();
     do {
         $fail = false;
         foreach ($remove as $package => $unused) {
             if (!isset($allparents[$package])) {
                 continue;
             }
             foreach ($allparents[$package] as $kid => $d1) {
                 foreach ($d1 as $depinfo) {
                     if ($depinfo[1]['type'] != 'optional') {
                         if (isset($badchildren[$kid])) {
                             continue;
                         }
                         $badchildren[$kid] = true;
                         $remove[$kid] = true;
                         $fail = true;
                         continue 2;
                     }
                 }
             }
             if ($fail) {
                 // start over, we removed some children
                 continue 2;
             }
         }
     } while ($fail);
     // next, construct the list of packages that can't be uninstalled
     $badpackages = array();
     $save = $this->_currentPackage;
     foreach ($perpackagelist as $package => $packagedeps) {
         foreach ($packagedeps as $parent) {
             if (!isset($remove[$parent[0]])) {
                 continue;
             }
             $packagename = $this->_registry->parsePackageName($parent[0]);
             $packagename['channel'] = $this->_registry->channelAlias($packagename['channel']);
             $pa = $this->_registry->getPackage($packagename['package'], $packagename['channel']);
             $packagename['package'] = $pa->getPackage();
             $this->_currentPackage = $packagename;
             // parent is not present in uninstall list, make sure we can actually
             // uninstall it (parent dep is optional)
             $parentname['channel'] = $this->_registry->channelAlias($parent[1]['dep']['channel']);
             $pa = $this->_registry->getPackage($parent[1]['dep']['name'], $parent[1]['dep']['channel']);
             $parentname['package'] = $pa->getPackage();
             $parent[1]['dep']['package'] = $parentname['package'];
             $parent[1]['dep']['channel'] = $parentname['channel'];
             if ($parent[1]['type'] == 'optional') {
                 $test = $this->_validatePackageUninstall($parent[1]['dep'], false, $dl);
                 if ($test !== true) {
                     $badpackages[$package]['warnings'][] = $test;
                 }
             } else {
                 $test = $this->_validatePackageUninstall($parent[1]['dep'], true, $dl);
                 if ($test !== true) {
                     $badpackages[$package]['errors'][] = $test;
                 }
             }
         }
     }
     $this->_currentPackage = $save;
     $dl->___uninstall_package_cache = $badpackages;
     if (isset($badpackages[$memyselfandI])) {
         if (isset($badpackages[$memyselfandI]['warnings'])) {
             foreach ($badpackages[$memyselfandI]['warnings'] as $warning) {
                 $dl->log(0, $warning[0]);
             }
         }
         if (isset($badpackages[$memyselfandI]['errors'])) {
             foreach ($badpackages[$memyselfandI]['errors'] as $error) {
                 if (is_array($error)) {
                     $dl->log(0, $error[0]);
                 } else {
                     $dl->log(0, $error->getMessage());
                 }
             }
             if (isset($this->_options['nodeps']) || isset($this->_options['force'])) {
                 return $this->warning('warning: %s should not be uninstalled, other installed packages depend ' . 'on this package');
             }
             return $this->raiseError('%s cannot be uninstalled, other installed packages depend on this package');
         }
     }
     return true;
 }