mirror of https://github.com/lukechilds/node.git
Browse Source
The old installer was a JS script, which didn't work if node had been cross-compiled for another architecture. Replace it with a python script. Fixes #3807.v0.8.7-release
Ben Noordhuis
13 years ago
3 changed files with 216 additions and 160 deletions
@ -0,0 +1,214 @@ |
|||
#!/usr/bin/env python |
|||
|
|||
import errno |
|||
import json |
|||
import os |
|||
import re |
|||
import shutil |
|||
import sys |
|||
|
|||
# set at init time |
|||
dst_dir = None |
|||
node_prefix = None # dst_dir without DESTDIR prefix |
|||
target_defaults = None |
|||
variables = None |
|||
|
|||
def abspath(*args): |
|||
path = os.path.join(*args) |
|||
return os.path.abspath(path) |
|||
|
|||
def load_config(): |
|||
s = open('config.gypi').read() |
|||
s = re.sub(r'#.*?\n', '', s) # strip comments |
|||
s = re.sub(r'\'', '"', s) # convert quotes |
|||
return json.loads(s) |
|||
|
|||
def try_unlink(path): |
|||
try: |
|||
os.unlink(path) |
|||
except OSError, e: |
|||
if e.errno != errno.ENOENT: raise |
|||
|
|||
def try_symlink(source_path, link_path): |
|||
print 'symlinking %s -> %s' % (source_path, link_path) |
|||
try_unlink(link_path) |
|||
os.symlink(source_path, link_path) |
|||
|
|||
def try_mkdir_r(path): |
|||
try: |
|||
os.makedirs(path) |
|||
except OSError, e: |
|||
if e.errno != errno.EEXIST: raise |
|||
|
|||
def try_rmdir_r(path): |
|||
path = abspath(path) |
|||
while path.startswith(dst_dir): |
|||
try: |
|||
os.rmdir(path) |
|||
except OSError, e: |
|||
if e.errno == errno.ENOTEMPTY: return |
|||
if e.errno == errno.ENOENT: return |
|||
raise |
|||
path = abspath(path, '..') |
|||
|
|||
def mkpaths(path, dst): |
|||
if dst.endswith('/'): |
|||
target_path = abspath(dst_dir, dst, os.path.basename(path)) |
|||
else: |
|||
target_path = abspath(dst_dir, dst) |
|||
return path, target_path |
|||
|
|||
def try_copy(path, dst): |
|||
source_path, target_path = mkpaths(path, dst) |
|||
print 'installing %s' % target_path |
|||
try_mkdir_r(os.path.dirname(target_path)) |
|||
return shutil.copy2(source_path, target_path) |
|||
|
|||
def try_remove(path, dst): |
|||
source_path, target_path = mkpaths(path, dst) |
|||
print 'removing %s' % target_path |
|||
try_unlink(target_path) |
|||
try_rmdir_r(os.path.dirname(target_path)) |
|||
|
|||
def install(paths, dst): map(lambda path: try_copy(path, dst), paths) |
|||
def uninstall(paths, dst): map(lambda path: try_remove(path, dst), paths) |
|||
|
|||
def waf_files(action): |
|||
action(['tools/node-waf'], 'bin/node-waf') |
|||
action(['tools/wafadmin/ansiterm.py', |
|||
'tools/wafadmin/Build.py', |
|||
'tools/wafadmin/Configure.py', |
|||
'tools/wafadmin/Constants.py', |
|||
'tools/wafadmin/Environment.py', |
|||
'tools/wafadmin/__init__.py', |
|||
'tools/wafadmin/Logs.py', |
|||
'tools/wafadmin/Node.py', |
|||
'tools/wafadmin/Options.py', |
|||
'tools/wafadmin/pproc.py', |
|||
'tools/wafadmin/py3kfixes.py', |
|||
'tools/wafadmin/Runner.py', |
|||
'tools/wafadmin/Scripting.py', |
|||
'tools/wafadmin/TaskGen.py', |
|||
'tools/wafadmin/Task.py', |
|||
'tools/wafadmin/Tools/ar.py', |
|||
'tools/wafadmin/Tools/cc.py', |
|||
'tools/wafadmin/Tools/ccroot.py', |
|||
'tools/wafadmin/Tools/compiler_cc.py', |
|||
'tools/wafadmin/Tools/compiler_cxx.py', |
|||
'tools/wafadmin/Tools/compiler_d.py', |
|||
'tools/wafadmin/Tools/config_c.py', |
|||
'tools/wafadmin/Tools/cxx.py', |
|||
'tools/wafadmin/Tools/dmd.py', |
|||
'tools/wafadmin/Tools/d.py', |
|||
'tools/wafadmin/Tools/gas.py', |
|||
'tools/wafadmin/Tools/gcc.py', |
|||
'tools/wafadmin/Tools/gdc.py', |
|||
'tools/wafadmin/Tools/gnu_dirs.py', |
|||
'tools/wafadmin/Tools/gob2.py', |
|||
'tools/wafadmin/Tools/gxx.py', |
|||
'tools/wafadmin/Tools/icc.py', |
|||
'tools/wafadmin/Tools/icpc.py', |
|||
'tools/wafadmin/Tools/__init__.py', |
|||
'tools/wafadmin/Tools/intltool.py', |
|||
'tools/wafadmin/Tools/libtool.py', |
|||
'tools/wafadmin/Tools/misc.py', |
|||
'tools/wafadmin/Tools/nasm.py', |
|||
'tools/wafadmin/Tools/node_addon.py', |
|||
'tools/wafadmin/Tools/osx.py', |
|||
'tools/wafadmin/Tools/preproc.py', |
|||
'tools/wafadmin/Tools/python.py', |
|||
'tools/wafadmin/Tools/suncc.py', |
|||
'tools/wafadmin/Tools/suncxx.py', |
|||
'tools/wafadmin/Tools/unittestw.py', |
|||
'tools/wafadmin/Tools/winres.py', |
|||
'tools/wafadmin/Tools/xlc.py', |
|||
'tools/wafadmin/Tools/xlcxx.py', |
|||
'tools/wafadmin/Utils.py'], |
|||
'lib/node/') |
|||
|
|||
def update_shebang(path, shebang): |
|||
print 'updating shebang of %s' % path |
|||
s = open(path, 'r').read() |
|||
s = re.sub(r'#!.*\n', '#!' + shebang + '\n', s) |
|||
open(path, 'w').write(s) |
|||
|
|||
def npm_files(action): |
|||
target_path = 'lib/node_modules/npm/' |
|||
|
|||
# don't install npm if the target path is a symlink, it probably means |
|||
# that a dev version of npm is installed there |
|||
if os.path.islink(abspath(dst_dir, target_path)): return |
|||
|
|||
# npm has a *lot* of files and it'd be a pain to maintain a fixed list here |
|||
# so we walk its source directory instead... |
|||
for dirname, subdirs, basenames in os.walk('deps/npm', topdown=True): |
|||
subdirs[:] = filter('test'.__ne__, subdirs) # skip test suites |
|||
paths = [os.path.join(dirname, basename) for basename in basenames] |
|||
action(paths, target_path + dirname[9:] + '/') |
|||
|
|||
# create/remove symlink |
|||
link_path = abspath(dst_dir, 'bin/npm') |
|||
if action == uninstall: |
|||
action([link_path], 'bin/npm') |
|||
elif action == install: |
|||
try_symlink('../lib/node_modules/npm/bin/npm-cli.js', link_path) |
|||
update_shebang(link_path, node_prefix + '/bin/node') |
|||
else: |
|||
assert(0) # unhandled action type |
|||
|
|||
def files(action): |
|||
action(['deps/uv/include/ares.h', |
|||
'deps/uv/include/ares_version.h', |
|||
'deps/uv/include/uv.h', |
|||
'deps/v8/include/v8-debug.h', |
|||
'deps/v8/include/v8-preparser.h', |
|||
'deps/v8/include/v8-profiler.h', |
|||
'deps/v8/include/v8-testing.h', |
|||
'deps/v8/include/v8.h', |
|||
'deps/v8/include/v8stdint.h', |
|||
'src/eio-emul.h', |
|||
'src/ev-emul.h', |
|||
'src/node.h', |
|||
'src/node_buffer.h', |
|||
'src/node_object_wrap.h', |
|||
'src/node_version.h'], |
|||
'include/node/') |
|||
action(['deps/uv/include/uv-private/eio.h', |
|||
'deps/uv/include/uv-private/ev.h', |
|||
'deps/uv/include/uv-private/ngx-queue.h', |
|||
'deps/uv/include/uv-private/tree.h', |
|||
'deps/uv/include/uv-private/uv-unix.h', |
|||
'deps/uv/include/uv-private/uv-win.h'], |
|||
'include/node/uv-private/') |
|||
action(['doc/node.1'], 'share/man/man1/') |
|||
action(['out/Release/node'], 'bin/node') |
|||
|
|||
# install unconditionally, checking if the platform supports dtrace doesn't |
|||
# work when cross-compiling and besides, there's at least one linux flavor |
|||
# with dtrace support now (oracle's "unbreakable" linux) |
|||
action(['src/node.d'], 'lib/dtrace/') |
|||
|
|||
if variables.get('node_install_waf'): waf_files(action) |
|||
if variables.get('node_install_npm'): npm_files(action) |
|||
|
|||
def run(args): |
|||
global dst_dir, node_prefix, target_defaults, variables |
|||
|
|||
# chdir to the project's top-level directory |
|||
os.chdir(abspath(os.path.dirname(__file__), '..')) |
|||
|
|||
conf = load_config() |
|||
variables = conf['variables'] |
|||
target_defaults = conf['target_defaults'] |
|||
|
|||
# argv[2] is a custom install prefix for packagers (think DESTDIR) |
|||
dst_dir = node_prefix = variables.get('node_prefix', '/usr/local') |
|||
if len(args) > 2: dst_dir = abspath(args[2] + '/' + dst_dir) |
|||
|
|||
cmd = args[1] if len(args) > 1 else 'install' |
|||
if cmd == 'install': return files(install) |
|||
if cmd == 'uninstall': return files(uninstall) |
|||
raise RuntimeError('Bad command: %s\n' % cmd) |
|||
|
|||
if __name__ == '__main__': |
|||
run(sys.argv[:]) |
@ -1,158 +0,0 @@ |
|||
var fs = require('fs'), |
|||
path = require('path'), |
|||
exec = require('child_process').exec, |
|||
cmd = process.argv[2], |
|||
dest_dir = process.argv[3] || ''; |
|||
|
|||
if (cmd !== 'install' && cmd !== 'uninstall') { |
|||
console.error('Unknown command: ' + cmd); |
|||
process.exit(1); |
|||
} |
|||
|
|||
// Use the built-in config reported by the current process
|
|||
var variables = process.config.variables, |
|||
node_prefix = variables.node_prefix || '/usr/local'; |
|||
|
|||
// Execution queue
|
|||
var queue = [], |
|||
dirs = []; |
|||
|
|||
// Copy file from src to dst
|
|||
function copy(src, dst, callback) { |
|||
// If src is array - copy each file separately
|
|||
if (Array.isArray(src)) { |
|||
src.forEach(function(src) { |
|||
copy(src, dst, callback); |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
dst = path.join(dest_dir, node_prefix, dst); |
|||
var dir = dst.replace(/\/[^\/]*$/, '/'); |
|||
|
|||
// Create directory if hasn't done this yet
|
|||
if (dirs.indexOf(dir) === -1) { |
|||
dirs.push(dir); |
|||
queue.push('mkdir -p ' + dir); |
|||
} |
|||
|
|||
// Queue file/dir copy
|
|||
queue.push('cp -rf ' + src + ' ' + dst); |
|||
} |
|||
|
|||
// Remove files
|
|||
function remove(files) { |
|||
files.forEach(function(file) { |
|||
file = path.join(dest_dir, node_prefix, file); |
|||
queue.push('rm -rf ' + file); |
|||
}); |
|||
} |
|||
|
|||
// Add/update shebang (#!) line so that npm uses
|
|||
// the newly installed node, rather than the first in PATH.
|
|||
function shebang(line, npmDir) { |
|||
var script = JSON.stringify(path.join(npmDir, 'scripts/relocate.sh')); |
|||
var bin = JSON.stringify(path.join(npmDir, 'bin/npm-cli.js')); |
|||
queue.push('/bin/sh ' + script + ' ' + line); |
|||
} |
|||
|
|||
// Run every command in queue, one-by-one
|
|||
function run() { |
|||
var cmd = queue.shift(); |
|||
if (!cmd) return; |
|||
|
|||
if (Array.isArray(cmd) && cmd[0] instanceof Function) { |
|||
var func = cmd[0]; |
|||
var args = cmd.slice(1); |
|||
console.log.apply(null, [func.name].concat(args)); |
|||
func.apply(null, args); |
|||
run(); |
|||
} else { |
|||
console.log(cmd); |
|||
exec(cmd, function(err, stdout, stderr) { |
|||
if (stderr) console.error(stderr); |
|||
if (err) process.exit(1); |
|||
|
|||
run(); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
if (cmd === 'install') { |
|||
// Copy includes
|
|||
copy([ |
|||
// Node
|
|||
'src/node.h', 'src/node_buffer.h', 'src/node_object_wrap.h', |
|||
'src/node_version.h', 'src/ev-emul.h', 'src/eio-emul.h', |
|||
// v8
|
|||
'deps/v8/include/v8-debug.h', 'deps/v8/include/v8-preparser.h', |
|||
'deps/v8/include/v8-profiler.h', 'deps/v8/include/v8-testing.h', |
|||
'deps/v8/include/v8.h', 'deps/v8/include/v8stdint.h', |
|||
// uv
|
|||
'deps/uv/include/uv.h' |
|||
], 'include/node/'); |
|||
|
|||
// man page
|
|||
copy(['doc/node.1'], 'share/man/man1/'); |
|||
|
|||
// dtrace
|
|||
if (!process.platform.match(/^linux/)) { |
|||
copy(['src/node.d'], 'lib/dtrace/'); |
|||
} |
|||
|
|||
// Private uv headers
|
|||
copy([ |
|||
'deps/uv/include/uv-private/eio.h', 'deps/uv/include/uv-private/ev.h', |
|||
'deps/uv/include/uv-private/ngx-queue.h', |
|||
'deps/uv/include/uv-private/tree.h', |
|||
'deps/uv/include/uv-private/uv-unix.h', |
|||
'deps/uv/include/uv-private/uv-win.h', |
|||
], 'include/node/uv-private/'); |
|||
|
|||
copy([ |
|||
'deps/uv/include/ares.h', |
|||
'deps/uv/include/ares_version.h' |
|||
], 'include/node/'); |
|||
|
|||
// Copy binary file
|
|||
copy('out/Release/node', 'bin/node'); |
|||
|
|||
// Install node-waf
|
|||
if (variables.node_install_waf) { |
|||
copy('tools/wafadmin', 'lib/node/'); |
|||
copy('tools/node-waf', 'bin/node-waf'); |
|||
} |
|||
|
|||
// Install npm (eventually)
|
|||
if (variables.node_install_npm) { |
|||
// Frequently, in development, the installed npm is a symbolic
|
|||
// link to the development folder, and so installing this is
|
|||
// a bit annoying. If it's a symlink, skip it.
|
|||
var isSymlink = false; |
|||
var exists = true; |
|||
var npmDir = path.resolve(node_prefix, 'lib/node_modules/npm'); |
|||
try { |
|||
var st = fs.lstatSync(npmDir); |
|||
isSymlink = st.isSymbolicLink(); |
|||
} catch (e) { |
|||
exists = true; |
|||
} |
|||
|
|||
if (!isSymlink) { |
|||
if (exists) queue.push('rm -rf ' + npmDir); |
|||
copy('deps/npm', 'lib/node_modules/npm'); |
|||
queue.push('ln -sf ../lib/node_modules/npm/bin/npm-cli.js ' + |
|||
path.join(dest_dir, node_prefix, 'bin/npm')); |
|||
shebang(path.join(node_prefix, 'bin/node'), |
|||
path.join(dest_dir, node_prefix, 'lib/node_modules/npm')); |
|||
} |
|||
} |
|||
} else { |
|||
remove([ |
|||
'bin/node', 'bin/npm', 'bin/node-waf', |
|||
'include/node/*', 'lib/node_modules', 'lib/node', |
|||
'lib/dtrace/node.d', 'share/man/man1/node.1' |
|||
]); |
|||
} |
|||
|
|||
run(); |
Loading…
Reference in new issue