Bug 680636 - Add support for running nsinstall natively under pymake and convert a bunch of cases over. r=ted
authorSiddharth Agarwal <sid.bugzilla@gmail.com>
Tue, 03 Jul 2012 12:13:30 +0530
changeset 102937 88aaf6c529b9e1bb2f5e332aa756df5d53e86c26
parent 102936 e149b8c85eb8bb398ff2e1638ad248c249f901af
child 102938 947af3f855e1404ae762f92522498ff11474db78
push id1316
push userakeybl@mozilla.com
push dateMon, 27 Aug 2012 22:37:00 +0000
treeherdermozilla-beta@db4b09302ee2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersted
bugs680636
milestone16.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 680636 - Add support for running nsinstall natively under pymake and convert a bunch of cases over. r=ted
config/config.mk
config/makefiles/xpidl.mk
config/nsinstall.py
config/rules.mk
config/tests/unit-nsinstall.py
js/src/config/config.mk
js/src/config/makefiles/xpidl.mk
js/src/config/nsinstall.py
js/src/config/rules.mk
--- a/config/config.mk
+++ b/config/config.mk
@@ -629,16 +629,21 @@ GARBAGE		+= $(DEPENDENCIES) $(MKDEPENDEN
 ifeq ($(OS_ARCH),Darwin)
 ifndef NSDISTMODE
 NSDISTMODE=absolute_symlink
 endif
 PWD := $(CURDIR)
 endif
 
 NSINSTALL_PY := $(PYTHON) $(call core_abspath,$(topsrcdir)/config/nsinstall.py)
+# For Pymake, wherever we use nsinstall.py we're also going to try to make it
+# a native command where possible. Since native commands can't be used outside
+# of single-line commands, we continue to provide INSTALL for general use.
+# Single-line commands should be switched over to install_cmd.
+NSINSTALL_NATIVECMD := %nsinstall nsinstall
 
 ifdef NSINSTALL_BIN
 NSINSTALL = $(NSINSTALL_BIN)
 else
 ifeq (OS2,$(CROSS_COMPILE)$(OS_ARCH))
 NSINSTALL = $(MOZ_TOOLS_DIR)/nsinstall
 else
 ifeq ($(HOST_OS_ARCH),WINNT)
@@ -646,30 +651,40 @@ NSINSTALL = $(NSINSTALL_PY)
 else
 NSINSTALL = $(CONFIG_TOOLS)/nsinstall$(HOST_BIN_SUFFIX)
 endif # WINNT
 endif # OS2
 endif # NSINSTALL_BIN
 
 
 ifeq (,$(CROSS_COMPILE)$(filter-out WINNT OS2, $(OS_ARCH)))
-INSTALL		= $(NSINSTALL) -t
+INSTALL = $(NSINSTALL) -t
+ifdef .PYMAKE
+install_cmd = $(NSINSTALL_NATIVECMD) -t $(1)
+endif # .PYMAKE
+
 else
 
 # This isn't laid out as conditional directives so that NSDISTMODE can be
 # target-specific.
 INSTALL         = $(if $(filter copy, $(NSDISTMODE)), $(NSINSTALL) -t, $(if $(filter absolute_symlink, $(NSDISTMODE)), $(NSINSTALL) -L $(PWD), $(NSINSTALL) -R))
 
 endif # WINNT/OS2
 
+# The default for install_cmd is simply INSTALL
+install_cmd ?= $(INSTALL) $(1)
+
 # Use nsinstall in copy mode to install files on the system
 SYSINSTALL	= $(NSINSTALL) -t
+# This isn't necessarily true, just here
+sysinstall_cmd = install_cmd
 
 # Directory nsinstall.
 DIR_INSTALL = $(INSTALL)
+dir_install_cmd = install_cmd
 
 #
 # Localization build automation
 #
 
 # Because you might wish to "make locales AB_CD=ab-CD", we don't hardcode
 # MOZ_UI_LOCALE directly, but use an intermediate variable that can be
 # overridden by the command line. (Besides, AB_CD is prettier).
--- a/config/makefiles/xpidl.mk
+++ b/config/makefiles/xpidl.mk
@@ -41,18 +41,18 @@ ifdef _xpidl-todo_ #{
 
 ## Logic batch #1
 xpidl-install-src-preqs=\
   $(XPIDLSRCS) \
   $(call mkdir_deps,$(IDL_DIR)) \
   $(NULL)
 
 xpidl-install-src: $(xpidl-install-src-preqs)
-	$(INSTALL) $(IFLAGS1) $(foreach val,$^,$(call mkdir_stem,$(val)))
+	$(call install_cmd,$(IFLAGS1) $(foreach val,$^,$(call mkdir_stem,$(val))))
 
 xpidl-install-headers-preqs =\
   $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.h, $(XPIDLSRCS)) \
   $(call mkdir_deps,$(DIST)/include) \
   $(NULL)
 xpidl-install-headers: $(xpidl-install-headers-preqs)
