Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TOOLS-2667: Support list of files for put and get subcommands in mongofiles #283

Merged
merged 26 commits into from Jul 31, 2020
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
31f5118
Implemented new --put and --get subcommands and modified existing tests
Jul 22, 2020
cd3f1a7
Formatting with go fmt and golangci-lint
Jul 22, 2020
58ead50
Create tests for new mongofiles --get and mongofiles --put implementa…
Jul 23, 2020
e47421e
Linting changes
Jul 23, 2020
bd616f1
Change new test name
Jul 23, 2020
29cd9fa
Merge branch 'master' of https://github.com/mongodb/mongo-tools into …
Jul 23, 2020
20597d6
Remove tests for old --get and --put functionality -- no longer needed
Jul 23, 2020
93b2722
Fix formatting for lint-go task
Jul 23, 2020
40d33a2
go fmt -s ...
Jul 23, 2020
7e4b968
Parametrize (*MongoFiles).handlePut(...) and separate cases for --put
Jul 23, 2020
accdd4b
Code review changes to mongofiles.go
Jul 27, 2020
29c026f
Code review changes to options_test.go
Jul 27, 2020
2e8bc4e
Revert "Remove tests for old --get and --put functionality -- no long…
Jul 27, 2020
c9b9a90
Change comments to show that `put` and `get` are subcommands, not opt…
Jul 27, 2020
b7380a3
Change test structure to check (*MongoFiles).FileNameList as well as …
Jul 27, 2020
55a7352
Add new test files for polyadic mongofiles put
Jul 28, 2020
e5da67f
Test harness for new lorem ipsum files
Jul 28, 2020
3deadb4
Make sure that files not included in the query are not copied in `get`
Jul 28, 2020
893a590
Rename local variable so that it doesn't shadow global variable
Jul 28, 2020
ff10ff1
Move check for unincluded test file to parent Convey block
Jul 28, 2020
d8699dd
Check that only the required test files are in GridFS
Jul 28, 2020
c9805ec
Remove unnecessary error check
Jul 29, 2020
e007c29
Reconcile symmetry between handleGet and handlePut
Jul 29, 2020
615dac2
Revert "Reconcile symmetry between handleGet and handlePut"
Jul 29, 2020
be873f0
Reconcile handleGet abstraction with handlePut
Jul 29, 2020
49f6913
Fix help message
Jul 30, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
109 changes: 74 additions & 35 deletions mongofiles/mongofiles.go
Expand Up @@ -61,6 +61,10 @@ type MongoFiles struct {
// ID to put into GridFS
Id string

// List of filenames for use as supporting
// arguments in put and get commands
FileNameList []string

// GridFS bucket to operate on
bucket *gridfs.Bucket
}
Expand Down Expand Up @@ -111,7 +115,15 @@ func (mf *MongoFiles) ValidateCommand(args []string) error {
} else {
mf.FileName = args[1]
}
case Search, Put, Get, Delete:
case Put, Get:
// monogofiles put ... and mongofiles get ... should work
// over a list of files, i.e. by using mf.FileNameList
if len(args) == 1 || args[1] == "" {
return fmt.Errorf("'%v' argument missing", args[0])
}

