Skip to content

Commit f9a0b87

Browse files
authored
feat: add a new providers bundled command (#164)
Signed-off-by: Diogenes Fernandes <diofeher@gmail.com>
1 parent 4fb20c2 commit f9a0b87

3 files changed

Lines changed: 149 additions & 0 deletions

File tree

internal/cmd/providers_command.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright (c) The OpenTofu Authors
2+
// SPDX-License-Identifier: MPL-2.0
3+
// Copyright (c) 2024 HashiCorp, Inc.
4+
// SPDX-License-Identifier: MPL-2.0
5+
6+
package cmd
7+
8+
import (
9+
"encoding/json"
10+
"flag"
11+
"fmt"
12+
"io/fs"
13+
"strings"
14+
15+
"github.com/mitchellh/cli"
16+
17+
"github.com/opentofu/tofu-ls/internal/schemas"
18+
)
19+
20+
type ProvidersBundledCommand struct {
21+
Ui cli.Ui
22+
FS fs.ReadDirFS
23+
24+
jsonOutput bool
25+
}
26+
27+
func (c *ProvidersBundledCommand) flags() *flag.FlagSet {
28+
fs := defaultFlagSet("providers bundled")
29+
30+
fs.BoolVar(&c.jsonOutput, "json", false, "output the provider list as JSON")
31+
32+
fs.Usage = func() { c.Ui.Error(c.Help()) }
33+
34+
return fs
35+
}
36+
37+
func (c *ProvidersBundledCommand) Run(args []string) int {
38+
f := c.flags()
39+
if err := f.Parse(args); err != nil {
40+
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s", err))
41+
return 1
42+
}
43+
44+
providers, err := schemas.ListBundledProviders(c.FS)
45+
if err != nil {
46+
c.Ui.Error(fmt.Sprintf("Error listing bundled providers: %s", err))
47+
return 1
48+
}
49+
50+
if len(providers) == 0 {
51+
c.Ui.Output("No bundled providers found.")
52+
return 0
53+
}
54+
55+
if c.jsonOutput {
56+
jsonOutput, err := json.MarshalIndent(providers, "", " ")
57+
if err != nil {
58+
c.Ui.Error(fmt.Sprintf("Error marshalling JSON: %s", err))
59+
return 1
60+
}
61+
c.Ui.Output(string(jsonOutput))
62+
return 0
63+
}
64+
65+
for _, p := range providers {
66+
c.Ui.Output(fmt.Sprintf("%s %s", p.Addr.ForDisplay(), p.Version))
67+
}
68+
return 0
69+
}
70+
71+
func (c *ProvidersBundledCommand) Help() string {
72+
helpText := `
73+
Usage: tofu-ls providers bundled [-json]
74+
75+
` + c.Synopsis() + "\n\n" + helpForFlags(c.flags())
76+
77+
return strings.TrimSpace(helpText)
78+
}
79+
80+
func (c *ProvidersBundledCommand) Synopsis() string {
81+
return "Lists the provider schemas bundled into tofu-ls binary"
82+
}

internal/schemas/schemas.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,66 @@ func (e SchemaNotAvailable) Error() string {
3434
return fmt.Sprintf("embedded schema not available for %s", e.Addr)
3535
}
3636

37+
type BundledProvider struct {
38+
Addr tfaddr.Provider
39+
Version *version.Version
40+
}
41+
42+
// ListBundledProviders returns a list of all bundled providers to the binary on the `data` folder.
43+
func ListBundledProviders(filesystem fs.ReadDirFS) ([]BundledProvider, error) {
44+
var providers []BundledProvider
45+
46+
// We only bundle the latest version of each provider, so we expect exactly one
47+
// version directory per provider. If there are more than one, that's an error
48+
// If there are zero, then that provider is not bundled and we skip it.
49+
hostname := tfaddr.DefaultProviderRegistryHost
50+
namespacePath := path.Join("data", hostname.String())
51+
namespaces, err := fs.ReadDir(filesystem, namespacePath)
52+
if err != nil {
53+
return nil, err
54+
}
55+
56+
for _, namespace := range namespaces {
57+
if !namespace.IsDir() {
58+
continue
59+
}
60+
61+
typePath := path.Join(namespacePath, namespace.Name())
62+
types, err := fs.ReadDir(filesystem, typePath)
63+
if err != nil {
64+
return nil, err
65+
}
66+
67+
for _, providerType := range types {
68+
if !providerType.IsDir() {
69+
continue
70+
}
71+
72+
versionPath := path.Join(typePath, providerType.Name())
73+
entries, err := fs.ReadDir(filesystem, versionPath)
74+
if err != nil {
75+
return nil, err
76+
}
77+
78+
if len(entries) != 1 {
79+
return nil, fmt.Errorf("%s/%s: expected one version, found %d", namespace.Name(), providerType.Name(), len(entries))
80+
}
81+
82+
v, err := version.NewVersion(entries[0].Name())
83+
if err != nil {
84+
return nil, err
85+
}
86+
87+
providers = append(providers, BundledProvider{
88+
Addr: tfaddr.NewProvider(hostname, namespace.Name(), providerType.Name()),
89+
Version: v,
90+
})
91+
}
92+
}
93+
94+
return providers, nil
95+
}
96+
3797
func FindProviderSchemaFile(filesystem fs.ReadDirFS, pAddr tfaddr.Provider) (*ProviderSchema, error) {
3898
providerPath := path.Join("data", pAddr.Hostname.String(), pAddr.Namespace, pAddr.Type)
3999

main.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/mitchellh/cli"
1212

1313
"github.com/opentofu/tofu-ls/internal/cmd"
14+
"github.com/opentofu/tofu-ls/internal/schemas"
1415
)
1516

1617
func main() {
@@ -44,6 +45,12 @@ func main() {
4445
Version: version,
4546
}, nil
4647
},
48+
"providers bundled": func() (cli.Command, error) {
49+
return &cmd.ProvidersBundledCommand{
50+
Ui: ui,
51+
FS: schemas.FS,
52+
}, nil
53+
},
4754
}
4855

4956
exitStatus, err := c.Run()

0 commit comments

Comments
 (0)