Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0674681
commit 8791965
Showing
6 changed files
with
528 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,220 @@ | ||
package segments | ||
|
||
import ( | ||
"crypto/sha1" | ||
"encoding/hex" | ||
"encoding/json" | ||
"fmt" | ||
"path/filepath" | ||
|
||
"github.com/jandedobbeleer/oh-my-posh/src/platform" | ||
"github.com/jandedobbeleer/oh-my-posh/src/properties" | ||
"gopkg.in/yaml.v3" | ||
) | ||
|
||
const ( | ||
FetchStack properties.Property = "fetch_stack" | ||
FetchAbout properties.Property = "fetch_about" | ||
|
||
JSON string = "json" | ||
YAML string = "yaml" | ||
|
||
pulumiJSON string = "Pulumi.json" | ||
pulumiYAML string = "Pulumi.yaml" | ||
) | ||
|
||
type Pulumi struct { | ||
props properties.Properties | ||
env platform.Environment | ||
|
||
Stack string | ||
Name string | ||
|
||
workspaceSHA1 string | ||
|
||
backend | ||
} | ||
|
||
type backend struct { | ||
URL string `json:"url"` | ||
User string `json:"user"` | ||
} | ||
|
||
type pulumiFileSpec struct { | ||
Name string `yaml:"name" json:"name"` | ||
} | ||
|
||
type pulumiWorkSpaceFileSpec struct { | ||
Stack string `json:"stack"` | ||
} | ||
|
||
func (p *Pulumi) Template() string { | ||
return "\U000f0d46 {{ .Stack }}{{if .User }} :: {{ .User }}@{{ end }}{{ if .URL }}{{ .URL }}{{ end }}" | ||
} | ||
|
||
func (p *Pulumi) Init(props properties.Properties, env platform.Environment) { | ||
p.props = props | ||
p.env = env | ||
} | ||
|
||
func (p *Pulumi) Enabled() bool { | ||
if !p.env.HasCommand("pulumi") { | ||
return false | ||
} | ||
|
||
err := p.getProjectName() | ||
if err != nil { | ||
p.env.Error(err) | ||
return false | ||
} | ||
|
||
if p.props.GetBool(FetchStack, false) { | ||
p.getPulumiStackName() | ||
} | ||
|
||
if p.props.GetBool(FetchAbout, false) { | ||
p.getPulumiAbout() | ||
} | ||
|
||
return true | ||
} | ||
|
||
func (p *Pulumi) getPulumiStackName() { | ||
if len(p.Name) == 0 || len(p.workspaceSHA1) == 0 { | ||
p.env.Debug("pulumi project name or workspace sha1 is empty") | ||
return | ||
} | ||
|
||
stackNameFile := p.Name + "-" + p.workspaceSHA1 + "-" + "workspace.json" | ||
|
||
homedir := p.env.Home() | ||
|
||
workspaceCacheDir := filepath.Join(homedir, ".pulumi", "workspaces") | ||
if !p.env.HasFolder(workspaceCacheDir) || !p.env.HasFilesInDir(workspaceCacheDir, stackNameFile) { | ||
return | ||
} | ||
|
||
workspaceCacheFile := filepath.Join(workspaceCacheDir, stackNameFile) | ||
workspaceCacheFileContent := p.env.FileContent(workspaceCacheFile) | ||
|
||
var pulumiWorkspaceSpec pulumiWorkSpaceFileSpec | ||
err := json.Unmarshal([]byte(workspaceCacheFileContent), &pulumiWorkspaceSpec) | ||
if err != nil { | ||
p.env.Error(fmt.Errorf("pulumi workspace file decode error")) | ||
return | ||
} | ||
|
||
p.env.DebugF("pulumi stack name: %s", pulumiWorkspaceSpec.Stack) | ||
p.Stack = pulumiWorkspaceSpec.Stack | ||
} | ||
|
||
func (p *Pulumi) getProjectName() error { | ||
var kind, fileName string | ||
for _, file := range []string{pulumiYAML, pulumiJSON} { | ||
if p.env.HasFiles(file) { | ||
fileName = file | ||
kind = filepath.Ext(file)[1:] | ||
} | ||
} | ||
|
||
if len(kind) == 0 { | ||
return fmt.Errorf("no pulumi spec file found") | ||
} | ||
|
||
var pulumiFileSpec pulumiFileSpec | ||
var err error | ||
|
||
pulumiFile := p.env.FileContent(fileName) | ||
|
||
switch kind { | ||
case YAML: | ||
err = yaml.Unmarshal([]byte(pulumiFile), &pulumiFileSpec) | ||
case JSON: | ||
err = json.Unmarshal([]byte(pulumiFile), &pulumiFileSpec) | ||
default: | ||
err = fmt.Errorf("unknown pulumi spec file format") | ||
} | ||
|
||
if err != nil { | ||
p.env.Error(err) | ||
return nil | ||
} | ||
|
||
p.Name = pulumiFileSpec.Name | ||
|
||
sha1HexString := func(value string) string { | ||
h := sha1.New() | ||
|
||
_, err := h.Write([]byte(value)) | ||
if err != nil { | ||
p.env.Error(err) | ||
return "" | ||
} | ||
|
||
return hex.EncodeToString(h.Sum(nil)) | ||
} | ||
|
||
p.workspaceSHA1 = sha1HexString(p.env.Pwd() + "/" + fileName) | ||
|
||
return nil | ||
} | ||
|
||
func (p *Pulumi) getPulumiAbout() { | ||
if len(p.Stack) == 0 { | ||
p.env.Error(fmt.Errorf("pulumi stack name is empty, use `fetch_stack` property to enable stack fetching")) | ||
return | ||
} | ||
|
||
cacheKey := "pulumi-" + p.Name + "-" + p.Stack + "-" + p.workspaceSHA1 + "-about" | ||
|
||
getAboutCache := func(key string) (*backend, error) { | ||
aboutBackend, OK := p.env.Cache().Get(key) | ||
if (!OK || len(aboutBackend) == 0) || (OK && len(aboutBackend) == 0) { | ||
return nil, fmt.Errorf("no data in cache") | ||
} | ||
|
||
var backend *backend | ||
err := json.Unmarshal([]byte(aboutBackend), &backend) | ||
if err != nil { | ||
p.env.DebugF("unable to decode about cache: %s", aboutBackend) | ||
p.env.Error(fmt.Errorf("pulling about cache decode error")) | ||
return nil, err | ||
} | ||
|
||
return backend, nil | ||
} | ||
|
||
aboutBackend, err := getAboutCache(cacheKey) | ||
if err == nil { | ||
p.backend = *aboutBackend | ||
return | ||
} | ||
|
||
aboutOutput, err := p.env.RunCommand("pulumi", "about", "--json") | ||
|
||
if err != nil { | ||
p.env.Error(fmt.Errorf("unable to get pulumi about output")) | ||
return | ||
} | ||
|
||
var about struct { | ||
Backend *backend `json:"backend"` | ||
} | ||
|
||
err = json.Unmarshal([]byte(aboutOutput), &about) | ||
if err != nil { | ||
p.env.Error(fmt.Errorf("pulumi about output decode error")) | ||
return | ||
} | ||
|
||
if about.Backend == nil { | ||
p.env.Debug("pulumi about backend is not set") | ||
return | ||
} | ||
|
||
p.backend = *about.Backend | ||
|
||
cacheTimeout := p.props.GetInt(properties.CacheTimeout, 43800) | ||
jso, _ := json.Marshal(about.Backend) | ||
p.env.Cache().Set(cacheKey, string(jso), cacheTimeout) | ||
} |
Oops, something went wrong.