Skip to content

Commit

Permalink
Merge f2cab00 into 56e6f8e
Browse files Browse the repository at this point in the history
  • Loading branch information
juancarlospaco committed Apr 14, 2018
2 parents 56e6f8e + f2cab00 commit 074f7db
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 2 deletions.
4 changes: 4 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,10 @@ Uses the ``django-admin.py`` script to start a new project named ``foo``, withou

Removes a virtualenv matching the given uuid from disk and cache index.

``fades --list-venvs``

List all virtualenvs, showing the information (UUID, timestamp, dependencies, interpreter, etc).


What if Python is updated in my system?
---------------------------------------
Expand Down
22 changes: 22 additions & 0 deletions fades/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import logging
import subprocess

from datetime import datetime
from urllib import request
from urllib.error import HTTPError

Expand Down Expand Up @@ -256,3 +257,24 @@ def check_pypi_exists(dependencies):
logger.error("%s doesn't exists in PyPI.", dependency)
return False
return True


def list_venvs(index_path):
"""List all venvs from an index file path and print info to stdout."""
if os.path.isfile(index_path):
tmplt = ("\nVirtualenv uuid:\t{uid}\n\ttimestamp:\t{dat}\n\tfull path:\t{pat}\n"
"\tdependencies:\t{pac}\n\tinterpreter:\t{pyv}\n\toptions:\t{opt}\n")
venv_info = ""
with open(index_path) as jotason:
for jotason_line in jotason:
v_dct_get = json.loads(jotason_line).get
venv_info += tmplt.format(
uid=v_dct_get("metadata")["env_path"][18:],
pat=v_dct_get("metadata")["env_path"],
pac=v_dct_get("installed"),
pyv=v_dct_get("interpreter"),
opt=v_dct_get("options"),
dat=datetime.fromtimestamp(v_dct_get("timestamp")).replace(
microsecond=0).astimezone().isoformat(" "))
print(venv_info)
return venv_info
7 changes: 6 additions & 1 deletion fades/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,14 @@ def go():
help=("Extra options to be supplied to python. (this option can be "
"used multiple times)"))
parser.add_argument('--rm', dest='remove', metavar='UUID',
help=("Remove a virtualenv by UUID."))
help=("Remove a virtualenv by UUID (see --list-venvs)."))
parser.add_argument('--clean-unused-venvs', action='store',
help=("This option remove venvs that haven't been used for more than "
"CLEAN_UNUSED_VENVS days. Appart from that, will compact usage "
"stats file.\n"
"When this option is present, the cleaning takes place at the "
"beginning of the execution."))
parser.add_argument('--list-venvs', action='store_true', help=("List all venvs"))
parser.add_argument('child_program', nargs='?', default=None)
parser.add_argument('child_options', nargs=argparse.REMAINDER)

Expand Down Expand Up @@ -161,6 +162,10 @@ def go():
logger.debug("Starting fades v. %s", fades.__version__)
logger.debug("Arguments: %s", args)

if args.list_venvs:
helpers.list_venvs(os.path.join(helpers.get_basedir(), 'venvs.idx'))
sys.exit(0)

# verify that the module is NOT being used from a virtualenv
if detect_inside_virtualenv(sys.prefix, getattr(sys, 'real_prefix', None),
getattr(sys, 'base_prefix', None)):
Expand Down
7 changes: 6 additions & 1 deletion man/fades.1
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ fades - A system that automatically handles the virtualenvs in the cases normall
[\fB--pip-options\fR=\fIoptions\fR]
[\fB--python-options\fR=\fIoptions\fR]
[\fB--check-updates\fR]
[\fB--list-venvs\fR]
[\fB--clean-unused-venvs\fR=\fImax_days_to_keep\fR]
[child_program [child_options]]

Expand Down Expand Up @@ -104,14 +105,18 @@ Extra options to be supplied to pip. (this option can beused multiple times)
.BR --python-options=\fIPYTHON_OPTION\fR
Extra options to be supplied to python. (this option can beused multiple times)

.TP
.TP
.BR --check-updates
Will check for updates in PyPI to verify if there are new versions for the requested dependencies. If a new version is available for a dependency, it will use it (if the dependency was requested without version) or just inform which new version is available (if the dependency was requested with a specific version).

.TP
.BR --clean-unused-venvs=\fIMAX_DAYS_TO_KEEP\fR
Will remove all virtualenvs that haven't been used for more than MAX_DAYS_TO_KEEP days.

.TP
.BR --list-venvs
List all virtualenvs, showing information (UUID, timestamp, path, dependencies, interpreter, etc).

.SH EXAMPLES

