From 22532c14f4ac9dd3e8027d27b7fb604ee3fb130b Mon Sep 17 00:00:00 2001 From: Abe Winter Date: Fri, 6 Sep 2024 13:29:31 -0400 Subject: [PATCH 1/5] make `packages export` org + name optional, read from meta.json if missing --- cli/app.go | 10 ++++------ cli/packages.go | 10 ++++++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/cli/app.go b/cli/app.go index 737ff3f93da..b3f6165740f 100644 --- a/cli/app.go +++ b/cli/app.go @@ -1768,14 +1768,12 @@ This won't work unless you have an existing installation of our GitHub app on yo Usage: "output directory for downloaded package", }, &cli.StringFlag{ - Name: generalFlagOrgID, - Required: true, - Usage: "organization ID of the requested package", + Name: generalFlagOrgID, + Usage: "organization ID or namespace of the requested package. if missing, will try to read from meta.json", }, &cli.StringFlag{ - Name: packageFlagName, - Required: true, - Usage: "name of the requested package", + Name: packageFlagName, + Usage: "name of the requested package. if missing, will try to read from meta.json", }, &cli.StringFlag{ Name: packageFlagVersion, diff --git a/cli/packages.go b/cli/packages.go index 53787264391..2b76e15ec6f 100644 --- a/cli/packages.go +++ b/cli/packages.go @@ -84,6 +84,16 @@ func (c *viamClient) packageExportAction(orgID, name, version, packageType, dest if err := c.ensureLoggedIn(); err != nil { return err } + if orgID == "" || name == "" { + if orgID != "" || name != "" { + return fmt.Errorf("if either of %s or %s is missing, both must be missing", generalFlagOrgID, packageFlagName) + } + manifest, err := loadManifest(defaultManifestFilename) + if err != nil { + return errors.Wrap(err, "trying to get package ID from meta.json") + } + orgID, name, _ = strings.Cut(manifest.ModuleID, ":") + } // Package ID is the / packageID := path.Join(orgID, name) packageTypeProto, err := convertPackageTypeToProto(packageType) From db3d14b0f3bc5505c1b0cd1d5553e13aeb7b1a8c Mon Sep 17 00:00:00 2001 From: Abe Winter Date: Fri, 6 Sep 2024 13:30:06 -0400 Subject: [PATCH 2/5] default packageFlagVersion to latest --- cli/app.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/app.go b/cli/app.go index b3f6165740f..8e08a78f641 100644 --- a/cli/app.go +++ b/cli/app.go @@ -1776,9 +1776,9 @@ This won't work unless you have an existing installation of our GitHub app on yo Usage: "name of the requested package. if missing, will try to read from meta.json", }, &cli.StringFlag{ - Name: packageFlagVersion, - Required: true, - Usage: "version of the requested package, can be `latest` to get the most recent version", + Name: packageFlagVersion, + Usage: "version of the requested package, can be `latest` to get the most recent version", + Value: "latest", }, &cli.StringFlag{ Name: packageFlagType, From 4382f7760da222578b1f2019d5f6285184684a55 Mon Sep 17 00:00:00 2001 From: Abe Winter Date: Fri, 6 Sep 2024 13:33:18 -0400 Subject: [PATCH 3/5] default download dir to . --- cli/app.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/app.go b/cli/app.go index 8e08a78f641..6c66c3e1989 100644 --- a/cli/app.go +++ b/cli/app.go @@ -1763,9 +1763,9 @@ This won't work unless you have an existing installation of our GitHub app on yo }, false), Flags: []cli.Flag{ &cli.PathFlag{ - Name: packageFlagDestination, - Required: true, - Usage: "output directory for downloaded package", + Name: packageFlagDestination, + Usage: "output directory for downloaded package", + Value: ".", }, &cli.StringFlag{ Name: generalFlagOrgID, From cff66671a74d63361705362f5534c732ed352270 Mon Sep 17 00:00:00 2001 From: Abe Winter Date: Fri, 6 Sep 2024 13:35:51 -0400 Subject: [PATCH 4/5] remove non-required flags --- cli/app.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cli/app.go b/cli/app.go index 6c66c3e1989..17f55232a16 100644 --- a/cli/app.go +++ b/cli/app.go @@ -1757,10 +1757,7 @@ This won't work unless you have an existing installation of our GitHub app on yo Name: "export", Usage: "download a package from Viam cloud", UsageText: createUsageText("packages export", - []string{ - packageFlagDestination, generalFlagOrgID, packageFlagName, - packageFlagVersion, packageFlagType, - }, false), + []string{packageFlagType}, false), Flags: []cli.Flag{ &cli.PathFlag{ Name: packageFlagDestination, From 58c3bd954a893a330d05290d56e55e1d59464752 Mon Sep 17 00:00:00 2001 From: Abe Winter Date: Fri, 6 Sep 2024 15:36:05 -0400 Subject: [PATCH 5/5] DownloadModuleAction with correct latest-version and platform behavior --- cli/app.go | 27 +++++++++++++++ cli/module_registry.go | 76 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/cli/app.go b/cli/app.go index 17f55232a16..5c19a4bb446 100644 --- a/cli/app.go +++ b/cli/app.go @@ -51,6 +51,7 @@ const ( moduleFlagLocal = "local" moduleFlagHomeDir = "home" moduleCreateLocalOnly = "local-only" + moduleFlagID = "id" moduleBuildFlagPath = "module" moduleBuildFlagRef = "ref" @@ -1746,6 +1747,32 @@ This won't work unless you have an existing installation of our GitHub app on yo }, Action: ReloadModuleAction, }, + { + Name: "download", + Usage: "download a module package from the registry", + UsageText: createUsageText("module download", []string{}, false), + Flags: []cli.Flag{ + &cli.PathFlag{ + Name: packageFlagDestination, + Usage: "output directory for downloaded package", + Value: ".", + }, + &cli.StringFlag{ + Name: moduleFlagID, + Usage: "module ID as org-id:name or namespace:name. if missing, will try to read from meta.json", + }, + &cli.StringFlag{ + Name: packageFlagVersion, + Usage: "version of the requested package, can be `latest` to get the most recent version", + Value: "latest", + }, + &cli.StringFlag{ + Name: moduleFlagPlatform, + Usage: "platform like 'linux/amd64'. if missing, will use platform of the CLI binary", + }, + }, + Action: DownloadModuleAction, + }, }, }, { diff --git a/cli/module_registry.go b/cli/module_registry.go index 7ce7681fe9c..c31b85d1332 100644 --- a/cli/module_registry.go +++ b/cli/module_registry.go @@ -12,7 +12,10 @@ import ( "math" "os" "os/exec" + "path" "path/filepath" + "runtime" + "slices" "strings" "github.com/google/uuid" @@ -877,3 +880,76 @@ func getNextModuleUploadRequest(file *os.File) (*apppb.UploadModuleFileRequest, }, }, nil } + +// DownloadModuleAction downloads a module. +func DownloadModuleAction(c *cli.Context) error { + moduleID := c.String(moduleFlagID) + if moduleID == "" { + manifest, err := loadManifest(defaultManifestFilename) + if err != nil { + return errors.Wrap(err, "trying to get package ID from meta.json") + } + moduleID = manifest.ModuleID + } + client, err := newViamClient(c) + if err != nil { + return err + } + if err := client.ensureLoggedIn(); err != nil { + return err + } + req := &apppb.GetModuleRequest{ModuleId: moduleID} + res, err := client.client.GetModule(c.Context, req) + if err != nil { + return err + } + if len(res.Module.Versions) == 0 { + return errors.New("module has 0 uploaded versions, nothing to download") + } + requestedVersion := c.String(packageFlagVersion) + var ver *apppb.VersionHistory + if requestedVersion == "latest" { + ver = res.Module.Versions[len(res.Module.Versions)-1] + } else { + for _, iVer := range res.Module.Versions { + if iVer.Version == requestedVersion { + ver = iVer + break + } + } + if ver == nil { + return fmt.Errorf("version %s not found in versions for module", requestedVersion) + } + } + infof(c.App.ErrWriter, "found version %s", ver.Version) + if len(ver.Files) == 0 { + return fmt.Errorf("version %s has 0 files uploaded", ver.Version) + } + platform := c.String(moduleFlagPlatform) + if platform == "" { + platform = fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) + infof(c.App.ErrWriter, "using default platform %s", platform) + } + if !slices.ContainsFunc(ver.Files, func(file *apppb.Uploads) bool { return file.Platform == platform }) { + return fmt.Errorf("platform %s not present for version %s", platform, ver.Version) + } + include := true + packageType := packagespb.PackageType_PACKAGE_TYPE_MODULE + // note: this is working around a GetPackage quirk where platform messes with version + fullVersion := fmt.Sprintf("%s-%s", ver.Version, strings.ReplaceAll(platform, "/", "-")) + pkg, err := client.packageClient.GetPackage(c.Context, &packagespb.GetPackageRequest{ + Id: strings.ReplaceAll(moduleID, ":", "/"), + Version: fullVersion, + IncludeUrl: &include, + Type: &packageType, + }) + if err != nil { + return err + } + destName := strings.ReplaceAll(moduleID, ":", "-") + infof(c.App.ErrWriter, "saving to %s", path.Join(c.String(packageFlagDestination), fullVersion, destName+".tar.gz")) + return downloadPackageFromURL(c.Context, client.authFlow.httpClient, + c.String(packageFlagDestination), destName, + fullVersion, pkg.Package.Url, client.conf.Auth, + ) +}