Commit c467b34c by Sébastien Eustace

Add hash check when installing/updating packages

parent 15f31faa
# Change Log # Change Log
## [Unreleased]
### Changed
- Added hashes check when installing packages.
## [0.4.2] - 2018-03-10 ## [0.4.2] - 2018-03-10
### Fixed ### Fixed
......
import os
import tempfile
from subprocess import CalledProcessError
from poetry.utils.venv import Venv from poetry.utils.venv import Venv
from .base_installer import BaseInstaller from .base_installer import BaseInstaller
...@@ -9,29 +14,69 @@ class PipInstaller(BaseInstaller): ...@@ -9,29 +14,69 @@ class PipInstaller(BaseInstaller):
self._venv = venv self._venv = venv
self._io = io self._io = io
def install(self, package): def install(self, package, update=False):
args = ['install', self.requirement(package), '--no-deps'] args = ['install', '--no-deps']
if package.source_type == 'legacy' and package.source_url: if package.source_type == 'legacy' and package.source_url:
args += ['--index-url', package.source_url] args += ['--index-url', package.source_url]
if update:
args.append('-U')
if package.hashes and not package.source_type:
# Format as a requirements.txt
# We need to create a requirements.txt file
# for each package in order to check hashes.
# This is far from optimal but we do not have any
# other choice since this is the only way for pip
# to verify hashes.
req = self.create_temporary_requirement(package)
args += ['-r', req]
try:
self.run(*args) self.run(*args)
finally:
os.unlink(req)
else:
args.append(self.requirement(package))
def update(self, source, target): self.run(*args)
args = ['install', self.requirement(target), '--no-deps', '-U']
if target.source_type == 'legacy' and target.source_url:
args += ['--index-url', target.source_url]
self.run('install', self.requirement(target), '--no-deps', '-U') def update(self, _, target):
self.install(target, update=True)
def remove(self, package): def remove(self, package):
try:
self.run('uninstall', package.name, '-y') self.run('uninstall', package.name, '-y')
except CalledProcessError as e:
if 'not installed' in str(e):
return
raise
def run(self, *args) -> str: def run(self, *args, **kwargs) -> str:
return self._venv.run('pip', *args) return self._venv.run('pip', *args, **kwargs)
def requirement(self, package, formatted=False) -> str:
if formatted and not package.source_type == 'git':
req = f'{package.name}=={package.version}'
for h in package.hashes:
req += f' --hash sha256:{h}'
req += '\n'
return req
def requirement(self, package) -> str:
if package.source_type == 'git': if package.source_type == 'git':
return f'git+{package.source_url}@{package.source_reference}' \ return f'git+{package.source_url}@{package.source_reference}' \
f'#egg={package.name}' f'#egg={package.name}'
return f'{package.name}=={package.version}' return f'{package.name}=={package.version}'
def create_temporary_requirement(self, package):
fd, name = tempfile.mkstemp('reqs.txt', f'{package.name}-{package.version}')
with open(fd, 'w') as f:
f.write(self.requirement(package, formatted=True))
return name
...@@ -73,12 +73,16 @@ class Venv: ...@@ -73,12 +73,16 @@ class Venv:
""" """
return self._bin('pip') return self._bin('pip')
def run(self, bin: str, *args) -> str: def run(self, bin: str, *args, **kwargs) -> str:
""" """
Run a command inside the virtual env. Run a command inside the virtual env.
""" """
cmd = [self._bin(bin)] + list(args) cmd = [self._bin(bin)] + list(args)
output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
output = subprocess.check_output(
cmd, stderr=subprocess.STDOUT,
**kwargs
)
return output.decode() return output.decode()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment