Skip to content

Commit bbe7948

Browse files
authored
Reproduce and fix repeated watch-close failure on OS-X (#393)
Previously after ~100 iterations, the provided `test("openClose")` case stops receiving events from OS-X. Presumably we must be leaking something Moving most of the relevant `CarbonApi()` calls into the `run` method so they all run on the same thread seems to make the problem go away. We still need one call running in constructor body for some reason, even if it doesn't do anything, because otherwise the calls in the `run` method seem to hang The test case hangs on my macbook without this PR, passes with
1 parent 641fbe6 commit bbe7948

File tree

6 files changed

+376
-77
lines changed

6 files changed

+376
-77
lines changed

.github/workflows/publish-artifacts.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
distribution: 'temurin'
2727
java-version: 11
2828
- name: Publish to Maven Central
29-
run: ./mill -i mill.scalalib.PublishModule/
29+
run: ./mill -i mill.scalalib.SonatypeCentralPublishModule/
3030

3131
- name: Create GitHub Release
3232
id: create_gh_release

.mill-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.12.0
1+
0.12.14-native

mill

Lines changed: 294 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,327 @@
11
#!/usr/bin/env sh
22

3-
# This is a wrapper script, that automatically download mill from GitHub release pages
4-
# You can give the required mill version with MILL_VERSION env variable
5-
# If no version is given, it falls back to the value of DEFAULT_MILL_VERSION
3+
# This is a wrapper script, that automatically selects or downloads Mill from Maven Central or GitHub release pages.
4+
#
5+
# This script determines the Mill version to use by trying these sources
6+
# - env-variable `MILL_VERSION`
7+
# - local file `.mill-version`
8+
# - local file `.config/mill-version`
9+
# - `mill-version` from YAML fronmatter of current buildfile
10+
# - if accessible, find the latest stable version available on Maven Central (https://repo1.maven.org/maven2)
11+
# - env-variable `DEFAULT_MILL_VERSION`
12+
#
13+
# If a version has the suffix '-native' a native binary will be used.
14+
# If a version has the suffix '-jvm' an executable jar file will be used, requiring an already installed Java runtime.
15+
# If no such suffix is found, the script will pick a default based on version and platform.
16+
#
17+
# Once a version was determined, it tries to use either
18+
# - a system-installed mill, if found and it's version matches
19+
# - an already downloaded version under ~/.cache/mill/download
20+
#
21+
# If no working mill version was found on the system,
22+
# this script downloads a binary file from Maven Central or Github Pages (this is version dependent)
23+
# into a cache location (~/.cache/mill/download).
24+
#
25+
# Mill Project URL: https://github.com/com-lihaoyi/mill
26+
# Script Version: 1.0.0-M1-21-7b6fae-DIRTY892b63e8
27+
#
28+
# If you want to improve this script, please also contribute your changes back!
29+
# This script was generated from: dist/scripts/src/mill.sh
30+
#
31+
# Licensed under the Apache License, Version 2.0
632

733
set -e
834

935
if [ -z "${DEFAULT_MILL_VERSION}" ] ; then
10-
DEFAULT_MILL_VERSION=0.11.12
36+
DEFAULT_MILL_VERSION="0.12.10"
1137
fi
1238

13-
if [ -z "$MILL_VERSION" ] ; then
39+
40+
if [ -z "${GITHUB_RELEASE_CDN}" ] ; then
41+
GITHUB_RELEASE_CDN=""
42+
fi
43+
44+
45+
MILL_REPO_URL="https://github.com/com-lihaoyi/mill"
46+
47+
if [ -z "${CURL_CMD}" ] ; then
48+
CURL_CMD=curl
49+
fi
50+
51+
# Explicit commandline argument takes precedence over all other methods
52+
if [ "$1" = "--mill-version" ] ; then
53+
echo "The --mill-version option is no longer supported." 1>&2
54+
fi
55+
56+
MILL_BUILD_SCRIPT=""
57+
58+
if [ -f "build.mill" ] ; then
59+
MILL_BUILD_SCRIPT="build.mill"
60+
elif [ -f "build.mill.scala" ] ; then
61+
MILL_BUILD_SCRIPT="build.mill.scala"
62+
elif [ -f "build.sc" ] ; then
63+
MILL_BUILD_SCRIPT="build.sc"
64+
fi
65+
66+
# Please note, that if a MILL_VERSION is already set in the environment,
67+
# We reuse it's value and skip searching for a value.
68+
69+
# If not already set, read .mill-version file
70+
if [ -z "${MILL_VERSION}" ] ; then
1471
if [ -f ".mill-version" ] ; then
15-
MILL_VERSION="$(head -n 1 .mill-version 2> /dev/null)"
72+
MILL_VERSION="$(tr '\r' '\n' < .mill-version | head -n 1 2> /dev/null)"
1673
elif [ -f ".config/mill-version" ] ; then
17-
MILL_VERSION="$(head -n 1 .config/mill-version 2> /dev/null)"
18-
elif [ -f "mill" ] && [ "$0" != "mill" ] ; then
19-
MILL_VERSION=$(grep -F "DEFAULT_MILL_VERSION=" "mill" | head -n 1 | cut -d= -f2)
20-
else
21-
MILL_VERSION=$DEFAULT_MILL_VERSION
74+
MILL_VERSION="$(tr '\r' '\n' < .config/mill-version | head -n 1 2> /dev/null)"
75+
elif [ -n "${MILL_BUILD_SCRIPT}" ] ; then
76+
MILL_VERSION="$(cat ${MILL_BUILD_SCRIPT} | grep '//[|] *mill-version: *' | sed 's;//| *mill-version: *;;')"
2277
fi
2378
fi
2479

25-
if [ "x${XDG_CACHE_HOME}" != "x" ] ; then
26-
MILL_DOWNLOAD_PATH="${XDG_CACHE_HOME}/mill/download"
27-
else
28-
MILL_DOWNLOAD_PATH="${HOME}/.cache/mill/download"
80+
MILL_USER_CACHE_DIR="${XDG_CACHE_HOME:-${HOME}/.cache}/mill"
81+
82+
if [ -z "${MILL_DOWNLOAD_PATH}" ] ; then
83+
MILL_DOWNLOAD_PATH="${MILL_USER_CACHE_DIR}/download"
2984
fi
30-
MILL_EXEC_PATH="${MILL_DOWNLOAD_PATH}/${MILL_VERSION}"
3185

32-
version_remainder="$MILL_VERSION"
33-
MILL_MAJOR_VERSION="${version_remainder%%.*}"; version_remainder="${version_remainder#*.}"
34-
MILL_MINOR_VERSION="${version_remainder%%.*}"; version_remainder="${version_remainder#*.}"
86+
# If not already set, try to fetch newest from Github
87+
if [ -z "${MILL_VERSION}" ] ; then
88+
# TODO: try to load latest version from release page
89+
echo "No mill version specified." 1>&2
90+
echo "You should provide a version via a '//| mill-version: ' comment or a '.mill-version' file." 1>&2
91+
92+
mkdir -p "${MILL_DOWNLOAD_PATH}"
93+
LANG=C touch -d '1 hour ago' "${MILL_DOWNLOAD_PATH}/.expire_latest" 2>/dev/null || (
94+
# we might be on OSX or BSD which don't have -d option for touch
95+
# but probably a -A [-][[hh]mm]SS
96+
touch "${MILL_DOWNLOAD_PATH}/.expire_latest"; touch -A -010000 "${MILL_DOWNLOAD_PATH}/.expire_latest"
97+
) || (
98+
# in case we still failed, we retry the first touch command with the intention
99+
# to show the (previously suppressed) error message
100+
LANG=C touch -d '1 hour ago' "${MILL_DOWNLOAD_PATH}/.expire_latest"
101+
)
102+
103+
# POSIX shell variant of bash's -nt operator, see https://unix.stackexchange.com/a/449744/6993
104+
# if [ "${MILL_DOWNLOAD_PATH}/.latest" -nt "${MILL_DOWNLOAD_PATH}/.expire_latest" ] ; then
105+
if [ -n "$(find -L "${MILL_DOWNLOAD_PATH}/.latest" -prune -newer "${MILL_DOWNLOAD_PATH}/.expire_latest")" ]; then
106+
# we know a current latest version
107+
MILL_VERSION=$(head -n 1 "${MILL_DOWNLOAD_PATH}"/.latest 2> /dev/null)
108+
fi
109+
110+
if [ -z "${MILL_VERSION}" ] ; then
111+
# we don't know a current latest version
112+
echo "Retrieving latest mill version ..." 1>&2
113+
LANG=C ${CURL_CMD} -s -i -f -I ${MILL_REPO_URL}/releases/latest 2> /dev/null | grep --ignore-case Location: | sed s'/^.*tag\///' | tr -d '\r\n' > "${MILL_DOWNLOAD_PATH}/.latest"
114+
MILL_VERSION=$(head -n 1 "${MILL_DOWNLOAD_PATH}"/.latest 2> /dev/null)
115+
fi
116+
117+
if [ -z "${MILL_VERSION}" ] ; then
118+
# Last resort
119+
MILL_VERSION="${DEFAULT_MILL_VERSION}"
120+
echo "Falling back to hardcoded mill version ${MILL_VERSION}" 1>&2
121+
else
122+
echo "Using mill version ${MILL_VERSION}" 1>&2
123+
fi
124+
fi
35125

36-
if [ ! -s "$MILL_EXEC_PATH" ] ; then
37-
mkdir -p "$MILL_DOWNLOAD_PATH"
38-
if [ "$MILL_MAJOR_VERSION" -gt 0 ] || [ "$MILL_MINOR_VERSION" -ge 5 ] ; then
39-
ASSEMBLY="-assembly"
126+
MILL_NATIVE_SUFFIX="-native"
127+
MILL_JVM_SUFFIX="-jvm"
128+
FULL_MILL_VERSION=$MILL_VERSION
129+
ARTIFACT_SUFFIX=""
130+
set_artifact_suffix(){
131+
if [ "$(expr substr $(uname -s) 1 5 2>/dev/null)" = "Linux" ]; then
132+
if [ "$(uname -m)" = "aarch64" ]; then
133+
ARTIFACT_SUFFIX="-native-linux-aarch64"
134+
else
135+
ARTIFACT_SUFFIX="-native-linux-amd64"
136+
fi
137+
elif [ "$(uname)" = "Darwin" ]; then
138+
if [ "$(uname -m)" = "arm64" ]; then
139+
ARTIFACT_SUFFIX="-native-mac-aarch64"
140+
else
141+
ARTIFACT_SUFFIX="-native-mac-amd64"
142+
fi
143+
else
144+
echo "This native mill launcher supports only Linux and macOS." 1>&2
145+
exit 1
40146
fi
41-
DOWNLOAD_FILE=$MILL_EXEC_PATH-tmp-download
42-
MILL_VERSION_TAG=$(echo $MILL_VERSION | sed -E 's/([^-]+)(-M[0-9]+)?(-.*)?/\1\2/')
43-
MILL_DOWNLOAD_URL="https://repo1.maven.org/maven2/com/lihaoyi/mill-dist/$MILL_VERSION/mill-dist-$MILL_VERSION.jar"
44-
curl --fail -L -o "$DOWNLOAD_FILE" "$MILL_DOWNLOAD_URL"
45-
chmod +x "$DOWNLOAD_FILE"
46-
mv "$DOWNLOAD_FILE" "$MILL_EXEC_PATH"
147+
}
148+
149+
case "$MILL_VERSION" in
150+
*"$MILL_NATIVE_SUFFIX")
151+
MILL_VERSION=${MILL_VERSION%"$MILL_NATIVE_SUFFIX"}
152+
set_artifact_suffix
153+
;;
154+
155+
*"$MILL_JVM_SUFFIX")
156+
MILL_VERSION=${MILL_VERSION%"$MILL_JVM_SUFFIX"}
157+
;;
158+
159+
*)
160+
case "$MILL_VERSION" in
161+
0.1.*) ;;
162+
0.2.*) ;;
163+
0.3.*) ;;
164+
0.4.*) ;;
165+
0.5.*) ;;
166+
0.6.*) ;;
167+
0.7.*) ;;
168+
0.8.*) ;;
169+
0.9.*) ;;
170+
0.10.*) ;;
171+
0.11.*) ;;
172+
0.12.*) ;;
173+
*)
174+
set_artifact_suffix
175+
esac
176+
;;
177+
esac
178+
179+
MILL="${MILL_DOWNLOAD_PATH}/$MILL_VERSION$ARTIFACT_SUFFIX"
180+
181+
try_to_use_system_mill() {
182+
if [ "$(uname)" != "Linux" ]; then
183+
return 0
184+
fi
185+
186+
MILL_IN_PATH="$(command -v mill || true)"
187+
188+
if [ -z "${MILL_IN_PATH}" ]; then
189+
return 0
190+
fi
191+
192+
SYSTEM_MILL_FIRST_TWO_BYTES=$(head --bytes=2 "${MILL_IN_PATH}")
193+
if [ "${SYSTEM_MILL_FIRST_TWO_BYTES}" = "#!" ]; then
194+
# MILL_IN_PATH is (very likely) a shell script and not the mill
195+
# executable, ignore it.
196+
return 0
197+
fi
198+
199+
SYSTEM_MILL_PATH=$(readlink -e "${MILL_IN_PATH}")
200+
SYSTEM_MILL_SIZE=$(stat --format=%s "${SYSTEM_MILL_PATH}")
201+
SYSTEM_MILL_MTIME=$(stat --format=%y "${SYSTEM_MILL_PATH}")
202+
203+
if [ ! -d "${MILL_USER_CACHE_DIR}" ]; then
204+
mkdir -p "${MILL_USER_CACHE_DIR}"
205+
fi
206+
207+
SYSTEM_MILL_INFO_FILE="${MILL_USER_CACHE_DIR}/system-mill-info"
208+
if [ -f "${SYSTEM_MILL_INFO_FILE}" ]; then
209+
parseSystemMillInfo() {
210+
LINE_NUMBER="${1}"
211+
# Select the line number of the SYSTEM_MILL_INFO_FILE, cut the
212+
# variable definition in that line in two halves and return
213+
# the value, and finally remove the quotes.
214+
sed -n "${LINE_NUMBER}p" "${SYSTEM_MILL_INFO_FILE}" |\
215+
cut -d= -f2 |\
216+
sed 's/"\(.*\)"/\1/'
217+
}
218+
219+
CACHED_SYSTEM_MILL_PATH=$(parseSystemMillInfo 1)
220+
CACHED_SYSTEM_MILL_VERSION=$(parseSystemMillInfo 2)
221+
CACHED_SYSTEM_MILL_SIZE=$(parseSystemMillInfo 3)
222+
CACHED_SYSTEM_MILL_MTIME=$(parseSystemMillInfo 4)
223+
224+
if [ "${SYSTEM_MILL_PATH}" = "${CACHED_SYSTEM_MILL_PATH}" ] \
225+
&& [ "${SYSTEM_MILL_SIZE}" = "${CACHED_SYSTEM_MILL_SIZE}" ] \
226+
&& [ "${SYSTEM_MILL_MTIME}" = "${CACHED_SYSTEM_MILL_MTIME}" ]; then
227+
if [ "${CACHED_SYSTEM_MILL_VERSION}" = "${MILL_VERSION}" ]; then
228+
MILL="${SYSTEM_MILL_PATH}"
229+
return 0
230+
else
231+
return 0
232+
fi
233+
fi
234+
fi
235+
236+
SYSTEM_MILL_VERSION=$(${SYSTEM_MILL_PATH} --version | head -n1 | sed -n 's/^Mill.*version \(.*\)/\1/p')
237+
238+
cat <<EOF > "${SYSTEM_MILL_INFO_FILE}"
239+
CACHED_SYSTEM_MILL_PATH="${SYSTEM_MILL_PATH}"
240+
CACHED_SYSTEM_MILL_VERSION="${SYSTEM_MILL_VERSION}"
241+
CACHED_SYSTEM_MILL_SIZE="${SYSTEM_MILL_SIZE}"
242+
CACHED_SYSTEM_MILL_MTIME="${SYSTEM_MILL_MTIME}"
243+
EOF
244+
245+
if [ "${SYSTEM_MILL_VERSION}" = "${MILL_VERSION}" ]; then
246+
MILL="${SYSTEM_MILL_PATH}"
247+
fi
248+
}
249+
try_to_use_system_mill
250+
251+
# If not already downloaded, download it
252+
if [ ! -s "${MILL}" ] || [ "$MILL_TEST_DRY_RUN_LAUNCHER_SCRIPT" = "1" ] ; then
253+
case $MILL_VERSION in
254+
0.0.* | 0.1.* | 0.2.* | 0.3.* | 0.4.* )
255+
DOWNLOAD_SUFFIX=""
256+
DOWNLOAD_FROM_MAVEN=0
257+
;;
258+
0.5.* | 0.6.* | 0.7.* | 0.8.* | 0.9.* | 0.10.* | 0.11.0-M* )
259+
DOWNLOAD_SUFFIX="-assembly"
260+
DOWNLOAD_FROM_MAVEN=0
261+
;;
262+
*)
263+
DOWNLOAD_SUFFIX="-assembly"
264+
DOWNLOAD_FROM_MAVEN=1
265+
;;
266+
esac
267+
case $MILL_VERSION in
268+
0.12.0 | 0.12.1 | 0.12.2 | 0.12.3 | 0.12.4 | 0.12.5 | 0.12.6 | 0.12.7 | 0.12.8 | 0.12.9 | 0.12.10 | 0.12.11 )
269+
DOWNLOAD_EXT="jar"
270+
;;
271+
0.12.* )
272+
DOWNLOAD_EXT="exe"
273+
;;
274+
0.* )
275+
DOWNLOAD_EXT="jar"
276+
;;
277+
*)
278+
DOWNLOAD_EXT="exe"
279+
;;
280+
esac
281+
282+
DOWNLOAD_FILE=$(mktemp mill.XXXXXX)
283+
if [ "$DOWNLOAD_FROM_MAVEN" = "1" ] ; then
284+
DOWNLOAD_URL="https://repo1.maven.org/maven2/com/lihaoyi/mill-dist${ARTIFACT_SUFFIX}/${MILL_VERSION}/mill-dist${ARTIFACT_SUFFIX}-${MILL_VERSION}.${DOWNLOAD_EXT}"
285+
else
286+
MILL_VERSION_TAG=$(echo "$MILL_VERSION" | sed -E 's/([^-]+)(-M[0-9]+)?(-.*)?/\1\2/')
287+
DOWNLOAD_URL="${GITHUB_RELEASE_CDN}${MILL_REPO_URL}/releases/download/${MILL_VERSION_TAG}/${MILL_VERSION}${DOWNLOAD_SUFFIX}"
288+
unset MILL_VERSION_TAG
289+
fi
290+
291+
if [ "$MILL_TEST_DRY_RUN_LAUNCHER_SCRIPT" = "1" ] ; then
292+
echo $DOWNLOAD_URL
293+
echo $MILL
294+
exit 0
295+
fi
296+
# TODO: handle command not found
297+
echo "Downloading mill ${MILL_VERSION} from ${DOWNLOAD_URL} ..." 1>&2
298+
${CURL_CMD} -f -L -o "${DOWNLOAD_FILE}" "${DOWNLOAD_URL}"
299+
chmod +x "${DOWNLOAD_FILE}"
300+
mkdir -p "${MILL_DOWNLOAD_PATH}"
301+
mv "${DOWNLOAD_FILE}" "${MILL}"
302+
47303
unset DOWNLOAD_FILE
48-
unset MILL_DOWNLOAD_URL
304+
unset DOWNLOAD_SUFFIX
49305
fi
50306

