about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-03-10 22:42:02 -0700
committerbors <bors@rust-lang.org>2014-03-10 22:42:02 -0700
commitb63cd004fc22089fbec7d74fc5a54536d093b1b4 (patch)
treef3a1ea1f55c3c85641184cb5e07e8e814d671d9e
parent294d3ddb89c86a91b0ac7298a31e729a9192171f (diff)
parent952380904b8e925851d96b55a959232ef360aede (diff)
downloadrust-b63cd004fc22089fbec7d74fc5a54536d093b1b4.tar.gz
rust-b63cd004fc22089fbec7d74fc5a54536d093b1b4.zip
auto merge of #12793 : brson/rust/installer, r=alexcrichton
Work towards #9876.

Several minor things here:
  * Fix the `need_ok` function in `configure`
  * Install man pages with non-executable permissions
  * Use the correct directory for man pages when installing (this was a recent regression)
  * Put all distributables in a new `dist/` directory in the build directory (there are soon to be significantly more of these)

Finally, this also creates a new, more precise way to install and uninstall Rust's files, the `install.sh` script, and creates a build target (currently `dist-tar-bins`) that creates a binary tarball containing all the installable files, boilerplate and license docs, and `install.sh`.

This binary tarball is the lowest-common denominator way to install Rust on Unix. We'll use it as the default installer on Linux (OS X will use .pkg).

## How `install.sh` works

* First, the makefiles (`prepare.mk` and `dist.mk`) put all the stuff that needs to be installed in a new directory in `dist/`.
* Then it puts `install.sh` in that same directory and a list of all the files to install at `rustlib/manifest`.
* Then the directory can be packaged and distributed.
* When `install.sh` runs it does some sanity checking then copies everything in the manifest to the install prefix, then copies the manifest as well.
* When `install.sh` runs again in the future it first looks for the existing manifest at the install prefix, and if it exists deletes everything in it. This is how the core distribution is upgraded - cargo is responsible for the rest.
* `install.sh --uninstall` will uninstall Rust