.TP
Expand Down
56 changes: 56 additions & 0 deletions tests/examples/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@

Virtualenv uuid: d1cf2e61-4ac5-467d-9b65-1a3c0e913bf3
timestamp: 2011-06-16 00:00:00-03:00
full path: /home/juan/.fades/d1cf2e61-4ac5-467d-9b65-1a3c0e913bf3
dependencies: {}
interpreter: /usr/bin/python3
options: {'pyvenv_options': [], 'virtualenv_options': []}

Virtualenv uuid: 032e6e2c-bc7e-4a7f-ad1d-66ecb9106884
timestamp: 2009-02-09 00:00:00-02:00
full path: /home/juan/.fades/032e6e2c-bc7e-4a7f-ad1d-66ecb9106884
dependencies: {}
interpreter: /usr/bin/python3
options: {'pyvenv_options': [], 'virtualenv_options': []}

Virtualenv uuid: 53c8f169-b105-4ed1-a7fc-25792b18fc4c
timestamp: 2001-06-17 00:00:00-03:00
full path: /home/juan/.fades/53c8f169-b105-4ed1-a7fc-25792b18fc4c
dependencies: {}
interpreter: /usr/bin/python3
options: {'pyvenv_options': [], 'virtualenv_options': []}

Virtualenv uuid: 8cc6666c-fb5e-474b-a8a7-217c9558d5e2
timestamp: 2017-08-05 00:00:00-03:00
full path: /home/juan/.fades/8cc6666c-fb5e-474b-a8a7-217c9558d5e2
dependencies: {}
interpreter: /usr/bin/python3
options: {'pyvenv_options': [], 'virtualenv_options': []}

Virtualenv uuid: 7a4a4eb8-b0d2-4d88-a890-4830278e0eb9
timestamp: 2015-09-06 00:00:00-03:00
full path: /home/juan/.fades/7a4a4eb8-b0d2-4d88-a890-4830278e0eb9
dependencies: {}
interpreter: /usr/bin/python3
options: {'pyvenv_options': [], 'virtualenv_options': []}

Virtualenv uuid: 7c10fa5f-037e-49b1-a9dd-3462c739e239
timestamp: 2007-01-15 00:00:00-03:00
full path: /home/juan/.fades/7c10fa5f-037e-49b1-a9dd-3462c739e239
dependencies: {}
interpreter: /usr/bin/python3
options: {'pyvenv_options': [], 'virtualenv_options': []}

Virtualenv uuid: 37de0f88-3db7-434a-a692-048aa35fbfe7
timestamp: 2002-07-08 00:00:00-03:00
full path: /home/juan/.fades/37de0f88-3db7-434a-a692-048aa35fbfe7
dependencies: {}
interpreter: /usr/bin/python3
options: {'pyvenv_options': [], 'virtualenv_options': []}

