common_utils.sh 8.23 KB
Newer Older
1
#!/bin/bash
2
# Utilities for both OSX and Docker Linux
3
# Python should be on the PATH
4
5
6
7
8
9
10
11

# Only source common_utils once
if [ -n "$COMMON_UTILS_SOURCED" ]; then
    return
fi
COMMON_UTILS_SOURCED=1

# Turn on exit-if-error
12
13
set -e

14
MULTIBUILD_DIR=$(dirname "${BASH_SOURCE[0]}")
15
if [ $(uname) == "Darwin" ]; then IS_OSX=1; fi
16

Matthew Brett's avatar
Matthew Brett committed
17
18
19
20
# Work round bug in travis xcode image described at
# https://github.com/direnv/direnv/issues/210
shell_session_update() { :; }

21
22
23
24
function abspath {
    python -c "import os.path; print(os.path.abspath('$1'))"
}

25
26
27
28
29
function relpath {
    # Path of first input relative to second (or $PWD if not specified)
    python -c "import os.path; print(os.path.relpath('$1','${2:-$PWD}'))"
}

Matthew Brett's avatar
Matthew Brett committed
30
31
32
33
function realpath {
    python -c "import os; print(os.path.realpath('$1'))"
}

34
35
36
37
38
39
40
41
function lex_ver {
    # Echoes dot-separated version string padded with zeros
    # Thus:
    # 3.2.1 -> 003002001
    # 3     -> 003000000
    echo $1 | awk -F "." '{printf "%03d%03d%03d", $1, $2, $3}'
}

42
43
44
45
46
47
48
49
50
51
52
53
function unlex_ver {
    # Reverses lex_ver to produce major.minor.micro
    # Thus:
    # 003002001 -> 3.2.1
    # 003000000 -> 3.0.0
    echo "$((10#${1:0:3}+0)).$((10#${1:3:3}+0)).$((10#${1:6:3}+0))"
}

function strip_ver_suffix {
    echo $(unlex_ver $(lex_ver $1))
}

54
function is_function {
55
56
57
    # Echo "true" if input argument string is a function
    # Allow errors during "set -e" blocks.
    (set +e; echo $($(declare -Ff "$1") > /dev/null && echo true))
58
59
}

60
61
62
63
64
65
66
function gh-clone {
    git clone https://github.com/$1
}

function rm_mkdir {
    # Remove directory if present, then make directory
    local path=$1
67
68
    if [ -z "$path" ]; then echo "Need not-empty path"; exit 1; fi
    if [ -d "$path" ]; then rm -rf $path; fi
69
70
71
    mkdir $path
}

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
function untar {
    local in_fname=$1
    if [ -z "$in_fname" ];then echo "in_fname not defined"; exit 1; fi
    local extension=${in_fname##*.}
    case $extension in
        tar) tar xf $in_fname ;;
        gz|tgz) tar zxf $in_fname ;;
        bz2) tar jxf $in_fname ;;
        zip) unzip $in_fname ;;
        xz) unxz -c $in_fname | tar xf ;;
        *) echo Did not recognize extension $extension; exit 1 ;;
    esac
}

function fetch_unpack {
    # Fetch input archive name from input URL
    # Parameters
    #    url - URL from which to fetch archive
    #    archive_fname (optional) archive name
    #
    # If `archive_fname` not specified then use basename from `url`
    # If `archive_fname` already present at download location, use that instead.
    local url=$1
    if [ -z "$url" ];then echo "url not defined"; exit 1; fi
    local archive_fname=${2:-$(basename $url)}
    local arch_sdir="${ARCHIVE_SDIR:-archives}"
    # Make the archive directory in case it doesn't exist
    mkdir -p $arch_sdir
    local out_archive="${arch_sdir}/${archive_fname}"
    # Fetch the archive if it does not exist
    if [ ! -f "$out_archive" ]; then
        curl -L $url > $out_archive
    fi
    # Unpack archive, refreshing contents
    rm_mkdir arch_tmp
    (cd arch_tmp && untar ../$out_archive && rsync --delete -avh * ..)
}

110
111
112
113
114
function clean_code {
    local repo_dir=${1:-$REPO_DIR}
    local build_commit=${2:-$BUILD_COMMIT}
    [ -z "$repo_dir" ] && echo "repo_dir not defined" && exit 1
    [ -z "$build_commit" ] && echo "build_commit not defined" && exit 1
115
116
117
118
119
    # The package $repo_dir may be a submodule. git submodules do not
    # have a .git directory. If $repo_dir is copied around, tools like
    # Versioneer which require that it be a git repository are unable
    # to determine the version.  Give submodule proper git directory
    fill_submodule "$repo_dir"
120
121
122
123
124
125
126
127
    (cd $repo_dir \
        && git fetch origin \
        && git checkout $build_commit \
        && git clean -fxd \
        && git reset --hard \
        && git submodule update --init --recursive)
}

