-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for bulk operations (#42)
* Add support for bulk operations * Fix mktemp * Fixup tests * Fix dirty working dir check * Add missing file (for dirty working dir check) * Fix dirty working dir check * Update readme with bulk docs
- Loading branch information
Showing
38 changed files
with
6,848 additions
and
299 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,4 +26,3 @@ moq_*_dst.txt | |
# other | ||
.envrc | ||
/.idea | ||
/.go |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// Package bulk is used to generate several Moqueries mocks at once | ||
package bulk | ||
|
||
import ( | ||
"io" | ||
"os" | ||
|
||
"github.com/myshkin5/moqueries/bulk/internal" | ||
"github.com/myshkin5/moqueries/generator" | ||
) | ||
|
||
// Initialize initializes bulk processing and creates the bulk processing state | ||
// file | ||
func Initialize(stateFile, rootDir string) error { | ||
createFn := func(name string) (io.WriteCloser, error) { | ||
//nolint:gosec // Users can use any file for bulk operations | ||
return os.Create(name) | ||
} | ||
|
||
return internal.Initialize(stateFile, rootDir, createFn) | ||
} | ||
|
||
// Append appends a mock generate request to the bulk state | ||
func Append(stateFile string, request generator.GenerateRequest) error { | ||
openFileFn := func(name string, flag int, perm os.FileMode) (internal.ReadWriteSeekCloser, error) { | ||
//nolint:gosec // Users can use any file for bulk operations | ||
return os.OpenFile(name, flag, perm) | ||
} | ||
|
||
return internal.Append(stateFile, request, openFileFn) | ||
} | ||
|
||
// Finalize complete bulk processing by generating all the requested mocks | ||
func Finalize(stateFile, rootDir string) error { | ||
openFn := func(name string) (io.ReadCloser, error) { | ||
//nolint:gosec // Users can use any file for bulk operations | ||
return os.Open(name) | ||
} | ||
|
||
return internal.Finalize(stateFile, rootDir, openFn, generator.Generate) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
package internal | ||
|
||
import ( | ||
"bufio" | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"go/build" | ||
"io" | ||
"os" | ||
"path" | ||
"path/filepath" | ||
"strings" | ||
|
||
"github.com/myshkin5/moqueries/generator" | ||
"github.com/myshkin5/moqueries/logs" | ||
) | ||
|
||
var ( | ||
// ErrBadAppendRequest is returned when a caller passes bad parameters to | ||
// Append | ||
ErrBadAppendRequest = errors.New("bad request") | ||
// ErrBulkState is returned when the bulk state is invalid | ||
ErrBulkState = errors.New("bulk state error") | ||
) | ||
|
||
//go:generate moqueries OpenFileFn | ||
|
||
// OpenFileFn is the function type of os.OpenFile | ||
type OpenFileFn func(name string, flag int, perm os.FileMode) (ReadWriteSeekCloser, error) | ||
|
||
//go:generate moqueries ReadWriteSeekCloser | ||
|
||
// ReadWriteSeekCloser is the interface that groups the basic Read, Write, | ||
// Seek and Close methods. | ||
type ReadWriteSeekCloser interface { | ||
io.Reader | ||
io.Writer | ||
io.Seeker | ||
io.Closer | ||
} | ||
|
||
// Append appends a mock generate request to the bulk state | ||
func Append(stateFile string, req generator.GenerateRequest, openFileFn OpenFileFn) error { | ||
if !path.IsAbs(req.WorkingDir) { | ||
return fmt.Errorf("%w: the request working directory must be absolute: %s", | ||
ErrBadAppendRequest, req.WorkingDir) | ||
} | ||
|
||
f, err := openFileFn(stateFile, os.O_RDWR|os.O_APPEND, 0) | ||
if err != nil { | ||
return fmt.Errorf("error opening state file: %w", err) | ||
} | ||
defer func() { | ||
err := f.Close() | ||
if err != nil { | ||
logs.Error("error closing state file", err) | ||
} | ||
}() | ||
|
||
_, err = verifyState(f, stateFile, req.WorkingDir, false) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = appendRequest(f, stateFile, req) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func verifyState(f io.ReadCloser, stateFile, workingDir string, rootDirOnly bool) (*bufio.Scanner, error) { | ||
scanner := bufio.NewScanner(f) | ||
if !scanner.Scan() { | ||
return nil, fmt.Errorf("%w: state file %s not initialized properly", | ||
ErrBulkState, stateFile) | ||
} | ||
|
||
txt := scanner.Text() | ||
err := scanner.Err() | ||
if err != nil { | ||
return nil, fmt.Errorf("error reading state file %s: %w", stateFile, err) | ||
} | ||
|
||
var state initialState | ||
err = json.Unmarshal([]byte(txt), &state) | ||
if err != nil { | ||
return nil, fmt.Errorf("error unmarshalling state file %s: %w", stateFile, err) | ||
} | ||
|
||
if state.GoPath != build.Default.GOPATH { | ||
return nil, fmt.Errorf("%w: current GOPATH doesn't match GOPATH from state file %s (%s != %s)", | ||
ErrBulkState, stateFile, build.Default.GOPATH, state.GoPath) | ||
} | ||
|
||
if rootDirOnly { | ||
if state.RootDir != workingDir { | ||
return nil, fmt.Errorf("%w: finalize root directory %s does"+ | ||
" not match root directory %s from state file %s", | ||
ErrBulkState, workingDir, state.RootDir, stateFile) | ||
} | ||
} else { | ||
rel, err := filepath.Rel(state.RootDir, workingDir) | ||
if err != nil { | ||
logs.Panicf("error getting relative path %s from %s: %#v", | ||
state.RootDir, workingDir, err) | ||
} | ||
|
||
if strings.HasPrefix(rel, "..") { | ||
return nil, fmt.Errorf("%w: working directory %s is not a"+ | ||
" child of root directory %s from state file %s", | ||
ErrBulkState, workingDir, state.RootDir, stateFile) | ||
} | ||
} | ||
|
||
return scanner, nil | ||
} | ||
|
||
func appendRequest(f ReadWriteSeekCloser, stateFile string, req generator.GenerateRequest) error { | ||
_, err := f.Seek(0, io.SeekEnd) | ||
if err != nil { | ||
return fmt.Errorf("error seeking end of state file %s: %w", stateFile, err) | ||
} | ||
_, err = f.Write(compact(req)) | ||
if err != nil { | ||
return fmt.Errorf("error writing state file %s: %w", stateFile, err) | ||
} | ||
_, err = f.Write([]byte("\n")) | ||
if err != nil { | ||
return fmt.Errorf("error finishing writing of state file %s: %w", stateFile, err) | ||
} | ||
return nil | ||
} |
Oops, something went wrong.