Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minimize tempfile churn #186

Merged
merged 3 commits into from
Nov 20, 2024
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
30 changes: 30 additions & 0 deletions test/tempfiles.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/sh
# shellcheck disable=SC2010,SC2126,SC2181

TRY_TOP="${TRY_TOP:-$(git rev-parse --show-toplevel --show-superproject-working-tree 2>/dev/null || echo "${0%/*}")}"
TRY="$TRY_TOP/try"

workdir="$(mktemp -d)"
cd "$workdir" || exit 1

initial_count="$(ls "${TMPDIR-/tmp}" | grep -e "^.*\.try-[0-9]*$" | wc -l)"

sandbox=$($TRY -n "touch $HOME/foo")
[ $? -eq 0 ] || exit 2

post_count="$(ls "${TMPDIR-/tmp}" | grep -e "^.*\.try-[0-9]*$" | wc -l)"

# just one new tempfile
[ "$((initial_count + 1))" -eq "$post_count" ] || exit 3
[ -f "$sandbox/upperdir$HOME/foo" ] || exit 4

# deliberately not the pattern of try sandboxes
sandbox=local
mkdir "$sandbox" || exit 5
$TRY -D "$sandbox" "touch $HOME/bar" || exit 6

final_count="$(ls "${TMPDIR-/tmp}" | grep -e "^.*\.try-[0-9]*$" | wc -l)"

# no new tempfiles!
[ "$post_count" -eq "$final_count" ] || exit 7
[ -f "$sandbox/upperdir$HOME/bar" ] || exit 8
39 changes: 28 additions & 11 deletions try
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,15 @@ try() {
if [ "$SANDBOX_DIR" ]
then
## If the name of a sandbox is given then we need to exit prematurely if its directory doesn't exist
! [ -d "$SANDBOX_DIR" ] && { error "could not find sandbox directory $SANDBOX_DIR" 2; }
[ -d "$SANDBOX_DIR" ] || error "could not find sandbox directory $SANDBOX_DIR" 2
# Force absolute path
SANDBOX_DIR="$(cd "$SANDBOX_DIR" && pwd)"

# shellcheck disable=SC2181
[ "$?" -eq 0 ] || error "could not find sandbox directory $SANDBOX_DIR (could not cd in)" 2
else
## Create a new sandbox if one was not given
SANDBOX_DIR=$(mktemp -d --suffix ".try-$EXECID")
SANDBOX_DIR="$(mktemp -d --suffix ".try-$EXECID")"
fi

## If the sandbox is not valid we exit early
Expand All @@ -50,7 +55,11 @@ try() {
## because we have already checked if it valid.
export SANDBOX_DIR

try_mount_log="$(mktemp --suffix ".try-$EXECID")"
# We created "$IGNORE_FILE" up front, but now we can stash it in the sandbox.
mv "$IGNORE_FILE" "$SANDBOX_DIR"/ignore
IGNORE_FILE="$SANDBOX_DIR"/ignore

try_mount_log="$SANDBOX_DIR"/mount.log
export try_mount_log

# If we're in a docker container, we want to mount tmpfs on sandbox_dir, #136
Expand All @@ -66,14 +75,14 @@ try() {
mkdir -p "$SANDBOX_DIR/upperdir" "$SANDBOX_DIR/workdir" "$SANDBOX_DIR/temproot"

## Find all the directories and mounts that need to be mounted
DIRS_AND_MOUNTS="$(mktemp --suffix ".try-$EXECID")"
DIRS_AND_MOUNTS="$SANDBOX_DIR"/mounts
export DIRS_AND_MOUNTS
find / -maxdepth 1 >"$DIRS_AND_MOUNTS"
findmnt --real -r -o target -n >>"$DIRS_AND_MOUNTS"
sort -u -o "$DIRS_AND_MOUNTS" "$DIRS_AND_MOUNTS"

# Calculate UPDATED_DIRS_AND_MOUNTS that contains the merge arguments in LOWER_DIRS
UPDATED_DIRS_AND_MOUNTS="$(mktemp --suffix ".try-$EXECID")"
UPDATED_DIRS_AND_MOUNTS="$SANDBOX_DIR"/mounts.updated
export UPDATED_DIRS_AND_MOUNTS
while IFS="" read -r mountpoint
do
Expand Down Expand Up @@ -124,9 +133,9 @@ try() {

chmod "$(stat -c %a /)" "$SANDBOX_DIR/temproot"

mount_and_execute="$(mktemp --suffix ".try-$EXECID")"
chroot_executable="$(mktemp --suffix ".try-$EXECID")"
script_to_execute="$(mktemp --suffix ".try-$EXECID")"
mount_and_execute="$SANDBOX_DIR"/mount_and_execute.sh
chroot_executable="$SANDBOX_DIR"/chroot_executable.sh
script_to_execute="$SANDBOX_DIR"/script_to_execute.sh

export chroot_executable
export script_to_execute
Expand Down Expand Up @@ -227,7 +236,8 @@ do
## We can ignore this mountpoint, if the user program tries to use it, it will crash, but if not we can run normally
printf "%s: Warning: Failed mounting $mountpoint as an overlay and mergerfs or unionfs not set and could not be found, see \"$try_mount_log\"\n" "$TRY_COMMAND" >&2
else
merger_dir=$(mktemp -d --suffix ".try-$EXECID")
merger_dir="$SANDBOX_DIR"/mergerdir."$(echo "$pure_mountpoint" | tr '/' '.')"
mkdir "$merger_dir"

## Create a union directory
"$UNION_HELPER" $mountpoint $merger_dir 2>>"$try_mount_log" ||
Expand Down Expand Up @@ -612,6 +622,9 @@ EOF
NO_COMMIT="interactive"

# Includes all patterns given using the `-i` flag; will be used with `grep -f`
#
# We have to create this temporary up front.
# We move it to $SANDBOX_DIR/ignore in `try()`, but delete it when we don't move it.
IGNORE_FILE="$(mktemp --suffix ".try-$EXECID")"

while getopts ":yvnhxi:D:U:L:" opt
Expand Down Expand Up @@ -657,9 +670,13 @@ fi
TRY_EXIT_STATUS=1
case "$1" in
(summary) : "${SANDBOX_DIR=$2}"
summary;;
summary
rm "$IGNORE_FILE" # we didn't move it to the sandbox, so clean up
;;
(commit) : "${SANDBOX_DIR=$2}"
commit;;
commit
rm "$IGNORE_FILE" # we didn't move it to the sandbox, so clean up
;;
(explore) : "${SANDBOX_DIR=$2}"
try "$SHELL";;
(--) shift
Expand Down