|
1 /* Title: Pure/Tools/dotnet_setup.scala |
|
2 Author: Makarius |
|
3 |
|
4 Dynamic setup of dotnet component. |
|
5 */ |
|
6 |
|
7 package isabelle |
|
8 |
|
9 |
|
10 object Dotnet_Setup { |
|
11 /* platforms */ |
|
12 |
|
13 sealed case class Platform_Info( |
|
14 family: Platform.Family.Value, |
|
15 name: String, |
|
16 os: String = "", |
|
17 arch: String = "x64", |
|
18 ext: String = "sh", |
|
19 exec: String = "bash", |
|
20 check: () => Unit = () => ()) |
|
21 |
|
22 val all_platforms = |
|
23 List( |
|
24 Platform_Info(Platform.Family.linux_arm, "arm64-linux", os = "linux", arch = "arm64"), |
|
25 Platform_Info(Platform.Family.linux, "x86_64-linux", os = "linux"), |
|
26 Platform_Info(Platform.Family.macos, "arm64-darwin", os = "osx", arch = "arm64"), |
|
27 Platform_Info(Platform.Family.macos, "x86_64-darwin", os = "osx"), |
|
28 Platform_Info(Platform.Family.windows, "x86_64-windows", |
|
29 ext = "ps1", |
|
30 exec = "powershell -ExecutionPolicy ByPass", |
|
31 check = () => Isabelle_System.require_command("powershell", "-NoProfile -Command Out-Null"))) |
|
32 |
|
33 def check_platform_spec(spec: String): String = { |
|
34 val all_specs = |
|
35 Library.distinct(all_platforms.map(_.family.toString) ::: all_platforms.map(_.name)) |
|
36 if (all_specs.contains(spec)) spec |
|
37 else { |
|
38 error("Bad platform specification " + quote(spec) + |
|
39 "\n expected " + commas_quote(all_specs)) |
|
40 } |
|
41 } |
|
42 |
|
43 |
|
44 /* dotnet download and setup */ |
|
45 |
|
46 def default_platform: String = Platform.Family.native(Platform.family) |
|
47 def default_target_dir: Path = Path.explode("$ISABELLE_COMPONENTS_BASE") |
|
48 def default_install_url: String = "https://dot.net/v1/dotnet-install" |
|
49 def default_version: String = "6.0.402" |
|
50 |
|
51 private val settings = """# -*- shell-script -*- :mode=shellscript: |
|
52 |
|
53 if [ -n "$ISABELLE_WINDOWS_PLATFORM64" -a -d "$COMPONENT/$ISABELLE_WINDOWS_PLATFORM64" ]; then |
|
54 ISABELLE_DOTNET="$COMPONENT/$ISABELLE_WINDOWS_PLATFORM64/dotnet.exe" |
|
55 elif [ -n "$ISABELLE_APPLE_PLATFORM64" -a -d "$COMPONENT/$ISABELLE_APPLE_PLATFORM64" ]; then |
|
56 ISABELLE_DOTNET="$COMPONENT/$ISABELLE_APPLE_PLATFORM64/dotnet" |
|
57 elif [ -d "$COMPONENT/$ISABELLE_PLATFORM64" ]; then |
|
58 ISABELLE_DOTNET="$COMPONENT/$ISABELLE_PLATFORM64/dotnet" |
|
59 fi |
|
60 """ |
|
61 |
|
62 def dotnet_setup( |
|
63 platform_spec: String = default_platform, |
|
64 target_dir: Path = default_target_dir, |
|
65 install_url: String = default_install_url, |
|
66 version: String = default_version, |
|
67 dry_run: Boolean = false, |
|
68 verbose: Boolean = false, |
|
69 progress: Progress = new Progress |
|
70 ): Unit = { |
|
71 check_platform_spec(platform_spec) |
|
72 |
|
73 for { |
|
74 platform <- all_platforms |
|
75 if platform.family.toString == platform_spec || platform.name == platform_spec |
|
76 } { |
|
77 progress.expose_interrupt() |
|
78 platform.check() |
|
79 |
|
80 |
|
81 /* component directory */ |
|
82 |
|
83 val component_dir = |
|
84 target_dir + Path.explode(if (version.isEmpty) "dotnet-latest" else "dotnet-" + version) |
|
85 |
|
86 if (!dry_run) { |
|
87 val etc_dir = Isabelle_System.make_directory(component_dir + Path.explode("etc")) |
|
88 val settings_path = etc_dir + Path.explode("settings") |
|
89 if (!settings_path.is_file) { |
|
90 progress.echo("Component " + component_dir.expand) |
|
91 File.write(settings_path, settings) |
|
92 } |
|
93 |
|
94 File.write(component_dir + Path.explode("README"), |
|
95 """This installation of Dotnet has been produced via "isabelle dotnet_setup". |
|
96 |
|
97 |
|
98 Makarius |
|
99 """ + Date.Format.date(Date.now()) + "\n") |
|
100 |
|
101 Components.update_components(true, component_dir) |
|
102 } |
|
103 |
|
104 |
|
105 /* platform directory */ |
|
106 |
|
107 Isabelle_System.with_tmp_file("install", ext = platform.ext) { install => |
|
108 Isabelle_System.download_file(install_url + "." + platform.ext, install) |
|
109 |
|
110 val platform_dir = component_dir + Path.explode(platform.name) |
|
111 if (platform_dir.is_dir) { |
|
112 progress.echo_warning("Platform " + platform.name + " already installed") |
|
113 } |
|
114 else { |
|
115 progress.echo("Platform " + platform.name + " ...") |
|
116 val script = |
|
117 platform.exec + " " + File.bash_platform_path(install) + |
|
118 (if (version.nonEmpty) " -Version " + Bash.string(version) else "") + |
|
119 " -Architecture " + Bash.string(platform.arch) + |
|
120 (if (platform.os.nonEmpty) " -OS " + Bash.string(platform.os) else "") + |
|
121 " -InstallDir " + Bash.string(platform.name) + |
|
122 (if (dry_run) " -DryRun" else "") + |
|
123 " -NoPath" |
|
124 progress.bash(script, echo = verbose, |
|
125 cwd = if (dry_run) null else component_dir.file).check |
|
126 } |
|
127 } |
|
128 } |
|
129 } |
|
130 |
|
131 |
|
132 /* Isabelle tool wrapper */ |
|
133 |
|
134 val isabelle_tool = |
|
135 Isabelle_Tool("dotnet_setup", "dynamic setup of dotnet component (for Fsharp)", |
|
136 Scala_Project.here, |
|
137 { args => |
|
138 |
|
139 var target_dir = default_target_dir |
|
140 var install_url = default_install_url |
|
141 var version = default_version |
|
142 var dry_run = false |
|
143 var platforms = List(default_platform) |
|
144 var verbose = false |
|
145 |
|
146 val getopts = Getopts(""" |
|
147 Usage: isabelle dotnet_setup [OPTIONS] |
|
148 |
|
149 Options are: |
|
150 -D DIR target directory (default: """ + default_target_dir.expand + """) |
|
151 -I URL URL for install script without extension (default: """ + quote(default_install_url) + """) |
|
152 -V VERSION version (empty means "latest", default: """ + quote(default_version) + """) |
|
153 -n dry run: try download without installation |
|
154 -p PLATFORMS list of platforms as family or formal name, separated by commas |
|
155 (default: """ + quote(default_platform) + """ |
|
156 -v verbose |
|
157 |
|
158 Download the Dotnet / Fsharp platform and configure it as Isabelle component. |
|
159 |
|
160 See also: |
|
161 https://fsharp.org |
|
162 https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-install-script |
|
163 |
|
164 Example: |
|
165 isabelle dotnet_setup |
|
166 isabelle dotnet fsi |
|
167 """, |
|
168 "D:" -> (arg => target_dir = Path.explode(arg)), |
|
169 "I:" -> (arg => install_url = arg), |
|
170 "V:" -> (arg => version = arg), |
|
171 "n" -> (_ => dry_run = true), |
|
172 "p:" -> (arg => platforms = Library.space_explode(',', arg).map(check_platform_spec)), |
|
173 "v" -> (_ => verbose = true)) |
|
174 |
|
175 val more_args = getopts(args) |
|
176 if (more_args.nonEmpty) getopts.usage() |
|
177 |
|
178 val progress = new Console_Progress() |
|
179 |
|
180 for (platform <- platforms) { |
|
181 dotnet_setup(platform_spec = platform, target_dir = target_dir, install_url = install_url, |
|
182 version = version, dry_run = dry_run, verbose = verbose, progress = progress) |
|
183 } |
|
184 }) |
|
185 } |