-	$(INSTALL) $(IFLAGS1) $(foreach val,$^,$(call mkdir_stem,$(val)))
+	$(call install_cmd,$(IFLAGS1) $(foreach val,$^,$(call mkdir_stem,$(val))))
 
 endif #} _xpidl-todo_
--- a/config/nsinstall.py
+++ b/config/nsinstall.py
@@ -12,17 +12,17 @@
 
 from optparse import OptionParser
 import os
 import os.path
 import sys
 import shutil
 import stat
 
-def nsinstall(argv):
+def _nsinstall_internal(argv):
   usage = "usage: %prog [options] arg1 [arg2 ...] target-directory"
   p = OptionParser(usage=usage)
 
   p.add_option('-D', action="store_true",
                help="Create a single directory only")
   p.add_option('-t', action="store_true",
                help="Preserve time stamp")
   p.add_option('-m', action="store",
@@ -47,23 +47,16 @@ def nsinstall(argv):
                callback=BadArg,
                help="NOT SUPPORTED")
   p.add_option('-o', action="callback", callback=BadArg,
                help="Set owner (NOT SUPPORTED)", metavar="owner")
   p.add_option('-g', action="callback", callback=BadArg,
                help="Set group (NOT SUPPORTED)", metavar="group")
 
   (options, args) = p.parse_args(argv)
-  # Switching to Unicode strings makes python use the wide Windows APIs, which is
-  # what we want here since the wide APIs normally do a better job at handling long
-  # paths and such.
-  if sys.stdin.encoding is None:
-    args = [unicode(arg) for arg in args]
-  else:
-    args = [unicode(arg, sys.stdin.encoding) for arg in args]
 
   if options.m:
     # mode is specified
     try:
       options.m = int(options.m, 8)
     except:
       sys.stderr.write('nsinstall: ' + options.m + ' is not a valid mode\n')
       return 1
@@ -147,30 +140,41 @@ def nsinstall(argv):
   # because we want to copy files into it and the mode might be read-only)
   rv = maybe_create_dir(target, None, True)
   if rv != 0:
     return rv
 
   copy_all_entries(args, target)
   return 0
 
+# nsinstall as a native command is always UTF-8
+def nsinstall(argv):
+  return _nsinstall_internal([unicode(arg, "utf-8") for arg in argv])
+
 if __name__ == '__main__':
   # sys.argv corrupts characters outside the system code page on Windows
-  # <http://bugs.python.org/issue2128>. Use ctypes instead.
+  # <http://bugs.python.org/issue2128>. Use ctypes instead. This is also
+  # useful because switching to Unicode strings makes python use the wide
+  # Windows APIs, which is what we want here since the wide APIs normally do a
+  # better job at handling long paths and such.
   if sys.platform == "win32":
     import ctypes
     from ctypes import wintypes
     GetCommandLine = ctypes.windll.kernel32.GetCommandLineW
     GetCommandLine.argtypes = []
     GetCommandLine.restype = wintypes.LPWSTR
 
     CommandLineToArgv = ctypes.windll.shell32.CommandLineToArgvW
     CommandLineToArgv.argtypes = [wintypes.LPWSTR, ctypes.POINTER(ctypes.c_int)]
     CommandLineToArgv.restype = ctypes.POINTER(wintypes.LPWSTR)
 
     argc = ctypes.c_int(0)
     argv_arr = CommandLineToArgv(GetCommandLine(), ctypes.byref(argc))