Virtualenv uuid: 000236c6-5ddb-4422-b210-93e09fab603f
timestamp: 2017-12-06 00:00:00-03:00
full path: /home/juan/.fades/000236c6-5ddb-4422-b210-93e09fab603f
dependencies: {}
interpreter: /usr/bin/python3
options: {'pyvenv_options': [], 'virtualenv_options': []}
8 changes: 8 additions & 0 deletions tests/examples/venvs.idx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{"timestamp": 1308193200, "installed": {}, "metadata": {"env_path": "/home/juan/.fades/d1cf2e61-4ac5-467d-9b65-1a3c0e913bf3", "env_bin_path": "/home/juan/.fades/d1cf2e61-4ac5-467d-9b65-1a3c0e913bf3/bin", "pip_installed": true}, "interpreter": "/usr/bin/python3", "options": {"pyvenv_options": [], "virtualenv_options": []}}
{"timestamp": 1234144800, "installed": {}, "metadata": {"env_path": "/home/juan/.fades/032e6e2c-bc7e-4a7f-ad1d-66ecb9106884", "env_bin_path": "/home/juan/.fades/032e6e2c-bc7e-4a7f-ad1d-66ecb9106884/bin", "pip_installed": true}, "interpreter": "/usr/bin/python3", "options": {"pyvenv_options": [], "virtualenv_options": []}}
{"timestamp": 992746800, "installed": {}, "metadata": {"env_path": "/home/juan/.fades/53c8f169-b105-4ed1-a7fc-25792b18fc4c", "env_bin_path": "/home/juan/.fades/53c8f169-b105-4ed1-a7fc-25792b18fc4c/bin", "pip_installed": true}, "interpreter": "/usr/bin/python3", "options": {"pyvenv_options": [], "virtualenv_options": []}}
{"timestamp": 1501902000, "installed": {}, "metadata": {"env_path": "/home/juan/.fades/8cc6666c-fb5e-474b-a8a7-217c9558d5e2", "env_bin_path": "/home/juan/.fades/8cc6666c-fb5e-474b-a8a7-217c9558d5e2/bin", "pip_installed": true}, "interpreter": "/usr/bin/python3", "options": {"pyvenv_options": [], "virtualenv_options": []}}
{"timestamp": 1441508400, "installed": {}, "metadata": {"env_path": "/home/juan/.fades/7a4a4eb8-b0d2-4d88-a890-4830278e0eb9", "env_bin_path": "/home/juan/.fades/7a4a4eb8-b0d2-4d88-a890-4830278e0eb9/bin", "pip_installed": true}, "interpreter": "/usr/bin/python3", "options": {"pyvenv_options": [], "virtualenv_options": []}}
{"timestamp": 1168830000, "installed": {}, "metadata": {"env_path": "/home/juan/.fades/7c10fa5f-037e-49b1-a9dd-3462c739e239", "env_bin_path": "/home/juan/.fades/7c10fa5f-037e-49b1-a9dd-3462c739e239/bin", "pip_installed": true}, "interpreter": "/usr/bin/python3", "options": {"pyvenv_options": [], "virtualenv_options": []}}
{"timestamp": 1026097200, "installed": {}, "metadata": {"env_path": "/home/juan/.fades/37de0f88-3db7-434a-a692-048aa35fbfe7", "env_bin_path": "/home/juan/.fades/37de0f88-3db7-434a-a692-048aa35fbfe7/bin", "pip_installed": true}, "interpreter": "/usr/bin/python3", "options": {"pyvenv_options": [], "virtualenv_options": []}}
{"timestamp": 1512529200, "installed": {}, "metadata": {"env_path": "/home/juan/.fades/000236c6-5ddb-4422-b210-93e09fab603f", "env_bin_path": "/home/juan/.fades/000236c6-5ddb-4422-b210-93e09fab603f/bin", "pip_installed": true}, "interpreter": "/usr/bin/python3", "options": {"pyvenv_options": [], "virtualenv_options": []}}
42 changes: 42 additions & 0 deletions tests/test_files/autogenerate_random_venvsidx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@


"""Tiny tool to autogenerate random 'venvs.idx' content for testing purposes."""


import os
from random import randint
from uuid import uuid4
from shutil import which
import datetime
import json


def main():
"""Build a valid random-ish Fades venvs.idx content."""
y3ar, h0me = datetime.date.today().year, os.path.join(os.path.expanduser("~"), ".fades")
venvs_idx = ""
for _ in range(randint(2, 9)):
random_envpath = os.path.join(h0me, str(uuid4()))
random_timestamp = int(datetime.datetime(year=randint(2000, y3ar),
month=randint(1, 12),
day=randint(1, 28)).timestamp())
venvs_idx += json.dumps({
"timestamp": random_timestamp,
"installed": {},
"metadata": {
"env_path": random_envpath,
"env_bin_path": os.path.join(random_envpath, "bin"),
"pip_installed": True
},
"interpreter": which("python3") or "/usr/bin/python3.6",
"options": {
"pyvenv_options": [],
"virtualenv_options": []
}
}) + "\n"
print(venvs_idx.strip())
return venvs_idx.strip()


if __name__ in "__main__":
main()
23 changes: 23 additions & 0 deletions tests/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,3 +375,26 @@ def test_redirect_response(self):
exists = helpers.check_pypi_exists(deps)
self.assertTrue(exists)
self.assertLoggedWarning("Got a (unexpected) HTTP_STATUS")


class ListVenvsTestCase(unittest.TestCase):

"""Utilities to list venvs."""

maxDiff, __slots__ = None, ()

@unittest.skipIf('TRAVIS' in os.environ,
"Travis weird scaping https://travis-ci.org/PyAr/fades/jobs/366371756#L764")
def test_list_venvs(self):
venvs_idx = os.path.join(PATH_TO_EXAMPLES, 'venvs.idx')
venvs_info = os.path.join(PATH_TO_EXAMPLES, 'output.txt')
str_list_venv = helpers.list_venvs(venvs_idx)
self.assertIsInstance(str_list_venv, str)
with open(venvs_info) as venvs_info_file:
self.assertEqual(str_list_venv, venvs_info_file.read())

def test_index_path_empty(self):
self.assertEqual(helpers.list_venvs(""), None)

def test_index_path_not_found(self):
self.assertEqual(helpers.list_venvs("directory_does_not_exist"), None)

0 comments on commit 074f7db

Please sign in to comment.