mf.FileNameList = args[1:]
case Search, Delete:
if len(args) > 2 {
return fmt.Errorf("too many non-URI positional arguments (If you are trying to specify a connection string, it must begin with mongodb:// or mongodb+srv://)")
}
Expand Down Expand Up @@ -182,16 +194,18 @@ func (mf *MongoFiles) getLocalFileName(gridFile *gfsFile) string {

// handleGet contains the logic for the 'get' and 'get_id' commands
func (mf *MongoFiles) handleGet() (err error) {
file, err := mf.getTargetGFSFile()
files, err := mf.getTargetGFSFiles()
if err != nil {
return err
}

if err = mf.writeGFSFileToLocal(file); err != nil {
return err
for _, file := range files {
if err = mf.writeGFSFileToLocal(file); err != nil {
return err
}
}

return err
return nil
}

// Gets all GridFS files that match the given query.
Expand All @@ -216,40 +230,56 @@ func (mf *MongoFiles) findGFSFiles(query bson.M) (files []*gfsFile, err error) {
}

// Gets the GridFS file the options specify. Use this for the get family of commands.
func (mf *MongoFiles) getTargetGFSFile() (*gfsFile, error) {
func (mf *MongoFiles) getTargetGFSFiles() ([]*gfsFile, error) {
var gridFiles []*gfsFile
var err error

var queryProp string
var query string
// If mongofiles get ... is called, then query for all files
// specified in mf.FileNameList -- otherwise, preserve correct
// behavior for mongofiles get_id ...
if len(mf.FileNameList) > 0 {
query := bson.M{"filename": bson.M{"$in": mf.FileNameList}}
huan-Mongo marked this conversation as resolved.
Show resolved Hide resolved

if mf.Id != "" {
queryProp = "_id"
query = mf.Id

id, err := mf.parseOrCreateID()
gridFiles, err = mf.findGFSFiles(query)
if err != nil {
return nil, err
}
gridFiles, err = mf.findGFSFiles(bson.M{"_id": id})
if err != nil {
return nil, err

if len(gridFiles) < len(mf.FileNameList) {
return nil, fmt.Errorf("requested files not found: %v", mf.FileNameList)
}
} else {
queryProp = "name"
query = mf.FileName
var queryProp string
var query string

if mf.Id != "" {
queryProp = "_id"
query = mf.Id

id, err := mf.parseOrCreateID()
if err != nil {
return nil, err
}
gridFiles, err = mf.findGFSFiles(bson.M{"_id": id})
if err != nil {
return nil, err
}
} else {
queryProp = "name"
query = mf.FileName

gridFiles, err = mf.findGFSFiles(bson.M{"filename": mf.FileName})
if err != nil {
return nil, err
gridFiles, err = mf.findGFSFiles(bson.M{"filename": mf.FileName})
if err != nil {
return nil, err
}
}
}

if len(gridFiles) == 0 {
return nil, fmt.Errorf("no such file with %v: %v", queryProp, query)
if len(gridFiles) == 0 {
huan-Mongo marked this conversation as resolved.
Show resolved Hide resolved
return nil, fmt.Errorf("no such file with %v: %v", queryProp, query)
}
}

return gridFiles[0], nil
return gridFiles, err
}

// Delete all files with the given filename.
Expand All @@ -271,11 +301,12 @@ func (mf *MongoFiles) deleteAll(filename string) error {

// handleDeleteID contains the logic for the 'delete_id' command
func (mf *MongoFiles) handleDeleteID() error {
file, err := mf.getTargetGFSFile()
files, err := mf.getTargetGFSFiles()
if err != nil {
return err
}

file := files[0]
if err := file.Delete(); err != nil {
return err
}
Expand Down Expand Up @@ -389,18 +420,26 @@ func (mf *MongoFiles) put(id interface{}, name string) (bytesWritten int64, err

// handlePut contains the logic for the 'put' and 'put_id' commands
func (mf *MongoFiles) handlePut() error {
id, err := mf.parseOrCreateID()
if err != nil {
return err
if len(mf.FileNameList) == 0 {
mf.FileNameList = []string{mf.FileName}
}

n, err := mf.put(id, mf.FileName)
if err != nil {
return err
}
for _, filename := range mf.FileNameList {
id, err := mf.parseOrCreateID()
if err != nil {
return err
}

log.Logvf(log.Always, "adding gridFile: %v\n", filename)

log.Logvf(log.DebugLow, "copied %v bytes to server", n)
log.Logvf(log.Always, fmt.Sprintf("added gridFile: %v\n", mf.FileName))
n, err := mf.put(id, filename)
if err != nil {
log.Logvf(log.Always, "error adding gridFile: %v\n", err)
return err
}
log.Logvf(log.DebugLow, "copied %v bytes to server", n)
log.Logvf(log.Always, "added gridFile: %v\n", filename)
}

return nil
}
Expand Down