github.com/shogo82148/std@v1.22.1-0.20240327122250-4e474527810c/cmd/go/internal/vcweb/vcweb.go (about)

     1  // Copyright 2022 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 serves version control repos for testing the go command.
     6  //
     7  // It is loosely derived from golang.org/x/build/vcs-test/vcweb,
     8  // which ran as a service hosted at vcs-test.golang.org.
     9  //
    10  // When a repository URL is first requested, the vcweb [Server] dynamically
    11  // regenerates the repository using a script interpreted by a [script.Engine].
    12  // The script produces the server's contents for a corresponding root URL and
    13  // all subdirectories of that URL, which are then cached: subsequent requests
    14  // for any URL generated by the script will serve the script's previous output
    15  // until the script is modified.
    16  //
    17  // The script engine includes all of the engine's default commands and
    18  // conditions, as well as commands for each supported VCS binary (bzr, fossil,
    19  // git, hg, and svn), a "handle" command that informs the script which protocol
    20  // or handler to use to serve the request, and utilities "at" (which sets
    21  // environment variables for Git timestamps) and "unquote" (which unquotes its
    22  // argument as if it were a Go string literal).
    23  //
    24  // The server's "/" endpoint provides a summary of the available scripts,
    25  // and "/help" provides documentation for the script environment.
    26  //
    27  // To run a standalone server based on the vcweb engine, use:
    28  //
    29  //	go test cmd/go/internal/vcweb/vcstest -v --port=0
    30  package vcweb
    31  
    32  import (
    33  	"github.com/shogo82148/std/cmd/go/internal/script"
    34  	"github.com/shogo82148/std/log"
    35  	"github.com/shogo82148/std/net/http"
    36  	"github.com/shogo82148/std/sync"
    37  )
    38  
    39  // A Server serves cached, dynamically-generated version control repositories.
    40  type Server struct {
    41  	env    []string
    42  	logger *log.Logger
    43  
    44  	scriptDir string
    45  	workDir   string
    46  	homeDir   string
    47  	engine    *script.Engine
    48  
    49  	scriptCache sync.Map
    50  
    51  	vcsHandlers map[string]vcsHandler
    52  }
    53  
    54  // NewServer returns a Server that generates and serves repositories in workDir
    55  // using the scripts found in scriptDir and its subdirectories.
    56  //
    57  // A request for the path /foo/bar/baz will be handled by the first script along
    58  // that path that exists: $scriptDir/foo.txt, $scriptDir/foo/bar.txt, or
    59  // $scriptDir/foo/bar/baz.txt.
    60  func NewServer(scriptDir, workDir string, logger *log.Logger) (*Server, error)
    61  
    62  func (s *Server) Close() error
    63  
    64  // ServeHTTP implements [http.Handler] for version-control repositories.
    65  func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request)
    66  
    67  // A ScriptNotFoundError indicates that the requested script file does not exist.
    68  // (It typically wraps a "stat" error for the script file.)
    69  type ScriptNotFoundError struct{ err error }
    70  
    71  func (e ScriptNotFoundError) Error() string
    72  func (e ScriptNotFoundError) Unwrap() error
    73  
    74  // A ServerNotInstalledError indicates that the server binary required for the
    75  // indicated VCS does not exist.
    76  type ServerNotInstalledError struct{ name string }
    77  
    78  func (v ServerNotInstalledError) Error() string
    79  
    80  // HandleScript ensures that the script at scriptRelPath has been evaluated
    81  // with its current contents.
    82  //
    83  // If the script completed successfully, HandleScript invokes f on the handler
    84  // with the script's result still read-locked, and waits for it to return. (That
    85  // ensures that cache invalidation does not race with an in-flight handler.)
    86  //
    87  // Otherwise, HandleScript returns the (cached) error from executing the script.
    88  func (s *Server) HandleScript(scriptRelPath string, logger *log.Logger, f func(http.Handler)) error