Skip to content

Commit

Permalink
feat(cmd.Init): added init command
Browse files Browse the repository at this point in the history
qri needs a clean way to initialize itself, so I'm adding an init
command.
  • Loading branch information
b5 committed Dec 14, 2017
1 parent c4ff240 commit a3530c1
Show file tree
Hide file tree
Showing 10 changed files with 254 additions and 179 deletions.
144 changes: 77 additions & 67 deletions cmd/config.go
Original file line number Diff line number Diff line change
@@ -1,30 +1,70 @@
package cmd

import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"

"github.com/qri-io/qri/core"
"github.com/qri-io/qri/p2p"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"gopkg.in/yaml.v2"
)

// Config configures the behaviour of qri
type Config struct {
Bootstrap []string `json:"bootstrap"`
// Initialized is a flag for when this repo has been properly initialized at least once.
// used to check weather default datasets should be added or not
Initialized bool
// Identity Configuration details
Identity IdentityCfg
// List of nodes to boostrap to
Bootstrap []string
// Datastore configuration details
// Datastore DatastoreCfg
// DefaultDatasets is a list of datasets to grab on initially joining the network
DefaultDatasets map[string]string
}

var defaultCfg = &Config{
Bootstrap: p2p.DefaultBootstrapAddresses,
// IdentityCfg holds details about user identity & configuration
type IdentityCfg struct {
// ID to feed to IPFS node, and for profile identification
PeerID string
// PrivateKey for
PrivateKey string
// Profile
Profile *core.Profile
}

// configCmd represents the config command
// DatastoreCfg configures the underlying IPFS datastore. WIP.
// type DatastoreCfg struct {
// StorageMax string
// StorageGCWatermark int
// GCPeriod string
// }

func defaultCfgBytes() []byte {
cfg := &Config{
Initialized: false,
Bootstrap: p2p.DefaultBootstrapAddresses,
// defaultDatasets is a hard-coded dataset added when a new qri repo is created
// these hashes should always/highly available
DefaultDatasets: map[string]string{
// fivethirtyeight comic characters
"comic_characters": "/ipfs/QmcqkHFA2LujZxY38dYZKmxsUstN4unk95azBjwEhwrnM6/dataset.json",
},
}

data, err := yaml.Marshal(cfg)
ExitIfErr(err)
return data
}

// configCmd represents commands that read & modify configuration settings
var configCmd = &cobra.Command{
Use: "config",
Short: "Edit settings",
Short: "Read & Edit settings",
Long: ``,
}

Expand All @@ -44,76 +84,46 @@ var configSetCommand = &cobra.Command{
},
}

func init() {
configCmd.AddCommand(configGetCommand)
configCmd.AddCommand(configSetCommand)
RootCmd.AddCommand(configCmd)
}

// initConfig reads in config file and ENV variables if set.
func initConfig() (created bool) {
var err error
home := userHomeDir()
SetNoColor()

// if cfgFile is specified, override
if cfgFile != "" {
viper.SetConfigFile(cfgFile)
err := viper.ReadInConfig()
ExitIfErr(err)
return
}

qriPath := os.Getenv("QRI_PATH")
if qriPath == "" {
qriPath = filepath.Join(home, ".qri")
}
// TODO - this is stupid
qriPath = strings.Replace(qriPath, "~", home, 1)
viper.SetDefault(QriRepoPath, filepath.Join(qriPath))
if err := os.MkdirAll(qriPath, os.ModePerm); err != nil {
fmt.Errorf("error creating home dir: %s\n", err.Error())
}

ipfsFsPath := os.Getenv("IPFS_PATH")
if ipfsFsPath == "" {
ipfsFsPath = filepath.Join(home, ".ipfs")
}
ipfsFsPath = strings.Replace(ipfsFsPath, "~", home, 1)
viper.SetDefault(IpfsFsPath, ipfsFsPath)

viper.SetConfigName("config") // name of config file (without extension)
viper.AddConfigPath(qriPath) // add QRI_PATH env var

created, err = EnsureConfigFile()
ExitIfErr(err)

err = viper.ReadInConfig()
ExitIfErr(err)

return
}

func configFilepath() string {
path := viper.ConfigFileUsed()
if path == "" {
path = filepath.Join(viper.GetString(QriRepoPath), "config.json")
path = filepath.Join(QriRepoPath, "config.yaml")
}
return path
}

func EnsureConfigFile() (bool, error) {
if _, err := os.Stat(configFilepath()); os.IsNotExist(err) {
fmt.Println("writing config file")
return true, WriteConfigFile(defaultCfg)
}
return false, nil
}
// func EnsureConfigFile() (bool, error) {
// if _, err := os.Stat(configFilepath()); os.IsNotExist(err) {
// fmt.Println("writing config file")
// return true, WriteConfigFile(defaultCfg)
// }
// return false, nil
// }

func WriteConfigFile(cfg *Config) error {
data, err := json.MarshalIndent(cfg, "", " ")
data, err := yaml.Marshal(cfg)
if err != nil {
return err
}
return ioutil.WriteFile(configFilepath(), data, os.ModePerm)
}

func loadConfig() {
viper.SetConfigName("config") // name of config file (without extension)
viper.AddConfigPath(QriRepoPath) // add QRI_PATH env var
viper.SetConfigType("yaml")
viper.SetEnvPrefix("QRI_")

// if cfgFile is specified, override
if cfgFile != "" {
viper.SetConfigFile(cfgFile)
}
viper.ReadInConfig()
// ExitIfErr(err)
}

func init() {
configCmd.AddCommand(configGetCommand)
configCmd.AddCommand(configSetCommand)
RootCmd.AddCommand(configCmd)
}
27 changes: 0 additions & 27 deletions cmd/init-ipfs.go

This file was deleted.

89 changes: 89 additions & 0 deletions cmd/init.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package cmd

import (
"fmt"
"io/ioutil"
"os"
"path/filepath"

ipfs "github.com/qri-io/cafs/ipfs"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"gopkg.in/yaml.v2"
)

var (
initOverwrite bool
initIPFS bool
initIPFSConfigFile string
)

// initCmd represents the init command
var initCmd = &cobra.Command{
Use: "init",
Short: "Initialize a qri repo",
Long: ``,
Run: func(cmd *cobra.Command, args []string) {
var cfgData []byte

if QRIRepoInitialized() && !initOverwrite {
ErrExit(fmt.Errorf("repo already initialized. use --overwrite to overwrite this repo, erasing all data"))
}

// if cfgFile is specified, override
if cfgFile != "" {
f, err := os.Open(cfgFile)
ExitIfErr(err)
cfgData, err = ioutil.ReadAll(f)
ExitIfErr(err)
} else {
cfgData = defaultCfgBytes()
}

cfg := &Config{}
err := yaml.Unmarshal(cfgData, cfg)
ExitIfErr(err)

if err := os.MkdirAll(QriRepoPath, os.ModePerm); err != nil {
ErrExit(fmt.Errorf("error creating home dir: %s\n", err.Error()))
}
err = WriteConfigFile(cfg)
ExitIfErr(err)

err = viper.ReadInConfig()
ExitIfErr(err)

if initIPFS {
err := ipfs.InitRepo(IpfsFsPath, initIPFSConfigFile)
ExitIfErr(err)
}
},
}

// QRIRepoInitialized checks to see if a repository has been initialized at $QRI_PATH
func QRIRepoInitialized() bool {
// for now this just checks for an existing config file
_, err := os.Stat(configFilepath())
return !os.IsNotExist(err)
}

func initRepoIfEmpty(repoPath, configPath string) error {
if repoPath != "" {
if _, err := os.Stat(filepath.Join(repoPath, "config")); os.IsNotExist(err) {
if err := os.MkdirAll(repoPath, os.ModePerm); err != nil {
return err
}
if err := ipfs.InitRepo(repoPath, configPath); err != nil {
return err
}
}
}
return nil
}

func init() {
RootCmd.AddCommand(initCmd)
initCmd.Flags().BoolVarP(&initOverwrite, "overwrite", "", false, "overwrite repo if one exists")
initCmd.Flags().BoolVarP(&initIPFS, "init-ipfs", "", true, "initialize an IPFS repo if one isn't present")
initCmd.Flags().StringVarP(&initIPFSConfigFile, "ipfs-config", "", "", "config file for initialization")
}
2 changes: 1 addition & 1 deletion cmd/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ var profileGetCmd = &cobra.Command{

var profileSetCmd = &cobra.Command{
Use: "set",
Short: "add peers to the profile list",
Short: "set profile details",
Run: func(cmd *cobra.Command, args []string) {
var (
dataFile *os.File
Expand Down
8 changes: 6 additions & 2 deletions cmd/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,24 @@ func GetRepo(online bool) repo.Repo {
return r
}

if !QRIRepoInitialized() {
ErrExit(fmt.Errorf("no qri repo found, please run `qri init`"))
}

fs := GetIpfsFilestore(online)
id := ""
if fs.Node().PeerHost != nil {
id = fs.Node().PeerHost.ID().Pretty()
}

r, err := fs_repo.NewRepo(fs, viper.GetString(QriRepoPath), id)
r, err := fs_repo.NewRepo(fs, QriRepoPath, id)
ExitIfErr(err)
return r
}

func GetIpfsFilestore(online bool) *ipfs.Filestore {
fs, err := ipfs.NewFilestore(func(cfg *ipfs.StoreCfg) {
cfg.FsRepoPath = viper.GetString(IpfsFsPath)
cfg.FsRepoPath = IpfsFsPath
cfg.Online = online
})
ExitIfErr(err)
Expand Down
Loading

0 comments on commit a3530c1

Please sign in to comment.