github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/env/actions/docs.go (about)

     1  // Copyright 2020 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package actions
    16  
    17  import (
    18  	"context"
    19  	"errors"
    20  
    21  	"github.com/dolthub/dolt/go/libraries/doltcore/doltdocs"
    22  
    23  	"github.com/dolthub/dolt/go/libraries/doltcore/diff"
    24  	"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
    25  	"github.com/dolthub/dolt/go/libraries/doltcore/env"
    26  )
    27  
    28  // SaveTrackedDocsFromWorking saves docs from the working root to the filesystem, and doesn't modify untracked docs.
    29  func SaveTrackedDocsFromWorking(ctx context.Context, dEnv *env.DoltEnv) error {
    30  	localDocs := dEnv.Docs
    31  	workingRoot, err := dEnv.WorkingRoot(ctx)
    32  	if err != nil {
    33  		return err
    34  	}
    35  
    36  	return SaveTrackedDocs(ctx, dEnv.DocsReadWriter(), workingRoot, workingRoot, localDocs)
    37  }
    38  
    39  // SaveDocsFromWorking saves docs from the working root to the filesystem, and could overwrite untracked docs.
    40  func SaveDocsFromWorking(ctx context.Context, dEnv *env.DoltEnv) error {
    41  	workingRoot, err := dEnv.WorkingRoot(ctx)
    42  	if err != nil {
    43  		return err
    44  	}
    45  
    46  	return SaveDocsFromRoot(ctx, workingRoot, dEnv)
    47  }
    48  
    49  // SaveDocsFromRoot saves docs from the root given to the filesystem, and could overwrite untracked docs.
    50  func SaveDocsFromRoot(ctx context.Context, root *doltdb.RootValue, dEnv *env.DoltEnv) error {
    51  	localDocs := dEnv.Docs
    52  	drw := dEnv.DocsReadWriter()
    53  
    54  	docs, err := doltdocs.GetDocsFromRoot(ctx, root, doltdocs.GetDocNamesFromDocs(doltdocs.SupportedDocs)...)
    55  	if err != nil {
    56  		return err
    57  	}
    58  
    59  	err = drw.WriteDocsToDisk(docs)
    60  	if err != nil {
    61  		// If we can't update docs on disk, attempt to revert the change
    62  		drw.WriteDocsToDisk(localDocs)
    63  		return err
    64  	}
    65  
    66  	return nil
    67  }
    68  
    69  // SaveTrackedDocs writes the docs from the targetRoot to the filesystem. The working root is used to identify untracked docs, which are left unchanged.
    70  func SaveTrackedDocs(ctx context.Context, drw env.DocsReadWriter, workRoot, targetRoot *doltdb.RootValue, localDocs doltdocs.Docs) error {
    71  	docDiffs, err := diff.NewDocDiffs(ctx, workRoot, nil, localDocs)
    72  	if err != nil {
    73  		return err
    74  	}
    75  
    76  	docs := removeUntrackedDocs(localDocs, docDiffs)
    77  
    78  	docs, err = doltdocs.GetDocsFromRoot(ctx, targetRoot, doltdocs.GetDocNamesFromDocs(docs)...)
    79  	if err != nil {
    80  		return err
    81  	}
    82  
    83  	err = drw.WriteDocsToDisk(docs)
    84  
    85  	if err != nil {
    86  		// If we can't update docs on disk, attempt to revert the change
    87  		_ = drw.WriteDocsToDisk(localDocs)
    88  		return err
    89  	}
    90  
    91  	return nil
    92  }
    93  
    94  func docIsUntracked(doc string, untracked []string) bool {
    95  	for _, val := range untracked {
    96  		if doc == val {
    97  			return true
    98  		}
    99  	}
   100  	return false
   101  }
   102  
   103  func removeUntrackedDocs(docs doltdocs.Docs, docDiffs *diff.DocDiffs) doltdocs.Docs {
   104  	result := doltdocs.Docs{}
   105  	untracked := getUntrackedDocs(docs, docDiffs)
   106  
   107  	for _, doc := range docs {
   108  		if !docIsUntracked(doc.DocPk, untracked) {
   109  			result = append(result, doc)
   110  		}
   111  	}
   112  	return result
   113  }
   114  
   115  func getUntrackedDocs(docs doltdocs.Docs, docDiffs *diff.DocDiffs) []string {
   116  	untracked := []string{}
   117  	for _, docName := range docDiffs.Docs {
   118  		dt := docDiffs.DocToType[docName]
   119  		if dt == diff.AddedDoc {
   120  			untracked = append(untracked, docName)
   121  		}
   122  	}
   123  
   124  	return untracked
   125  }
   126  
   127  func getUpdatedWorkingAndStagedWithDocs(ctx context.Context, working, staged, head *doltdb.RootValue, docs doltdocs.Docs) (currRoot, stgRoot *doltdb.RootValue, retDocs doltdocs.Docs, err error) {
   128  	root := head
   129  	_, ok, err := staged.GetTable(ctx, doltdb.DocTableName)
   130  	if err != nil {
   131  		return nil, nil, nil, err
   132  	} else if ok {
   133  		root = staged
   134  	}
   135  
   136  	docs, err = doltdocs.GetDocsFromRoot(ctx, root, doltdocs.GetDocNamesFromDocs(docs)...)
   137  	if err != nil {
   138  		return nil, nil, nil, err
   139  	}
   140  
   141  	currRoot, err = doltdocs.UpdateRootWithDocs(ctx, working, docs)
   142  	if err != nil {
   143  		return nil, nil, nil, err
   144  	}
   145  
   146  	stgRoot, err = doltdocs.UpdateRootWithDocs(ctx, staged, docs)
   147  	if err != nil {
   148  		return nil, nil, nil, err
   149  	}
   150  
   151  	return currRoot, stgRoot, docs, nil
   152  }
   153  
   154  // GetUnstagedDocs retrieves the unstaged docs (docs from the filesystem).
   155  func GetUnstagedDocs(ctx context.Context, dbData env.DbData) (doltdocs.Docs, error) {
   156  	_, unstagedDocDiffs, err := diff.GetDocDiffs(ctx, dbData.Ddb, dbData.Rsr, dbData.Drw)
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  	unstagedDocs := doltdocs.Docs{}
   161  	for _, docName := range unstagedDocDiffs.Docs {
   162  		docAr, err := dbData.Drw.GetDocsOnDisk(docName)
   163  		if err != nil {
   164  			return nil, err
   165  		}
   166  		if len(docAr) < 1 {
   167  			return nil, errors.New("error: Failed getting unstaged docs")
   168  		}
   169  
   170  		unstagedDocs = append(unstagedDocs, docAr[0])
   171  	}
   172  	return unstagedDocs, nil
   173  }
   174  
   175  // SaveDocsFromWorkingExcludingFSChanges saves docs from the working root to the filesystem, and does not overwrite changes to docs on the FS.
   176  // Intended to be called after checking that no conflicts exist (during a checkout or merge, i.e.).
   177  func SaveDocsFromWorkingExcludingFSChanges(ctx context.Context, dEnv *env.DoltEnv, docsToExclude doltdocs.Docs) error {
   178  	workingRoot, err := dEnv.WorkingRoot(ctx)
   179  	if err != nil {
   180  		return err
   181  	}
   182  
   183  	var docsToSave doltdocs.Docs
   184  	if len(docsToExclude) > 0 {
   185  		for _, doc := range dEnv.Docs {
   186  			for _, excludedDoc := range docsToExclude {
   187  				if doc.DocPk != excludedDoc.DocPk {
   188  					docsToSave = append(docsToSave, doc)
   189  				}
   190  			}
   191  		}
   192  	} else {
   193  		docsToSave = dEnv.Docs
   194  	}
   195  
   196  	return SaveTrackedDocs(ctx, dEnv.DocsReadWriter(), workingRoot, workingRoot, docsToSave)
   197  }
   198  
   199  // GetTablesOrDocs takes a slice of table or file names. Table names are returned as given. Supported doc names are
   200  // read from disk and their name replace with the names of the dolt_docs system table in the input slice. Supported docs
   201  // are returned in the second return param.
   202  func GetTablesOrDocs(drw env.DocsReadWriter, tablesOrFiles []string) (tables []string, docs doltdocs.Docs, err error) {
   203  	for i, tbl := range tablesOrFiles {
   204  		if _, ok := doltdocs.IsSupportedDoc(tbl); ok {
   205  			docAr, err := drw.GetDocsOnDisk(tbl)
   206  			if err != nil {
   207  				return nil, nil, err
   208  			}
   209  			if len(docAr) < 1 {
   210  				return nil, nil, errors.New("error: Failed getting docs")
   211  			}
   212  
   213  			doc := docAr[0]
   214  			if doc.DocPk == "" {
   215  				return nil, nil, errors.New("Supported doc not found on disk.")
   216  			}
   217  			docs = append(docs, doc)
   218  			tablesOrFiles[i] = doltdb.DocTableName
   219  		}
   220  	}
   221  	return tablesOrFiles, docs, nil
   222  }