vcweb

Imports

Imports #

"log"
"net/http"
"io"
"log"
"net"
"net/http"
"os/exec"
"strings"
"sync"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"path"
"strings"
"log"
"net/http"
"fmt"
"log"
"net/http"
"net/http/cgi"
"os"
"os/exec"
"path/filepath"
"sync"
"log"
"net/http"
"net/http/cgi"
"os/exec"
"runtime"
"slices"
"sync"
"bufio"
"bytes"
"cmd/internal/script"
"context"
"errors"
"fmt"
"internal/txtar"
"io"
"log"
"net/http"
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"strings"
"time"
"golang.org/x/mod/module"
"golang.org/x/mod/zip"
"bufio"
"cmd/internal/script"
"context"
"crypto/sha256"
"errors"
"fmt"
"io"
"io/fs"
"log"
"net/http"
"os"
"os/exec"
"path"
"path/filepath"
"runtime/debug"
"strings"
"sync"
"text/tabwriter"
"time"
"log"
"net/http"
"bufio"
"context"
"errors"
"io"
"log"
"net/http"
"net/http/httputil"
"net/url"
"os"
"os/exec"
"slices"
"strings"
"sync"
"time"

Constants & Variables

gitConfig var #

gitConfig contains a ~/.gitconfg file that attempts to provide deterministic, platform-agnostic behavior for the 'git' command.

var gitConfig = *ast.SliceExpr

hgrc var #

hgrc contains a ~/.hgrc file that attempts to provide deterministic, platform-agnostic behavior for the 'hg' command.

var hgrc = *ast.SliceExpr

Interfaces

vcsHandler interface #

A vcsHandler serves repositories over HTTP for a known version-control tool.

type vcsHandler interface {
Available() bool
Handler(dir string, env []string, logger *log.Logger) (http.Handler, error)
}

Structs

ScriptNotFoundError struct #

A ScriptNotFoundError indicates that the requested script file does not exist. (It typically wraps a "stat" error for the script file.)

type ScriptNotFoundError struct {
err error
}

Server struct #

A Server serves cached, dynamically-generated version control repositories.

type Server struct {
env []string
logger *log.Logger
scriptDir string
workDir string
homeDir string
engine *script.Engine
scriptCache sync.Map
vcsHandlers map[string]vcsHandler
}

ServerNotInstalledError struct #

A ServerNotInstalledError indicates that the server binary required for the indicated VCS does not exist.

type ServerNotInstalledError struct {
name string
}

accessToken struct #

type accessToken struct {
Username string
Password string
StatusCode int
Message string
}

authHandler struct #

authHandler serves requests only if the Basic Auth data sent with the request matches the contents of a ".access" file in the requested directory. For each request, the handler looks for a file named ".access" and parses it as a JSON-serialized accessToken. If the credentials from the request match the accessToken, the file is served normally; otherwise, it is rejected with the StatusCode and Message provided by the token.

type authHandler struct {

}

bzrHandler struct #

type bzrHandler struct {

}

dirHandler struct #

dirHandler is a vcsHandler that serves the raw contents of a directory.

type dirHandler struct {

}

fossilHandler struct #

type fossilHandler struct {
once sync.Once
fossilPath string
fossilPathErr error
}

gitHandler struct #

type gitHandler struct {
once sync.Once
gitPath string
gitPathErr error
}

hgHandler struct #

type hgHandler struct {
once sync.Once
hgPath string
hgPathErr error
}

insecureHandler struct #

insecureHandler redirects requests to the same host and path but using the "http" scheme instead of "https".

type insecureHandler struct {

}

scriptCtx struct #

A scriptCtx is a context.Context that stores additional state for script commands.

type scriptCtx struct {
context.Context
server *Server
commitTime time.Time
handlerName string
handler http.Handler
}

scriptCtxKey struct #

scriptCtxKey is the key associating the *scriptCtx in a script's Context..

type scriptCtxKey struct {

}

scriptResult struct #

A scriptResult describes the cached result of executing a vcweb script.

type scriptResult struct {
mu sync.RWMutex
hash [sha256.Size]byte
hashTime time.Time
handler http.Handler
err error
}

svnHandler struct #

An svnHandler serves requests for Subversion repos. Unlike the other vcweb handlers, svnHandler does not serve the Subversion protocol directly over the HTTP connection. Instead, it opens a separate port that serves the (non-HTTP) 'svn' protocol. The test binary can retrieve the URL for that port by sending an HTTP request with the query parameter "vcwebsvn=1". We take this approach because the 'svn' protocol is implemented by a lightweight 'svnserve' binary that is usually packaged along with the 'svn' client binary, whereas only known implementation of the Subversion HTTP protocol is the mod_dav_svn apache2 module. Apache2 has a lot of dependencies and also seems to rely on global configuration via well-known file paths, so implementing a hermetic test using apache2 would require the test to run in a complicated container environment, which wouldn't be nearly as straightforward for Go contributors to set up and test against on their local machine.

type svnHandler struct {
svnRoot string
logger *log.Logger
pathOnce sync.Once
svnservePath string
svnserveErr error
listenOnce sync.Once
s chan *svnState
}

svnState struct #

An svnState describes the state of a port serving the 'svn://' protocol.

