forked from dotnet/buildtools
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbootstrap.sh
269 lines (228 loc) · 8.06 KB
/
bootstrap.sh
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
#!/usr/bin/env bash
# Stop script on NZEC
set -e
# Stop script if unbound variable found (use ${var:-} if intentional)
set -u
# By default cmd1 | cmd2 returns exit code of cmd2 regardless of cmd1 success
# This is causing it to fail
set -o pipefail
# Use in the the functions: eval $invocation
invocation='say_verbose "Calling: ${FUNCNAME[0]}"'
# standard output may be used as a return value in the functions
# we need a way to write text on the screen in the functions so that
# it won't interfere with the return value.
# Exposing stream 3 as a pipe to standard output of the script itself
exec 3>&1
say_err() {
printf "%b\n" "bootstrap: Error: $1" >&2
}
say() {
# using stream 3 (defined in the beginning) to not interfere with stdout of functions
# which may be used as return value
printf "%b\n" "bootstrap: $1" >&3
}
say_verbose() {
if [ "$verbose" = true ]; then
say "$1"
fi
}
machine_has() {
eval $invocation
hash "$1" > /dev/null 2>&1
return $?
}
check_min_reqs() {
if ! machine_has "curl"; then
say_err "curl is required to download dotnet. Install curl to proceed."
return 1
fi
return 0
}
# args:
# remote_path - $1
# [out_path] - $2 - stdout if not provided
download() {
eval $invocation
local remote_path=$1
local out_path=${2:-}
local failed=false
if [ -z "$out_path" ]; then
curl --retry 10 -sSL --create-dirs $remote_path || failed=true
else
curl --retry 10 -sSL --create-dirs -o $out_path $remote_path || failed=true
fi
if [ "$failed" = true ]; then
say_err "Download failed"
return 1
fi
}
verbose=false
repoRoot=`pwd`
toolsLocalPath="<auto>"
cliLocalPath="<auto>"
symlinkPath="<auto>"
sharedFxVersion="<auto>"
force=
forcedCliLocalPath="<none>"
architecture="<auto>"
while [ $# -ne 0 ]
do
name=$1
case $name in
-r|--repositoryRoot|-[Rr]epositoryRoot)
shift
repoRoot="$1"
;;
-t|--toolsLocalPath|-[Tt]oolsLocalPath)
shift
toolsLocalPath="$1"
;;
-c|--cliInstallPath|--cliLocalPath|-[Cc]liLocalPath)
shift
cliLocalPath="$1"
;;
-u|--useLocalCli|-[Uu]seLocalCli)
shift
forcedCliLocalPath="$1"
;;
-a|--architecture|-[Aa]rchitecture)
shift
architecture="$1"
;;
--sharedFrameworkSymlinkPath|--symlink|-[Ss]haredFrameworkSymlinkPath)
shift
symlinkPath="$1"
;;
--sharedFrameworkVersion|-[Ss]haredFrameworkVersion)
sharedFxVersion="$1"
;;
--force|-[Ff]orce)
force=true
;;
-v|--verbose|-[Vv]erbose)
verbose=true
;;
*)
say_err "Unknown argument \`$name\`"
exit 1
;;
esac
shift
done
if [ $toolsLocalPath = "<auto>" ]; then
toolsLocalPath="$repoRoot/Tools"
fi
if [ $cliLocalPath = "<auto>" ]; then
if [ $forcedCliLocalPath = "<none>" ]; then
cliLocalPath="$toolsLocalPath/dotnetcli"
else
cliLocalPath=$forcedCliLocalPath
fi
fi
if [ $symlinkPath = "<auto>" ]; then
symlinkPath="$toolsLocalPath/dotnetcli/shared/Microsoft.NETCore.App/version"
fi
rootToolVersions="$repoRoot/.toolversions"
bootstrapComplete="$toolsLocalPath/bootstrap.complete"
# if the force switch is specified delete the semaphore file if it exists
if [[ $force && -f $bootstrapComplete ]]; then
rm -f $bootstrapComplete
fi
# if the semaphore file exists and is identical to the specified version then exit
if [[ -f $bootstrapComplete && ! `cmp $bootstrapComplete $rootToolVersions` ]]; then
say "$bootstrapComplete appears to show that bootstrapping is complete. Use --force if you want to re-bootstrap."
exit 0
fi
initCliScript="dotnet-install.sh"
dotnetInstallPath="$toolsLocalPath/$initCliScript"
# blow away the tools directory so we can start from a known state
if [ -d $toolsLocalPath ]; then
# if the bootstrap.sh script was downloaded to the tools directory don't delete it
find $toolsLocalPath -type f -not -name bootstrap.sh -exec rm -f {} \;
else
mkdir $toolsLocalPath
fi
if [ $forcedCliLocalPath = "<none>" ]; then
check_min_reqs
# download CLI boot-strapper script
download "https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/scripts/obtain/dotnet-install.sh" "$dotnetInstallPath"
chmod u+x "$dotnetInstallPath"
# load the version of the CLI
rootCliVersion="$repoRoot/.cliversion"
dotNetCliVersion=`cat $rootCliVersion`
if [ ! -e $cliLocalPath ]; then
mkdir -p "$cliLocalPath"
fi
# now execute the script
say_verbose "installing CLI: $dotnetInstallPath --version \"$dotNetCliVersion\" --install-dir $cliLocalPath --architecture \"$architecture\""
$dotnetInstallPath --version "$dotNetCliVersion" --install-dir $cliLocalPath --architecture "$architecture"
if [ $? != 0 ]; then
say_err "The .NET CLI installation failed with exit code $?"
exit $?
fi
fi
runtimesPath="$cliLocalPath/shared/Microsoft.NETCore.App"
if [ $sharedFxVersion = "<auto>" ]; then
# OSX doesn't support --version-sort, https://stackoverflow.com/questions/21394536/how-to-simulate-sort-v-on-mac-osx
sharedFxVersion=`ls $runtimesPath | sed 's/^[0-9]\./0&/; s/\.\([0-9]\)$/.0\1/; s/\.\([0-9]\)\./.0\1./g; s/\.\([0-9]\)\./.0\1./g' | sort -r | sed 's/^0// ; s/\.0/./g' | head -n 1`
fi
# create a junction to the shared FX version directory. this is
# so we have a stable path to dotnet.exe regardless of version.
junctionTarget="$runtimesPath/$sharedFxVersion"
junctionParent="$(dirname "$symlinkPath")"
if [ ! -d $junctionParent ]; then
mkdir -p $junctionParent
fi
if [ ! -e $symlinkPath ]; then
ln -s $junctionTarget $symlinkPath
fi
# create a project.json for the packages to restore
projectJson="$toolsLocalPath/project.json"
pjContent="{ \"dependencies\": {"
while read v; do
IFS='=' read -r -a line <<< "$v"
pjContent="$pjContent \"${line[0]}\": \"${line[1]}\","
done <$rootToolVersions
pjContent="$pjContent }, \"frameworks\": { \"netcoreapp1.0\": { } } }"
echo $pjContent > $projectJson
# now restore the packages
buildToolsSource="${BUILDTOOLS_SOURCE:-https://dotnet.myget.org/F/dotnet-buildtools/api/v3/index.json}"
nugetOrgSource="https://api.nuget.org/v3/index.json"
packagesPath="$repoRoot/packages"
dotNetExe="$cliLocalPath/dotnet"
restoreArgs="restore $projectJson --packages $packagesPath --source $buildToolsSource --source $nugetOrgSource"
say_verbose "Running $dotNetExe $restoreArgs"
$dotNetExe $restoreArgs
if [ $? != 0 ]; then
say_err "project.json restore failed with exit code $?"
exit $?
fi
# now stage the contents to tools directory and run any init scripts
while read v; do
IFS='=' read -r -a line <<< "$v"
# verify that the version we expect is what was restored
pkgVerPath="$packagesPath/${line[0]}/${line[1]}"
if [ ! -d $pkgVerPath ]; then
say_err "Directory $pkgVerPath doesn't exist, ensure that the version restore matches the version specified."
exit 1
fi
# at present we have the following conventions when staging package content:
# 1. if a package contains a "tools" directory then recursively copy its contents
# to a directory named the package ID that's under $ToolsLocalPath.
# 2. if a package contains a "libs" directory then recursively copy its contents
# under the $ToolsLocalPath directory.
# 3. if a package contains a file "lib\init-tools.cmd" execute it.
if [ -d "$pkgVerPath/tools" ]; then
destination="$toolsLocalPath/${line[0]}"
mkdir -p $destination
cp -r $pkgVerPath/* $destination
fi
if [ -d "$pkgVerPath/lib" ]; then
cp -r $pkgVerPath/lib/* $toolsLocalPath
fi
if [ -f "$pkgVerPath/lib/init-tools.sh" ]; then
"$pkgVerPath/lib/init-tools.sh" "$repoRoot" "$dotNetExe" "$toolsLocalPath" > "init-${line[0]}.log"
fi
done <$rootToolVersions
cp $rootToolVersions $bootstrapComplete
say "Bootstrap finished successfully."