## Future work:

  * Modify `install.sh` to accept `--man-dir` etc
  * Rewrite `install.mk` to delegate to `install.sh`
  * Investigate how `install.sh` does or doesn't work with .pkg on Mac
  * Modify `dist.mk` to create `.pkg` files for all hosts
  * Possibly use [makeself](http://www.megastep.org/makeself/) to create self-extracting installers
  * Modify dist-snap bots run on mac as well, uploading binary tarballs and .pkg files for the four combos of linux, mac, x86, and x86_64.
  * Adjust build system to be able to augment versions with '-nightly'
  * Adjust build system to name dist artifacts without version numbers e.g. `rust-nightly-...pkg`. This is so we don't leave a huge trail of old nightly binaries on S3 - they just get overwritten.
  * Create new dist-nightly builder
  * Give the build master a new cron job to push to dist-nightly every night
  * Add docs to distributables
  * Update README.md to reflect the new reality
  * Modernize the website to promote new installers


-rw-r--r--.gitignore1
-rwxr-xr-xconfigure13
-rw-r--r--mk/dist.mk49
-rw-r--r--mk/prepare.mk28
-rw-r--r--src/etc/install.sh283
5 files changed, 349 insertions, 25 deletions
diff --git a/.gitignore b/.gitignore
index a72ba1be0df..9ed279d9d74 100644
--- a/.gitignore
+++ b/.gitignore
@@ -65,6 +65,7 @@ config.mk
 /mingw-build/
 src/.DS_Store
 /tmp/
+/dist/
 /stage0/
 /dl/
 /stage1/
diff --git a/configure b/configure
index a69069183e7..11edfbca655 100755
--- a/configure
+++ b/configure
@@ -22,7 +22,7 @@ err() {
 need_ok() {
     if [ $? -ne 0 ]
     then
-        err $1
+        err "$1"
     fi
 }
 
@@ -340,7 +340,7 @@ DEFAULT_BUILD="${CFG_CPUTYPE}-${CFG_OSTYPE}"
 
 CFG_SRC_DIR="$(cd $(dirname $0) && pwd)/"
 CFG_BUILD_DIR="$(pwd)/"
-CFG_SELF=${CFG_SRC_DIR}$(basename $0)
+CFG_SELF="$0"
 CFG_CONFIGURE_ARGS="$@"
 
 OPTIONS=""
@@ -412,16 +412,15 @@ fi
 valopt libdir "${CFG_PREFIX}/${CFG_LIBDIR_RELATIVE}" "install libraries"
 valopt rustlibdir "rustlib" "subdirectory name for rustc's libraries"
 
-# Validate Options
-step_msg "validating $CFG_SELF args"
-validate_opt
-
 if [ $HELP -eq 1 ]
 then
     echo
     exit 0
 fi
 
+# Validate Options
+step_msg "validating $CFG_SELF args"
+validate_opt
 
 step_msg "looking for build programs"
 
@@ -728,7 +727,7 @@ step_msg "making directories"
 
 for i in \
     doc doc/std doc/extra \
-    dl tmp
+    dl tmp dist
 do
     make_dir $i
 done
diff --git a/mk/dist.mk b/mk/dist.mk
index 17afeaae377..01ee7a7947b 100644
--- a/mk/dist.mk
+++ b/mk/dist.mk
@@ -4,16 +4,16 @@
 
 PKG_NAME := rust
 PKG_DIR = $(PKG_NAME)-$(CFG_RELEASE)
-PKG_TAR = $(PKG_DIR).tar.gz
+PKG_TAR = dist/$(PKG_DIR).tar.gz
 
 ifdef CFG_ISCC
 PKG_ISS = $(wildcard $(S)src/etc/pkg/*.iss)
 PKG_ICO = $(S)src/etc/pkg/rust-logo.ico
-PKG_EXE = $(PKG_DIR)-install.exe
+PKG_EXE = dist/$(PKG_DIR)-install.exe
 endif
 
 ifeq ($(CFG_OSTYPE), apple-darwin)
-PKG_OSX = $(PKG_DIR).pkg
+PKG_OSX = dist/$(PKG_DIR).pkg
 endif
 
 PKG_GITMODULES := $(S)src/libuv $(S)src/llvm $(S)src/gyp $(S)src/compiler-rt
@@ -71,14 +71,15 @@ dist-prepare-win: PREPARE_DIR_CMD=$(DEFAULT_PREPARE_DIR_CMD)
 dist-prepare-win: PREPARE_BIN_CMD=$(DEFAULT_PREPARE_BIN_CMD)
 dist-prepare-win: PREPARE_LIB_CMD=$(DEFAULT_PREPARE_LIB_CMD)
 dist-prepare-win: PREPARE_MAN_CMD=$(DEFAULT_PREPARE_MAN_CMD)
+dist-prepare-win: PREPARE_CLEAN=true
 dist-prepare-win: prepare-base
 
 endif
 
 $(PKG_TAR): $(PKG_FILES)
 	@$(call E, making dist dir)
-	$(Q)rm -Rf dist
-	$(Q)mkdir -p dist/$(PKG_DIR)
+	$(Q)rm -Rf tmp/dist/$(PKG_DIR)
+	$(Q)mkdir -p tmp/dist/$(PKG_DIR)
 	$(Q)tar \
          -C $(S) \
          --exclude-vcs \
@@ -89,9 +90,9 @@ $(PKG_TAR): $(PKG_FILES)
          --exclude=*/llvm/test/*/*/*.ll \
          --exclude=*/llvm/test/*/*/*.td \
          --exclude=*/llvm/test/*/*/*.s \
-         -c $(UNROOTED_PKG_FILES) | tar -x -C dist/$(PKG_DIR)
-	$(Q)tar -czf $(PKG_TAR) -C dist $(PKG_DIR)
-	$(Q)rm -Rf dist
+         -c $(UNROOTED_PKG_FILES) | tar -x -C tmp/dist/$(PKG_DIR)
+	$(Q)tar -czf $(PKG_TAR) -C tmp/dist $(PKG_DIR)
+	$(Q)rm -Rf tmp/dist/$(PKG_DIR)
 
 .PHONY: dist distcheck
 
@@ -156,3 +157,35 @@ distcheck-osx: $(PKG_OSX)
 	@echo -----------------------------------------------
 
 endif
+
+dist-install-dir: $(foreach host,$(CFG_HOST),dist-install-dir-$(host))
+
+dist-tar-bins: $(foreach host,$(CFG_HOST),dist/$(PKG_DIR)-$(host).tar.gz)
+
+define DEF_INSTALLER
+dist-install-dir-$(1): PREPARE_HOST=$(1)
+dist-install-dir-$(1): PREPARE_TARGETS=$(1)
+dist-install-dir-$(1): PREPARE_STAGE=2
+dist-install-dir-$(1): PREPARE_DEST_DIR=tmp/dist/$$(PKG_DIR)-$(1)
+dist-install-dir-$(1): PREPARE_DIR_CMD=$(DEFAULT_PREPARE_DIR_CMD)
+dist-install-dir-$(1): PREPARE_BIN_CMD=$(DEFAULT_PREPARE_BIN_CMD)
+dist-install-dir-$(1): PREPARE_LIB_CMD=$(DEFAULT_PREPARE_LIB_CMD)
+dist-install-dir-$(1): PREPARE_MAN_CMD=$(DEFAULT_PREPARE_MAN_CMD)
+dist-install-dir-$(1): PREPARE_CLEAN=true
+dist-install-dir-$(1): prepare-base
+	$$(Q)(cd $$(PREPARE_DEST_DIR)/ && find -type f) \
+      > $$(PREPARE_DEST_DIR)/$$(CFG_LIBDIR_RELATIVE)/$$(CFG_RUSTLIBDIR)/manifest
+	$$(Q)$$(PREPARE_MAN_CMD) $$(S)COPYRIGHT $$(PREPARE_DEST_DIR)
+	$$(Q)$$(PREPARE_MAN_CMD) $$(S)LICENSE-APACHE $$(PREPARE_DEST_DIR)
+	$$(Q)$$(PREPARE_MAN_CMD) $$(S)LICENSE-MIT $$(PREPARE_DEST_DIR)
+	$$(Q)$$(PREPARE_MAN_CMD) $$(S)README.md $$(PREPARE_DEST_DIR)
+	$$(Q)$$(PREPARE_BIN_CMD) $$(S)src/etc/install.sh $$(PREPARE_DEST_DIR)
+
+dist/$$(PKG_DIR)-$(1).tar.gz: dist-install-dir-$(1)
+	@$(call E, build: $$@)
+	$$(Q)tar -czf dist/$$(PKG_DIR)-$(1).tar.gz -C tmp/dist $$(PKG_DIR)-$(1)
+
+endef
+
+$(foreach host,$(CFG_HOST),\
+  $(eval $(call DEF_INSTALLER,$(host))))
diff --git a/mk/prepare.mk b/mk/prepare.mk
index 356ce2e908e..304806f12ad 100644
--- a/mk/prepare.mk
+++ b/mk/prepare.mk
@@ -33,7 +33,7 @@ prepare-base: PREPARE_SOURCE_LIB_DIR=$(PREPARE_SOURCE_DIR)/$(CFG_LIBDIR_RELATIVE
 prepare-base: PREPARE_SOURCE_MAN_DIR=$(S)/man
 prepare-base: PREPARE_DEST_BIN_DIR=$(PREPARE_DEST_DIR)/bin
 prepare-base: PREPARE_DEST_LIB_DIR=$(PREPARE_DEST_DIR)/$(CFG_LIBDIR_RELATIVE)
-prepare-base: PREPARE_DEST_MAN_DIR=$(PREPARE_DEST_DIR)/man1
+prepare-base: PREPARE_DEST_MAN_DIR=$(PREPARE_DEST_DIR)/man/man1
 prepare-base: prepare-host prepare-targets
 
 prepare-everything: prepare-host prepare-targets
@@ -41,7 +41,7 @@ prepare-everything: prepare-host prepare-targets
 DEFAULT_PREPARE_DIR_CMD = umask 022 && mkdir -p
 DEFAULT_PREPARE_BIN_CMD = install -m755
 DEFAULT_PREPARE_LIB_CMD = install -m644
-DEFAULT_PREPARE_MAN_CMD = install -m755
+DEFAULT_PREPARE_MAN_CMD = install -m644
 
 # On windows we install from stage3, but on unix only stage2
 # Because of the way these rules are organized, preparing from any
@@ -55,14 +55,14 @@ endif
 # Create a directory
 # $(1) is the directory
 define PREPARE_DIR
-	@$(Q)$(call E, install: $(1))
+	@$(Q)$(call E, prepare: $(1))
 	$(Q)$(PREPARE_DIR_CMD) $(1)
 endef
 
 # Copy an executable
 # $(1) is the filename/libname-glob
 define PREPARE_BIN
-	@$(call E, install: $(PREPARE_DEST_BIN_DIR)/$(1))
+	@$(call E, prepare: $(PREPARE_DEST_BIN_DIR)/$(1))
 	$(Q)$(PREPARE_BIN_CMD) $(PREPARE_SOURCE_BIN_DIR)/$(1) $(PREPARE_DEST_BIN_DIR)/$(1)
 endef
 
@@ -75,7 +75,7 @@ endef
 # problem. I'm sorry, just don't remove the $(nop), alright?
 define PREPARE_LIB
 	$(nop)
-	@$(call E, install: $(PREPARE_WORKING_DEST_LIB_DIR)/$(1))
+	@$(call E, prepare: $(PREPARE_WORKING_DEST_LIB_DIR)/$(1))
 	$(Q)LIB_NAME="$(notdir $(lastword $(wildcard $(PREPARE_WORKING_SOURCE_LIB_DIR)/$(1))))"; \
 	MATCHES="$(filter-out %$(notdir $(lastword $(wildcard $(PREPARE_WORKING_SOURCE_LIB_DIR)/$(1)))),\
                         $(wildcard $(PREPARE_WORKING_DEST_LIB_DIR)/$(1)))"; \
@@ -91,7 +91,7 @@ endef
 # Copy a man page
 # $(1) - source dir
 define PREPARE_MAN
-	@$(call E, install: $(PREPARE_DEST_MAN_DIR)/$(1))
+	@$(call E, prepare: $(PREPARE_DEST_MAN_DIR)/$(1))
 	$(Q)$(PREPARE_MAN_CMD) $(PREPARE_SOURCE_MAN_DIR)/$(1) $(PREPARE_DEST_MAN_DIR)/$(1)
 endef
 
@@ -106,7 +106,7 @@ prepare-host-tools: \
             $(foreach host,$(CFG_HOST),\
               prepare-host-tool-$(tool)-$(stage)-$(host))))
 
-prepare-host-dirs:
+prepare-host-dirs: prepare-maybe-clean
 	$(call PREPARE_DIR,$(PREPARE_DEST_BIN_DIR))
 	$(call PREPARE_DIR,$(PREPARE_DEST_LIB_DIR))
 	$(call PREPARE_DIR,$(PREPARE_DEST_MAN_DIR))
@@ -115,7 +115,8 @@ prepare-host-dirs:
 # $(2) is stage
 # $(3) is host
 define DEF_PREPARE_HOST_TOOL
-prepare-host-tool-$(1)-$(2)-$(3): $$(foreach dep,$$(TOOL_DEPS_$(1)),prepare-host-lib-$$(dep)-$(2)-$(3)) \
+prepare-host-tool-$(1)-$(2)-$(3): prepare-maybe-clean \
+                                  $$(foreach dep,$$(TOOL_DEPS_$(1)),prepare-host-lib-$$(dep)-$(2)-$(3)) \
                                   $$(HBIN$(2)_H_$(3))/$(1)$$(X_$(3)) \
                                   prepare-host-dirs
 	$$(if $$(findstring $(2), $$(PREPARE_STAGE)),\
@@ -140,7 +141,8 @@ $(foreach tool,$(PREPARE_TOOLS),\
 define DEF_PREPARE_HOST_LIB
 prepare-host-lib-$(1)-$(2)-$(3): PREPARE_WORKING_SOURCE_LIB_DIR=$$(PREPARE_SOURCE_LIB_DIR)
 prepare-host-lib-$(1)-$(2)-$(3): PREPARE_WORKING_DEST_LIB_DIR=$$(PREPARE_DEST_LIB_DIR)
-prepare-host-lib-$(1)-$(2)-$(3): $$(foreach dep,$$(RUST_DEPS_$(1)),prepare-host-lib-$$(dep)-$(2)-$(3))\
+prepare-host-lib-$(1)-$(2)-$(3): prepare-maybe-clean \
+                                 $$(foreach dep,$$(RUST_DEPS_$(1)),prepare-host-lib-$$(dep)-$(2)-$(3))\
                                  $$(HLIB$(2)_H_$(3))/stamp.$(1) \
                                  prepare-host-dirs
 	$$(if $$(findstring $(2), $$(PREPARE_STAGE)),\
@@ -166,7 +168,7 @@ define DEF_PREPARE_TARGET_N
 # Rebind PREPARE_*_LIB_DIR to point to rustlib, then install the libs for the targets
 prepare-target-$(2)-host-$(3)-$(1): PREPARE_WORKING_SOURCE_LIB_DIR=$$(PREPARE_SOURCE_LIB_DIR)/$$(CFG_RUSTLIBDIR)/$(2)/lib
 prepare-target-$(2)-host-$(3)-$(1): PREPARE_WORKING_DEST_LIB_DIR=$$(PREPARE_DEST_LIB_DIR)/$$(CFG_RUSTLIBDIR)/$(2)/lib
-prepare-target-$(2)-host-$(3)-$(1): \
+prepare-target-$(2)-host-$(3)-$(1): prepare-maybe-clean \
         $$(foreach crate,$$(TARGET_CRATES), \
           $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(crate)) \
         $$(if $$(findstring $(2),$$(CFG_HOST)), \
@@ -194,3 +196,9 @@ $(foreach host,$(CFG_HOST),\
   $(foreach target,$(CFG_TARGET), \
     $(foreach stage,$(PREPARE_STAGES),\
       $(eval $(call DEF_PREPARE_TARGET_N,$(stage),$(target),$(host))))))
+
+prepare-maybe-clean:
+	$(if $(findstring true,$(PREPARE_CLEAN)),\
+      @$(call E, cleaning destination $@),)
+	$(if $(findstring true,$(PREPARE_CLEAN)),\
+      $(Q)rm -rf $(PREPARE_DEST_DIR),)
diff --git a/src/etc/install.sh b/src/etc/install.sh
new file mode 100644
index 00000000000..9e718a61d88
--- /dev/null
+++ b/src/etc/install.sh
@@ -0,0 +1,283 @@
+#!/bin/sh
+# Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+msg() {
+    echo "install: $1"
+}
+
+step_msg() {
+    msg
+    msg "$1"
+    msg
+}
+
+warn() {
+    echo "install: WARNING: $1"
+}
+
+err() {
+    echo "install: error: $1"
+    exit 1
+}
+
+need_ok() {
+    if [ $? -ne 0 ]
+    then
+        err "$1"
+    fi
+}
+
+putvar() {
+    local T
+    eval T=\$$1
+    eval TLEN=\${#$1}
+    if [ $TLEN -gt 35 ]
+    then
+        printf "install: %-20s := %.35s ...\n" $1 "$T"
+    else
+        printf "install: %-20s := %s %s\n" $1 "$T" "$2"
+    fi
+    printf "%-20s := %s\n" $1 "$T" >>config.tmp
+}
+
+valopt() {
+    VAL_OPTIONS="$VAL_OPTIONS $1"
+
+    local OP=$1
+    local DEFAULT=$2
+    shift
+    shift
+    local DOC="$*"
+    if [ $HELP -eq 0 ]
+    then
+        local UOP=$(echo $OP | tr '[:lower:]' '[:upper:]' | tr '\-' '\_')
+        local V="CFG_${UOP}"
+        eval $V="$DEFAULT"
+        for arg in $CFG_ARGS
+        do
+            if echo "$arg" | grep -q -- "--$OP="
+            then
+                val=$(echo "$arg" | cut -f2 -d=)
+                eval $V=$val
+            fi
+        done
+        putvar $V
+    else
+        if [ -z "$DEFAULT" ]
+        then
+            DEFAULT="<none>"
+        fi
+        OP="${OP}=[${DEFAULT}]"
+        printf "    --%-30s %s\n" "$OP" "$DOC"
+    fi
+}
+
+opt() {
+    BOOL_OPTIONS="$BOOL_OPTIONS $1"
+
+    local OP=$1
+    local DEFAULT=$2
+    shift
+    shift
+    local DOC="$*"
+    local FLAG=""
+
+    if [ $DEFAULT -eq 0 ]
+    then
+        FLAG="enable"
+    else
+        FLAG="disable"
+        DOC="don't $DOC"
+    fi
+
+    if [ $HELP -eq 0 ]
+    then
+        for arg in $CFG_ARGS
+        do
+            if [ "$arg" = "--${FLAG}-${OP}" ]
+            then
+                OP=$(echo $OP | tr 'a-z-' 'A-Z_')
+                FLAG=$(echo $FLAG | tr 'a-z' 'A-Z')
+                local V="CFG_${FLAG}_${OP}"
+                eval $V=1
+                putvar $V
+            fi
+        done
+    else
+        if [ ! -z "$META" ]
+        then
+            OP="$OP=<$META>"
+        fi
+        printf "    --%-30s %s\n" "$FLAG-$OP" "$DOC"
+     fi
+}
+
+flag() {
+    BOOL_OPTIONS="$BOOL_OPTIONS $1"
+
+    local OP=$1
+    shift
+    local DOC="$*"
+
+    if [ $HELP -eq 0 ]
+    then
+        for arg in $CFG_ARGS
+        do
+            if [ "$arg" = "--${OP}" ]
+            then
+                OP=$(echo $OP | tr 'a-z-' 'A-Z_')
+                local V="CFG_${OP}"
+                eval $V=1
+                putvar $V
+            fi
+        done
+    else
+        if [ ! -z "$META" ]
+        then
+            OP="$OP=<$META>"
+        fi
+        printf "    --%-30s %s\n" "$OP" "$DOC"
+     fi
+}
+
+validate_opt () {
+    for arg in $CFG_ARGS
+    do
+        isArgValid=0
+        for option in $BOOL_OPTIONS
+        do
+            if test --disable-$option = $arg
+            then
+                isArgValid=1
+            fi
+            if test --enable-$option = $arg
+            then
+                isArgValid=1
+            fi
+            if test --$option = $arg
+            then
+                isArgValid=1
+            fi
+        done
+        for option in $VAL_OPTIONS
+        do
+            if echo "$arg" | grep -q -- "--$option="
+            then
+                isArgValid=1
+            fi
+        done
+        if [ "$arg" = "--help" ]
+        then
+            echo
+            echo "No more help available for Configure options,"
+            echo "check the Wiki or join our IRC channel"
+            break
+        else
+            if test $isArgValid -eq 0
+            then
+                err "Option '$arg' is not recognized"
+            fi
+        fi
+    done
+}
+
+CFG_SRC_DIR="$(cd $(dirname $0) && pwd)/"
+CFG_SELF="$0"
+CFG_ARGS="$@"
+
+HELP=0
+if [ "$1" = "--help" ]
+then
+    HELP=1
+    shift
+    echo
+    echo "Usage: $CFG_SELF [options]"
+    echo
+    echo "Options:"
+    echo
+else
+    step_msg "processing $CFG_SELF args"
+fi
+
+OPTIONS=""
+BOOL_OPTIONS=""
+VAL_OPTIONS=""
+
+flag uninstall "only uninstall from the installation prefix"
+valopt prefix "/usr/local" "set installation prefix"
+
+if [ $HELP -eq 1 ]
+then
+    echo
+    exit 0
+fi
+
+step_msg "validating $CFG_SELF args"
+validate_opt
+
+# Sanity check: can we can write to the destination?
+touch "${CFG_PREFIX}/lib/rust-install-probe" 2> /dev/null
+if [ $? -ne 0 ]
+then
+    err "can't write to destination. try again with 'sudo'."
+fi
+rm -r "${CFG_PREFIX}/lib/rust-install-probe"
+need_ok "failed to remove install probe"
+
+# Sanity check: can we run these binaries?
+"${CFG_SRC_DIR}/bin/rustc" --version > /dev/null
+need_ok "can't run these binaries on this platform"
+
+# First, uninstall from the installation prefix
+# FIXME: Hardcoded 'rustlib' ignores CFG_RUSTLIBDIR
+if [ -f "${CFG_PREFIX}/lib/rustlib/manifest" ]
+then
+    while read p; do
+        msg "uninstall ${CFG_PREFIX}/$p"
+        rm "${CFG_PREFIX}/$p"
+        need_ok "failed to remove file"
+    done < "${CFG_PREFIX}/lib/rustlib/manifest"
+
+    # Remove 'rustlib' directory
+    msg "uninstall ${CFG_PREFIX}/lib/rustlib"
+    rm -r "${CFG_PREFIX}/lib/rustlib"
+    need_ok "failed to remove rustlib"
+fi
+
+# If we're only uninstalling then exit
+if [ -n "${CFG_UNINSTALL}" ]
+then
+    exit 0
+fi
+
+# Iterate through the new manifest and install files
+while read p; do
+
+    umask 022 && mkdir -p "${CFG_PREFIX}/$(dirname $p)"
+    need_ok "directory creation failed"
+
+    msg "${CFG_PREFIX}/$p"
+    if echo "$p" | grep "/bin/" > /dev/null
+    then
+        install -m755 "${CFG_SRC_DIR}/$p" "${CFG_PREFIX}/$p"
+    else
+        install -m644 "${CFG_SRC_DIR}/$p" "${CFG_PREFIX}/$p"
+    fi
+    need_ok "file creation failed"
+
+# The manifest lists all files to install
+done < "${CFG_SRC_DIR}/lib/rustlib/manifest"
+
+echo
+echo "    Rust is ready to roll."
+echo
+
+