type svnState struct {
listener net.Listener
listenErr error
conns map[net.Conn]struct{...}
closing bool
done chan struct{...}
}

Functions

Available method #

func (*dirHandler) Available() bool

Available method #

func (h *insecureHandler) Available() bool

Available method #

func (h *svnHandler) Available() bool

Available method #

func (h *hgHandler) Available() bool

Available method #

func (h *authHandler) Available() bool

Available method #

func (h *gitHandler) Available() bool

Available method #

func (h *fossilHandler) Available() bool

Available method #

func (*bzrHandler) Available() bool

Close method #

func (s *Server) Close() error

Close method #

Close stops accepting new svn:// connections and terminates the existing ones, then waits for the 'svnserve' subprocesses to complete.

func (h *svnHandler) Close() error

Error method #

func (e ScriptNotFoundError) Error() string

Error method #

func (v ServerNotInstalledError) Error() string

HandleScript method #

HandleScript ensures that the script at scriptRelPath has been evaluated with its current contents. If the script completed successfully, HandleScript invokes f on the handler with the script's result still read-locked, and waits for it to return. (That ensures that cache invalidation does not race with an in-flight handler.) Otherwise, HandleScript returns the (cached) error from executing the script.

func (s *Server) HandleScript(scriptRelPath string, logger *log.Logger, f func(http.Handler)) error

Handler method #

func (*dirHandler) Handler(dir string, env []string, logger *log.Logger) (http.Handler, error)

Handler method #

func (h *gitHandler) Handler(dir string, env []string, logger *log.Logger) (http.Handler, error)

Handler method #

func (*bzrHandler) Handler(dir string, env []string, logger *log.Logger) (http.Handler, error)

Handler method #

func (h *fossilHandler) Handler(dir string, env []string, logger *log.Logger) (http.Handler, error)

Handler method #

func (h *authHandler) Handler(dir string, env []string, logger *log.Logger) (http.Handler, error)

Handler method #

Handler returns an http.Handler that checks for the "vcwebsvn" query parameter and then serves the 'svn://' URL for the repository at the requested path. The HTTP client is expected to read that URL and pass it to the 'svn' client.

func (h *svnHandler) Handler(dir string, env []string, logger *log.Logger) (http.Handler, error)

Handler method #

func (h *hgHandler) Handler(dir string, env []string, logger *log.Logger) (http.Handler, error)

Handler method #

func (h *insecureHandler) Handler(dir string, env []string, logger *log.Logger) (http.Handler, error)

NewServer function #

NewServer returns a Server that generates and serves repositories in workDir using the scripts found in scriptDir and its subdirectories. A request for the path /foo/bar/baz will be handled by the first script along that path that exists: $scriptDir/foo.txt, $scriptDir/foo/bar.txt, or $scriptDir/foo/bar/baz.txt.

func NewServer(scriptDir string, workDir string, logger *log.Logger) (*Server, error)

ServeHTTP method #

ServeHTTP implements [http.Handler] for version-control repositories.

func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request)

ServeHTTP method #

func (h *insecureHandler) ServeHTTP(w http.ResponseWriter, req *http.Request)

Unwrap method #

func (e ScriptNotFoundError) Unwrap() error

Value method #

func (sc *scriptCtx) Value(key any) any

getScriptCtx function #

func getScriptCtx(st *script.State) (*scriptCtx, error)

help method #

help serves a plain-text summary of the server's supported script language.

func (s *Server) help(w http.ResponseWriter, req *http.Request)

homeEnvName function #

homeEnvName returns the environment variable used by os.UserHomeDir to locate the user's home directory.

func homeEnvName() string

loadScript method #

loadScript interprets the given script content using the vcweb script engine. loadScript always returns either a non-nil handler or a non-nil error. The script content must be a txtar archive with a comment containing a script with exactly one "handle" command and zero or more VCS commands to prepare the repository to be served.

func (s *Server) loadScript(ctx context.Context, logger *log.Logger, scriptPath string, scriptContent []byte, workDir string) (http.Handler, error)

newScriptEngine function #

newScriptEngine returns a script engine augmented with commands for reproducing version-control repositories by replaying commits.

func newScriptEngine() *script.Engine

newState method #

newState returns a new script.State for executing scripts in workDir.

func (s *Server) newState(ctx context.Context, workDir string) (*script.State, error)

overview method #

overview serves an HTML summary of the status of the scripts in the server's script directory.

func (s *Server) overview(w http.ResponseWriter, r *http.Request)

pathEnvName function #

pathEnvName returns the environment variable used by exec.LookPath to identify directories to search for executables.

func pathEnvName() string

scriptAt function #

func scriptAt() script.Cmd

scriptEnviron function #

scriptEnviron returns a new environment that attempts to provide predictable behavior for the supported version-control tools.

func scriptEnviron(homeDir string) []string

scriptHandle function #

func scriptHandle() script.Cmd

scriptModzip function #

func scriptModzip() script.Cmd

scriptUnquote function #

func scriptUnquote() script.Cmd

serve method #

serve serves a single 'svn://' connection on c.

func (h *svnHandler) serve(c net.Conn)

tempEnvName function #

tempEnvName returns the environment variable used by os.TempDir to locate the default directory for temporary files.

func tempEnvName() string

Generated with Arrow