def install(self): try: r = Requirement(self.req) updater = Updater(skip=True) if self.upgrading: updater.remove_files(self.req) r.install() # Now let's install dependencies Installer._install_deps(r.reqset, r.name, updater) logger.success('{0} installed successfully', r.name) except (KeyboardInterrupt, Exception) as e: try: msg = e.args[0] except IndexError: msg = repr(e) if isinstance(e, KeyboardInterrupt): logger.warn('Process interrupted...') else: logger.warn('Error: An error occurred during the {0} of {1}: {2}', 'upgrading' if self.upgrading else 'installation', self.req, msg) if self.upgrading: logger.info('Restoring files...') updater.restore_files(self.req) else: logger.info('Removing broken files...') Uninstaller(self.req).uninstall() logger.error(msg, exc=InstallationError)
def upgrade(self, package_name, json, version): ''' Upgrade a package to the most recent version. ''' logger.info('Removing {0} old version', package_name) self.remove_files(package_name) args_manager['install']['upgrade'] = True logger.info('Upgrading {0} to {1}', package_name, version) logger.indent += 8 for release in json['urls']: logger.info('Installing {0}...', release['filename']) logger.indent += 4 try: Installer.from_url(release['url']) break except Exception as e: try: msg = e.args[0] except IndexError: msg = repr(e) logger.error('Error: An error occurred while installing {0}: {1}', package_name, msg) logger.info('Trying another file...') logger.indent -= 4 else: logger.warn('Error: Did not find any installable release on PyPI for {0}', package_name) try: Requirement('{0}=={1}'.format(package_name, version))._install_from_links(args_manager['install']['packages_url']) except Exception as e: logger.fatal('Error: {0}', e, exc=InstallationError) logger.info('Restoring uninstalled files') self.restore_files(package_name) logger.indent = 0
def uninstall(self): path_re = re.compile(r'\./{0}-[\d\w\.]+-py\d\.\d.egg'.format(self.name), re.I) path_re2 = re.compile(r'\.{0}'.format(self.name), re.I) to_del = self.find_files() if not to_del: logger.warn('{0}: did not find any files to delete', self.name) raise PygError logger.info('Uninstalling {0}', self.name) logger.indent += 8 for d in to_del: logger.info(d) logger.indent -= 8 do_it = logger.ask('Proceed', bool=('remove files', 'cancel'), dont_ask=args_manager['install']['yes']) if do_it: for d in to_del: try: logger.verbose('Deleting: {0}', d) shutil.rmtree(d) except OSError: ## It is not a directory try: os.remove(d) except OSError: logger.error('Error: cannot delete {0}', d) logger.verbose('Removing egg path from easy_install.pth...') with open(EASY_INSTALL) as f: lines = f.readlines() with open(EASY_INSTALL, 'w') as f: for line in lines: if path_re.match(line) or path_re2.match(line): continue f.write(line) logger.success('{0} uninstalled succesfully', self.name) else: logger.info('{0} has not been uninstalled', self.name)
def find(self): def _get_all(url): match = self._pkg_re.search(url) if match is None: return None, None, None return map(match.group, ('package_name', 'version', 'ext')) def _remove_query(url): return urlparse.urlunsplit(urlparse.urlsplit(url)[:3] + ('',) * 2) def _get_version(filename): ## A bit hacky but there is no solution because some packages ## are in the form {package_name}-{version}-{something_else}-{?pyx.y}.{ext} ## and we cannot predict where is the version in that mess. _version_re = re.compile(r'\d[\.\d\w]*') parts = name(filename).split('-') for part in parts: match = _version_re.search(part) if match is not None: return match.group() found = list(self.package_manager.find()) if not found: logger.warn('Warning: did not find any files on PyPI') for link in get_links(self.name, args_manager['install']['packages_url']): package_name = _remove_query(link).split('/')[-1] version = _get_version(package_name) e = ext(package_name) if package_name is None or version is None: package_name, version, e = _get_all(link) found.append((version, package_name, None, link, e)) return found
def search_func(query, exact, show_all_version): def _pypi_order(item): # this is the old implementation, that looks buggy (try on "sphinx") return item['_pypi_ordering'] def _pkgresources_order(item): return (item[0],) + item[2].v res = sorted(PyPIXmlRpc(index_url=args_manager['install']['index_url']).search({'name': query, 'summary': query}, 'or')) processed = {} for release in res: name, version, summary = release['name'], Version(release['version']), release['summary'] ## We have already parsed a different version if name in processed: if show_all_version: processed[name].append((version, summary)) elif version > processed[name][0][0]: processed[name] = [(version, summary)] continue ## This is the first time processed[name] = [(version, summary)] pattern = re.compile('$|'.join(query) + '$') results = [] for name, values in processed.iteritems(): try: _installed = Version(pkg_resources.get_distribution(name).version) except pkg_resources.DistributionNotFound: _installed = None except Exception: logger.warn("WARN: Can't get package data for %r"%name) _installed = None if exact: if pattern.match(name) is None: continue for version in values: if not _installed: dec = '' elif _installed == version[0]: dec = '@' else: dec = '*' results.append((name, dec, version[0], version[1])) results = sorted(results, key=_pkgresources_order) output = '\n'.join('{0} {1}{2} - {3}'.format(name, dec, version, summary) for name, dec, version, summary in results) return sys.stdout.write(output + '\n')
def link(path): path = os.path.abspath(path) if not os.path.exists(path): logger.error('{0} does not exist', path) if not os.path.exists(PYG_LINKS): if not os.path.exists(os.path.dirname(PYG_LINKS)): os.makedirs(os.path.dirname(PYG_LINKS)) open(PYG_LINKS, 'w').close() path = os.path.abspath(path) logger.info('Linking {0} in {1}...', path, PYG_LINKS) if path in open(PYG_LINKS, 'r').read(): logger.warn('{0} is already linked, exiting now...', path) with open(PYG_LINKS, 'a') as f: f.write(path) f.write('\n')
def load(self, path): ''' Load options from a config file. The syntax is as follows:: [section_name] option=value If a option is shared between two or more section you can also write:: [section1 & section2 & section_n] option=value Real example:: [install] upgrade_all=True [remove] yes=True The option tree is in the protected variable :attr:`OPTS`. ''' cp = ConfigParser.ConfigParser() with open(path) as f: cp.readfp(f, os.path.basename(path)) for section in cp.sections(): if '&' in section: sections = [s.strip() for s in section.split('&')] else: sections = [section] for s in sections: if s not in self._OPTS: logger.warn('Warning: section does not exist: {0}', section) continue for option, value in cp.items(section): option = option.replace('-', '_') if option not in self._OPTS[s]: logger.warn('Warning: section {0} does not have such option: {1}', s, option) continue if value not in self.NOT_BOOL: if value in ('False', '0', 'false'): value = False else: value = bool(value) if s == 'install' and option == 'upgrade_all': self._OPTS['install']['upgrade'] = True self._OPTS[s][option] = value
def download(self, dest): dest = os.path.abspath(dest) files = self.files() ## We need a placeholder because of the nested for loops success = False for p in self.pref: if success: break if not files[p]: logger.warn('{0} files not found. Continue searching...', p) continue for v, name, hash, url in files[p]: if success: break if p == '.egg' and not right_egg(name): logger.info('Found egg file for another Python version: {0}. Continue searching...', version_egg(name)) continue try: data = download(url, 'Retrieving data for {0}'.format(self.name)).getvalue() except (urllib2.URLError, urllib2.HTTPError) as e: logger.debug('urllib2 error: {0}', e.args) continue if not data: logger.debug('debug: Request failed') continue if not os.path.exists(dest): os.makedirs(dest) try: # Fix for packages with no version in the name if '-' not in name: name = '{0}-{1}{2}'.format(name, v, p) logger.info('Writing data into {0}', name) with open(os.path.join(dest, name), 'w') as f: f.write(data) except (IOError, OSError): logger.debug('debug: Error while writing data') continue logger.success('{0} downloaded successfully', self.name) success = True self.downloaded_name = name self.downloaded_version = v
def from_req_file(filepath): path = os.path.abspath(filepath) not_installed = set() parser = init_parser() with open(path) as f: logger.info('{0}:', path) for line in f: line = line.strip() if line.startswith('#'): logger.debug('debug: Comment found: {0}', line) continue try: logger.indent = 8 logger.info('Installing: {0}', line) logger.indent = 16 parser.dispatch(argv=['install'] + line.split()) except AlreadyInstalled: continue except InstallationError: not_installed.add(line) except SystemExit as e: if e.code != 0: logger.warn('W: {0} tried to raise SystemExit: skipping installation') else: logger.info('{0} tried to raise SystemExit, but the exit code was 0') if not_installed: logger.warn('These packages have not been installed:') logger.indent = 8 for req in not_installed: logger.warn(req) logger.indent = 0 raise InstallationError()