-    # The first argument will be "python", the second will be the .py file
+    # The first argv will be "python", the second will be the .py file
     argv = argv_arr[1:argc.value]
   else:
-    argv = sys.argv
+    # For consistency, do it on Unix as well
+    if sys.stdin.encoding is not None:
+      argv = [unicode(arg, sys.stdin.encoding) for arg in sys.argv]
+    else:
+      argv = [unicode(arg) for arg in sys.argv]
 
-  sys.exit(nsinstall(argv[1:]))
+  sys.exit(_nsinstall_internal(argv[1:]))
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -1185,24 +1185,24 @@ ifneq ($(XPI_NAME),)
 	$(NSINSTALL) -D $@
 
 export:: $(FINAL_TARGET)
 endif
 
 ifndef NO_DIST_INSTALL
 ifneq (,$(EXPORTS))
 export:: $(EXPORTS)
-	$(INSTALL) $(IFLAGS1) $^ $(DIST)/include
+	$(call install_cmd,$(IFLAGS1) $^ $(DIST)/include)
 endif
 endif # NO_DIST_INSTALL
 
 define EXPORT_NAMESPACE_RULE
 ifndef NO_DIST_INSTALL
 export:: $(EXPORTS_$(namespace))
-	$(INSTALL) $(IFLAGS1) $$^ $(DIST)/include/$(namespace)
+	$(call install_cmd,$(IFLAGS1) $$^ $(DIST)/include/$(namespace))
 endif # NO_DIST_INSTALL
 endef
 
 $(foreach namespace,$(EXPORTS_NAMESPACES),$(eval $(EXPORT_NAMESPACE_RULE)))
 
 ################################################################################
 # Copy each element of PREF_JS_EXPORTS
 
@@ -1241,17 +1241,17 @@ endif
 # Copy each element of AUTOCFG_JS_EXPORTS to $(FINAL_TARGET)/defaults/autoconfig
 
 ifneq ($(AUTOCFG_JS_EXPORTS),)
 $(FINAL_TARGET)/defaults/autoconfig::
 	$(NSINSTALL) -D $@
 
 ifndef NO_DIST_INSTALL
 export:: $(AUTOCFG_JS_EXPORTS) $(FINAL_TARGET)/defaults/autoconfig
-	$(INSTALL) $(IFLAGS1) $^
+	$(call install_cmd,$(IFLAGS1) $^)
 endif
 
 endif
 
 ################################################################################
 # Export the elements of $(XPIDLSRCS)
 # generating .h and .xpt files and moving them to the appropriate places.
 
@@ -1307,17 +1307,17 @@ ifndef NO_GEN_XPT
 # no need to link together if XPIDLSRCS contains only XPIDL_MODULE
 ifneq ($(XPIDL_MODULE).idl,$(strip $(XPIDLSRCS)))
 $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt: $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.xpt,$(XPIDLSRCS)) $(GLOBAL_DEPS)
 	$(XPIDL_LINK) $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.xpt,$(XPIDLSRCS))
 endif # XPIDL_MODULE.xpt != XPIDLSRCS
 
 libs:: $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt
 ifndef NO_DIST_INSTALL
-	$(INSTALL) $(IFLAGS1) $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt $(FINAL_TARGET)/components
+	$(call install_cmd,$(IFLAGS1) $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt $(FINAL_TARGET)/components)
 ifndef NO_INTERFACES_MANIFEST
 	@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/components/interfaces.manifest "interfaces $(XPIDL_MODULE).xpt"
 	@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest "manifest components/interfaces.manifest"
 endif
 endif
 
 endif # NO_GEN_XPT
 
@@ -1335,17 +1335,17 @@ endif
 $(IDL_DIR):
 	$(NSINSTALL) -D $@
 
 export-idl:: $(SUBMAKEFILES) $(MAKE_DIRS)
 
 ifneq ($(XPIDLSRCS),)
 ifndef NO_DIST_INSTALL
 export-idl:: $(XPIDLSRCS) $(IDL_DIR)
