14
14
15
15
set -e
16
16
17
+ # Needed because if it is set, cd may print the path it changed to.
17
18
unset CDPATH
18
19
19
- function _rmlock () {
20
- [ -n " $FLUTTER_UPGRADE_LOCK " ] && rm -f " $FLUTTER_UPGRADE_LOCK "
21
- }
22
-
23
20
function retry_upgrade {
24
21
local total_tries=" 10"
25
22
local remaining_tries=$(( total_tries - 1 ))
@@ -37,50 +34,78 @@ function retry_upgrade {
37
34
return 0
38
35
}
39
36
40
- function upgrade_flutter () {
41
- mkdir -p " $FLUTTER_ROOT /bin/cache"
37
+ # Trap function for removing any remaining lock file at exit.
38
+ function _rmlock () {
39
+ [ -n " $FLUTTER_UPGRADE_LOCK " ] && rm -rf " $FLUTTER_UPGRADE_LOCK "
40
+ }
42
41
43
- # This function is executed with a redirect that pipes the source of
44
- # this script into file descriptor 3.
45
- #
46
- # To ensure that we don't simultaneously update Dart in multiple
47
- # parallel instances, we try to obtain an exclusive lock on this
48
- # file descriptor (and thus this script's source file) while we are
49
- # updating Dart and compiling the script. To do this, we try to use
50
- # the command line program "flock", which is available on many
51
- # Unix-like platforms, in particular on most Linux distributions.
52
- # You give it a file descriptor, and it locks the corresponding
53
- # file, having inherited the file descriptor from the shell.
54
- #
55
- # Complicating matters, there are two major scenarios where this
56
- # will not work.
57
- #
58
- # The first is if the platform doesn't have "flock", for example on Mac.
59
- # There is not a direct equivalent, so on platforms that don't have flock,
60
- # we fall back to using a lockfile and spinlock with "shlock". This
61
- # doesn't work as well over NFS as it relies on PIDs. Any platform
62
- # without either of these tools has no locking at all. To determine if we
63
- # have "flock" or "shlock" available, we abuse the "hash" shell built-in.
64
- #
65
- # The second complication is NFS. On NFS, to obtain an exclusive
66
- # lock you need a file descriptor that is open for writing, because
67
- # NFS implements exclusive locks by writing, or some such. Thus, we
68
- # ignore errors from flock. We do so by using the '|| true' trick,
69
- # since we are running in a 'set -e' environment wherein all errors
70
- # are fatal, and by redirecting all output to /dev/null, since
71
- # users will typically not care about errors from flock and are
72
- # more likely to be confused by them than helped.
73
- #
74
- # For "flock", the lock is released when the file descriptor goes out of
75
- # scope, i.e. when this function returns. The lock is released via
76
- # a trap when using "shlock".
42
+ # Determines which lock method to use, based on what is available on the system.
43
+ # Returns a non-zero value if the lock was not acquired, zero if acquired.
44
+ function _lock () {
77
45
if hash flock 2> /dev/null; then
78
- flock 3 2> /dev/null || true
79
- elif hash shlock 2> /dev/null; then
80
- FLUTTER_UPGRADE_LOCK=" $FLUTTER_ROOT /bin/cache/.upgrade_lock"
81
- while ! shlock -f " $FLUTTER_UPGRADE_LOCK " -p $$ ; do sleep .1 ; done
82
- trap _rmlock EXIT
46
+ flock --nonblock --exclusive 7 2> /dev/null
47
+ else
48
+ mkdir " $1 " 2> /dev/null
83
49
fi
50
+ }
51
+
52
+ # Waits for an update lock to be acquired.
53
+ #
54
+ # To ensure that we don't simultaneously update Dart in multiple parallel
55
+ # instances, we try to obtain an exclusive lock on this file descriptor (and
56
+ # thus this script's source file) while we are updating Dart and compiling the
57
+ # script. To do this, we try to use the command line program "flock", which is
58
+ # available on many Unix-like platforms, in particular on most Linux
59
+ # distributions. You give it a file descriptor, and it locks the corresponding
60
+ # file, having inherited the file descriptor from the shell.
61
+ #
62
+ # Complicating matters, there are two major scenarios where this will not
63
+ # work.
64
+ #
65
+ # The first is if the platform doesn't have "flock", for example on macOS. There
66
+ # is not a direct equivalent, so on platforms that don't have flock, we fall
67
+ # back to using mkdir as an atomic operation to create a lock directory. If
68
+ # mkdir is able to create the directory, then the lock is acquired. To determine
69
+ # if we have "flock" available, we use the "hash" shell built-in.
70
+ #
71
+ # The second complication is NFS. On NFS, to obtain an exclusive lock you need a
72
+ # file descriptor that is open for writing. Thus, we ignore errors from flock by
73
+ # redirecting all output to /dev/null, since users will typically not care about
74
+ # errors from flock and are more likely to be confused by them than helped.
75
+ #
76
+ # The upgrade_flutter function calling _wait_for_lock is executed in a subshell
77
+ # with a redirect that pipes the source of this script into file descriptor 7.
78
+ # A flock lock is released when this subshell exits and file descriptor 7 is
79
+ # closed. The mkdir lock is released via an exit trap from the subshell that
80
+ # deletes the lock directory.
81
+ function _wait_for_lock () {
82
+ FLUTTER_UPGRADE_LOCK=" $FLUTTER_ROOT /bin/cache/.upgrade_lock"
83
+ local waiting_message_displayed
84
+ while ! _lock " $FLUTTER_UPGRADE_LOCK " ; do
85
+ if [[ -z $waiting_message_displayed ]]; then
86
+ # Print with a return so that if the Dart code also prints this message
87
+ # when it does its own lock, the message won't appear twice. Be sure that
88
+ # the clearing printf below has the same number of space characters.
89
+ printf " Waiting for another flutter command to release the startup lock...\r" ;
90
+ waiting_message_displayed=" true"
91
+ fi
92
+ sleep .1;
93
+ done
94
+ # Clear the waiting message so it doesn't overlap any following text.
95
+ printf " \r" ;
96
+ unset waiting_message_displayed
97
+ # If the lock file is acquired, make sure that it is removed on exit.
98
+ trap _rmlock INT TERM EXIT
99
+ }
100
+
101
+ # This function is always run in a subshell. Running the function in a subshell
102
+ # is required to make sure any lock directory is cleaned up by the exit trap in
103
+ # _wait_for_lock.
104
+ function upgrade_flutter () (
105
+ mkdir -p " $FLUTTER_ROOT /bin/cache"
106
+
107
+ # Waits for the update lock to be acquired.
108
+ _wait_for_lock
84
109
85
110
local revision=" $( cd " $FLUTTER_ROOT " ; git rev-parse HEAD) "
86
111
@@ -111,15 +136,15 @@ function upgrade_flutter () {
111
136
" $DART " --disable-dart-dev $FLUTTER_TOOL_ARGS --snapshot=" $SNAPSHOT_PATH " --packages=" $FLUTTER_TOOLS_DIR /.packages" --no-enable-mirrors " $SCRIPT_PATH "
112
137
echo " $revision " > " $STAMP_PATH "
113
138
fi
114
- # The exit here is duplicitous since the function is run in a subshell,
115
- # but this serves as documentation that running the function in a
116
- # subshell is required to make sure any lockfile created by shlock
117
- # is cleaned up.
139
+ # The exit here is extraneous since the function is run in a subshell, but
140
+ # this serves as documentation that running the function in a subshell is
141
+ # required to make sure any lock directory created by mkdir is cleaned up.
118
142
exit $?
119
- }
143
+ )
120
144
121
145
# This function is intended to be executed by entrypoints (e.g. `//bin/flutter`
122
- # and `//bin/dart`)
146
+ # and `//bin/dart`). PROG_NAME and BIN_DIR should already be set by those
147
+ # entrypoints.
123
148
function shared::execute() {
124
149
export FLUTTER_ROOT=" $( cd " ${BIN_DIR} /.." ; pwd -P) "
125
150
@@ -132,8 +157,8 @@ function shared::execute() {
132
157
DART=" $DART_SDK_PATH /bin/dart"
133
158
PUB=" $DART_SDK_PATH /bin/pub"
134
159
135
- # If running over git-bash, overrides the default UNIX
136
- # executables with win32 executables
160
+ # If running over git-bash, overrides the default UNIX executables with win32
161
+ # executables
137
162
case " $( uname -s) " in
138
163
MINGW32* )
139
164
DART=" $DART .exe"
@@ -159,8 +184,8 @@ function shared::execute() {
159
184
if [[ ! -e " $FLUTTER_ROOT /.git" ]]; then
160
185
echo " Error: The Flutter directory is not a clone of the GitHub project."
161
186
echo " The flutter tool requires Git in order to operate properly;"
162
- echo " to set up Flutter, run the following command :"
163
- echo " git clone -b stable https://github.com/ flutter/flutter.git "
187
+ echo " to install Flutter, see the instructions at :"
188
+ echo " https://flutter.dev/get-started "
164
189
exit 1
165
190
fi
166
191
@@ -169,13 +194,13 @@ function shared::execute() {
169
194
# FLUTTER_TOOL_ARGS="--enable-asserts $FLUTTER_TOOL_ARGS"
170
195
# FLUTTER_TOOL_ARGS="$FLUTTER_TOOL_ARGS --observe=65432"
171
196
172
- ( upgrade_flutter) 3 < " $PROG_NAME "
197
+ upgrade_flutter 7 < " $PROG_NAME "
173
198
174
199
BIN_NAME=" $( basename " $PROG_NAME " ) "
175
200
case " $BIN_NAME " in
176
201
flutter* )
177
- # FLUTTER_TOOL_ARGS aren't quoted below, because it is meant to
178
- # be considered as separate space-separated args.
202
+ # FLUTTER_TOOL_ARGS aren't quoted below, because it is meant to be
203
+ # considered as separate space-separated args.
179
204
" $DART " --disable-dart-dev --packages=" $FLUTTER_TOOLS_DIR /.packages" $FLUTTER_TOOL_ARGS " $SNAPSHOT_PATH " " $@ "
180
205
;;
181
206
dart* )
0 commit comments