Skip to content

Commit 49e0749

Browse files
authored
fix(taskfiles)!: Prevent CMAKE_SETTINGS_DIR initialization race conditions in concurrent dependency installs using run-once make-or-clear-dir. (#91)
1 parent f335467 commit 49e0749

File tree

2 files changed

+34
-2
lines changed

2 files changed

+34
-2
lines changed

exports/taskfiles/utils/cmake.yaml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
version: "3"
22

33
includes:
4+
misc: "misc.yaml"
45
remote: "remote.yaml"
56

67
set: ["u", "pipefail"]
@@ -224,6 +225,13 @@ tasks:
224225
# 3. combining each dependency's settings file into a single settings file (CMAKE_SETTINGS_FILE)
225226
# for use inside a CMake project.
226227
#
228+
# This task runs once per unique label, since a project should never repeat the same dependency
229+
# installation workflow (i.e. `DEP_TASK`) within a single `task` invocation.
230+
#
231+
# Additionally, if multiple `DEP_TASK`s share the same `CMAKE_SETTINGS_DIR`, we use helper task
232+
# `misc:make-or-clear-dir` to ensure that the directory is only initialized once, avoiding race
233+
# conditions and ensuring that later tasks do not overwrite progress made by earlier ones.
234+
#
227235
# @param {string} CMAKE_SETTINGS_DIR The directory where CMake settings files should be stored.
228236
# @param {string} DEP_TASK The task to run that will install all dependencies. NOTE:
229237
# - The task name must be qualified from the root of the project.
@@ -241,9 +249,13 @@ tasks:
241249
{{default (printf "%s/all.cmake" .CMAKE_SETTINGS_DIR) .CMAKE_SETTINGS_FILE}}
242250
requires:
243251
vars: ["CMAKE_SETTINGS_DIR", "DEP_TASK"]
252+
run: "when_changed"
244253
cmds:
245-
- "rm -rf {{.CMAKE_SETTINGS_DIR}}"
246-
- "mkdir -p {{.CMAKE_SETTINGS_DIR}}"
254+
- task: "misc:make-or-clear-dir"
255+
vars:
256+
DIR_PATH: "{{.CMAKE_SETTINGS_DIR}}"
257+
- "mkdir -p '{{dir .CMAKE_SETTINGS_FILE}}'"
258+
- "rm -f '{{.CMAKE_SETTINGS_FILE}}'"
247259

248260
# NOTE: We prefix DEP_TASK with `::` assuming that this taskfile is included through the
249261
# `utils` taskfile, and that in turn is included in the user's taskfile.

exports/taskfiles/utils/misc.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,23 @@ tasks:
4141
. "{{.OUTPUT_DIR}}/bin/activate"
4242
pip3 install --upgrade pip
4343
pip3 install --upgrade -r "{{.REQUIREMENTS_FILE}}"
44+
45+
make-or-clear-dir:
46+
# Clears all contents under `DIR_PATH` or creates the directory if it does not exist.
47+
#
48+
# This task ensures `DIR_PATH` exists as an empty directory after it is run. It runs once per
49+
# unique directory path (fingerprinted by the task label). To prevent accidental label
50+
# collisions, `DIR_PATH` must be absolute.
51+
#
52+
# @param {string} DIR_PATH Absolute path to the directory to clear or create.
53+
internal: true
54+
label: "{{.TASK}}:{{.DIR_PATH}}"
55+
requires:
56+
vars: ["DIR_PATH"]
57+
run: "when_changed"
58+
preconditions:
59+
- sh: "{{osIsAbs .DIR_PATH}}"
60+
msg: "DIR_PATH `{{.DIR_PATH}}` is not absolute."
61+
cmds:
62+
- "rm -rf '{{.DIR_PATH}}'"
63+
- "mkdir -p '{{.DIR_PATH}}'"

0 commit comments

Comments
 (0)