-	$(INSTALL) $(IFLAGS1) $^
+	$(call install_cmd,$(IFLAGS1) $^)
 endif
 endif
 	$(LOOP_OVER_PARALLEL_DIRS)
 	$(LOOP_OVER_DIRS)
 	$(LOOP_OVER_TOOL_DIRS)
 
 ################################################################################
 # Copy each element of EXTRA_COMPONENTS to $(FINAL_TARGET)/components
@@ -1355,17 +1355,17 @@ ifndef NO_JS_MANIFEST
 $(error .js component without matching .manifest. See https://developer.mozilla.org/en/XPCOM/XPCOM_changes_in_Gecko_2.0)
 endif
 endif
 endif
 
 ifdef EXTRA_COMPONENTS
 libs:: $(EXTRA_COMPONENTS)
 ifndef NO_DIST_INSTALL
-	$(INSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)/components
+	$(call install_cmd,$(IFLAGS1) $^ $(FINAL_TARGET)/components)
 endif
 
 endif
 
 ifdef EXTRA_PP_COMPONENTS
 libs:: $(EXTRA_PP_COMPONENTS)
 ifndef NO_DIST_INSTALL
 	$(EXIT_ON_ERROR) \
@@ -1385,17 +1385,17 @@ libs::
 	$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest $(patsubst %,"manifest components/%",$(notdir $(EXTRA_MANIFESTS)))
 endif
 
 ################################################################################
 # Copy each element of EXTRA_JS_MODULES to $(FINAL_TARGET)/modules
 ifdef EXTRA_JS_MODULES
 libs:: $(EXTRA_JS_MODULES)
 ifndef NO_DIST_INSTALL
-	$(INSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)/modules
+	$(call install_cmd,$(IFLAGS1) $^ $(FINAL_TARGET)/modules)
 endif
 
 endif
 
 ifdef EXTRA_PP_JS_MODULES
 libs:: $(EXTRA_PP_JS_MODULES)
 ifndef NO_DIST_INSTALL
 	$(EXIT_ON_ERROR) \
@@ -1418,42 +1418,42 @@ endif
 
 ifdef TESTING_JS_MODULES
 testmodulesdir = $(DEPTH)/_tests/modules/$(TESTING_JS_MODULE_DIR)
 
 GENERATED_DIRS += $(testmodulesdir)
 
 libs:: $(TESTING_JS_MODULES)
 ifndef NO_DIST_INSTALL
-	$(INSTALL) $(IFLAGS) $^ $(testmodulesdir)
+	$(call install_cmd,$(IFLAGS) $^ $(testmodulesdir))
 endif
 
 endif
 
 ################################################################################
 # SDK
 
 ifneq (,$(SDK_LIBRARY))
 $(SDK_LIB_DIR)::
 	$(NSINSTALL) -D $@
 
 ifndef NO_DIST_INSTALL
 libs:: $(SDK_LIBRARY) $(SDK_LIB_DIR)
-	$(INSTALL) $(IFLAGS2) $^
+	$(call install_cmd,$(IFLAGS2) $^)
 endif
 
 endif # SDK_LIBRARY
 
 ifneq (,$(strip $(SDK_BINARY)))
 $(SDK_BIN_DIR)::
 	$(NSINSTALL) -D $@
 
 ifndef NO_DIST_INSTALL
 libs:: $(SDK_BINARY) $(SDK_BIN_DIR)
-	$(INSTALL) $(IFLAGS2) $^
+	$(call install_cmd,$(IFLAGS2) $^)
 endif
 
 endif # SDK_BINARY
 
 ################################################################################
 # CHROME PACKAGING
 
 JAR_MANIFEST := $(srcdir)/jar.mn
--- a/config/tests/unit-nsinstall.py
+++ b/config/tests/unit-nsinstall.py
@@ -132,30 +132,28 @@ class TestNsinstall(unittest.TestCase):
         "Test that nsinstall -d works (create directories in target)"
         # -d makes no sense to me, but ok!
         testfile = self.touch("testfile")
         testdir = self.mkdirs("testdir")
         destdir = os.path.join(testdir, "subdir")
         self.assertEqual(nsinstall(["-d", testfile, destdir]), 0)
         self.assert_(os.path.isdir(os.path.join(destdir, "testfile")))
 
-    # Disable this temporarily on Windows (will be re-enabled by bug 680636)
-    if RUN_NON_ASCII_TESTS and sys.platform != "win32":
+    if RUN_NON_ASCII_TESTS:
         def test_nsinstall_non_ascii(self):
             "Test that nsinstall handles non-ASCII files"
             filename = u"\u2325\u3452\u2415\u5081"
             testfile = self.touch(filename)
             testdir = self.mkdirs(u"\u4241\u1D04\u1414")
             self.assertEqual(nsinstall([testfile.encode("utf-8"),
                                         testdir.encode("utf-8")]), 0)
 
             destfile = os.path.join(testdir, filename)
             self.assert_(os.path.isfile(destfile))
 
-    if RUN_NON_ASCII_TESTS:
         def test_nsinstall_non_ascii_subprocess(self):
             "Test that nsinstall as a subprocess handles non-ASCII files"
             filename = u"\u2325\u3452\u2415\u5081"
             testfile = self.touch(filename)
             testdir = self.mkdirs(u"\u4241\u1D04\u1414")
             # We don't use subprocess because it can't handle Unicode on
             # Windows <http://bugs.python.org/issue1759845>. mozprocess calls
             # CreateProcessW directly so it's perfect.
--- a/js/src/config/config.mk
+++ b/js/src/config/config.mk
@@ -629,16 +629,21 @@ GARBAGE		+= $(DEPENDENCIES) $(MKDEPENDEN
 ifeq ($(OS_ARCH),Darwin)
 ifndef NSDISTMODE
 NSDISTMODE=absolute_symlink
 endif
 PWD := $(CURDIR)
 endif
 
 NSINSTALL_PY := $(PYTHON) $(call core_abspath,$(topsrcdir)/config/nsinstall.py)
+# For Pymake, wherever we use nsinstall.py we're also going to try to make it
+# a native command where possible. Since native commands can't be used outside
+# of single-line commands, we continue to provide INSTALL for general use.
+# Single-line commands should be switched over to install_cmd.
+NSINSTALL_NATIVECMD := %nsinstall nsinstall
 
 ifdef NSINSTALL_BIN
 NSINSTALL = $(NSINSTALL_BIN)
 else
 ifeq (OS2,$(CROSS_COMPILE)$(OS_ARCH))
 NSINSTALL = $(MOZ_TOOLS_DIR)/nsinstall
 else
 ifeq ($(HOST_OS_ARCH),WINNT)
@@ -646,30 +651,40 @@ NSINSTALL = $(NSINSTALL_PY)
 else
 NSINSTALL = $(CONFIG_TOOLS)/nsinstall$(HOST_BIN_SUFFIX)
 endif # WINNT
 endif # OS2
 endif # NSINSTALL_BIN
 
 
 ifeq (,$(CROSS_COMPILE)$(filter-out WINNT OS2, $(OS_ARCH)))
-INSTALL		= $(NSINSTALL) -t
+INSTALL = $(NSINSTALL) -t
+ifdef .PYMAKE
+install_cmd = $(NSINSTALL_NATIVECMD) -t $(1)
+endif # .PYMAKE
+
 else
 
 # This isn't laid out as conditional directives so that NSDISTMODE can be
 # target-specific.
 INSTALL         = $(if $(filter copy, $(NSDISTMODE)), $(NSINSTALL) -t, $(if $(filter absolute_symlink, $(NSDISTMODE)), $(NSINSTALL) -L $(PWD), $(NSINSTALL) -R))
 
 endif # WINNT/OS2
 
+# The default for install_cmd is simply INSTALL
+install_cmd ?= $(INSTALL) $(1)
+
 # Use nsinstall in copy mode to install files on the system
 SYSINSTALL	= $(NSINSTALL) -t
+# This isn't necessarily true, just here
+sysinstall_cmd = install_cmd
 
 # Directory nsinstall.
 DIR_INSTALL = $(INSTALL)
+dir_install_cmd = install_cmd
 
 #
 # Localization build automation
 #
 
 # Because you might wish to "make locales AB_CD=ab-CD", we don't hardcode
 # MOZ_UI_LOCALE directly, but use an intermediate variable that can be
 # overridden by the command line. (Besides, AB_CD is prettier).
--- a/js/src/config/makefiles/xpidl.mk
+++ b/js/src/config/makefiles/xpidl.mk
@@ -41,18 +41,18 @@ ifdef _xpidl-todo_ #{
 
 ## Logic batch #1
 xpidl-install-src-preqs=\
   $(XPIDLSRCS) \
   $(call mkdir_deps,$(IDL_DIR)) \
   $(NULL)
 
 xpidl-install-src: $(xpidl-install-src-preqs)
-	$(INSTALL) $(IFLAGS1) $(foreach val,$^,$(call mkdir_stem,$(val)))
+	$(call install_cmd,$(IFLAGS1) $(foreach val,$^,$(call mkdir_stem,$(val))))
 
 xpidl-install-headers-preqs =\
   $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.h, $(XPIDLSRCS)) \
   $(call mkdir_deps,$(DIST)/include) \
   $(NULL)
 xpidl-install-headers: $(xpidl-install-headers-preqs)
-	$(INSTALL) $(IFLAGS1) $(foreach val,$^,$(call mkdir_stem,$(val)))
+	$(call install_cmd,$(IFLAGS1) $(foreach val,$^,$(call mkdir_stem,$(val))))
 
 endif #} _xpidl-todo_
--- a/js/src/config/nsinstall.py
+++ b/js/src/config/nsinstall.py
@@ -12,17 +12,17 @@
 
 from optparse import OptionParser
 import os
 import os.path
 import sys
 import shutil
 import stat
 
-def nsinstall(argv):
+def _nsinstall_internal(argv):
   usage = "usage: %prog [options] arg1 [arg2 ...] target-directory"
   p = OptionParser(usage=usage)
 
   p.add_option('-D', action="store_true",
                help="Create a single directory only")
   p.add_option('-t', action="store_true",
                help="Preserve time stamp")
   p.add_option('-m', action="store",
@@ -47,23 +47,16 @@ def nsinstall(argv):
                callback=BadArg,
                help="NOT SUPPORTED")
   p.add_option('-o', action="callback", callback=BadArg,
                help="Set owner (NOT SUPPORTED)", metavar="owner")
   p.add_option('-g', action="callback", callback=BadArg,
                help="Set group (NOT SUPPORTED)", metavar="group")
 
   (options, args) = p.parse_args(argv)
-  # Switching to Unicode strings makes python use the wide Windows APIs, which is
-  # what we want here since the wide APIs normally do a better job at handling long
-  # paths and such.
-  if sys.stdin.encoding is None:
-    args = [unicode(arg) for arg in args]
-  else:
-    args = [unicode(arg, sys.stdin.encoding) for arg in args]
 
   if options.m:
     # mode is specified
     try:
       options.m = int(options.m, 8)
     except:
       sys.stderr.write('nsinstall: ' + options.m + ' is not a valid mode\n')
       return 1
@@ -147,30 +140,41 @@ def nsinstall(argv):
   # because we want to copy files into it and the mode might be read-only)
   rv = maybe_create_dir(target, None, True)
   if rv != 0:
     return rv
 
   copy_all_entries(args, target)
   return 0
 
+# nsinstall as a native command is always UTF-8
+def nsinstall(argv):
+  return _nsinstall_internal([unicode(arg, "utf-8") for arg in argv])
+
 if __name__ == '__main__':
   # sys.argv corrupts characters outside the system code page on Windows
-  # <http://bugs.python.org/issue2128>. Use ctypes instead.
+  # <http://bugs.python.org/issue2128>. Use ctypes instead. This is also
+  # useful because switching to Unicode strings makes python use the wide
+  # Windows APIs, which is what we want here since the wide APIs normally do a
+  # better job at handling long paths and such.
   if sys.platform == "win32":
     import ctypes
     from ctypes import wintypes
     GetCommandLine = ctypes.windll.kernel32.GetCommandLineW
     GetCommandLine.argtypes = []
     GetCommandLine.restype = wintypes.LPWSTR
 
     CommandLineToArgv = ctypes.windll.shell32.CommandLineToArgvW
     CommandLineToArgv.argtypes = [wintypes.LPWSTR, ctypes.POINTER(ctypes.c_int)]
     CommandLineToArgv.restype = ctypes.POINTER(wintypes.LPWSTR)
 
     argc = ctypes.c_int(0)
     argv_arr = CommandLineToArgv(GetCommandLine(), ctypes.byref(argc))
-    # The first argument will be "python", the second will be the .py file
+    # The first argv will be "python", the second will be the .py file
     argv = argv_arr[1:argc.value]
   else:
-    argv = sys.argv
+    # For consistency, do it on Unix as well
+    if sys.stdin.encoding is not None:
+      argv = [unicode(arg, sys.stdin.encoding) for arg in sys.argv]
+    else:
+      argv = [unicode(arg) for arg in sys.argv]
 
-  sys.exit(nsinstall(argv[1:]))
+  sys.exit(_nsinstall_internal(argv[1:]))
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -1185,24 +1185,24 @@ ifneq ($(XPI_NAME),)
 	$(NSINSTALL) -D $@
 
 export:: $(FINAL_TARGET)
 endif
 
 ifndef NO_DIST_INSTALL
 ifneq (,$(EXPORTS))
 export:: $(EXPORTS)
-	$(INSTALL) $(IFLAGS1) $^ $(DIST)/include
+	$(call install_cmd,$(IFLAGS1) $^ $(DIST)/include)
 endif
 endif # NO_DIST_INSTALL
 
 define EXPORT_NAMESPACE_RULE
 ifndef NO_DIST_INSTALL
 export:: $(EXPORTS_$(namespace))
-	$(INSTALL) $(IFLAGS1) $$^ $(DIST)/include/$(namespace)
+	$(call install_cmd,$(IFLAGS1) $$^ $(DIST)/include/$(namespace))
 endif # NO_DIST_INSTALL
 endef
 
 $(foreach namespace,$(EXPORTS_NAMESPACES),$(eval $(EXPORT_NAMESPACE_RULE)))
 
 ################################################################################
 # Copy each element of PREF_JS_EXPORTS
 
@@ -1241,17 +1241,17 @@ endif
 # Copy each element of AUTOCFG_JS_EXPORTS to $(FINAL_TARGET)/defaults/autoconfig
 
 ifneq ($(AUTOCFG_JS_EXPORTS),)
 $(FINAL_TARGET)/defaults/autoconfig::
 	$(NSINSTALL) -D $@
 
 ifndef NO_DIST_INSTALL
 export:: $(AUTOCFG_JS_EXPORTS) $(FINAL_TARGET)/defaults/autoconfig
-	$(INSTALL) $(IFLAGS1) $^
+	$(call install_cmd,$(IFLAGS1) $^)
 endif
 
 endif
 
 ################################################################################
 # Export the elements of $(XPIDLSRCS)
 # generating .h and .xpt files and moving them to the appropriate places.
 
@@ -1307,17 +1307,17 @@ ifndef NO_GEN_XPT
 # no need to link together if XPIDLSRCS contains only XPIDL_MODULE
 ifneq ($(XPIDL_MODULE).idl,$(strip $(XPIDLSRCS)))
 $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt: $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.xpt,$(XPIDLSRCS)) $(GLOBAL_DEPS)
 	$(XPIDL_LINK) $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.xpt,$(XPIDLSRCS))
 endif # XPIDL_MODULE.xpt != XPIDLSRCS
 
 libs:: $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt
 ifndef NO_DIST_INSTALL
