summaryrefslogtreecommitdiff
path: root/scripts/tasks.sh
blob: a8c194c180af75aeeacde64bdb50e99a78723d15 (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
#!/usr/bin/env bash
# ./script/task.sh: Run a VSCode task from tasks.json including its dependencies.
#
# Usage: ./scripts/task.sh TASK_LABEL
#
# This script looks for .vscode/tasks.json in your workspace folder (or current directory)
# and executes the command associated with the given task label.
#
# It also handles the "dependsOn" field recursively.
#
# Requirements: jq sed

# https://jackson.dev/post/a-portable-nix-shell-shebang/
if [ -z "$INSIDE_NIX_RANDOMSTRING" ] && command -v nix &> /dev/null; then
  # If the user has nix, relaunch in nix shell with dependencies added
  INSIDE_NIX_RANDOMSTRING=1 nix shell \
      nixpkgs#jq \
      nixpkgs#gnused \
      --command "$0" "$@"
  exit $?
fi

required_dependencies=(jq sed)

# Check if the dependencies are installed
for cmd in "${required_dependencies[@]}"; do
    if ! command -v "$cmd" &> /dev/null; then
        echo "Error: '$cmd' is not installed. Please install it and try again." >&2
        exit 1
    fi
done


set -euo pipefail

# Use WORKSPACE_FOLDER if set; otherwise, assume current directory.
WORKSPACE_FOLDER="${WORKSPACE_FOLDER:-$(pwd)}"
TASKS_FILE="$WORKSPACE_FOLDER/.vscode/tasks.json"

if [ ! -f "$TASKS_FILE" ]; then
  echo "Error: tasks.json not found at $TASKS_FILE" >&2
  exit 1
fi

if [ $# -lt 1 ]; then
  echo "Usage: $0 TASK_LABEL" >&2
  exit 1
fi

# Remove comment lines (lines starting with //) from the tasks file to be compliant with the JSON format.
TASKS_JSON=$(sed '/^[[:space:]]*\/\//d' "$TASKS_FILE")

TASK_LABEL="$1"
shift

# run_task recursively looks up the task by label,
# runs any dependencies first, then executes its command.
run_task() {
  local label="$1"
  echo "Looking up task: $label"

  # Get the task object from the cleaned JSON.
  local task
  task=$(echo "$TASKS_JSON" | jq --arg label "$label" -r '.tasks[] | select(.label == $label)')
  if [ -z "$task" ]; then
    echo "Error: Task with label '$label' not found in $TASKS_FILE" >&2
    exit 1
  fi

  # If the task has dependencies, run them first.
  local depends
  depends=$(echo "$task" | jq -r '.dependsOn? // empty')
  if [ -n "$depends" ] && [ "$depends" != "null" ]; then
    # "dependsOn" can be an array or a string.
    if echo "$depends" | jq -e 'if type=="array" then . else empty end' >/dev/null; then
      for dep in $(echo "$depends" | jq -r '.[]'); do
        run_task "$dep"
      done
    else
      run_task "$depends"
    fi
  fi

  # Check if the task has either a command or script.
  local has_command has_script
  has_command=$(echo "$task" | jq -r 'has("command")')
  has_script=$(echo "$task" | jq -r 'has("script")')
  if [[ "$has_command" != "true" && "$has_script" != "true" ]]; then
    echo "Task '$label' has no command or script; skipping execution."
    return
  fi

  # Determine the command to run:
  local cmd=""
  if echo "$task" | jq 'has("command")' | grep -q "true"; then
    cmd=$(echo "$task" | jq -r '.command')
  elif echo "$task" | jq 'has("script")' | grep -q "true"; then
    local script
    script=$(echo "$task" | jq -r '.script')
    local path
    path=$(echo "$task" | jq -r '.path // empty')
    if [ -n "$path" ]; then
      cmd="cd $path && npm run $script"
    else
      cmd="npm run $script"
    fi
  else
    echo "Error: Task '$label' does not have a command or script." >&2
    exit 1
  fi

  # Substitute ${workspaceFolder} with the actual folder path.
  cmd="${cmd//\$\{workspaceFolder\}/$WORKSPACE_FOLDER}"

  echo "Running task '$label': $cmd"
  # Run the task in a subshell so that directory changes don't persist.
  ( eval "$cmd" )
}

run_task "$TASK_LABEL"