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

     1  package component
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/qri-io/dataset"
     8  	"github.com/qri-io/qfs"
     9  )
    10  
    11  // Component represents one of two things, either a single component (meta, body), or a collection
    12  // of components, such as an entire dataset or a directory of files that encode components.
    13  type Component interface {
    14  	Base() *BaseComponent
    15  	Compare(Component) (bool, error)
    16  	WriteTo(dirPath string) (targetFile string, err error)
    17  	RemoveFrom(dirPath string) error
    18  	DropDerivedValues()
    19  	LoadAndFill(*dataset.Dataset) error
    20  	StructuredData() (interface{}, error)
    21  }
    22  
    23  // NumberPossibleComponents is the number of subcomponents plus "dataset".
    24  const NumberPossibleComponents = 8
    25  
    26  // AllSubcomponentNames is the names of subcomponents that can live on a collection.
    27  func AllSubcomponentNames() []string {
    28  	return []string{"commit", "meta", "structure", "readme", "viz", "transform", "body"}
    29  }
    30  
    31  // ConvertDatasetToComponents will convert a dataset to a component collection
    32  func ConvertDatasetToComponents(ds *dataset.Dataset, qfilesys qfs.Filesystem) Component {
    33  	dc := DatasetComponent{}
    34  	dc.Value = ds
    35  	dc.Subcomponents = make(map[string]Component)
    36  
    37  	dc.Subcomponents["dataset"] = &dc
    38  	if ds.Meta != nil {
    39  		mc := MetaComponent{}
    40  		mc.Value = ds.Meta
    41  		dc.Subcomponents["meta"] = &mc
    42  	}
    43  	if ds.Structure != nil {
    44  		sc := StructureComponent{}
    45  		sc.Value = ds.Structure
    46  		dc.Subcomponents["structure"] = &sc
    47  	}
    48  	if ds.Commit != nil {
    49  		cc := CommitComponent{}
    50  		cc.Value = ds.Commit
    51  		dc.Subcomponents["commit"] = &cc
    52  	}
    53  	if ds.Readme != nil {
    54  		rc := ReadmeComponent{Resolver: qfilesys}
    55  		rc.Value = ds.Readme
    56  		rc.Format = "md"
    57  		dc.Subcomponents["readme"] = &rc
    58  	}
    59  	if ds.Transform != nil {
    60  		dc.Subcomponents["transform"] = &TransformComponent{
    61  			BaseComponent: BaseComponent{Format: "star"},
    62  			Resolver:      qfilesys,
    63  			Value:         ds.Transform,
    64  		}
    65  	}
    66  
    67  	if ds.Body != nil {
    68  		bc := BodyComponent{Resolver: qfilesys}
    69  		bc.Value = ds.Body
    70  		bc.BodyFile = ds.BodyFile()
    71  		bc.Structure = ds.Structure
    72  		if ds.Structure != nil {
    73  			bc.Format = ds.Structure.Format
    74  		}
    75  		dc.Subcomponents["body"] = &bc
    76  	} else if ds.BodyPath != "" {
    77  		bc := BodyComponent{Resolver: qfilesys}
    78  		bc.SourceFile = ds.BodyPath
    79  		bc.BodyFile = ds.BodyFile()
    80  		bc.Structure = ds.Structure
    81  		if ds.Structure != nil {
    82  			bc.Format = ds.Structure.Format
    83  		}
    84  		dc.Subcomponents["body"] = &bc
    85  	}
    86  
    87  	return &dc
    88  }
    89  
    90  // ToDataset converts a component to a dataset. Should only be used on a
    91  // component representing an entire dataset.
    92  func ToDataset(comp Component) (*dataset.Dataset, error) {
    93  	dsComp := comp.Base().GetSubcomponent("dataset")
    94  	if dsComp == nil {
    95  		comp := DatasetComponent{}
    96  		comp.Value = &dataset.Dataset{}
    97  		dsComp = &comp
    98  	}
    99  	dsCont, ok := dsComp.(*DatasetComponent)
   100  	if !ok {
   101  		return nil, fmt.Errorf("could not cast component to a Dataset")
   102  	}
   103  	ds := dsCont.Value
   104  	if mdComponent := comp.Base().GetSubcomponent("meta"); mdComponent != nil {
   105  		if err := mdComponent.LoadAndFill(ds); err != nil {
   106  			return nil, err
   107  		}
   108  	}
   109  	if cmComponent := comp.Base().GetSubcomponent("commit"); cmComponent != nil {
   110  		if err := cmComponent.LoadAndFill(ds); err != nil {
   111  			return nil, err
   112  		}
   113  	}
   114  	if stComponent := comp.Base().GetSubcomponent("structure"); stComponent != nil {
   115  		if err := stComponent.LoadAndFill(ds); err != nil {
   116  			return nil, err
   117  		}
   118  	}
   119  	if rmComponent := comp.Base().GetSubcomponent("readme"); rmComponent != nil {
   120  		if err := rmComponent.LoadAndFill(ds); err != nil {
   121  			return nil, err
   122  		}
   123  	}
   124  	if tfComponent := comp.Base().GetSubcomponent("transform"); tfComponent != nil {
   125  		if err := tfComponent.LoadAndFill(ds); err != nil {
   126  			return nil, err
   127  		}
   128  	}
   129  	if bdComponent := comp.Base().GetSubcomponent("body"); bdComponent != nil {
   130  		if !bdComponent.Base().IsLoaded {
   131  			ds.BodyPath = bdComponent.Base().SourceFile
   132  		}
   133  	}
   134  	return ds, nil
   135  }
   136  
   137  // BaseComponent is the data elements common to any component
   138  type BaseComponent struct {
   139  	Subcomponents  map[string]Component
   140  	ProblemKind    string
   141  	ProblemMessage string
   142  	// File information:
   143  	ModTime    time.Time
   144  	SourceFile string
   145  	IsLoaded   bool
   146  	Format     string
   147  }