summaryrefslogtreecommitdiff
path: root/tools/copy_tests.sh
blob: 2ea9d51ec212dae840cc13a5c3f1a04e55e57c3f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/usr/bin/env bash

# A little helper for copying built tests into an implementation's repo, for
# testing changes.
#
# The destination directory is specified with `-d`, `--dest` or `--destination`.
# Source files can be positional (in which case, they are ignored if not found
# to be relative to the test directory), or specified via utilities such as
# `--head` (tests changed in the current working directory), or `--since N`
# (tests changed in the last N commits).

script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
root_dir="$( dirname "$script_dir" )"
tests_dir="$root_dir/test"

help_msg="$(cat <<-END

Help:

    -d <argument>             | -d=<argument>
    --dest <argument>         | --dest=<argument>
    --destination <argument>  | --destination=<argument>

        Specify a destination directory to receive copied tests. If not present,
        the script runs in dry-run mode and does not copy files.

    -n
    --dryrun
    --dry-run

        Don't copy files, but print the operations which would be performed.
        Useful for debugging.

    --head

        Copy test files which have changed in the working directory since the
        last commit. Performs \`git diff HEAD --name-only\`.

    -s <argument>             | -s=<argument>
    --diff <argument>         | --diff=<argument>
    --since <argument>        | --since=<argument>

        Copy files which have changed in the past N commits. Also includes
        changes in the current working directory since the last commit. Performs
        \`git diff HEAD~\<argument> --name-only\`.

    -h
    --help

        Print this help message.

END
)"

check_path() {
    local file="$1"
    if ( [ ! -f "$file" ] ); then
        return
    fi

    local path=$(echo "$( realpath --relative-to="$root_dir/test" "$file" )" | tr "/" " ")
    for part in $path; do
        if [ "$part" = ".." ]; then
            return
        fi
    done

    echo "$file"
}

files=( )
dry_run=0
while [[ $# -gt 0 ]]; do
    case "$1" in
        -d|--dest|--destination)
            # Select the destination to copy into (value is following
            # positional parameter)
            destination="$2"
            shift
            shift
            ;;
        -d=*|--dest=*|--destination=*)
            # Select the destination to copy into (value follows `=` sign)
            destination="${i#*=}"
            shift
            ;;
        -n|--dryrun|--dry-run)
            # Don't actually copy files, but instead list the files to copy
            dry_run=1
            shift
            ;;
        --head)
            # Add test files changed since the last commit
            files+=( "$( git diff HEAD --name-only --diff-filter=d | grep "^test/" )" )
            shift
            ;;
        -s|--diff|--since)
            # Add test files changed in the last N commits (N is following
            # positional parameter)
            files+=( "$( git diff HEAD~$2 --name-only --diff-filter=d | grep "^test/" )" )
            shift
            shift
            ;;
        -s=*|--diff=*|--since=*)
            # Add test files changed in the last N commits (N follows `=` sign)
            files+=( "$( git diff HEAD~${i#*=} --name-only --diff-filter=d | grep "^test/" )" )
            shift
            ;;
        -h|--help)
            echo -n "$help_msg"
            exit 0
            ;;
        *)
            # Add a specific test, if it's a file relative to $tests_dir
            if [ -n "$( check_path "$1" )" ]; then
              files+=( "$1" )
            fi
            shift
            ;;
    esac
done

if [ ${#destination} -eq 0 ]; then
  echo -n "Error: No destination specified."
  echo -n "$help_msg"
  exit 1
fi

function main {
    for file in $files; do
        # Convert absolute path to relative path
        file="$( realpath --relative-to="$root_dir" "$file" )"
        target_path="$destination/$( dirname "$file" )"
        cmd=$( cat <<-END
mkdir -p "$target_path"
cp -f "$file" "$target_path"

END
)
        if [ $dry_run -eq 0 ]; then
          eval "$cmd"
        else
          echo "$cmd"
          echo ""
        fi
    done
}

old_dir=$( pwd )
cd "$root_dir"
main
cd "$old_dir"