51307
if [ -z "$MILL_MAIN_CLI" ] ; then
52308
MILL_MAIN_CLI="${0}"
53309
fi
54310

55311
MILL_FIRST_ARG=""
56-
57-
# first arg is a long flag for "--interactive" or starts with "-i"
58-
if [ "$1" = "--bsp" ] || [ "${1#"-i"}" != "$1" ] || [ "$1" = "--interactive" ] || [ "$1" = "--no-server" ] || [ "$1" = "--repl" ] || [ "$1" = "--help" ] ; then
312+
if [ "$1" = "--bsp" ] || [ "$1" = "-i" ] || [ "$1" = "--interactive" ] || [ "$1" = "--no-server" ] || [ "$1" = "--no-daemon" ] || [ "$1" = "--repl" ] || [ "$1" = "--help" ] ; then
59313
# Need to preserve the first position of those listed options
60314
MILL_FIRST_ARG=$1
61315
shift
62316
fi
63317

64318
unset MILL_DOWNLOAD_PATH
319+
unset MILL_OLD_DOWNLOAD_PATH
320+
unset OLD_MILL
65321
unset MILL_VERSION
322+
unset MILL_REPO_URL
66323

67-
exec $MILL_EXEC_PATH $MILL_FIRST_ARG -D "mill.main.cli=${MILL_MAIN_CLI}" "$@"
324+
# -D mill.main.cli is for compatibility with Mill 0.10.9 - 0.13.0-M2
325+
# We don't quote MILL_FIRST_ARG on purpose, so we can expand the empty value without quotes
326+
# shellcheck disable=SC2086
327+
exec "${MILL}" $MILL_FIRST_ARG -D "mill.main.cli=${MILL_MAIN_CLI}" "$@"

os/watch/src/CarbonApi.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import com.sun.jna._
55
import com.sun.jna.ptr.PointerByReference
66

77
object CarbonApi {
8+
def apply() = INSTANCE
89
val INSTANCE = Native.load("Carbon", classOf[CarbonApi]).asInstanceOf[CarbonApi]
910
}
1011

@@ -20,6 +21,8 @@ trait FSEventStreamCallback extends Callback {
2021
}
2122

2223
trait CarbonApi extends Library {
24+
def CFRelease(cfTypeRef: Any): Unit
25+
2326
def CFArrayCreate(
2427
allocator: CFAllocatorRef, // always set to Pointer.NULL
2528
values: Array[Pointer],

0 commit comments

Comments
 (0)