github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/env/actions/reset.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/doltdb" 22 "github.com/dolthub/dolt/go/libraries/doltcore/doltdocs" 23 "github.com/dolthub/dolt/go/libraries/doltcore/env" 24 "github.com/dolthub/dolt/go/libraries/utils/argparser" 25 ) 26 27 func resetHardTables(ctx context.Context, dbData env.DbData, cSpecStr string, workingRoot, stagedRoot, headRoot *doltdb.RootValue) (*doltdb.Commit, error) { 28 ddb := dbData.Ddb 29 rsr := dbData.Rsr 30 rsw := dbData.Rsw 31 32 var newHead *doltdb.Commit 33 if cSpecStr != "" { 34 cs, err := doltdb.NewCommitSpec(cSpecStr) 35 if err != nil { 36 return nil, err 37 } 38 39 newHead, err = ddb.Resolve(ctx, cs, rsr.CWBHeadRef()) 40 if err != nil { 41 return nil, err 42 } 43 44 headRoot, err = newHead.GetRootValue() 45 if err != nil { 46 return nil, err 47 } 48 } 49 50 // need to save the state of files that aren't tracked 51 untrackedTables := make(map[string]*doltdb.Table) 52 wTblNames, err := workingRoot.GetTableNames(ctx) 53 54 if err != nil { 55 return nil, err 56 } 57 58 for _, tblName := range wTblNames { 59 untrackedTables[tblName], _, err = workingRoot.GetTable(ctx, tblName) 60 61 if err != nil { 62 return nil, err 63 } 64 } 65 66 headTblNames, err := stagedRoot.GetTableNames(ctx) 67 68 if err != nil { 69 return nil, err 70 } 71 72 for _, tblName := range headTblNames { 73 delete(untrackedTables, tblName) 74 } 75 76 newWkRoot := headRoot 77 for tblName, tbl := range untrackedTables { 78 if tblName != doltdb.DocTableName { 79 newWkRoot, err = newWkRoot.PutTable(ctx, tblName, tbl) 80 } 81 if err != nil { 82 return nil, errors.New("error: failed to write table back to database") 83 } 84 } 85 86 _, err = env.UpdateWorkingRoot(ctx, ddb, rsw, newWkRoot) 87 88 if err != nil { 89 return nil, err 90 } 91 92 _, err = env.UpdateStagedRoot(ctx, ddb, rsw, headRoot) 93 94 if err != nil { 95 return nil, err 96 } 97 98 return newHead, nil 99 } 100 101 // ResetHardTables resets the tables in working, staged, and head based on the given parameters. Returns the commit hash 102 // if head is updated. 103 func ResetHardTables(ctx context.Context, dbData env.DbData, cSpecStr string, workingRoot, stagedRoot, headRoot *doltdb.RootValue) (string, error) { 104 newHead, err := resetHardTables(ctx, dbData, cSpecStr, workingRoot, stagedRoot, headRoot) 105 106 if err != nil { 107 return "", err 108 } 109 110 ddb := dbData.Ddb 111 rsr := dbData.Rsr 112 113 if newHead != nil { 114 if err := ddb.SetHeadToCommit(ctx, rsr.CWBHeadRef(), newHead); err != nil { 115 return "", err 116 } 117 118 h, err := newHead.HashOf() 119 if err != nil { 120 return "", err 121 } 122 123 return h.String(), nil 124 } 125 126 return "", nil 127 } 128 129 func ResetHard(ctx context.Context, dEnv *env.DoltEnv, cSpecStr string, workingRoot, stagedRoot, headRoot *doltdb.RootValue) error { 130 dbData := dEnv.DbData() 131 132 newHead, err := resetHardTables(ctx, dbData, cSpecStr, workingRoot, stagedRoot, headRoot) 133 134 if err != nil { 135 return err 136 } 137 138 err = SaveTrackedDocsFromWorking(ctx, dEnv) 139 if err != nil { 140 return err 141 } 142 143 ddb := dbData.Ddb 144 rsr := dbData.Rsr 145 146 if newHead != nil { 147 if err = ddb.SetHeadToCommit(ctx, rsr.CWBHeadRef(), newHead); err != nil { 148 return err 149 } 150 } 151 152 return nil 153 } 154 155 func ResetSoftTables(ctx context.Context, dbData env.DbData, apr *argparser.ArgParseResults, stagedRoot, headRoot *doltdb.RootValue) (*doltdb.RootValue, error) { 156 tables, err := getUnionedTables(ctx, apr.Args(), stagedRoot, headRoot) 157 tables = RemoveDocsTable(tables) 158 159 if err != nil { 160 return nil, err 161 } 162 163 err = ValidateTables(context.TODO(), tables, stagedRoot, headRoot) 164 165 if err != nil { 166 return nil, err 167 } 168 169 stagedRoot, err = resetStaged(ctx, dbData.Ddb, dbData.Rsw, tables, stagedRoot, headRoot) 170 171 if err != nil { 172 return nil, err 173 } 174 175 return stagedRoot, nil 176 } 177 178 func ResetSoft(ctx context.Context, dbData env.DbData, tables []string, stagedRoot, headRoot *doltdb.RootValue) (*doltdb.RootValue, error) { 179 tables, err := getUnionedTables(ctx, tables, stagedRoot, headRoot) 180 181 if err != nil { 182 return nil, err 183 } 184 185 tables, docs, err := GetTablesOrDocs(dbData.Drw, tables) 186 if err != nil { 187 return nil, err 188 } 189 190 if len(docs) > 0 { 191 tables = RemoveDocsTable(tables) 192 } 193 194 err = ValidateTables(context.TODO(), tables, stagedRoot, headRoot) 195 196 if err != nil { 197 return nil, err 198 } 199 200 stagedRoot, err = resetDocs(ctx, dbData, headRoot, stagedRoot, docs) 201 if err != nil { 202 return nil, err 203 } 204 205 stagedRoot, err = resetStaged(ctx, dbData.Ddb, dbData.Rsw, tables, stagedRoot, headRoot) 206 207 if err != nil { 208 return nil, err 209 } 210 211 return stagedRoot, nil 212 } 213 214 // ResetSoftToRef matches the `git reset --soft <REF>` pattern. It resets both staged and head to the previous ref 215 // and leaves the working unset. The user can then choose to create a commit that contains all changes since the ref. 216 func ResetSoftToRef(ctx context.Context, dbData env.DbData, cSpecStr string) error { 217 cs, err := doltdb.NewCommitSpec(cSpecStr) 218 if err != nil { 219 return err 220 } 221 222 newHead, err := dbData.Ddb.Resolve(ctx, cs, dbData.Rsr.CWBHeadRef()) 223 if err != nil { 224 return err 225 } 226 227 foundRoot, err := newHead.GetRootValue() 228 if err != nil { 229 return err 230 } 231 232 // Changed the stage to old the root. Leave the working as is. 233 _, err = env.UpdateStagedRoot(ctx, dbData.Ddb, dbData.Rsw, foundRoot) 234 if err != nil { 235 return err 236 } 237 238 // Update the head to this commit 239 if err = dbData.Ddb.SetHeadToCommit(ctx, dbData.Rsr.CWBHeadRef(), newHead); err != nil { 240 return err 241 } 242 243 return err 244 } 245 246 func getUnionedTables(ctx context.Context, tables []string, stagedRoot, headRoot *doltdb.RootValue) ([]string, error) { 247 if len(tables) == 0 || (len(tables) == 1 && tables[0] == ".") { 248 var err error 249 tables, err = doltdb.UnionTableNames(ctx, stagedRoot, headRoot) 250 251 if err != nil { 252 return nil, err 253 } 254 } 255 256 return tables, nil 257 } 258 259 // resetDocs resets the working and staged docs with docs from head. 260 func resetDocs(ctx context.Context, dbData env.DbData, headRoot *doltdb.RootValue, staged *doltdb.RootValue, docs doltdocs.Docs) (newStgRoot *doltdb.RootValue, err error) { 261 docs, err = doltdocs.GetDocsFromRoot(ctx, headRoot, doltdocs.GetDocNamesFromDocs(docs)...) 262 if err != nil { 263 return nil, err 264 } 265 266 working, err := env.WorkingRoot(ctx, dbData.Ddb, dbData.Rsr) 267 if err != nil { 268 return nil, err 269 } 270 271 working, err = doltdocs.UpdateRootWithDocs(ctx, working, docs) 272 if err != nil { 273 return nil, err 274 } 275 276 _, err = env.UpdateWorkingRoot(ctx, dbData.Ddb, dbData.Rsw, working) 277 if err != nil { 278 return nil, err 279 } 280 281 return doltdocs.UpdateRootWithDocs(ctx, staged, docs) 282 } 283 284 func resetStaged(ctx context.Context, ddb *doltdb.DoltDB, rsw env.RepoStateWriter, tbls []string, staged, head *doltdb.RootValue) (*doltdb.RootValue, error) { 285 updatedRoot, err := MoveTablesBetweenRoots(ctx, tbls, head, staged) 286 287 if err != nil { 288 return nil, err 289 } 290 291 return updatedRoot, env.UpdateStagedRootWithVErr(ddb, rsw, updatedRoot) 292 } 293 294 // ValidateIsRef validates whether the input parameter is a valid cString 295 func ValidateIsRef(ctx context.Context, cSpecStr string, ddb *doltdb.DoltDB, rsr env.RepoStateReader) bool { 296 cs, err := doltdb.NewCommitSpec(cSpecStr) 297 if err != nil { 298 return false 299 } 300 301 _, err = ddb.Resolve(ctx, cs, rsr.CWBHeadRef()) 302 if err != nil { 303 return false 304 } 305 306 return true 307 }