diff --git a/api/datasets.go b/api/datasets.go index 9e260ad48..a426faab4 100644 --- a/api/datasets.go +++ b/api/datasets.go @@ -364,13 +364,19 @@ func (h *DatasetHandlers) addHandler(w http.ResponseWriter, r *http.Request) { return } + // TODO (b5) - move this into lib.Add if ref.Peername == "" || ref.Name == "" { util.WriteErrResponse(w, http.StatusBadRequest, fmt.Errorf("need peername and dataset name: '/add/[peername]/[datasetname]'")) return } + p := &lib.AddParams{ + Ref: ref.String(), + LinkDir: r.FormValue("dir"), + } + res := repo.DatasetRef{} - err = h.Add(&ref, &res) + err = h.Add(p, &res) if err != nil { util.WriteErrResponse(w, http.StatusInternalServerError, err) return diff --git a/cmd/add.go b/cmd/add.go index 2edb0e019..4314a66ff 100644 --- a/cmd/add.go +++ b/cmd/add.go @@ -2,6 +2,7 @@ package cmd import ( "fmt" + "path/filepath" "github.com/qri-io/ioes" "github.com/qri-io/qri/lib" @@ -35,12 +36,15 @@ the name of the peer that originally added the dataset. You must have }, } + cmd.Flags().StringVar(&o.LinkDir, "link", "", "path to directory to link dataset to") + return cmd } // AddOptions encapsulates state for the add command type AddOptions struct { ioes.IOStreams + LinkDir string DatasetRequests *lib.DatasetRequests } @@ -57,20 +61,32 @@ func (o *AddOptions) Run(args []string) error { o.StartSpinner() defer o.StopSpinner() + if len(args) > 1 && o.LinkDir != "" { + return fmt.Errorf("link flag can only be used with a single reference") + } + for _, arg := range args { - ref, err := parseCmdLineDatasetRef(arg) - if err != nil { - return err + if o.LinkDir != "" { + abs, err := filepath.Abs(o.LinkDir) + if err != nil { + return err + } + o.LinkDir = abs + } + + p := &lib.AddParams{ + Ref: arg, + LinkDir: o.LinkDir, } res := repo.DatasetRef{} - if err = o.DatasetRequests.Add(&ref, &res); err != nil { + if err := o.DatasetRequests.Add(p, &res); err != nil { return err } refStr := refStringer(res) fmt.Fprintf(o.Out, "\n%s", refStr.String()) - printInfo(o.Out, "Successfully added dataset %s", ref) + printInfo(o.Out, "Successfully added dataset %s", arg) } return nil diff --git a/lib/datasets.go b/lib/datasets.go index d58dbe632..50d9a3a21 100644 --- a/lib/datasets.go +++ b/lib/datasets.go @@ -614,21 +614,48 @@ func (r *DatasetRequests) Remove(p *RemoveParams, res *RemoveResponse) error { return nil } +// AddParams encapsulates parameters to the add command +type AddParams struct { + Ref string + LinkDir string + RemoteAddr string // remote to attempt to pull from +} + // Add adds an existing dataset to a peer's repository -func (r *DatasetRequests) Add(ref *repo.DatasetRef, res *repo.DatasetRef) (err error) { +func (r *DatasetRequests) Add(p *AddParams, res *repo.DatasetRef) (err error) { if r.cli != nil { - return r.cli.Call("DatasetRequests.Add", ref, res) + return r.cli.Call("DatasetRequests.Add", p, res) } ctx := context.TODO() - defaultAddr := "" - if r.inst != nil && r.inst.cfg.Registry != nil { - defaultAddr = r.inst.cfg.Registry.Location + ref, err := repo.ParseDatasetRef(p.Ref) + if err != nil { + return err + } + + if p.RemoteAddr == "" && r.inst != nil && r.inst.cfg.Registry != nil { + p.RemoteAddr = r.inst.cfg.Registry.Location } - err = actions.AddDataset(ctx, r.node, r.inst.RemoteClient(), defaultAddr, ref) - *res = *ref - return err + if err = actions.AddDataset(ctx, r.node, r.inst.RemoteClient(), p.RemoteAddr, &ref); err != nil { + return err + } + + *res = ref + + if p.LinkDir != "" { + checkoutp := &CheckoutParams{ + Ref: ref.String(), + Dir: p.LinkDir, + } + m := NewFSIMethods(r.inst) + checkoutRes := "" + if err = m.Checkout(checkoutp, &checkoutRes); err != nil { + return err + } + } + + return nil } // ValidateDatasetParams defines parameters for dataset diff --git a/lib/datasets_test.go b/lib/datasets_test.go index e3b213696..1f2423631 100644 --- a/lib/datasets_test.go +++ b/lib/datasets_test.go @@ -767,11 +767,11 @@ func TestDatasetRequestsRemove(t *testing.T) { func TestDatasetRequestsAdd(t *testing.T) { cases := []struct { - p *repo.DatasetRef + p *AddParams res *repo.DatasetRef err string }{ - {&repo.DatasetRef{Name: "abc", Path: "hash###"}, nil, "node is not online and no registry is configured"}, + {&AddParams{Ref: "abc/hash###"}, nil, "node is not online and no registry is configured"}, } mr, err := testrepo.NewTestRepo() @@ -842,12 +842,15 @@ func TestDatasetRequestsAddP2P(t *testing.T) { index, _ := strconv.ParseInt(num, 10, 32) name := datasets[index] ref := repo.DatasetRef{Peername: profile.Peername, Name: name} + p := &AddParams{ + Ref: ref.AliasString(), + } // Build requests for peer1 to peer2. dsr := NewDatasetRequests(p0, nil) got := &repo.DatasetRef{} - err := dsr.Add(&ref, got) + err := dsr.Add(p, got) if err != nil { pro1, _ := p0.Repo.Profile() pro2, _ := p1.Repo.Profile()