Skip to content

Commit

Permalink
fix(export): Export can be used while running qri connect
Browse files Browse the repository at this point in the history
Move the main functionality of export down to lib/. Invoke the RPC call if
needed. Remove the Repo method from Factory, and make the Node method more
explicit (only `qri connect` needs it). Now all commands can be run while
connected.
  • Loading branch information
dustmop committed Jan 15, 2019
1 parent d19da13 commit a5a56d1
Show file tree
Hide file tree
Showing 10 changed files with 228 additions and 173 deletions.
10 changes: 5 additions & 5 deletions cmd/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,13 @@ func (o *ConnectOptions) Complete(f Factory, args []string) (err error) {
return fmt.Errorf("no qri repo exists")
}

// TODO - calling f.Node has the side effect of
// calling init if we haven't initialized so far. Should this be made
// more explicit?
o.Node, err = f.Node()
if err != nil {
if err = f.Init(); err != nil {
return err
}
o.Node, err = f.ConnectionNode()
if err != nil {
return fmt.Errorf("%s, is `qri connect` already running?", err)
}
o.Config, err = f.Config()
return
}
Expand Down
147 changes: 11 additions & 136 deletions cmd/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@ import (
"fmt"
"io/ioutil"
"os"
"path/filepath"

"github.com/qri-io/dataset/dsutil"
"github.com/qri-io/ioes"
"github.com/qri-io/qri/lib"
"github.com/qri-io/qri/repo"
"github.com/qri-io/qri/repo/profile"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -71,10 +68,8 @@ type ExportOptions struct {
BodyFormat string
NoBody bool

UsingRPC bool
Repo repo.Repo
Profile *profile.Profile
DatasetRequests *lib.DatasetRequests
UsingRPC bool
ExportRequests *lib.ExportRequests
}

// Complete adds any missing configuration that can only be added just before calling Run
Expand All @@ -85,16 +80,7 @@ func (o *ExportOptions) Complete(f Factory, args []string) (err error) {
if f.RPC() != nil {
return usingRPCError("export")
}

o.DatasetRequests, err = f.DatasetRequests()
// TODO (dlong): All other callers of this method have removed their need of it. Remove
// this call and then remove it from the factory interface.
o.Repo, err = f.Repo()
if err != nil {
return
}

o.Profile, err = o.Repo.Profile()
o.ExportRequests, err = f.ExportRequests()
return err
}

Expand Down Expand Up @@ -142,134 +128,23 @@ func (o *ExportOptions) Run() error {
return fmt.Errorf("%s is not an accepted data format, options are json, csv, and cbor", bodyFormat)
}

dsr, err := repo.ParseDatasetRef(o.Ref)
if err != nil && err != repo.ErrEmptyRef {
return err
}

res := &repo.DatasetRef{}
if err = o.DatasetRequests.Get(&dsr, res); err != nil {
if err == repo.ErrEmptyRef {
return lib.NewError(err, "please provide a dataset reference")
}
return err
}

ds, err := res.DecodeDataset()
ref, err := repo.ParseDatasetRef(o.Ref)
if err != nil {
return err
}

if o.PeerDir {
peerName := dsr.Peername
if peerName == "me" {
peerName = o.Profile.Peername
}
path = filepath.Join(path, peerName)
p := &lib.ExportParams{
Ref: ref,
PeerDir: false,
Format: format,
}
path = filepath.Join(path, dsr.Name)

// TODO (dlong): When --zip flag is not required, don't always do this.
dst, err := os.Create(fmt.Sprintf("%s.zip", path))
if err != nil {
return err
}

// TODO (dlong): Use --body-format here to convert the body and ds.Structure.Format, before
// passing ds to WriteZipArchive.
if err = dsutil.WriteZipArchive(o.Repo.Store(), ds, format, res.String(), dst); err != nil {
ok := false
if err = o.ExportRequests.Export(p, &ok); err != nil {
return err
}
return dst.Close()

// TODO (dlong): Document the full functionality of export, and restore this code below. Allow
// non-zip formats like dataset.json with inline body, body.json by itself, outputting to a
// a directory, along with yaml, and xlsx.
/*if path != "" {
if err = os.MkdirAll(path, os.ModePerm); err != nil {
return err
}
}
if !o.NoBody {
if bodyFormat == "" {
bodyFormat = ds.Structure.Format.String()
}
df, err := dataset.ParseDataFormatString(bodyFormat)
if err != nil {
return err
}
p := &lib.LookupParams{
Format: df,
Path: ds.Path().String(),
All: true,
}
r := &lib.LookupResult{}
if err = o.DatasetRequests.LookupBody(p, r); err != nil {
return err
}
dataPath := filepath.Join(path, fmt.Sprintf("data.%s", bodyFormat))
dst, err := os.Create(dataPath)
if err != nil {
return err
}
if p.Format == dataset.CBORDataFormat {
r.Data = []byte(hex.EncodeToString(r.Data))
}
if _, err = dst.Write(r.Data); err != nil {
return err
}
if err = dst.Close(); err != nil {
return err
}
printSuccess(o.Out, "exported data to: %s", dataPath)
}
dsPath := filepath.Join(path, dsfs.PackageFileDataset.String())
var dsBytes []byte
switch format {
case "json":
dsBytes, err = json.MarshalIndent(ds, "", " ")
if err != nil {
return err
}
default:
dsBytes, err = yaml.Marshal(ds)
if err != nil {
return err
}
dsPath = fmt.Sprintf("%s.yaml", strings.TrimSuffix(dsPath, filepath.Ext(dsPath)))
}
if err = ioutil.WriteFile(dsPath, dsBytes, os.ModePerm); err != nil {
return err
}
if ds.Transform != nil && ds.Transform.ScriptPath != "" {
f, err := o.Repo.Store().Get(datastore.NewKey(ds.Transform.ScriptPath))
if err != nil {
return err
}
scriptData, err := ioutil.ReadAll(f)
if err != nil {
return err
}
// TODO - transformations should have default file extensions
if err = ioutil.WriteFile(filepath.Join(path, "transform.sky"), scriptData, os.ModePerm); err != nil {
return err
}
printSuccess(o.Out, "exported transform script to: %s", filepath.Join(path, "transform.sky"))
}
printSuccess(o.Out, "exported dataset.json to: %s", dsPath)

return nil*/
return nil
}

const blankYamlDataset = `# This file defines a qri dataset. Change this file, save it, then from a terminal run:
Expand Down
6 changes: 2 additions & 4 deletions cmd/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/qri-io/qri/config"
"github.com/qri-io/qri/lib"
"github.com/qri-io/qri/p2p"
"github.com/qri-io/qri/repo"
"github.com/qri-io/qri/repo/gen"
)

Expand All @@ -23,14 +22,13 @@ type Factory interface {
CryptoGenerator() gen.CryptoGenerator

Init() error
// TODO (dlong): This function is deprecated. Don't add new calls. Remove it soon.
Repo() (repo.Repo, error)
Node() (*p2p.QriNode, error)
RPC() *rpc.Client
ConnectionNode() (*p2p.QriNode, error)

DatasetRequests() (*lib.DatasetRequests, error)
RegistryRequests() (*lib.RegistryRequests, error)
LogRequests() (*lib.LogRequests, error)
ExportRequests() (*lib.ExportRequests, error)
PeerRequests() (*lib.PeerRequests, error)
ProfileRequests() (*lib.ProfileRequests, error)
SearchRequests() (*lib.SearchRequests, error)
Expand Down
12 changes: 6 additions & 6 deletions cmd/factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,8 @@ func (t TestFactory) Init() error {
return nil
}

// Repo returns from internal state
func (t TestFactory) Repo() (repo.Repo, error) {
return t.repo, nil
}

// Node returns the internal qri node from state
func (t TestFactory) Node() (*p2p.QriNode, error) {
func (t TestFactory) ConnectionNode() (*p2p.QriNode, error) {
return t.node, nil
}

Expand All @@ -120,6 +115,11 @@ func (t TestFactory) LogRequests() (*lib.LogRequests, error) {
return lib.NewLogRequests(t.node, t.rpc), nil
}

// ExportRequests generates a lib.ExportRequests from internal state
func (t TestFactory) ExportRequests() (*lib.ExportRequests, error) {
return lib.NewExportRequests(t.node, t.rpc), nil
}

// PeerRequests generates a lib.PeerRequests from internal state
func (t TestFactory) PeerRequests() (*lib.PeerRequests, error) {
return lib.NewPeerRequests(t.node, t.rpc), nil
Expand Down
29 changes: 11 additions & 18 deletions cmd/qri.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,25 +208,10 @@ func (o *QriOptions) RPC() *rpc.Client {
return o.rpc
}

// Repo returns from internal state
// TODO (dlong): This function is deprecated. Don't add new calls. Remove it soon.
func (o *QriOptions) Repo() (repo.Repo, error) {
if err := o.Init(); err != nil {
return nil, err
}
// ConnectionNode returns the internal QriNode, if it is available
func (o *QriOptions) ConnectionNode() (*p2p.QriNode, error) {
if o.repo == nil {
return nil, fmt.Errorf("repo not available (are you running qri in another terminal?)")
}
return o.repo, nil
}

// Node returns the internal QriNode
func (o *QriOptions) Node() (*p2p.QriNode, error) {
if err := o.Init(); err != nil {
return nil, err
}
if o.repo == nil {
return nil, fmt.Errorf("repo not available (are you running qri in another terminal?)")
return nil, fmt.Errorf("repo not available")
}
return o.node, nil
}
Expand Down Expand Up @@ -255,6 +240,14 @@ func (o *QriOptions) LogRequests() (*lib.LogRequests, error) {
return lib.NewLogRequests(o.node, o.rpc), nil
}

// ExportRequests generates a lib.ExportRequests from internal state
func (o *QriOptions) ExportRequests() (*lib.ExportRequests, error) {
if err := o.Init(); err != nil {
return nil, err
}
return lib.NewExportRequests(o.node, o.rpc), nil
}

// PeerRequests generates a lib.PeerRequests from internal state
func (o *QriOptions) PeerRequests() (*lib.PeerRequests, error) {
if err := o.Init(); err != nil {
Expand Down
9 changes: 7 additions & 2 deletions cmd/render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,16 @@ func TestRenderRun(t *testing.T) {

templateFile := cafs.NewMemfileBytes("template.html", []byte(`<html><h2>{{.Peername}}/{{.Name}}</h2></html>`))

r, err := f.Repo()
if err := f.Init(); err != nil {
t.Errorf("error initializing: %s", err)
return
}
node, err := f.ConnectionNode()
if err != nil {
t.Errorf("error getting repo from factory: %s", err)
t.Errorf("error getting node from factory: %s", err)
return
}
r := node.Repo

key, err := r.Store().Put(templateFile, false)
if err != nil {
Expand Down
Loading

0 comments on commit a5a56d1

Please sign in to comment.