PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/vem/manager.py

https://bitbucket.org/deets/virtualenvmanager
Python | 428 lines | 405 code | 17 blank | 6 comment | 21 complexity | f9a4c7cd3a0caf3f23f760a88f9fe6f1 MD5 | raw file
  1. """
  2. notes on windows
  3. ----------------
  4. A standard windows python installation is assumed. This means that the python directory contains
  5. a directory called 'Scripts' which is the default location for executables that are installed
  6. by distutils.
  7. usage on windows
  8. ----------------
  9. create a new virtualenv via 'vem create <virtenv_name>'
  10. An activation script named 'activate_<virtenv_name>.bat' will be placed into the standard Scripts
  11. directory.
  12. Running 'vem remove <virtenv_name>' will remove that script.
  13. The virtual environment is activated by calling 'activate_<virtenv_name>.bat' (assuming the
  14. Scripts directory is in the path).
  15. """
  16. from __future__ import print_function
  17. import sys
  18. import os
  19. import subprocess
  20. import glob
  21. import optparse
  22. import shutil
  23. import platform
  24. import logging
  25. import virtualenv
  26. virtualenv.logger = virtualenv.Logger([])
  27. is_windows = platform.system() == 'Windows'
  28. version = "%i.%i" % sys.version_info[:2]
  29. _ACTIVE_MARKER = ".active"
  30. _DEFAULT_BASE = "~/.virtualenvs%s" % version
  31. if is_windows:
  32. _ACTIVE_MARKER = "_active"
  33. _DEFAULT_BASE = os.path.join(os.environ.get('USERPROFILE', 'C:\\'),'_virtualenvs%s') % version
  34. class Manager(object):
  35. ACTIVE_MARKER = _ACTIVE_MARKER
  36. DEFAULT_BASE = _DEFAULT_BASE
  37. def __init__(self):
  38. self.opts = None
  39. self._active_ve = None
  40. self._environments = None
  41. self._base_path = None
  42. self.restargs = None
  43. if is_windows:
  44. # only usefull if no cygwin python etc. is used
  45. self.python_base = os.path.split(os.path.split(os.__file__)[0])[0]
  46. def run(self):
  47. self.opts, rest = self.parser.parse_args(sys.argv[1:])
  48. if len(rest) < 1:
  49. self.error("Please give a subcommand!")
  50. command = rest[0]
  51. self.restargs = rest[1:]
  52. def unknown_command():
  53. self.unknown_command(command)
  54. command_method = getattr(self, "cmd_%s" % command, unknown_command)
  55. command_method()
  56. def cmd_list(self):
  57. bp = self.base_path
  58. quiet = self.opts.quiet
  59. active_ve = self.active_ve
  60. if os.path.exists(bp):
  61. envs = self.environments
  62. if envs:
  63. if not quiet:
  64. print("Existing environments:\n")
  65. for env in envs:
  66. sys.stdout.write(env)
  67. if not quiet and env == active_ve:
  68. sys.stdout.write(" *")
  69. sys.stdout.write("\n")
  70. elif not quiet:
  71. print("No environments")
  72. if not quiet:
  73. print()
  74. def cmd_create(self, vems=None):
  75. if vems is None:
  76. vems = self.restargs
  77. bp = self.base_path
  78. if not os.path.exists(bp):
  79. os.mkdir(bp)
  80. for vem in vems:
  81. home_path = os.path.join(bp, vem)
  82. virtualenv.create_environment(
  83. home_path, site_packages=not self.opts.no_site_packages)
  84. if is_windows:
  85. virtualenv_name = [x for x in self.restargs if not x.startswith('-')][0]
  86. newname = 'activate_%s.bat' % virtualenv_name
  87. src = os.path.join(bp,virtualenv_name,'Scripts','activate.bat')
  88. dst = os.path.join(self.python_base,'Scripts',newname)
  89. shutil.copyfile(src, dst)
  90. def cmd_remove(self, vems=None):
  91. if vems is None:
  92. vems = self.restargs
  93. if len(vems) < 1:
  94. self.error("Please give existing VE(s) as argument.")
  95. for ve in vems:
  96. if ve not in self.environments:
  97. self.error("No such environment: %s" % ve, dont_exit=True)
  98. continue
  99. shutil.rmtree(os.path.join(self.base_path, ve))
  100. if self.active_ve == ve:
  101. self.active_ve = ""
  102. if is_windows:
  103. name = 'activate_%s.bat' % ve
  104. dst = os.path.join(self.python_base,'Scripts',name)
  105. if os.path.exists(dst):
  106. os.unlink(os.path.join(self.python_base,'Scripts', name))
  107. def cmd_recreate(self):
  108. if len(self.restargs) < 1:
  109. self.error("Please give existing VE(s) as argument.")
  110. for ve in self.restargs:
  111. self.cmd_remove([ve])
  112. self.cmd_create([ve])
  113. def cmd_location(self):
  114. """
  115. Where the current active VE is located.
  116. """
  117. if "VIRTUAL_ENV" in os.environ:
  118. print(os.environ["VIRTUAL_ENV"])
  119. else:
  120. environments = self.environments
  121. active = self.active_ve
  122. if active not in environments:
  123. sys.stderr("Can't determine active VE!")
  124. sys.exit(1)
  125. print(os.path.join(self.base_path, active))
  126. def cmd_compare(self):
  127. vems = self.restargs
  128. assert len(vems) == 2
  129. envs = self.environments
  130. for vem in vems:
  131. assert vem in envs
  132. left = glob.glob(os.path.join(self.base_path, vems[0], "lib", "python*", "site-packages"))[0]
  133. right = glob.glob(os.path.join(self.base_path, vems[1], "lib", "python*", "site-packages"))[0]
  134. ignore_equal = self.opts.ignore_equal
  135. left = sorted(os.listdir(left))
  136. right = sorted(os.listdir(right))
  137. lit = iter(left)
  138. rit = iter(right)
  139. def next(it):
  140. name = next(it)
  141. base = name.split("-")[0]
  142. return name, base
  143. leftmax = max(len(e) for e in left)
  144. def output(left, right):
  145. if left is None:
  146. left = " " * leftmax
  147. else:
  148. left = left + (" " * (leftmax - len(left)))
  149. if right is None:
  150. right = ""
  151. print("%s | %s" % (left, right))
  152. left, left_base = next(lit)
  153. right, right_base = next(rit)
  154. try:
  155. while True:
  156. while left_base < right_base:
  157. output(left, None)
  158. left, left_base = next(lit)
  159. while right_base < left_base:
  160. output(None, right)
  161. right, right_base = next(rit)
  162. while left_base == right_base:
  163. if left < right:
  164. output(left, None)
  165. left, left_base = next(lit)
  166. continue
  167. elif right < left:
  168. output(None, right)
  169. right, right_base = next(rit)
  170. continue
  171. elif not ignore_equal:
  172. output(left, right)
  173. left, left_base = next(lit)
  174. try:
  175. right, right_base = next(rit)
  176. except StopIteration:
  177. output(left, None)
  178. for rest in lit:
  179. output(rest, None)
  180. raise
  181. except StopIteration:
  182. pass
  183. for rest in lit:
  184. output(rest, None)
  185. for rest in rit:
  186. output(None, rest)
  187. def cmd_activate(self):
  188. envs = self.environments
  189. try:
  190. to_activate = self.restargs[0]
  191. if to_activate not in envs:
  192. self.error("No such environment: %s" % to_activate)
  193. self.active_ve = to_activate
  194. bindir = 'bin'
  195. activate_command = os.path.join(self.base_path, to_activate, bindir, "activate")
  196. if not self.opts.quiet:
  197. sys.stdout.write("""Please execute the following command to activate the environment
  198. in the shell:
  199. source """)
  200. sys.stdout.write(activate_command)
  201. if not self.opts.quiet:
  202. sys.stdout.write("\n")
  203. except IndexError:
  204. self.error("You need to give a ve name")
  205. def cmd_scripts(self):
  206. command = os.path.basename(sys.argv[0])
  207. scripts = """function %(command)s_activate() {
  208. cmd=`%(command)s activate -q $@`
  209. source $cmd
  210. }
  211. _%(command)s_activate()
  212. {
  213. local cur
  214. COMPREPLY=()
  215. cur="${COMP_WORDS[COMP_CWORD]}"
  216. opts=`%(command)s list -q`
  217. COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
  218. return 0
  219. }
  220. complete -F _%(command)s_activate %(command)s_activate
  221. #
  222. # Activate the virtualenv whose name is the current working directory
  223. function %(command)sac()
  224. {
  225. deactivate;
  226. vename=`pwd | awk -F / "{print \\$NF}"`
  227. %(command)s_activate $vename
  228. }
  229. #
  230. # Remove, recreate, and activate the virtualenv whose name is the
  231. # current working directory, then run "python setup.py develop".
  232. function %(command)sfresh()
  233. {
  234. deactivate;
  235. vename=`pwd | awk -F / "{print \\$NF}"`
  236. %(command)s remove $vename
  237. %(command)s create $vename
  238. %(command)s_activate $vename
  239. python setup.py develop
  240. }
  241. """ % dict(command=command)
  242. print(scripts)
  243. @property
  244. def base_path(self):
  245. if self._base_path is None:
  246. if self.opts is None or self.opts.base_path is None:
  247. bp = os.environ.get("VEM_BASE_PATH", self.DEFAULT_BASE)
  248. else:
  249. bp = self.opts.base_path
  250. self._base_path = os.path.abspath(os.path.expanduser(bp))
  251. return self._base_path
  252. @property
  253. def environments(self):
  254. if self._environments is None:
  255. self._environments = envs = []
  256. bp = self.base_path
  257. if os.path.exists(bp) and os.path.isdir(bp):
  258. for fname in glob.glob(os.path.join(bp, "*")):
  259. name = os.path.basename(fname)
  260. if name == self.ACTIVE_MARKER:
  261. continue
  262. envs.append(name)
  263. return self._environments
  264. @property
  265. def active_ve(self):
  266. """
  267. Get or set the name of the active VE.
  268. """
  269. if self._active_ve is None:
  270. fname = os.path.join(self.base_path, self.ACTIVE_MARKER)
  271. if os.path.exists(fname) and os.path.isfile(fname):
  272. inf = open(fname)
  273. active_ve = inf.read().strip()
  274. inf.close()
  275. else:
  276. active_ve = ""
  277. self._active_ve = active_ve
  278. return self._active_ve
  279. @active_ve.setter
  280. def active_ve(self, value):
  281. fname = os.path.join(self.base_path, self.ACTIVE_MARKER)
  282. if os.path.exists(fname) and os.path.isfile(fname):
  283. outf = open(fname, "w")
  284. outf.write(value.strip())
  285. outf.close()
  286. self._active_ve = value
  287. @property
  288. def active_prefix(self):
  289. av = self.active_ve
  290. if av:
  291. return os.path.join(self.base_path, av)
  292. def unknown_command(self, command):
  293. """
  294. Unknown command.
  295. """
  296. self.error("Unknown command '%s'" % command)
  297. def error(self, message, dont_exit=False):
  298. sys.stderr.write("\n")
  299. sys.stderr.write(message)
  300. sys.stderr.write("\n")
  301. if not dont_exit:
  302. sys.exit(1)
  303. def python(self):
  304. """
  305. """
  306. try:
  307. if self.active_prefix:
  308. bindir = 'bin'
  309. if is_windows:
  310. bindir = 'Scripts'
  311. exe = glob.glob(os.path.join(self.active_prefix, bindir, "python*"))[0]
  312. os.execv(exe, [exe] + sys.argv[1:])
  313. else:
  314. # provoke the error-message
  315. [][0]
  316. except IndexError:
  317. raise Exception("No interpreter found for VE %r" % self.active_ve)
  318. COMMANDS = [name[4:] for name in locals().keys() if name[:4] == "cmd_"]
  319. USAGE = """usage: %%prog <command> [options] <args>
  320. where command is one of:
  321. %s""" % "\n ".join(COMMANDS)
  322. parser = optparse.OptionParser(usage=USAGE)
  323. parser.add_option("-b", "--base-path", action="store", default=None)
  324. parser.add_option("-q", "--quiet", action="store_true", default=False, help="Quiet output mode")
  325. parser.add_option("-S", "--no-site-packages", action="store_true", default=False,
  326. help="Don't make packages in site-packages available to this venv")
  327. parser.add_option("-D", "--use-distribute", action="store_true", default=False,
  328. help="Use Distribute instead of setuptools.")
  329. parser.add_option("-i", "--ignore-equal",
  330. action="store_true",
  331. default=False,
  332. help="When comparing, only report diffing module.")
  333. def main():
  334. Manager().run()
  335. def python():
  336. Manager().python()