@@ -160,6 +160,11 @@ func New(opts *Options) *Handler {
160
160
handler .buildInfoJSON = html .EscapeString (string (buildInfoResponse ))
161
161
handler .handler = mux .ServeHTTP
162
162
163
+ handler .installScript , err = parseInstallScript (opts .SiteFS , opts .BuildInfo )
164
+ if err != nil {
165
+ _ , _ = fmt .Fprintf (os .Stderr , "install.sh will be unavailable: %v" , err .Error ())
166
+ }
167
+
163
168
return handler
164
169
}
165
170
@@ -169,8 +174,8 @@ type Handler struct {
169
174
secureHeaders * secure.Secure
170
175
handler http.HandlerFunc
171
176
htmlTemplates * template.Template
172
-
173
177
buildInfoJSON string
178
+ installScript []byte
174
179
175
180
// RegionsFetcher will attempt to fetch the more detailed WorkspaceProxy data, but will fall back to the
176
181
// regions if the user does not have the correct permissions.
@@ -217,6 +222,16 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
217
222
// If the asset does not exist, this will return a 404.
218
223
h .handler .ServeHTTP (rw , r )
219
224
return
225
+ // If requesting the install.sh script, respond with the preprocessed version
226
+ // which contains the correct hostname and version information.
227
+ case reqFile == "install.sh" :
228
+ if h .installScript == nil {
229
+ http .NotFound (rw , r )
230
+ return
231
+ }
232
+ rw .Header ().Add ("Content-Type" , "text/plain; charset=utf-8" )
233
+ http .ServeContent (rw , r , reqFile , time.Time {}, bytes .NewReader (h .installScript ))
234
+ return
220
235
// If the original file path exists we serve it.
221
236
case h .exists (reqFile ):
222
237
if ShouldCacheFile (reqFile ) {
@@ -533,6 +548,32 @@ func findAndParseHTMLFiles(files fs.FS) (*template.Template, error) {
533
548
return root , nil
534
549
}
535
550
551
+ type installScriptState struct {
552
+ Origin string
553
+ Version string
554
+ }
555
+
556
+ func parseInstallScript (files fs.FS , buildInfo codersdk.BuildInfoResponse ) ([]byte , error ) {
557
+ scriptFile , err := fs .ReadFile (files , "install.sh" )
558
+ if err != nil {
559
+ return nil , err
560
+ }
561
+
562
+ script , err := template .New ("install.sh" ).Parse (string (scriptFile ))
563
+ if err != nil {
564
+ return nil , err
565
+ }
566
+
567
+ var buf bytes.Buffer
568
+ state := installScriptState {Origin : buildInfo .DashboardURL , Version : buildInfo .Version }
569
+ err = script .Execute (& buf , state )
570
+ if err != nil {
571
+ return nil , err
572
+ }
573
+
574
+ return buf .Bytes (), nil
575
+ }
576
+
536
577
// ExtractOrReadBinFS checks the provided fs for compressed coder binaries and
537
578
// extracts them into dest/bin if found. As a fallback, the provided FS is
538
579
// checked for a /bin directory, if it is non-empty it is returned. Finally
0 commit comments