-	$(INSTALL) $(IFLAGS1) $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt $(FINAL_TARGET)/components
+	$(call install_cmd,$(IFLAGS1) $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt $(FINAL_TARGET)/components)
 ifndef NO_INTERFACES_MANIFEST
 	@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/components/interfaces.manifest "interfaces $(XPIDL_MODULE).xpt"
 	@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest "manifest components/interfaces.manifest"
 endif
 endif
 
 endif # NO_GEN_XPT
 
@@ -1335,17 +1335,17 @@ endif
 $(IDL_DIR):
 	$(NSINSTALL) -D $@
 
 export-idl:: $(SUBMAKEFILES) $(MAKE_DIRS)
 
 ifneq ($(XPIDLSRCS),)
 ifndef NO_DIST_INSTALL
 export-idl:: $(XPIDLSRCS) $(IDL_DIR)
-	$(INSTALL) $(IFLAGS1) $^
+	$(call install_cmd,$(IFLAGS1) $^)
 endif
 endif
 	$(LOOP_OVER_PARALLEL_DIRS)
 	$(LOOP_OVER_DIRS)
 	$(LOOP_OVER_TOOL_DIRS)
 
 ################################################################################
 # Copy each element of EXTRA_COMPONENTS to $(FINAL_TARGET)/components
