diff --git a/exe.go b/exe.go index 9b383542..95e90b92 100644 --- a/exe.go +++ b/exe.go @@ -139,37 +139,3 @@ func copyBinary(from, to string) error { _, err = io.Copy(writer, reader) return err } - -type nopTestDeps struct{} - -func (nopTestDeps) MatchString(pat, str string) (result bool, err error) { - return false, nil -} - -func (nopTestDeps) StartCPUProfile(w io.Writer) error { - return nil -} - -func (nopTestDeps) StopCPUProfile() {} - -func (nopTestDeps) WriteProfileTo(name string, w io.Writer, debug int) error { - return nil -} - -func (nopTestDeps) ImportPath() string { - return "" -} -func (nopTestDeps) StartTestLog(w io.Writer) {} - -func (nopTestDeps) StopTestLog() error { - return nil -} - -// Note: WriteHeapProfile is needed for Go 1.10 but not Go 1.11. -func (nopTestDeps) WriteHeapProfile(io.Writer) error { - // Not needed for Go 1.10. - return nil -} - -// Note: SetPanicOnExit0 was added in Go 1.16. -func (nopTestDeps) SetPanicOnExit0(bool) {} diff --git a/exe_go118.go b/exe_go118.go deleted file mode 100644 index a9bdd810..00000000 --- a/exe_go118.go +++ /dev/null @@ -1,48 +0,0 @@ -package testscript - -import ( - "reflect" - "testing" - "time" -) - -func mainStart() *testing.M { - // Note: testing.MainStart acquired an extra argument in Go 1.18. - return testing.MainStart(nopTestDeps{}, nil, nil, nil, nil) -} - -// Note: corpusEntry is an anonymous struct type used by some method stubs. -type corpusEntry = struct { - Parent string - Path string - Data []byte - Values []interface{} - Generation int - IsSeed bool -} - -// Note: CoordinateFuzzing was added in Go 1.18. -func (nopTestDeps) CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error { - return nil -} - -// Note: RunFuzzWorker was added in Go 1.18. -func (nopTestDeps) RunFuzzWorker(func(corpusEntry) error) error { - return nil -} - -// Note: ReadCorpus was added in Go 1.18. -func (nopTestDeps) ReadCorpus(string, []reflect.Type) ([]corpusEntry, error) { - return nil, nil -} - -// Note: CheckCorpus was added in Go 1.18. -func (nopTestDeps) CheckCorpus([]interface{}, []reflect.Type) error { - return nil -} - -// Note: ResetCoverage was added in Go 1.18. -func (nopTestDeps) ResetCoverage() {} - -// Note: SnapshotCoverage was added in Go 1.18. -func (nopTestDeps) SnapshotCoverage() {} diff --git a/go.mod b/go.mod index 0bd85f6b..60d685dc 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,6 @@ module fortio.org/testscript go 1.20 require ( - golang.org/x/sys v0.8.0 - golang.org/x/tools v0.8.0 + golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f + golang.org/x/tools v0.1.12 ) diff --git a/go.sum b/go.sum index b13d5c28..7bd4c707 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,4 @@ -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= -golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= diff --git a/gotooltest/setup.go b/gotooltest/setup.go new file mode 100644 index 00000000..c8d9ec07 --- /dev/null +++ b/gotooltest/setup.go @@ -0,0 +1,174 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package gotooltest implements functionality useful for testing +// tools that use the go command. +package gotooltest + +import ( + "bytes" + "encoding/json" + "fmt" + "os" + "os/exec" + "path/filepath" + "regexp" + "runtime" + "strings" + "sync" + + "github.com/rogpeppe/go-internal/testscript" +) + +var ( + goVersionRegex = regexp.MustCompile(`^go([1-9][0-9]*)\.([1-9][0-9]*)$`) + + goEnv struct { + GOROOT string + GOCACHE string + GOPROXY string + goversion string + releaseTags []string + once sync.Once + err error + } +) + +// initGoEnv initialises goEnv. It should only be called using goEnv.once.Do, +// as in Setup. +// +// Run all of these probe commands in a temporary directory, so as not to make +// any assumptions about the caller's working directory. +func initGoEnv() (err error) { + td, err := os.MkdirTemp("", "gotooltest-initGoEnv") + if err != nil { + return fmt.Errorf("failed to create temporary directory for go command tests: %w", err) + } + defer func() { + if rerr := os.RemoveAll(td); rerr != nil && err == nil { + err = fmt.Errorf("failed to remove temporary directory for go command tests: %w", rerr) + } + }() + + // Write a temporary go.mod file in td. This ensures that we create + // a porcelain environment in which to run these probe commands. + if err := os.WriteFile(filepath.Join(td, "go.mod"), []byte("module gotooltest"), 0600); err != nil { + return fmt.Errorf("failed to write temporary go.mod file: %w", err) + } + + run := func(args ...string) (*bytes.Buffer, *bytes.Buffer, error) { + var stdout, stderr bytes.Buffer + cmd := exec.Command(args[0], args[1:]...) + cmd.Dir = td + cmd.Stdout = &stdout + cmd.Stderr = &stderr + return &stdout, &stderr, cmd.Run() + } + + lout, stderr, err := run("go", "list", "-f={{context.ReleaseTags}}", "runtime") + if err != nil { + return fmt.Errorf("failed to determine release tags from go command: %v\n%v", err, stderr.String()) + } + tagStr := strings.TrimSpace(lout.String()) + tagStr = strings.Trim(tagStr, "[]") + goEnv.releaseTags = strings.Split(tagStr, " ") + + eout, stderr, err := run("go", "env", "-json", + "GOROOT", + "GOCACHE", + "GOPROXY", + ) + if err != nil { + return fmt.Errorf("failed to determine environment from go command: %v\n%v", err, stderr) + } + if err := json.Unmarshal(eout.Bytes(), &goEnv); err != nil { + return fmt.Errorf("failed to unmarshal GOROOT and GOCACHE tags from go command out: %v\n%v", err, eout) + } + + version := goEnv.releaseTags[len(goEnv.releaseTags)-1] + if !goVersionRegex.MatchString(version) { + return fmt.Errorf("invalid go version %q", version) + } + goEnv.goversion = version[2:] + + return nil +} + +// Setup sets up the given test environment for tests that use the go +// command. It adds support for go tags to p.Condition and adds the go +// command to p.Cmds. It also wraps p.Setup to set up the environment +// variables for running the go command appropriately. +// +// It checks go command can run, but not that it can build or run +// binaries. +func Setup(p *testscript.Params) error { + goEnv.once.Do(func() { + goEnv.err = initGoEnv() + }) + if goEnv.err != nil { + return goEnv.err + } + + origSetup := p.Setup + p.Setup = func(e *testscript.Env) error { + e.Vars = goEnviron(e.Vars) + if origSetup != nil { + return origSetup(e) + } + return nil + } + if p.Cmds == nil { + p.Cmds = make(map[string]func(ts *testscript.TestScript, neg bool, args []string)) + } + p.Cmds["go"] = cmdGo + return nil +} + +func goEnviron(env0 []string) []string { + env := environ(env0) + workdir := env.get("WORK") + return append(env, []string{ + "GOPATH=" + filepath.Join(workdir, ".gopath"), + "CCACHE_DISABLE=1", // ccache breaks with non-existent HOME + "GOARCH=" + runtime.GOARCH, + "GOOS=" + runtime.GOOS, + "GOROOT=" + goEnv.GOROOT, + "GOCACHE=" + goEnv.GOCACHE, + "GOPROXY=" + goEnv.GOPROXY, + "goversion=" + goEnv.goversion, + }...) +} + +func cmdGo(ts *testscript.TestScript, neg bool, args []string) { + if len(args) < 1 { + ts.Fatalf("usage: go subcommand ...") + } + err := ts.Exec("go", args...) + if err != nil { + ts.Logf("[%v]\n", err) + if !neg { + ts.Fatalf("unexpected go command failure") + } + } else { + if neg { + ts.Fatalf("unexpected go command success") + } + } +} + +type environ []string + +func (e0 *environ) get(name string) string { + e := *e0 + for i := len(e) - 1; i >= 0; i-- { + v := e[i] + if len(v) <= len(name) { + continue + } + if strings.HasPrefix(v, name) && v[len(name)] == '=' { + return v[len(name)+1:] + } + } + return "" +} diff --git a/internal/syscall/windows/registry/key.go b/internal/syscall/windows/registry/key.go deleted file mode 100644 index 8ac59d20..00000000 --- a/internal/syscall/windows/registry/key.go +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build windows -// +build windows - -// Package registry provides access to the Windows registry. -// -// Here is a simple example, opening a registry key and reading a string value from it. -// -// k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE) -// if err != nil { -// log.Fatal(err) -// } -// defer k.Close() -// -// s, _, err := k.GetStringValue("SystemRoot") -// if err != nil { -// log.Fatal(err) -// } -// fmt.Printf("Windows system root is %q\n", s) -// -// NOTE: This package is a copy of golang.org/x/sys/windows/registry -// with KeyInfo.ModTime removed to prevent dependency cycles. -package registry - -import ( - "io" - "syscall" -) - -const ( - // Registry key security and access rights. - // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724878.aspx - // for details. - ALL_ACCESS = 0xf003f - CREATE_LINK = 0x00020 - CREATE_SUB_KEY = 0x00004 - ENUMERATE_SUB_KEYS = 0x00008 - EXECUTE = 0x20019 - NOTIFY = 0x00010 - QUERY_VALUE = 0x00001 - READ = 0x20019 - SET_VALUE = 0x00002 - WOW64_32KEY = 0x00200 - WOW64_64KEY = 0x00100 - WRITE = 0x20006 -) - -// Key is a handle to an open Windows registry key. -// Keys can be obtained by calling OpenKey; there are -// also some predefined root keys such as CURRENT_USER. -// Keys can be used directly in the Windows API. -type Key syscall.Handle - -const ( - // Windows defines some predefined root keys that are always open. - // An application can use these keys as entry points to the registry. - // Normally these keys are used in OpenKey to open new keys, - // but they can also be used anywhere a Key is required. - CLASSES_ROOT = Key(syscall.HKEY_CLASSES_ROOT) - CURRENT_USER = Key(syscall.HKEY_CURRENT_USER) - LOCAL_MACHINE = Key(syscall.HKEY_LOCAL_MACHINE) - USERS = Key(syscall.HKEY_USERS) - CURRENT_CONFIG = Key(syscall.HKEY_CURRENT_CONFIG) -) - -// Close closes open key k. -func (k Key) Close() error { - return syscall.RegCloseKey(syscall.Handle(k)) -} - -// OpenKey opens a new key with path name relative to key k. -// It accepts any open key, including CURRENT_USER and others, -// and returns the new key and an error. -// The access parameter specifies desired access rights to the -// key to be opened. -func OpenKey(k Key, path string, access uint32) (Key, error) { - p, err := syscall.UTF16PtrFromString(path) - if err != nil { - return 0, err - } - var subkey syscall.Handle - err = syscall.RegOpenKeyEx(syscall.Handle(k), p, 0, access, &subkey) - if err != nil { - return 0, err - } - return Key(subkey), nil -} - -// ReadSubKeyNames returns the names of subkeys of key k. -// The parameter n controls the number of returned names, -// analogous to the way os.File.Readdirnames works. -func (k Key) ReadSubKeyNames(n int) ([]string, error) { - names := make([]string, 0) - // Registry key size limit is 255 bytes and described there: - // https://msdn.microsoft.com/library/windows/desktop/ms724872.aspx - buf := make([]uint16, 256) //plus extra room for terminating zero byte -loopItems: - for i := uint32(0); ; i++ { - if n > 0 { - if len(names) == n { - return names, nil - } - } - l := uint32(len(buf)) - for { - err := syscall.RegEnumKeyEx(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil) - if err == nil { - break - } - if err == syscall.ERROR_MORE_DATA { - // Double buffer size and try again. - l = uint32(2 * len(buf)) - buf = make([]uint16, l) - continue - } - if err == _ERROR_NO_MORE_ITEMS { - break loopItems - } - return names, err - } - names = append(names, syscall.UTF16ToString(buf[:l])) - } - if n > len(names) { - return names, io.EOF - } - return names, nil -} - -// CreateKey creates a key named path under open key k. -// CreateKey returns the new key and a boolean flag that reports -// whether the key already existed. -// The access parameter specifies the access rights for the key -// to be created. -func CreateKey(k Key, path string, access uint32) (newk Key, openedExisting bool, err error) { - var h syscall.Handle - var d uint32 - err = regCreateKeyEx(syscall.Handle(k), syscall.StringToUTF16Ptr(path), - 0, nil, _REG_OPTION_NON_VOLATILE, access, nil, &h, &d) - if err != nil { - return 0, false, err - } - return Key(h), d == _REG_OPENED_EXISTING_KEY, nil -} - -// DeleteKey deletes the subkey path of key k and its values. -func DeleteKey(k Key, path string) error { - return regDeleteKey(syscall.Handle(k), syscall.StringToUTF16Ptr(path)) -} - -// A KeyInfo describes the statistics of a key. It is returned by Stat. -type KeyInfo struct { - SubKeyCount uint32 - MaxSubKeyLen uint32 // size of the key's subkey with the longest name, in Unicode characters, not including the terminating zero byte - ValueCount uint32 - MaxValueNameLen uint32 // size of the key's longest value name, in Unicode characters, not including the terminating zero byte - MaxValueLen uint32 // longest data component among the key's values, in bytes - lastWriteTime syscall.Filetime -} - -// Stat retrieves information about the open key k. -func (k Key) Stat() (*KeyInfo, error) { - var ki KeyInfo - err := syscall.RegQueryInfoKey(syscall.Handle(k), nil, nil, nil, - &ki.SubKeyCount, &ki.MaxSubKeyLen, nil, &ki.ValueCount, - &ki.MaxValueNameLen, &ki.MaxValueLen, nil, &ki.lastWriteTime) - if err != nil { - return nil, err - } - return &ki, nil -} diff --git a/internal/syscall/windows/registry/mksyscall.go b/internal/syscall/windows/registry/mksyscall.go deleted file mode 100644 index 07721535..00000000 --- a/internal/syscall/windows/registry/mksyscall.go +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package registry - -//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go diff --git a/internal/syscall/windows/registry/syscall.go b/internal/syscall/windows/registry/syscall.go deleted file mode 100644 index bb612793..00000000 --- a/internal/syscall/windows/registry/syscall.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build windows -// +build windows - -package registry - -import "syscall" - -const ( - _REG_OPTION_NON_VOLATILE = 0 - - _REG_CREATED_NEW_KEY = 1 - _REG_OPENED_EXISTING_KEY = 2 - - _ERROR_NO_MORE_ITEMS syscall.Errno = 259 -) - -func LoadRegLoadMUIString() error { - return procRegLoadMUIStringW.Find() -} - -//sys regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) = advapi32.RegCreateKeyExW -//sys regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) = advapi32.RegDeleteKeyW -//sys regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) = advapi32.RegSetValueExW -//sys regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegEnumValueW -//sys regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) = advapi32.RegDeleteValueW -//sys regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) = advapi32.RegLoadMUIStringW - -//sys expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) = kernel32.ExpandEnvironmentStringsW diff --git a/internal/syscall/windows/registry/value.go b/internal/syscall/windows/registry/value.go deleted file mode 100644 index b89bfd82..00000000 --- a/internal/syscall/windows/registry/value.go +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build windows -// +build windows - -package registry - -import ( - "errors" - "io" - "syscall" - "unicode/utf16" - "unsafe" -) - -const ( - // Registry value types. - NONE = 0 - SZ = 1 - EXPAND_SZ = 2 - BINARY = 3 - DWORD = 4 - DWORD_BIG_ENDIAN = 5 - LINK = 6 - MULTI_SZ = 7 - RESOURCE_LIST = 8 - FULL_RESOURCE_DESCRIPTOR = 9 - RESOURCE_REQUIREMENTS_LIST = 10 - QWORD = 11 -) - -var ( - // ErrShortBuffer is returned when the buffer was too short for the operation. - ErrShortBuffer = syscall.ERROR_MORE_DATA - - // ErrNotExist is returned when a registry key or value does not exist. - ErrNotExist = syscall.ERROR_FILE_NOT_FOUND - - // ErrUnexpectedType is returned by Get*Value when the value's type was unexpected. - ErrUnexpectedType = errors.New("unexpected key value type") -) - -// GetValue retrieves the type and data for the specified value associated -// with an open key k. It fills up buffer buf and returns the retrieved -// byte count n. If buf is too small to fit the stored value it returns -// ErrShortBuffer error along with the required buffer size n. -// If no buffer is provided, it returns true and actual buffer size n. -// If no buffer is provided, GetValue returns the value's type only. -// If the value does not exist, the error returned is ErrNotExist. -// -// GetValue is a low level function. If value's type is known, use the appropriate -// Get*Value function instead. -func (k Key) GetValue(name string, buf []byte) (n int, valtype uint32, err error) { - pname, err := syscall.UTF16PtrFromString(name) - if err != nil { - return 0, 0, err - } - var pbuf *byte - if len(buf) > 0 { - pbuf = (*byte)(unsafe.Pointer(&buf[0])) - } - l := uint32(len(buf)) - err = syscall.RegQueryValueEx(syscall.Handle(k), pname, nil, &valtype, pbuf, &l) - if err != nil { - return int(l), valtype, err - } - return int(l), valtype, nil -} - -func (k Key) getValue(name string, buf []byte) (date []byte, valtype uint32, err error) { - p, err := syscall.UTF16PtrFromString(name) - if err != nil { - return nil, 0, err - } - var t uint32 - n := uint32(len(buf)) - for { - err = syscall.RegQueryValueEx(syscall.Handle(k), p, nil, &t, (*byte)(unsafe.Pointer(&buf[0])), &n) - if err == nil { - return buf[:n], t, nil - } - if err != syscall.ERROR_MORE_DATA { - return nil, 0, err - } - if n <= uint32(len(buf)) { - return nil, 0, err - } - buf = make([]byte, n) - } -} - -// GetStringValue retrieves the string value for the specified -// value name associated with an open key k. It also returns the value's type. -// If value does not exist, GetStringValue returns ErrNotExist. -// If value is not SZ or EXPAND_SZ, it will return the correct value -// type and ErrUnexpectedType. -func (k Key) GetStringValue(name string) (val string, valtype uint32, err error) { - data, typ, err2 := k.getValue(name, make([]byte, 64)) - if err2 != nil { - return "", typ, err2 - } - switch typ { - case SZ, EXPAND_SZ: - default: - return "", typ, ErrUnexpectedType - } - if len(data) == 0 { - return "", typ, nil - } - u := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:] - return syscall.UTF16ToString(u), typ, nil -} - -// GetMUIStringValue retrieves the localized string value for -// the specified value name associated with an open key k. -// If the value name doesn't exist or the localized string value -// can't be resolved, GetMUIStringValue returns ErrNotExist. -// GetMUIStringValue panics if the system doesn't support -// regLoadMUIString; use LoadRegLoadMUIString to check if -// regLoadMUIString is supported before calling this function. -func (k Key) GetMUIStringValue(name string) (string, error) { - pname, err := syscall.UTF16PtrFromString(name) - if err != nil { - return "", err - } - - buf := make([]uint16, 1024) - var buflen uint32 - var pdir *uint16 - - err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir) - if err == syscall.ERROR_FILE_NOT_FOUND { // Try fallback path - - // Try to resolve the string value using the system directory as - // a DLL search path; this assumes the string value is of the form - // @[path]\dllname,-strID but with no path given, e.g. @tzres.dll,-320. - - // This approach works with tzres.dll but may have to be revised - // in the future to allow callers to provide custom search paths. - - var s string - s, err = ExpandString("%SystemRoot%\\system32\\") - if err != nil { - return "", err - } - pdir, err = syscall.UTF16PtrFromString(s) - if err != nil { - return "", err - } - - err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir) - } - - for err == syscall.ERROR_MORE_DATA { // Grow buffer if needed - if buflen <= uint32(len(buf)) { - break // Buffer not growing, assume race; break - } - buf = make([]uint16, buflen) - err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir) - } - - if err != nil { - return "", err - } - - return syscall.UTF16ToString(buf), nil -} - -// ExpandString expands environment-variable strings and replaces -// them with the values defined for the current user. -// Use ExpandString to expand EXPAND_SZ strings. -func ExpandString(value string) (string, error) { - if value == "" { - return "", nil - } - p, err := syscall.UTF16PtrFromString(value) - if err != nil { - return "", err - } - r := make([]uint16, 100) - for { - n, err := expandEnvironmentStrings(p, &r[0], uint32(len(r))) - if err != nil { - return "", err - } - if n <= uint32(len(r)) { - u := (*[1 << 29]uint16)(unsafe.Pointer(&r[0]))[:] - return syscall.UTF16ToString(u), nil - } - r = make([]uint16, n) - } -} - -// GetStringsValue retrieves the []string value for the specified -// value name associated with an open key k. It also returns the value's type. -// If value does not exist, GetStringsValue returns ErrNotExist. -// If value is not MULTI_SZ, it will return the correct value -// type and ErrUnexpectedType. -func (k Key) GetStringsValue(name string) (val []string, valtype uint32, err error) { - data, typ, err2 := k.getValue(name, make([]byte, 64)) - if err2 != nil { - return nil, typ, err2 - } - if typ != MULTI_SZ { - return nil, typ, ErrUnexpectedType - } - if len(data) == 0 { - return nil, typ, nil - } - p := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:len(data)/2] - if len(p) == 0 { - return nil, typ, nil - } - if p[len(p)-1] == 0 { - p = p[:len(p)-1] // remove terminating null - } - val = make([]string, 0, 5) - from := 0 - for i, c := range p { - if c == 0 { - val = append(val, string(utf16.Decode(p[from:i]))) - from = i + 1 - } - } - return val, typ, nil -} - -// GetIntegerValue retrieves the integer value for the specified -// value name associated with an open key k. It also returns the value's type. -// If value does not exist, GetIntegerValue returns ErrNotExist. -// If value is not DWORD or QWORD, it will return the correct value -// type and ErrUnexpectedType. -func (k Key) GetIntegerValue(name string) (val uint64, valtype uint32, err error) { - data, typ, err2 := k.getValue(name, make([]byte, 8)) - if err2 != nil { - return 0, typ, err2 - } - switch typ { - case DWORD: - if len(data) != 4 { - return 0, typ, errors.New("DWORD value is not 4 bytes long") - } - return uint64(*(*uint32)(unsafe.Pointer(&data[0]))), DWORD, nil - case QWORD: - if len(data) != 8 { - return 0, typ, errors.New("QWORD value is not 8 bytes long") - } - return uint64(*(*uint64)(unsafe.Pointer(&data[0]))), QWORD, nil - default: - return 0, typ, ErrUnexpectedType - } -} - -// GetBinaryValue retrieves the binary value for the specified -// value name associated with an open key k. It also returns the value's type. -// If value does not exist, GetBinaryValue returns ErrNotExist. -// If value is not BINARY, it will return the correct value -// type and ErrUnexpectedType. -func (k Key) GetBinaryValue(name string) (val []byte, valtype uint32, err error) { - data, typ, err2 := k.getValue(name, make([]byte, 64)) - if err2 != nil { - return nil, typ, err2 - } - if typ != BINARY { - return nil, typ, ErrUnexpectedType - } - return data, typ, nil -} - -func (k Key) setValue(name string, valtype uint32, data []byte) error { - p, err := syscall.UTF16PtrFromString(name) - if err != nil { - return err - } - if len(data) == 0 { - return regSetValueEx(syscall.Handle(k), p, 0, valtype, nil, 0) - } - return regSetValueEx(syscall.Handle(k), p, 0, valtype, &data[0], uint32(len(data))) -} - -// SetDWordValue sets the data and type of a name value -// under key k to value and DWORD. -func (k Key) SetDWordValue(name string, value uint32) error { - return k.setValue(name, DWORD, (*[4]byte)(unsafe.Pointer(&value))[:]) -} - -// SetQWordValue sets the data and type of a name value -// under key k to value and QWORD. -func (k Key) SetQWordValue(name string, value uint64) error { - return k.setValue(name, QWORD, (*[8]byte)(unsafe.Pointer(&value))[:]) -} - -func (k Key) setStringValue(name string, valtype uint32, value string) error { - v, err := syscall.UTF16FromString(value) - if err != nil { - return err - } - buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2] - return k.setValue(name, valtype, buf) -} - -// SetStringValue sets the data and type of a name value -// under key k to value and SZ. The value must not contain a zero byte. -func (k Key) SetStringValue(name, value string) error { - return k.setStringValue(name, SZ, value) -} - -// SetExpandStringValue sets the data and type of a name value -// under key k to value and EXPAND_SZ. The value must not contain a zero byte. -func (k Key) SetExpandStringValue(name, value string) error { - return k.setStringValue(name, EXPAND_SZ, value) -} - -// SetStringsValue sets the data and type of a name value -// under key k to value and MULTI_SZ. The value strings -// must not contain a zero byte. -func (k Key) SetStringsValue(name string, value []string) error { - ss := "" - for _, s := range value { - for i := 0; i < len(s); i++ { - if s[i] == 0 { - return errors.New("string cannot have 0 inside") - } - } - ss += s + "\x00" - } - v := utf16.Encode([]rune(ss + "\x00")) - buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2] - return k.setValue(name, MULTI_SZ, buf) -} - -// SetBinaryValue sets the data and type of a name value -// under key k to value and BINARY. -func (k Key) SetBinaryValue(name string, value []byte) error { - return k.setValue(name, BINARY, value) -} - -// DeleteValue removes a named value from the key k. -func (k Key) DeleteValue(name string) error { - return regDeleteValue(syscall.Handle(k), syscall.StringToUTF16Ptr(name)) -} - -// ReadValueNames returns the value names of key k. -// The parameter n controls the number of returned names, -// analogous to the way os.File.Readdirnames works. -func (k Key) ReadValueNames(n int) ([]string, error) { - ki, err := k.Stat() - if err != nil { - return nil, err - } - names := make([]string, 0, ki.ValueCount) - buf := make([]uint16, ki.MaxValueNameLen+1) // extra room for terminating null character -loopItems: - for i := uint32(0); ; i++ { - if n > 0 { - if len(names) == n { - return names, nil - } - } - l := uint32(len(buf)) - for { - err := regEnumValue(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil) - if err == nil { - break - } - if err == syscall.ERROR_MORE_DATA { - // Double buffer size and try again. - l = uint32(2 * len(buf)) - buf = make([]uint16, l) - continue - } - if err == _ERROR_NO_MORE_ITEMS { - break loopItems - } - return names, err - } - names = append(names, syscall.UTF16ToString(buf[:l])) - } - if n > len(names) { - return names, io.EOF - } - return names, nil -} diff --git a/internal/syscall/windows/registry/zsyscall_windows.go b/internal/syscall/windows/registry/zsyscall_windows.go deleted file mode 100644 index 04f54d55..00000000 --- a/internal/syscall/windows/registry/zsyscall_windows.go +++ /dev/null @@ -1,111 +0,0 @@ -// Code generated by 'go generate'; DO NOT EDIT. - -package registry - -import ( - "syscall" - "unsafe" - - "fortio.org/testscript/internal/syscall/windows/sysdll" -) - -var _ unsafe.Pointer - -// Do the interface allocations only once for common -// Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - -var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) -) - -// errnoErr returns common boxed Errno values, to prevent -// allocations at runtime. -func errnoErr(e syscall.Errno) error { - switch e { - case 0: - return nil - case errnoERROR_IO_PENDING: - return errERROR_IO_PENDING - } - // TODO: add more here, after collecting data on the common - // error values see on Windows. (perhaps when running - // all.bat?) - return e -} - -var ( - modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll")) - modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll")) - - procRegCreateKeyExW = modadvapi32.NewProc("RegCreateKeyExW") - procRegDeleteKeyW = modadvapi32.NewProc("RegDeleteKeyW") - procRegSetValueExW = modadvapi32.NewProc("RegSetValueExW") - procRegEnumValueW = modadvapi32.NewProc("RegEnumValueW") - procRegDeleteValueW = modadvapi32.NewProc("RegDeleteValueW") - procRegLoadMUIStringW = modadvapi32.NewProc("RegLoadMUIStringW") - procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW") -) - -func regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) { - r0, _, _ := syscall.Syscall9(procRegCreateKeyExW.Addr(), 9, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(reserved), uintptr(unsafe.Pointer(class)), uintptr(options), uintptr(desired), uintptr(unsafe.Pointer(sa)), uintptr(unsafe.Pointer(result)), uintptr(unsafe.Pointer(disposition))) - if r0 != 0 { - regerrno = syscall.Errno(r0) - } - return -} - -func regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) { - r0, _, _ := syscall.Syscall(procRegDeleteKeyW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(subkey)), 0) - if r0 != 0 { - regerrno = syscall.Errno(r0) - } - return -} - -func regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) { - r0, _, _ := syscall.Syscall6(procRegSetValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(valueName)), uintptr(reserved), uintptr(vtype), uintptr(unsafe.Pointer(buf)), uintptr(bufsize)) - if r0 != 0 { - regerrno = syscall.Errno(r0) - } - return -} - -func regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) { - r0, _, _ := syscall.Syscall9(procRegEnumValueW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen)), 0) - if r0 != 0 { - regerrno = syscall.Errno(r0) - } - return -} - -func regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) { - r0, _, _ := syscall.Syscall(procRegDeleteValueW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(name)), 0) - if r0 != 0 { - regerrno = syscall.Errno(r0) - } - return -} - -func regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) { - r0, _, _ := syscall.Syscall9(procRegLoadMUIStringW.Addr(), 7, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(unsafe.Pointer(buflenCopied)), uintptr(flags), uintptr(unsafe.Pointer(dir)), 0, 0) - if r0 != 0 { - regerrno = syscall.Errno(r0) - } - return -} - -func expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) { - r0, _, e1 := syscall.Syscall(procExpandEnvironmentStringsW.Addr(), 3, uintptr(unsafe.Pointer(src)), uintptr(unsafe.Pointer(dst)), uintptr(size)) - n = uint32(r0) - if n == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} diff --git a/internal/textutil/diff.go b/internal/textutil/diff.go deleted file mode 100644 index 59f9e01a..00000000 --- a/internal/textutil/diff.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package textutil - -import ( - "fmt" - "strings" -) - -// Diff returns a formatted diff of the two texts, -// showing the entire text and the minimum line-level -// additions and removals to turn text1 into text2. -// (That is, lines only in text1 appear with a leading -, -// and lines only in text2 appear with a leading +.) -func Diff(text1, text2 string) string { - if text1 != "" && !strings.HasSuffix(text1, "\n") { - text1 += "(missing final newline)" - } - lines1 := strings.Split(text1, "\n") - lines1 = lines1[:len(lines1)-1] // remove empty string after final line - if text2 != "" && !strings.HasSuffix(text2, "\n") { - text2 += "(missing final newline)" - } - lines2 := strings.Split(text2, "\n") - lines2 = lines2[:len(lines2)-1] // remove empty string after final line - - // Naive dynamic programming algorithm for edit distance. - // https://en.wikipedia.org/wiki/Wagner–Fischer_algorithm - // dist[i][j] = edit distance between lines1[:len(lines1)-i] and lines2[:len(lines2)-j] - // (The reversed indices make following the minimum cost path - // visit lines in the same order as in the text.) - dist := make([][]int, len(lines1)+1) - for i := range dist { - dist[i] = make([]int, len(lines2)+1) - if i == 0 { - for j := range dist[0] { - dist[0][j] = j - } - continue - } - for j := range dist[i] { - if j == 0 { - dist[i][0] = i - continue - } - cost := dist[i][j-1] + 1 - if cost > dist[i-1][j]+1 { - cost = dist[i-1][j] + 1 - } - if lines1[len(lines1)-i] == lines2[len(lines2)-j] { - if cost > dist[i-1][j-1] { - cost = dist[i-1][j-1] - } - } - dist[i][j] = cost - } - } - - var buf strings.Builder - i, j := len(lines1), len(lines2) - for i > 0 || j > 0 { - cost := dist[i][j] - if i > 0 && j > 0 && cost == dist[i-1][j-1] && lines1[len(lines1)-i] == lines2[len(lines2)-j] { - fmt.Fprintf(&buf, " %s\n", lines1[len(lines1)-i]) - i-- - j-- - } else if i > 0 && cost == dist[i-1][j]+1 { - fmt.Fprintf(&buf, "-%s\n", lines1[len(lines1)-i]) - i-- - } else { - fmt.Fprintf(&buf, "+%s\n", lines2[len(lines2)-j]) - j-- - } - } - return buf.String() -} diff --git a/internal/textutil/diff_test.go b/internal/textutil/diff_test.go deleted file mode 100644 index 4d61f8fe..00000000 --- a/internal/textutil/diff_test.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package textutil_test - -import ( - "strings" - "testing" - - "fortio.org/testscript/internal/textutil" -) - -var diffTests = []struct { - text1 string - text2 string - diff string -}{ - {"a b c", "a b d e f", "a b -c +d +e +f"}, - {"", "a b c", "+a +b +c"}, - {"a b c", "", "-a -b -c"}, - {"a b c", "d e f", "-a -b -c +d +e +f"}, - {"a b c d e f", "a b d e f", "a b -c d e f"}, - {"a b c e f", "a b c d e f", "a b c +d e f"}, -} - -func TestDiff(t *testing.T) { - for _, tt := range diffTests { - // Turn spaces into \n. - text1 := strings.Replace(tt.text1, " ", "\n", -1) - if text1 != "" { - text1 += "\n" - } - text2 := strings.Replace(tt.text2, " ", "\n", -1) - if text2 != "" { - text2 += "\n" - } - out := textutil.Diff(text1, text2) - // Cut final \n, cut spaces, turn remaining \n into spaces. - out = strings.Replace(strings.Replace(strings.TrimSuffix(out, "\n"), " ", "", -1), "\n", " ", -1) - if out != tt.diff { - t.Errorf("diff(%q, %q) = %q, want %q", text1, text2, out, tt.diff) - } - } -} diff --git a/internal/textutil/doc.go b/internal/textutil/doc.go deleted file mode 100644 index f4a041a7..00000000 --- a/internal/textutil/doc.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// package textutil contains text processing utilities. -// -// This package came to life as a result of refactoring code common to -// internal packages we have factored out of the Go repo. -package textutil