-
Notifications
You must be signed in to change notification settings - Fork 66
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(registry cmd): add commands for working with registries
I've refactored a bunch of the logic around working with registries to make the process more explicit & controllable.
- Loading branch information
Showing
11 changed files
with
281 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package cmd | ||
|
||
import ( | ||
"github.com/qri-io/qri/repo" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
// RegistryCmd is the subcommand for working with configured registries | ||
var RegistryCmd = &cobra.Command{ | ||
Use: "registry", | ||
Short: "commands for working with a qri registry", | ||
Long: `Registries are federated public records of datasets and peers. | ||
These records form a public facing central lookup for your datasets, so others | ||
can find them through search tools and via web links. You can use registry | ||
commands to control how your datasets are published to registries, opting out | ||
on a dataset-by-dataset basis. | ||
By default qri is configured to publish to https://registry.qri.io, | ||
the main public collection of datasets & peers. "qri add" and "qri update" | ||
default to publishing to a registry as part of dataset creation unless run | ||
with the "no-registry" flag. | ||
Unpublished dataset info will be held locally so you can still interact | ||
with it. And your datasets will be available to others peers when you run | ||
"qri connect", but will not show up in search results, and will not be | ||
displayed on lists of registry datasets. | ||
Qri is designed to work without a registry should you want to opt out of | ||
centralized listing entirely, but know that peers who *do* participate in | ||
registries may choose to deprioritize connections with you. Opting out of a | ||
registry entirely is better left to advanced users. | ||
You can opt out of registries entirely by running: | ||
$ qri config set registry.location ""`, | ||
|
||
Annotations: map[string]string{ | ||
"group": "network", | ||
}, | ||
} | ||
|
||
// publishCmd represents the export command | ||
var publishCmd = &cobra.Command{ | ||
Use: "publish", | ||
Short: "publish dataset info to the registry", | ||
Example: ` Publish a dataset you've created to the registry: | ||
$ qri registry publish me/dataset_name`, | ||
PreRun: func(cmd *cobra.Command, args []string) { | ||
loadConfig() | ||
}, | ||
Args: cobra.MinimumNArgs(1), | ||
Run: func(cmd *cobra.Command, args []string) { | ||
req, err := registryRequests(false) | ||
ExitIfErr(err) | ||
|
||
var res bool | ||
for _, arg := range args { | ||
ref, err := repo.ParseDatasetRef(arg) | ||
ExitIfErr(err) | ||
|
||
err = req.Publish(&ref, &res) | ||
ExitIfErr(err) | ||
printInfo("published dataset %s", ref) | ||
} | ||
}, | ||
} | ||
|
||
// unpublishCmd represents the export command | ||
var unpublishCmd = &cobra.Command{ | ||
Use: "unpublish", | ||
Short: "remove dataset info from the registry", | ||
Example: ` Remove a dataset from the registry: | ||
$ qri registry unpublish me/dataset_name`, | ||
PreRun: func(cmd *cobra.Command, args []string) { | ||
loadConfig() | ||
}, | ||
Args: cobra.MinimumNArgs(1), | ||
Run: func(cmd *cobra.Command, args []string) { | ||
req, err := registryRequests(false) | ||
ExitIfErr(err) | ||
|
||
var res bool | ||
for _, arg := range args { | ||
ref, err := repo.ParseDatasetRef(arg) | ||
ExitIfErr(err) | ||
|
||
err = req.Unpublish(&ref, &res) | ||
ExitIfErr(err) | ||
printInfo("unpublished dataset %s", ref) | ||
} | ||
}, | ||
} | ||
|
||
func init() { | ||
RegistryCmd.AddCommand(publishCmd) | ||
RegistryCmd.AddCommand(unpublishCmd) | ||
RootCmd.AddCommand(RegistryCmd) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package core | ||
|
||
import ( | ||
"fmt" | ||
"net/rpc" | ||
|
||
"github.com/qri-io/qri/repo" | ||
"github.com/qri-io/qri/repo/actions" | ||
) | ||
|
||
// RegistryRequests defines business logic for working with registries | ||
type RegistryRequests struct { | ||
repo actions.Registry | ||
cli *rpc.Client | ||
} | ||
|
||
// CoreRequestsName implements the Requests interface | ||
func (RegistryRequests) CoreRequestsName() string { return "registry" } | ||
|
||
// NewRegistryRequests creates a DatasetRequests pointer from either a repo | ||
// or an rpc.Client | ||
func NewRegistryRequests(r repo.Repo, cli *rpc.Client) *RegistryRequests { | ||
if r != nil && cli != nil { | ||
panic(fmt.Errorf("both repo and client supplied to NewRegistryRequests")) | ||
} | ||
|
||
return &RegistryRequests{ | ||
repo: actions.Registry{r}, | ||
cli: cli, | ||
} | ||
} | ||
|
||
// Publish a dataset to a registry | ||
func (r *RegistryRequests) Publish(ref *repo.DatasetRef, done *bool) error { | ||
if r.cli != nil { | ||
return r.cli.Call("RegistryRequests.Publish", ref, done) | ||
} | ||
return r.repo.Publish(*ref) | ||
} | ||
|
||
// Unpublish a dataset from a registry | ||
func (r *RegistryRequests) Unpublish(ref *repo.DatasetRef, done *bool) error { | ||
if r.cli != nil { | ||
return r.cli.Call("RegistryRequests.Unpublish", ref, done) | ||
} | ||
return r.repo.Unpublish(*ref) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package actions | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/ipfs/go-datastore" | ||
"github.com/libp2p/go-libp2p-crypto" | ||
"github.com/qri-io/dataset" | ||
"github.com/qri-io/dataset/dsfs" | ||
"github.com/qri-io/qri/repo" | ||
"github.com/qri-io/qri/repo/profile" | ||
"github.com/qri-io/registry/regclient" | ||
) | ||
|
||
// Registry wraps a repo.Repo, adding actions related to working | ||
// with registries | ||
type Registry struct { | ||
repo.Repo | ||
} | ||
|
||
// Publish a dataset to a repo's specified registry | ||
func (act Registry) Publish(ref repo.DatasetRef) (err error) { | ||
cli, pub, ds, err := act.dsParams(&ref) | ||
if err != nil { | ||
return err | ||
} | ||
if err = act.permission(ref); err != nil { | ||
return | ||
} | ||
return cli.PutDataset(ref.Peername, ref.Name, ds.Encode(), pub) | ||
} | ||
|
||
// Unpublish a dataset from a repo's specified registry | ||
func (act Registry) Unpublish(ref repo.DatasetRef) (err error) { | ||
cli, pub, ds, err := act.dsParams(&ref) | ||
if err != nil { | ||
return err | ||
} | ||
if err = act.permission(ref); err != nil { | ||
return | ||
} | ||
return cli.DeleteDataset(ref.Peername, ref.Name, ds.Encode(), pub) | ||
} | ||
|
||
// dsParams is a convenience func that collects params for registry dataset interaction | ||
func (act Registry) dsParams(ref *repo.DatasetRef) (cli *regclient.Client, pub crypto.PubKey, ds *dataset.Dataset, err error) { | ||
if cli = act.Registry(); cli == nil { | ||
err = fmt.Errorf("no configured registry") | ||
return | ||
} | ||
|
||
pk := act.PrivateKey() | ||
if pk == nil { | ||
err = fmt.Errorf("repo has no configured private key") | ||
return | ||
} | ||
pub = pk.GetPublic() | ||
|
||
if err = repo.CanonicalizeDatasetRef(act, ref); err != nil { | ||
err = fmt.Errorf("canonicalizing dataset reference: %s", err.Error()) | ||
return | ||
} | ||
|
||
if ref.Path == "" { | ||
if *ref, err = act.GetRef(*ref); err != nil { | ||
return | ||
} | ||
} | ||
|
||
ds, err = dsfs.LoadDataset(act.Store(), datastore.NewKey(ref.Path)) | ||
return | ||
} | ||
|
||
// permission returns an error if a repo's configured user does not have the right | ||
// to publish ref to a registry | ||
func (act Registry) permission(ref repo.DatasetRef) (err error) { | ||
var pro *profile.Profile | ||
if pro, err = act.Profile(); err != nil { | ||
return err | ||
} | ||
if pro.Peername != ref.Peername { | ||
return fmt.Errorf("peername mismatch. '%s' doesn't have permission to publish a dataset created by '%s'", pro.Peername, ref.Peername) | ||
} | ||
return nil | ||
} |