2015-12-14 21:43:16 +03:00
|
|
|
#!/usr/bin/env python
|
|
|
|
from __future__ import print_function
|
|
|
|
import json
|
|
|
|
import re
|
|
|
|
import sys
|
|
|
|
from bisect import bisect
|
|
|
|
from datetime import datetime
|
|
|
|
from datetime import timedelta
|
2015-12-16 15:51:45 +03:00
|
|
|
import ssl
|
2015-12-14 21:43:16 +03:00
|
|
|
|
2015-12-15 00:23:08 +03:00
|
|
|
try:
|
2015-12-16 15:51:45 +03:00
|
|
|
from urllib.request import Request, build_opener, HTTPSHandler, URLError
|
2015-12-15 00:23:08 +03:00
|
|
|
except ImportError:
|
2015-12-16 15:51:45 +03:00
|
|
|
from urllib2 import Request, build_opener, HTTPSHandler, URLError
|
2015-12-15 00:23:08 +03:00
|
|
|
|
2015-12-15 12:26:17 +03:00
|
|
|
from pip.commands.uninstall import UninstallCommand
|
2015-12-14 21:43:16 +03:00
|
|
|
from pip.commands.install import InstallCommand
|
2015-12-15 12:26:17 +03:00
|
|
|
from pip import get_installed_distributions
|
2015-12-14 21:43:16 +03:00
|
|
|
|
|
|
|
|
|
|
|
def get_releases(package_name):
|
2015-12-16 15:51:45 +03:00
|
|
|
url = 'https://pypi.python.org/pypi/%s/json' % package_name
|
|
|
|
|
|
|
|
ssl_context = HTTPSHandler(
|
|
|
|
context=ssl.SSLContext(ssl.PROTOCOL_TLSv1))
|
|
|
|
opener = build_opener(ssl_context)
|
|
|
|
|
|
|
|
retries = 10
|
|
|
|
while retries > 0:
|
|
|
|
try:
|
|
|
|
r = opener.open(Request(url))
|
|
|
|
break
|
|
|
|
except URLError:
|
|
|
|
retries -= 1
|
|
|
|
|
|
|
|
return json.loads(r.read().decode('utf8'))['releases']
|
2015-12-14 21:43:16 +03:00
|
|
|
|
|
|
|
|
|
|
|
def parse_iso8601(s):
|
|
|
|
return datetime(*map(int, re.split('[^\d]', s)))
|
|
|
|
|
|
|
|
|
|
|
|
def select_version(select_date, package_name):
|
|
|
|
versions = []
|
|
|
|
for version, dists in get_releases(package_name).items():
|
|
|
|
date = [parse_iso8601(d['upload_time']) for d in dists]
|
|
|
|
if date:
|
|
|
|
versions.append((sorted(date)[0], version))
|
|
|
|
|
|
|
|
versions = sorted(versions)
|
|
|
|
min_date = versions[0][0]
|
|
|
|
if select_date < min_date:
|
|
|
|
raise Exception('invalid select_date: %s, must be '
|
|
|
|
'%s or newer.' % (select_date, min_date))
|
|
|
|
|
|
|
|
return versions[bisect([x[0] for x in versions], select_date) - 1][1]
|
|
|
|
|
|
|
|
|
2015-12-15 12:26:17 +03:00
|
|
|
installed_packages = [
|
|
|
|
package.project_name
|
|
|
|
for package in
|
|
|
|
get_installed_distributions()
|
|
|
|
if (not package.location.endswith('dist-packages') and
|
|
|
|
package.project_name not in ('pip', 'setuptools'))
|
|
|
|
]
|
|
|
|
|
2015-12-16 14:46:12 +03:00
|
|
|
if installed_packages:
|
|
|
|
pip = UninstallCommand()
|
|
|
|
options, args = pip.parse_args(installed_packages)
|
|
|
|
options.yes = True
|
|
|
|
|
|
|
|
try:
|
|
|
|
pip.run(options, args)
|
|
|
|
except OSError as e:
|
|
|
|
if e.errno != 13:
|
|
|
|
raise e
|
|
|
|
print("You lack permissions to uninstall this package. Perhaps run with sudo? Exiting.")
|
|
|
|
exit(13)
|
2015-12-15 12:26:17 +03:00
|
|
|
|
|
|
|
|
2015-12-14 21:43:16 +03:00
|
|
|
date = parse_iso8601(sys.argv[1])
|
2015-12-15 12:26:17 +03:00
|
|
|
packages = {p: select_version(date, p) for p in sys.argv[2:]}
|
|
|
|
args = ['=='.join(a) for a in packages.items()]
|
2015-12-14 21:43:16 +03:00
|
|
|
|
2015-12-15 12:26:17 +03:00
|
|
|
cmd = InstallCommand()
|
|
|
|
options, args = cmd.parse_args(args)
|
2015-12-14 21:43:16 +03:00
|
|
|
options.ignore_installed = True
|
2015-12-15 12:26:17 +03:00
|
|
|
options.force_reinstall = True
|
2015-12-14 21:43:16 +03:00
|
|
|
|
|
|
|
try:
|
2015-12-15 12:26:17 +03:00
|
|
|
print(cmd.run(options, args))
|
2015-12-14 21:43:16 +03:00
|
|
|
except OSError as e:
|
|
|
|
if e.errno != 13:
|
|
|
|
raise e
|
|
|
|
print("You lack permissions to uninstall this package. Perhaps run with sudo? Exiting.")
|
|
|
|
exit(13)
|