Skip to content

Instantly share code, notes, and snippets.

@Jc2k
Last active January 3, 2016 11:09
Show Gist options
  • Save Jc2k/8454645 to your computer and use it in GitHub Desktop.
Save Jc2k/8454645 to your computer and use it in GitHub Desktop.
Thinking about python virtualenvs and node/npm
#! /usr/bin/env python
import os
import tempfile
import shutil
import tarfile
import sys
import subprocess
import optparse
NPM_URL = "http://registry.npmjs.org/npm/-/npm-1.3.23.tgz"
def search_path(b):
path = os.environ.get("PATH", "/usr/bin").split(":")
for p in path:
binary = os.path.join(p, b)
if os.path.exists(binary):
return binary
def bootstrap_npm_from_internet(virtualenv_dir, node=None):
# This method can install NPM when no NPM is available. In practice this
# doesn't happen any more - npm ships with nodejs these days
node = node or search_path("node")
if not node:
return False
d = tempfile.mkdtemp(dir=virtualenv_dir)
try:
package_tgz = os.path.join(d, "npm.tgz")
package_dir = os.path.join(d, "npm")
cli_js = os.path.join(package_dir, "package", "cli.js")
print("-> Downloading npm bootstrap (%s)" % NPM_URL)
try:
import urllib.request
urllib.request.urlretrieve(NPM_URL, package_tgz)
except ImportError:
import urllib
urllib.urlretrieve(NPM_URL, package_tgz)
print("-> Extracting")
t = tarfile.open(package_tgz)
t.extractall(package_dir)
print("-> Installing")
subprocess.check_call([node, cli_js, "install", "-g", "--prefix", virtualenv_dir, "npm"])
finally:
shutil.rmtree(d)
def bootstrap_npm_from_npm(virtualenv_dir):
# Given a working npm, install it somewhere else
print("-> Installing")
npm = search_path("npm")
if not npm:
return False
subprocess.check_call([npm, "install", "-g", "--prefix", virtualenv_dir, "npm"])
return True
def setup_virtualenv(virtualenv_dir, node=None):
virtualenv_dir = os.path.abspath(virtualenv_dir)
bin_dir = os.path.join(virtualenv_dir, "bin")
lib_dir = os.path.join(virtualenv_dir, "lib")
node_modules_dir = os.path.join(lib_dir, "node_modules")
if not os.path.exists(os.path.join(bin_dir, "npm")):
if not bootstrap_npm_from_npm(virtualenv_dir):
if not bootstrap_npm_from_internet(virtualenv_dir, node=node):
print("Cannot find existing 'npm'/'node'")
sys.exit(1)
print("-> Setting npm default settings")
with open(os.path.join(node_modules_dir, "npm", "npmrc"), "w") as fp:
fp.write("\n".join([
"prefix=%s" % virtualenv_dir,
"global=true",
]))
print("Done.")
if __name__ == "__main__":
p = optparse.OptionParser()
p.add_option("-n", "--node")
opts, args = p.parse_args()
if len(args) != 1:
p.print_help()
sys.exit(1)
setup_virtualenv(args[0], node=opts.node)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment