internal/cli: add support for removedb (#478)

* internal/cli: add support for removedb

* update docs

* internal/cli: use constant path, handle err
This commit is contained in:
Manav Darji 2022-08-09 09:16:42 +05:30 committed by GitHub
parent 16408ba324
commit ac559bcd16
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 170 additions and 2 deletions

View file

@ -40,6 +40,8 @@
- [```peers status```](./peers_status.md)
- [```removedb```](./removedb.md)
- [```server```](./server.md)
- [```status```](./status.md)

7
docs/cli/removedb.md Normal file
View file

@ -0,0 +1,7 @@
# RemoveDB
The ```bor removedb``` command will remove the blockchain and state databases at the given datadir location
## Options
- ```datadir```: Path of the data directory to store information

View file

@ -184,6 +184,11 @@ func Commands() map[string]MarkDownCommandFactory {
UI: ui,
}, nil
},
"removedb": func() (MarkDownCommand, error) {
return &RemoveDBCommand{
Meta2: meta2,
}, nil
},
}
}

154
internal/cli/removedb.go Normal file
View file

@ -0,0 +1,154 @@
package cli
import (
"fmt"
"os"
"path/filepath"
"strings"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/internal/cli/flagset"
"github.com/ethereum/go-ethereum/internal/cli/server"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/mitchellh/cli"
)
// RemoveDBCommand is for removing blockchain and state databases
type RemoveDBCommand struct {
*Meta2
datadir string
}
const (
chaindataPath string = "chaindata"
ancientPath string = "ancient"
lightchaindataPath string = "lightchaindata"
)
// MarkDown implements cli.MarkDown interface
func (c *RemoveDBCommand) MarkDown() string {
items := []string{
"# RemoveDB",
"The ```bor removedb``` command will remove the blockchain and state databases at the given datadir location",
c.Flags().MarkDown(),
}
return strings.Join(items, "\n\n")
}
// Help implements the cli.Command interface
func (c *RemoveDBCommand) Help() string {
return `Usage: bor removedb <datadir>
This command will remove the blockchain and state databases at the given datadir location`
}
// Synopsis implements the cli.Command interface
func (c *RemoveDBCommand) Synopsis() string {
return "Remove blockchain and state databases"
}
func (c *RemoveDBCommand) Flags() *flagset.Flagset {
flags := c.NewFlagSet("removedb")
flags.StringFlag(&flagset.StringFlag{
Name: "datadir",
Value: &c.datadir,
Usage: "Path of the data directory to store information",
})
return flags
}
// Run implements the cli.Command interface
func (c *RemoveDBCommand) Run(args []string) int {
flags := c.Flags()
// parse datadir
if err := flags.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
datadir := c.datadir
if datadir == "" {
datadir = server.DefaultDataDir()
}
// create ethereum node config with just the datadir
nodeCfg := &node.Config{DataDir: datadir}
// Remove the full node state database
path := nodeCfg.ResolvePath(chaindataPath)
if common.FileExist(path) {
confirmAndRemoveDB(c.UI, path, "full node state database")
} else {
log.Info("Full node state database missing", "path", path)
}
// Remove the full node ancient database
// Note: The old cli used DatabaseFreezer path from config if provided explicitly
// We don't have access to eth config and hence we assume it to be
// under the "chaindata" folder.
path = filepath.Join(nodeCfg.ResolvePath(chaindataPath), ancientPath)
if common.FileExist(path) {
confirmAndRemoveDB(c.UI, path, "full node ancient database")
} else {
log.Info("Full node ancient database missing", "path", path)
}
// Remove the light node database
path = nodeCfg.ResolvePath(lightchaindataPath)
if common.FileExist(path) {
confirmAndRemoveDB(c.UI, path, "light node database")
} else {
log.Info("Light node database missing", "path", path)
}
return 0
}
// confirmAndRemoveDB prompts the user for a last confirmation and removes the
// folder if accepted.
func confirmAndRemoveDB(ui cli.Ui, database string, kind string) {
for {
confirm, err := ui.Ask(fmt.Sprintf("Remove %s (%s)? [y/n]", kind, database))
switch {
case err != nil:
ui.Output(err.Error())
return
case confirm != "":
switch strings.ToLower(confirm) {
case "y":
start := time.Now()
err = filepath.Walk(database, func(path string, info os.FileInfo, err error) error {
// If we're at the top level folder, recurse into
if path == database {
return nil
}
// Delete all the files, but not subfolders
if !info.IsDir() {
return os.Remove(path)
}
return filepath.SkipDir
})
if err != nil && err != filepath.SkipDir {
ui.Output(err.Error())
} else {
log.Info("Database successfully deleted", "path", database, "elapsed", common.PrettyDuration(time.Since(start)))
}
return
case "n":
log.Info("Database deletion skipped", "path", database)
return
}
}
}
}

View file

@ -394,7 +394,7 @@ func DefaultConfig() *Config {
Identity: Hostname(),
RequiredBlocks: map[string]string{},
LogLevel: "INFO",
DataDir: defaultDataDir(),
DataDir: DefaultDataDir(),
P2P: &P2PConfig{
MaxPeers: 30,
MaxPendPeers: 50,
@ -1040,7 +1040,7 @@ func parseBootnodes(urls []string) ([]*enode.Node, error) {
return dst, nil
}
func defaultDataDir() string {
func DefaultDataDir() string {
// Try to place the data folder in the user's home dir
home, _ := homedir.Dir()
if home == "" {