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