128
129
130
131
132
function build_wheel_cmd {
    # Builds wheel with named command, puts into $WHEEL_SDIR
    #
    # Parameters:
    #     cmd  (optional, default "pip_wheel_cmd"
Andrew Murray's avatar
Andrew Murray committed
133
    #        Name of command for building wheel
134
    #     repo_dir  (optional, default $REPO_DIR)
135
136
137
138
139
140
    #
    # Depends on
    #     REPO_DIR  (or via input argument)
    #     WHEEL_SDIR  (optional, default "wheelhouse")
    #     BUILD_DEPENDS (optional, default "")
    #     MANYLINUX_URL (optional, default "") (via pip_opts function)
141
142
    local cmd=${1:-pip_wheel_cmd}
    local repo_dir=${2:-$REPO_DIR}
143
144
    [ -z "$repo_dir" ] && echo "repo_dir not defined" && exit 1
    local wheelhouse=$(abspath ${WHEEL_SDIR:-wheelhouse})
145
    if [ -n "$(is_function "pre_build")" ]; then pre_build; fi
146
147
148
149
    if [ -n "$BUILD_DEPENDS" ]; then
        pip install $(pip_opts) $BUILD_DEPENDS
    fi
    (cd $repo_dir && $cmd $wheelhouse)
150
151
152
    repair_wheelhouse $wheelhouse
}

153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
function pip_wheel_cmd {
    local abs_wheelhouse=$1
    pip wheel $(pip_opts) -w $abs_wheelhouse --no-deps .
}

function bdist_wheel_cmd {
    # Builds wheel with bdist_wheel, puts into wheelhouse
    #
    # It may sometimes be useful to use bdist_wheel for the wheel building
    # process.  For example, versioneer has problems with versions which are
    # fixed with bdist_wheel:
    # https://github.com/warner/python-versioneer/issues/121
    local abs_wheelhouse=$1
    python setup.py bdist_wheel
    cp dist/*.whl $abs_wheelhouse
}

170
function build_pip_wheel {
171
172
173
174
175
176
177
178
179
    # Standard wheel building command with pip wheel
    build_wheel_cmd "pip_wheel_cmd" $@
}

function build_bdist_wheel {
    # Wheel building with bdist_wheel. See bdist_wheel_cmd
    build_wheel_cmd "bdist_wheel_cmd" $@
}

180
181
182
183
184
function build_wheel {
    # Set default building method to pip
    build_pip_wheel $@
}

185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
function build_index_wheel {
    # Builds wheel from some index, usually pypi
    #
    # Parameters:
    #     project_spec
    #        requirement to install, e.g. "tornado" or "tornado==4.4.1"
    #     *args
    #        Any other arguments to be passed to pip `install`  and `wheel`
    #        commands.
    #
    # Depends on
    #     WHEEL_SDIR  (optional, default "wheelhouse")
    #     BUILD_DEPENDS (optional, default "")
    #     MANYLINUX_URL (optional, default "") (via pip_opts function)
    #
    # You can also override `pip_opts` command to set indices other than pypi
    local project_spec=$1
    [ -z "$project_spec" ] && echo "project_spec not defined" && exit 1
    # Discard first argument to pass remainder to pip
    shift
    local wheelhouse=$(abspath ${WHEEL_SDIR:-wheelhouse})
    if [ -n "$(is_function "pre_build")" ]; then pre_build; fi
    if [ -n "$BUILD_DEPENDS" ]; then
        pip install $(pip_opts) $@ $BUILD_DEPENDS
    fi
Matthew Brett's avatar
Matthew Brett committed
210
    pip wheel $(pip_opts) $@ -w $wheelhouse --no-deps $project_spec
211
212
213
    repair_wheelhouse $wheelhouse
}

214
215
function pip_opts {
    [ -n "$MANYLINUX_URL" ] && echo "--find-links $MANYLINUX_URL"
216
}
217

218
219
220
221
222
function get_platform {
    # Report platform as given by uname
    python -c 'import platform; print(platform.uname()[4])'
}

223
224
function install_wheel {
    # Install test dependencies and built wheel
225
    #
226
    # Pass any input flags to pip install steps
227
    #
228
    # Depends on:
229
230
231
232
    #     WHEEL_SDIR  (optional, default "wheelhouse")
    #     TEST_DEPENDS  (optional, default "")
    #     MANYLINUX_URL (optional, default "") (via pip_opts function)
    local wheelhouse=$(abspath ${WHEEL_SDIR:-wheelhouse})
233
    if [ -n "$TEST_DEPENDS" ]; then
234
        pip install $(pip_opts) $@ $TEST_DEPENDS
235
236
    fi
    # Install compatible wheel
237
    pip install $(pip_opts) $@ \
238
        $(python $MULTIBUILD_DIR/supported_wheels.py $wheelhouse/*.whl)
239
}
240
241
242
243
244
245
246

function install_run {
    # Depends on function `run_tests` defined in `config.sh`
    install_wheel
    mkdir tmp_for_test
    (cd tmp_for_test && run_tests)
}
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263

function fill_submodule {
    # Restores .git directory to submodule, if necessary
    # See:
    # http://stackoverflow.com/questions/41776331/is-there-a-way-to-reconstruct-a-git-directory-for-a-submodule
    local repo_dir="$1"
    [ -z "$repo_dir" ] && echo "repo_dir not defined" && exit 1
    local git_loc="$repo_dir/.git"
    # For ordinary submodule, .git is a file.
    [ -d "$git_loc" ] && return
    # Need to recreate .git directory for submodule
    local origin_url=$(cd "$repo_dir" && git config --get remote.origin.url)
    git clone --recursive --mirror "$repo_dir" "$repo_dir/.git-full"
    rm "$git_loc"
    mv "$repo_dir/.git-full" "$git_loc"
    (cd "$repo_dir" && git remote set-url origin $origin_url)
}