github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/go/vcweb/fossil.go (about)

     1  // Copyright 2017 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package vcweb
     6  
     7  import (
     8  	"fmt"
     9  	"log"
    10  	"net/http"
    11  	"net/http/cgi"
    12  	"os"
    13  	"os/exec"
    14  	"path/filepath"
    15  	"sync"
    16  )
    17  
    18  type fossilHandler struct {
    19  	once          sync.Once
    20  	fossilPath    string
    21  	fossilPathErr error
    22  }
    23  
    24  func (h *fossilHandler) Available() bool {
    25  	h.once.Do(func() {
    26  		h.fossilPath, h.fossilPathErr = exec.LookPath("fossil")
    27  	})
    28  	return h.fossilPathErr == nil
    29  }
    30  
    31  func (h *fossilHandler) Handler(dir string, env []string, logger *log.Logger) (http.Handler, error) {
    32  	if !h.Available() {
    33  		return nil, ServerNotInstalledError{name: "fossil"}
    34  	}
    35  
    36  	name := filepath.Base(dir)
    37  	db := filepath.Join(dir, name+".fossil")
    38  
    39  	cgiPath := db + ".cgi"
    40  	cgiScript := fmt.Sprintf("#!%s\nrepository: %s\n", h.fossilPath, db)
    41  	if err := os.WriteFile(cgiPath, []byte(cgiScript), 0755); err != nil {
    42  		return nil, err
    43  	}
    44  
    45  	handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
    46  		if _, err := os.Stat(db); err != nil {
    47  			http.Error(w, err.Error(), http.StatusInternalServerError)
    48  			return
    49  		}
    50  		ch := &cgi.Handler{
    51  			Env:    env,
    52  			Logger: logger,
    53  			Path:   h.fossilPath,
    54  			Args:   []string{cgiPath},
    55  			Dir:    dir,
    56  		}
    57  		ch.ServeHTTP(w, req)
    58  	})
    59  
    60  	return handler, nil
    61  }