github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/cmd/ref_select.go (about)

     1  package cmd
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/qri-io/qri/dsref"
     7  	"github.com/qri-io/qri/repo"
     8  )
     9  
    10  // RefSelect represents zero or more references
    11  type RefSelect struct {
    12  	refs []string
    13  }
    14  
    15  // NewEmptyRefSelect returns an empty reference selection
    16  func NewEmptyRefSelect() *RefSelect {
    17  	return &RefSelect{refs: []string{}}
    18  }
    19  
    20  // NewRefSelect returns a single explicitly provided reference
    21  func NewRefSelect(ref string) *RefSelect {
    22  	return &RefSelect{refs: []string{ref}}
    23  }
    24  
    25  // NewListOfRefSelects returns a list of explicitly provided references
    26  func NewListOfRefSelects(refs []string) *RefSelect {
    27  	return &RefSelect{refs: refs}
    28  }
    29  
    30  // Ref returns the reference as a string
    31  func (r *RefSelect) Ref() string {
    32  	if r == nil || len(r.refs) == 0 {
    33  		return ""
    34  	}
    35  	return r.refs[0]
    36  }
    37  
    38  // RefList returns a list of all references
    39  func (r *RefSelect) RefList() []string {
    40  	if r == nil {
    41  		return []string{""}
    42  	}
    43  	return r.refs
    44  }
    45  
    46  const (
    47  	// AnyNumberOfReferences is for commands that can work on any number of dataset references
    48  	AnyNumberOfReferences = -1
    49  
    50  	// BadUpperCaseOkayWhenSavingExistingDataset is for the save command, which can have bad
    51  	// upper-case characters in its reference but only if it already exists
    52  	BadUpperCaseOkayWhenSavingExistingDataset = -2
    53  )
    54  
    55  // GetCurrentRefSelect returns the current reference selection. This could be explicitly provided
    56  // as command-line arguments, or could be determined by being in a linked directory, or could be
    57  // selected by the `use` command. This order is also the precedence, from most important to least.
    58  // This is the recommended method for command-line commands to get references.
    59  // If an Ensurer is passed in, it is used to ensure that the ref in the .qri-ref linkfile matches
    60  // what is in the repo.
    61  func GetCurrentRefSelect(f Factory, args []string, allowed int) (*RefSelect, error) {
    62  	// If reference is specified by the user provide command-line arguments, use that reference.
    63  	if len(args) > 0 {
    64  		// If bad upper-case characters are allowed, skip checking for them
    65  		if allowed == BadUpperCaseOkayWhenSavingExistingDataset {
    66  			// Bad upper-case characters are ignored, references will be checked again inside lib.
    67  			allowed = 1
    68  		} else {
    69  			// For each argument, make sure it's a valid and not using upper-case chracters.
    70  			for _, refstr := range args {
    71  				_, err := dsref.Parse(refstr)
    72  				if err == dsref.ErrBadCaseName {
    73  					// TODO(dustmop): For now, this is just a warning but not a fatal error.
    74  					// In the near future, change to: `return nil, dsref.ErrBadCaseShouldRename`
    75  					// The test `TestBadCaseIsJustWarning` in cmd/cmd_test.go verifies that this
    76  					// is not a fatal error.
    77  					// TODO(dustmop): Change to a fatal error after qri 0.9.9 releases.
    78  					log.Error(dsref.ErrBadCaseShouldRename)
    79  				}
    80  			}
    81  		}
    82  		if allowed == AnyNumberOfReferences {
    83  			return NewListOfRefSelects(args), nil
    84  		}
    85  		if len(args) > allowed {
    86  			return nil, fmt.Errorf("%d references allowed but %d were given", allowed, len(args))
    87  		}
    88  		if allowed == 1 {
    89  			return NewRefSelect(args[0]), nil
    90  		}
    91  		return NewListOfRefSelects(args), nil
    92  	}
    93  
    94  	// Empty refselect
    95  	return NewEmptyRefSelect(), repo.ErrEmptyRef
    96  }