github.com/palisadeinc/bor@v0.0.0-20230615125219-ab7196213d15/internal/cli/removedb.go (about) 1 package cli 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "strings" 8 "time" 9 10 "github.com/ethereum/go-ethereum/common" 11 "github.com/ethereum/go-ethereum/internal/cli/flagset" 12 "github.com/ethereum/go-ethereum/internal/cli/server" 13 "github.com/ethereum/go-ethereum/log" 14 "github.com/ethereum/go-ethereum/node" 15 16 "github.com/mitchellh/cli" 17 ) 18 19 // RemoveDBCommand is for removing blockchain and state databases 20 type RemoveDBCommand struct { 21 *Meta2 22 23 datadir string 24 } 25 26 const ( 27 chaindataPath string = "chaindata" 28 ancientPath string = "ancient" 29 trieCacheJournalPath string = "triecache" 30 lightchaindataPath string = "lightchaindata" 31 ) 32 33 // MarkDown implements cli.MarkDown interface 34 func (c *RemoveDBCommand) MarkDown() string { 35 items := []string{ 36 "# RemoveDB", 37 "The ```bor removedb``` command will remove the blockchain and state databases at the given datadir location", 38 c.Flags().MarkDown(), 39 } 40 41 return strings.Join(items, "\n\n") 42 } 43 44 // Help implements the cli.Command interface 45 func (c *RemoveDBCommand) Help() string { 46 return `Usage: bor removedb <datadir> 47 48 This command will remove the blockchain and state databases at the given datadir location` 49 } 50 51 // Synopsis implements the cli.Command interface 52 func (c *RemoveDBCommand) Synopsis() string { 53 return "Remove blockchain and state databases" 54 } 55 56 func (c *RemoveDBCommand) Flags() *flagset.Flagset { 57 flags := c.NewFlagSet("removedb") 58 59 flags.StringFlag(&flagset.StringFlag{ 60 Name: "datadir", 61 Value: &c.datadir, 62 Usage: "Path of the data directory to store information", 63 }) 64 65 return flags 66 } 67 68 // Run implements the cli.Command interface 69 func (c *RemoveDBCommand) Run(args []string) int { 70 flags := c.Flags() 71 72 // parse datadir 73 if err := flags.Parse(args); err != nil { 74 c.UI.Error(err.Error()) 75 return 1 76 } 77 78 datadir := c.datadir 79 if datadir == "" { 80 datadir = server.DefaultDataDir() 81 } 82 83 // create ethereum node config with just the datadir 84 nodeCfg := &node.Config{DataDir: datadir} 85 86 // Remove the full node state database 87 path := nodeCfg.ResolvePath(chaindataPath) 88 if common.FileExist(path) { 89 confirmAndRemoveDB(c.UI, path, "full node state database") 90 } else { 91 log.Info("Full node state database missing", "path", path) 92 } 93 94 // Remove the full node ancient database 95 // Note: The old cli used DatabaseFreezer path from config if provided explicitly 96 // We don't have access to eth config and hence we assume it to be 97 // under the "chaindata" folder. 98 path = filepath.Join(nodeCfg.ResolvePath(chaindataPath), ancientPath) 99 if common.FileExist(path) { 100 confirmAndRemoveDB(c.UI, path, "full node ancient database") 101 } else { 102 log.Info("Full node ancient database missing", "path", path) 103 } 104 105 // Remove the light node database 106 path = nodeCfg.ResolvePath(lightchaindataPath) 107 if common.FileExist(path) { 108 confirmAndRemoveDB(c.UI, path, "light node database") 109 } else { 110 log.Info("Light node database missing", "path", path) 111 } 112 113 return 0 114 } 115 116 // confirmAndRemoveDB prompts the user for a last confirmation and removes the 117 // folder if accepted. 118 func confirmAndRemoveDB(ui cli.Ui, database string, kind string) { 119 for { 120 confirm, err := ui.Ask(fmt.Sprintf("Remove %s (%s)? [y/n]", kind, database)) 121 122 switch { 123 case err != nil: 124 ui.Output(err.Error()) 125 return 126 case confirm != "": 127 switch strings.ToLower(confirm) { 128 case "y": 129 start := time.Now() 130 err = filepath.Walk(database, func(path string, info os.FileInfo, err error) error { 131 // If we're at the top level folder, recurse into 132 if path == database { 133 return nil 134 } 135 // Delete all the files, but not subfolders 136 if !info.IsDir() { 137 return os.Remove(path) 138 } 139 return filepath.SkipDir 140 }) 141 142 if err != nil && err != filepath.SkipDir { 143 ui.Output(err.Error()) 144 } else { 145 log.Info("Database successfully deleted", "path", database, "elapsed", common.PrettyDuration(time.Since(start))) 146 } 147 148 return 149 case "n": 150 log.Info("Database deletion skipped", "path", database) 151 return 152 } 153 } 154 } 155 }