Add an installation script to the repo

This updates the `make install` target and adds a new `make dist` target which
will prepare a distributable tarball with an install script. All work is based
off the equivalent rust nightly tarball and nightly installation scripts.

Closes #159
Closes #184
This commit is contained in:
Alex Crichton 2014-07-14 08:06:14 -07:00
parent 4ef91beed0
commit 1aaaf85166
4 changed files with 542 additions and 24 deletions

View File

@ -1,7 +1,8 @@
RUSTC_FLAGS ?= RUSTC_FLAGS ?=
DESTDIR ?= DESTDIR ?=
PREFIX ?= /usr/local PREFIX ?= /usr/local
BINDIR ?= $(PREFIX)/bin TARGET ?= target
PKG_NAME ?= cargo-nightly
ifeq ($(wildcard rustc/bin),) ifeq ($(wildcard rustc/bin),)
export RUSTC := rustc export RUSTC := rustc
@ -29,8 +30,11 @@ DEPS = -L libs/hammer.rs/target -L libs/toml-rs/build
TOML = libs/toml-rs/build/$(shell $(RUSTC) --print-file-name libs/toml-rs/src/toml.rs) TOML = libs/toml-rs/build/$(shell $(RUSTC) --print-file-name libs/toml-rs/src/toml.rs)
HAMMER = libs/hammer.rs/target/$(shell $(RUSTC) --crate-type=lib --print-file-name libs/hammer.rs/src/hammer.rs) HAMMER = libs/hammer.rs/target/$(shell $(RUSTC) --crate-type=lib --print-file-name libs/hammer.rs/src/hammer.rs)
HAMCREST = libs/hamcrest-rust/target/libhamcrest.timestamp HAMCREST = libs/hamcrest-rust/target/libhamcrest.timestamp
LIBCARGO = target/libcargo.timestamp LIBCARGO = $(TARGET)/libcargo.rlib
BIN_TARGETS = $(patsubst %,target/%,$(BINS)) TESTDIR = $(TARGET)/tests
DISTDIR = $(TARGET)/dist
PKGDIR = $(DISTDIR)/$(PKG_NAME)
BIN_TARGETS = $(BINS:%=$(TARGET)/%)
all: $(BIN_TARGETS) all: $(BIN_TARGETS)
@ -45,36 +49,39 @@ $(TOML): $(wildcard libs/toml-rs/src/*.rs)
$(HAMCREST): $(shell find libs/hamcrest-rust/src/hamcrest -name '*.rs') $(HAMCREST): $(shell find libs/hamcrest-rust/src/hamcrest -name '*.rs')
$(MAKE) -C libs/hamcrest-rust $(MAKE) -C libs/hamcrest-rust
$(TARGET)/:
mkdir -p $@
$(TESTDIR)/:
mkdir -p $@
# === Cargo # === Cargo
$(LIBCARGO): $(SRC) $(HAMMER) $(TOML) $(LIBCARGO): $(SRC) $(HAMMER) $(TOML) | $(TARGET)/
mkdir -p target $(RUSTC) $(RUSTC_FLAGS) $(DEPS) --out-dir $(TARGET) src/cargo/lib.rs
$(RUSTC) $(RUSTC_FLAGS) $(DEPS) --out-dir target src/cargo/lib.rs
touch $(LIBCARGO)
libcargo: $(LIBCARGO) libcargo: $(LIBCARGO)
# === Commands # === Commands
$(BIN_TARGETS): target/%: src/bin/%.rs $(HAMMER) $(TOML) $(LIBCARGO) $(BIN_TARGETS): $(TARGET)/%: src/bin/%.rs $(HAMMER) $(TOML) $(LIBCARGO)
$(RUSTC) $(RUSTC_FLAGS) $(DEPS) -Ltarget --out-dir target $< $(RUSTC) $(RUSTC_FLAGS) $(DEPS) -L$(TARGET) --out-dir $(TARGET) $<
# === Tests # === Tests
TEST_SRC = $(shell find tests -name '*.rs') TEST_SRC = $(shell find tests -name '*.rs')
TEST_DEPS = $(DEPS) -L libs/hamcrest-rust/target TEST_DEPS = $(DEPS) -L libs/hamcrest-rust/target
target/tests/test-integration: $(HAMCREST) $(TEST_SRC) $(BIN_TARGETS) $(TESTDIR)/test-integration: $(HAMCREST) $(TEST_SRC) $(BIN_TARGETS) | $(TESTDIR)/
$(RUSTC) --test --crate-type=lib $(TEST_DEPS) -Ltarget -o $@ tests/tests.rs $(RUSTC) --test $(TEST_DEPS) -L$(TARGET) -o $@ tests/tests.rs
target/tests/test-unit: $(TOML) $(HAMCREST) $(SRC) $(HAMMER) $(TESTDIR)/test-unit: $(TOML) $(HAMCREST) $(SRC) $(HAMMER) | $(TESTDIR)/
mkdir -p target/tests
$(RUSTC) --test -g $(RUSTC_FLAGS) $(TEST_DEPS) -o $@ src/cargo/lib.rs $(RUSTC) --test -g $(RUSTC_FLAGS) $(TEST_DEPS) -o $@ src/cargo/lib.rs
test-unit: target/tests/test-unit test-unit: $(TESTDIR)/test-unit
target/tests/test-unit $(only) $< $(only)
test-integration: target/tests/test-integration test-integration: $(TESTDIR)/test-integration
$< $(only) $< $(only)
test: test-unit test-integration style no-exes test: test-unit test-integration style no-exes
@ -88,14 +95,42 @@ no-exes:
&& exit 1 || exit 0 && exit 1 || exit 0
clean: clean:
rm -rf target rm -rf $(TARGET)
clean-all: clean clean-all: clean
git submodule foreach make clean git submodule foreach make clean
install: dist: $(DISTDIR)/$(PKG_NAME).tar.gz
install -d $(DESTDIR)$(BINDIR)
install target/cargo target/cargo-* $(DESTDIR)$(BINDIR) distcheck: dist
rm -rf $(TARGET)/distcheck
mkdir -p $(TARGET)/distcheck
(cd $(TARGET)/distcheck && tar xf ../dist/$(PKG_NAME).tar.gz)
$(TARGET)/distcheck/$(PKG_NAME)/install.sh \
--prefix=$(TARGET)/distcheck/install
$(TARGET)/distcheck/install/bin/cargo -h > /dev/null
$(TARGET)/distcheck/$(PKG_NAME)/install.sh \
--prefix=$(TARGET)/distcheck/install --uninstall
[ -f $(TARGET)/distcheck/install/bin/cargo ] && exit 1 || exit 0
$(DISTDIR)/$(PKG_NAME).tar.gz: $(PKGDIR)/lib/cargo/manifest.in
tar -czvf $@ -C $(DISTDIR) $(PKG_NAME)
$(PKGDIR)/lib/cargo/manifest.in: $(BIN_TARGETS) Makefile
rm -rf $(PKGDIR)
mkdir -p $(PKGDIR)/bin $(PKGDIR)/lib/cargo
cp $(TARGET)/cargo $(PKGDIR)/bin
cp $(BIN_TARGETS) $(PKGDIR)/lib/cargo
rm $(PKGDIR)/lib/cargo/cargo
(cd $(PKGDIR) && find . -type f | sed 's/^\.\///') \
> $(DISTDIR)/manifest-$(PKG_NAME).in
cp src/install.sh $(PKGDIR)
cp README.md LICENSE-MIT LICENSE-APACHE $(PKGDIR)
cp LICENSE-MIT $(PKGDIR)
mv $(DISTDIR)/manifest-$(PKG_NAME).in $(PKGDIR)/lib/cargo/manifest.in
install: $(PKGDIR)/lib/cargo/manifest.in
$(PKGDIR)/install.sh --prefix=$(PREFIX)
# Setup phony tasks # Setup phony tasks
.PHONY: all clean distclean test test-unit test-integration libcargo style .PHONY: all clean distclean test test-unit test-integration libcargo style

View File

@ -2,7 +2,7 @@ Cargo downloads your Rust projects dependencies and compiles your project.
Learn more at http://crates.io/. Learn more at http://crates.io/.
## Installing cargo ## Installing cargo from nightlies
Cargo has nightlies available for use. The cargo source is not always guaranteed Cargo has nightlies available for use. The cargo source is not always guaranteed
to compile on rust master as it may lag behind by a day or two. Nightlies, to compile on rust master as it may lag behind by a day or two. Nightlies,
@ -11,7 +11,7 @@ however, will run regardless of this fact!
``` ```
$ curl -O http://static.rust-lang.org/cargo-dist/cargo-nightly-linux.tar.gz $ curl -O http://static.rust-lang.org/cargo-dist/cargo-nightly-linux.tar.gz
$ tar xf cargo-nightly-linux.tar.gz $ tar xf cargo-nightly-linux.tar.gz
$ ./cargo-nightly/bin/cargo build $ ./cargo-nightly/install.sh
``` ```
The current nightlies available are: The current nightlies available are:

View File

@ -58,9 +58,20 @@ fn execute() {
println!("Options (for all commands):\n\n{}", options); println!("Options (for all commands):\n\n{}", options);
}, },
_ => { _ => {
let command = format!("cargo-{}", cmd); let command = format!("cargo-{}{}", cmd, os::consts::EXE_SUFFIX);
let mut command = match os::self_exe_path() { let mut command = match os::self_exe_path() {
Some(path) => Command::new(path.join(command)), Some(path) => {
let p1 = path.join("../lib/cargo").join(command.as_slice());
let p2 = path.join(command.as_slice());
println!("{} {}", p1.display(), p2.display());
if p1.exists() {
Command::new(p1)
} else if p2.exists() {
Command::new(p2)
} else {
Command::new(command)
}
}
None => Command::new(command), None => Command::new(command),
}; };
let command = command let command = command

472
src/install.sh Executable file
View File

@ -0,0 +1,472 @@
#!/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
}
need_cmd() {
if command -v $1 >/dev/null 2>&1
then msg "found $1"
else err "need $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
}
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
}
absolutify() {
FILE_PATH="${1}"
FILE_PATH_DIRNAME="$(dirname ${FILE_PATH})"
FILE_PATH_BASENAME="$(basename ${FILE_PATH})"
FILE_ABS_PATH="$(cd ${FILE_PATH_DIRNAME} && pwd)"
FILE_PATH="${FILE_ABS_PATH}/${FILE_PATH_BASENAME}"
# This is the return value
ABSOLUTIFIED="${FILE_PATH}"
}
msg "looking for install programs"
need_cmd mkdir
need_cmd printf
need_cmd cut
need_cmd grep
need_cmd uname
need_cmd tr
need_cmd sed
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
# Check for mingw or cygwin in order to special case $CFG_LIBDIR_RELATIVE.
# This logic is duplicated from configure in order to get the correct libdir
# for Windows installs.
CFG_OSTYPE=$(uname -s)
case $CFG_OSTYPE in
MINGW32*)
CFG_OSTYPE=pc-mingw32
;;
MINGW64*)
# msys2, MSYSTEM=MINGW64
CFG_OSTYPE=w64-mingw32
;;
# Thad's Cygwin identifers below
# Vista 32 bit
CYGWIN_NT-6.0)
CFG_OSTYPE=pc-mingw32
;;
# Vista 64 bit
CYGWIN_NT-6.0-WOW64)
CFG_OSTYPE=w64-mingw32
;;
# Win 7 32 bit
CYGWIN_NT-6.1)
CFG_OSTYPE=pc-mingw32
;;
# Win 7 64 bit
CYGWIN_NT-6.1-WOW64)
CFG_OSTYPE=w64-mingw32
;;
esac
OPTIONS=""
BOOL_OPTIONS=""
VAL_OPTIONS=""
# On windows we just store the libraries in the bin directory because
# there's no rpath. This is where the build system itself puts libraries;
# --libdir is used to configure the installation directory.
# FIXME: Thise needs to parameterized over target triples. Do it in platform.mk
CFG_LIBDIR_RELATIVE=lib
if [ "$CFG_OSTYPE" = "pc-mingw32" ] || [ "$CFG_OSTYPE" = "w64-mingw32" ]
then
CFG_LIBDIR_RELATIVE=bin
fi
flag uninstall "only uninstall from the installation prefix"
opt verify 1 "verify that the installed binaries run correctly"
valopt prefix "/usr/local" "set installation prefix"
# NB This isn't quite the same definition as in `configure`.
# just using 'lib' instead of CFG_LIBDIR_RELATIVE
valopt libdir "${CFG_PREFIX}/${CFG_LIBDIR_RELATIVE}" "install libraries"
valopt mandir "${CFG_PREFIX}/share/man" "install man pages in PATH"
if [ $HELP -eq 1 ]
then
echo
exit 0
fi
step_msg "validating $CFG_SELF args"
validate_opt
# OK, let's get installing ...
# Sanity check: can we run the binaries?
if [ -z "${CFG_DISABLE_VERIFY}" ]
then
# Don't do this if uninstalling. Failure here won't help in any way.
if [ -z "${CFG_UNINSTALL}" ]
then
msg "verifying platform can run binaries"
"${CFG_SRC_DIR}/bin/cargo" -h > /dev/null
if [ $? -ne 0 ]
then
err "can't execute rustc binary on this platform"
fi
fi
fi
# Sanity check: can we can write to the destination?
msg "verifying destination is writable"
umask 022 && mkdir -p "${CFG_LIBDIR}"
need_ok "can't write to destination. consider \`sudo\`."
touch "${CFG_LIBDIR}/rust-install-probe" > /dev/null
if [ $? -ne 0 ]
then
err "can't write to destination. consider \`sudo\`."
fi
rm -f "${CFG_LIBDIR}/rust-install-probe"
need_ok "failed to remove install probe"
# Sanity check: don't install to the directory containing the installer.
# That would surely cause chaos.
msg "verifying destination is not the same as source"
INSTALLER_DIR="$(cd $(dirname $0) && pwd)"
PREFIX_DIR="$(cd ${CFG_PREFIX} && pwd)"
if [ "${INSTALLER_DIR}" = "${PREFIX_DIR}" ]
then
err "can't install to same directory as installer"
fi
# Using an absolute path to libdir in a few places so that the status
# messages are consistently using absolute paths.
absolutify "${CFG_LIBDIR}"
ABS_LIBDIR="${ABSOLUTIFIED}"
# The file name of the manifest we're going to create during install
INSTALLED_MANIFEST="${ABS_LIBDIR}/cargo/manifest"
# First, uninstall from the installation prefix.
# Errors are warnings - try to rm everything in the manifest even if some fail.
if [ -f "${INSTALLED_MANIFEST}" ]
then
# Iterate through installed manifest and remove files
while read p; do
# The installed manifest contains absolute paths
msg "removing $p"
if [ -f "$p" ]
then
rm -f "$p"
if [ $? -ne 0 ]
then
warn "failed to remove $p"
fi
else
warn "supposedly installed file $p does not exist!"
fi
done < "${INSTALLED_MANIFEST}"
# If we fail to remove cargo below, then the installed manifest will
# still be full; the installed manifest needs to be empty before install.
msg "removing ${INSTALLED_MANIFEST}"
rm -f "${INSTALLED_MANIFEST}"
# For the above reason, this is a hard error
need_ok "failed to remove installed manifest"
# Remove 'rustlib' directory
msg "removing ${ABS_LIBDIR}/cargo"
rm -Rf "${ABS_LIBDIR}/cargo"
if [ $? -ne 0 ]
then
warn "failed to remove cargo"
fi
else
# There's no manifest. If we were asked to uninstall, then that's a problem.
if [ -n "${CFG_UNINSTALL}" ]
then
err "unable to find installation manifest at ${CFG_LIBDIR}/cargo"
fi
fi
# If we're only uninstalling then exit
if [ -n "${CFG_UNINSTALL}" ]
then
echo
echo " Cargo is uninstalled."
echo
exit 0
fi
# Create the installed manifest, which we will fill in with absolute file paths
mkdir -p "${CFG_LIBDIR}/cargo"
need_ok "failed to create cargo"
touch "${INSTALLED_MANIFEST}"
need_ok "failed to create installed manifest"
# Now install, iterate through the new manifest and copy files
while read p; do
# Decide the destination of the file
FILE_INSTALL_PATH="${CFG_PREFIX}/$p"
if echo "$p" | grep "^lib/" > /dev/null
then
pp=`echo $p | sed 's/^lib\///'`
FILE_INSTALL_PATH="${CFG_LIBDIR}/$pp"
fi
if echo "$p" | grep "^share/man/" > /dev/null
then
pp=`echo $p | sed 's/^share\/man\///'`
FILE_INSTALL_PATH="${CFG_MANDIR}/$pp"
fi
# Make sure there's a directory for it
umask 022 && mkdir -p "$(dirname ${FILE_INSTALL_PATH})"
need_ok "directory creation failed"
# Make the path absolute so we can uninstall it later without
# starting from the installation cwd
absolutify "${FILE_INSTALL_PATH}"
FILE_INSTALL_PATH="${ABSOLUTIFIED}"
# Install the file
msg "${FILE_INSTALL_PATH}"
if echo "$p" | grep "^bin/\\|/cargo-" > /dev/null
then
install -m755 "${CFG_SRC_DIR}/$p" "${FILE_INSTALL_PATH}"
else
install -m644 "${CFG_SRC_DIR}/$p" "${FILE_INSTALL_PATH}"
fi
need_ok "file creation failed"
# Update the manifest
echo "${FILE_INSTALL_PATH}" >> "${INSTALLED_MANIFEST}"
need_ok "failed to update manifest"
# The manifest lists all files to install
done < "${CFG_SRC_DIR}/${CFG_LIBDIR_RELATIVE}/cargo/manifest.in"
# Sanity check: can we run the installed binaries?
if [ -z "${CFG_DISABLE_VERIFY}" ]
then
msg "verifying installed binaries are executable"
"${CFG_PREFIX}/bin/cargo" -h > /dev/null
if [ $? -ne 0 ]
then
ERR="can't execute installed rustc binary. "
ERR="${ERR}installation may be broken. "
ERR="${ERR}if this is expected then rerun install.sh with \`--disable-verify\` "
ERR="${ERR}or \`make install\` with \`--disable-verify-install\`"
err "${ERR}"
fi
fi
echo
echo " Cargo is ready to roll."
echo