@@ -1355,17 +1355,17 @@ ifndef NO_JS_MANIFEST
 $(error .js component without matching .manifest. See https://developer.mozilla.org/en/XPCOM/XPCOM_changes_in_Gecko_2.0)
 endif
 endif
 endif
 
 ifdef EXTRA_COMPONENTS
 libs:: $(EXTRA_COMPONENTS)
 ifndef NO_DIST_INSTALL
-	$(INSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)/components
+	$(call install_cmd,$(IFLAGS1) $^ $(FINAL_TARGET)/components)
 endif
 
 endif
 
 ifdef EXTRA_PP_COMPONENTS
 libs:: $(EXTRA_PP_COMPONENTS)
 ifndef NO_DIST_INSTALL
 	$(EXIT_ON_ERROR) \
@@ -1385,17 +1385,17 @@ libs::
 	$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest $(patsubst %,"manifest components/%",$(notdir $(EXTRA_MANIFESTS)))
 endif
 
 ################################################################################
 # Copy each element of EXTRA_JS_MODULES to $(FINAL_TARGET)/modules
 ifdef EXTRA_JS_MODULES
 libs:: $(EXTRA_JS_MODULES)
 ifndef NO_DIST_INSTALL
-	$(INSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)/modules
+	$(call install_cmd,$(IFLAGS1) $^ $(FINAL_TARGET)/modules)
 endif
 
 endif
 
 ifdef EXTRA_PP_JS_MODULES
 libs:: $(EXTRA_PP_JS_MODULES)
 ifndef NO_DIST_INSTALL
 	$(EXIT_ON_ERROR) \
@@ -1418,42 +1418,42 @@ endif
 
 ifdef TESTING_JS_MODULES
 testmodulesdir = $(DEPTH)/_tests/modules/$(TESTING_JS_MODULE_DIR)
 
 GENERATED_DIRS += $(testmodulesdir)
 
 libs:: $(TESTING_JS_MODULES)
 ifndef NO_DIST_INSTALL
-	$(INSTALL) $(IFLAGS) $^ $(testmodulesdir)
+	$(call install_cmd,$(IFLAGS) $^ $(testmodulesdir))
 endif
 
 endif
 
 ################################################################################
 # SDK
 
 ifneq (,$(SDK_LIBRARY))
 $(SDK_LIB_DIR)::
 	$(NSINSTALL) -D $@
 
 ifndef NO_DIST_INSTALL
 libs:: $(SDK_LIBRARY) $(SDK_LIB_DIR)
-	$(INSTALL) $(IFLAGS2) $^
+	$(call install_cmd,$(IFLAGS2) $^)
 endif
 
 endif # SDK_LIBRARY
 
 ifneq (,$(strip $(SDK_BINARY)))
 $(SDK_BIN_DIR)::
 	$(NSINSTALL) -D $@
 
 ifndef NO_DIST_INSTALL
 libs:: $(SDK_BINARY) $(SDK_BIN_DIR)
-	$(INSTALL) $(IFLAGS2) $^
+	$(call install_cmd,$(IFLAGS2) $^)
 endif
 
 endif # SDK_BINARY
 
 ################################################################################
 # CHROME PACKAGING
 
 JAR_MANIFEST := $(srcdir)/jar.mn