@@ -160,6 +160,11 @@ func New(opts *Options) *Handler {
160160 handler .buildInfoJSON = html .EscapeString (string (buildInfoResponse ))
161161 handler .handler = mux .ServeHTTP
162162
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+
163168 return handler
164169}
165170
@@ -169,8 +174,8 @@ type Handler struct {
169174 secureHeaders * secure.Secure
170175 handler http.HandlerFunc
171176 htmlTemplates * template.Template
172-
173177 buildInfoJSON string
178+ installScript []byte
174179
175180 // RegionsFetcher will attempt to fetch the more detailed WorkspaceProxy data, but will fall back to the
176181 // regions if the user does not have the correct permissions.
@@ -217,6 +222,16 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
217222 // If the asset does not exist, this will return a 404.
218223 h .handler .ServeHTTP (rw , r )
219224 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
220235 // If the original file path exists we serve it.
221236 case h .exists (reqFile ):
222237 if ShouldCacheFile (reqFile ) {
@@ -533,6 +548,32 @@ func findAndParseHTMLFiles(files fs.FS) (*template.Template, error) {
533548 return root , nil
534549}
535550
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+
536577// ExtractOrReadBinFS checks the provided fs for compressed coder binaries and
537578// extracts them into dest/bin if found. As a fallback, the provided FS is
538579// checked for a /bin directory, if it is non-empty it is returned. Finally
0 commit comments