Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Or use `./run.sh`, which also does a `git pull`, installs the dependencies (pyga

To play in a pygame window instead, install pygame and change `INTERFACE_TYPE` near the top of `src/fishE.py` from `UIType.CONSOLE` to `UIType.PYGAME`. The two browser front-ends are started differently; see [Play in your browser](#play-in-your-browser) below.

On a Debian-based machine, `install.sh` (run as root) clones the game into `/usr/games/FishE` and adds a `fishe` command that runs `./run.sh` there; `uninstall.sh` removes both.
On a Debian-based machine, `install.sh` (run as root) clones the game into `/usr/games/FishE` and adds a `fishe` command that runs `./run.sh` there; `uninstall.sh` removes both. It runs without prompting and is safe to run again: a second run updates the existing clone with `git pull` rather than cloning over it.

## Features

Expand Down
24 changes: 18 additions & 6 deletions install.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
mkdir /usr/games
#!/bin/sh
# Usage: sudo sh install.sh
# Safe to run again: an existing install is updated rather than cloned over.
set -e

INSTALL_DIR=/usr/games/FishE

mkdir -p /usr/games

apt-get update
apt-get install git
cd /usr/games && git clone https://github.com/Stephenson-Software/FishE
apt-get install -y git

echo "cd /usr/games/FishE && ./run.sh" > /bin/fishe
chmod +x /usr/games/FishE/run.sh
if [ -d "$INSTALL_DIR/.git" ]; then
echo "Existing install found in $INSTALL_DIR - updating it."
git -C "$INSTALL_DIR" pull
else
git clone https://github.com/Stephenson-Software/FishE "$INSTALL_DIR"
fi

echo "cd $INSTALL_DIR && ./run.sh" > /bin/fishe
chmod +x "$INSTALL_DIR/run.sh"
chmod +x /bin/fishe

echo "Installation complete. Type 'fishe' to play."

100 changes: 100 additions & 0 deletions tests/test_installScript.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
"""install.sh must run unattended, and must survive being run a second time.

The script needs root and changes /usr/games and /bin, so neither CI nor a
contributor's test run can execute it. These tests assert its contract from the
text instead: a shell to run it under, stopping at the first failure, no step
that waits on a prompt, and an existing install updated rather than cloned over.
"""

import os

REPOSITORY_ROOT = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))


def readInstallScript():
with open(os.path.join(REPOSITORY_ROOT, "install.sh"), encoding="utf-8") as script:
return script.read()


def commandLines(script):
"""The lines of the script that run something, with comments and blank
lines dropped so a mention in prose can't stand in for the real thing."""
commands = []
for line in script.splitlines():
stripped = line.strip()
if stripped and not stripped.startswith("#"):
commands.append(stripped)
return commands


def test_install_sh_names_its_shell():
# prepare
script = readInstallScript()

# call
firstLine = script.splitlines()[0]

# check
assert firstLine == "#!/bin/sh"


def test_install_sh_stops_at_the_first_failure():
# prepare
script = readInstallScript()

# call
commands = commandLines(script)

# check
assert "set -e" in commands
# before anything that installs or writes, so a failed step can't leave
# /bin/fishe pointing at a directory that was never cloned
assert commands.index("set -e") < min(
index for index, command in enumerate(commands) if "apt-get" in command
)


def test_install_sh_does_not_fail_on_an_existing_games_directory():
# prepare
script = readInstallScript()

# call
mkdirCommands = [
command for command in commandLines(script) if command.startswith("mkdir")
]

# check
assert mkdirCommands
for command in mkdirCommands:
assert command.startswith("mkdir -p ")


def test_install_sh_does_not_wait_on_an_apt_prompt():
# prepare
script = readInstallScript()

# call
installCommands = [
command for command in commandLines(script) if "apt-get install" in command
]

# check
assert installCommands
for command in installCommands:
assert " -y " in command


def test_install_sh_updates_an_existing_install_instead_of_cloning_over_it():
# prepare
script = readInstallScript()

# call
commands = commandLines(script)
cloneLine = next(
index for index, command in enumerate(commands) if "git clone" in command
)

# check
assert 'if [ -d "$INSTALL_DIR/.git" ]; then' in commands[:cloneLine]
assert 'git -C "$INSTALL_DIR" pull' in commands[:cloneLine]
assert commands[cloneLine - 1] == "else"
Loading