From b61ec064ddb35ae37dea3be78cf0eb578ecee8a2 Mon Sep 17 00:00:00 2001 From: Hadron Collider Date: Fri, 1 Apr 2022 12:54:33 +0300 Subject: [PATCH] feat(project): cargo and poetry support --- docs/docs/segment-project.md | 7 +++- src/go.mod | 2 +- src/segments/project.go | 79 ++++++++++++++++++++++++++++++------ src/segments/project_test.go | 29 +++++++++++-- 4 files changed, 97 insertions(+), 20 deletions(-) diff --git a/docs/docs/segment-project.md b/docs/docs/segment-project.md index e8a12077..31f8f3d1 100644 --- a/docs/docs/segment-project.md +++ b/docs/docs/segment-project.md @@ -11,6 +11,8 @@ Display the current version of your project defined in the package file. Supports: - Node.js project (`package.json`) +- Cargo project (`Cargo.toml`) +- Poetry project (`pyproject.toml`) ## Sample Configuration @@ -21,7 +23,7 @@ Supports: "powerline_symbol": "\uE0B0", "foreground": "#193549", "background": "#ffeb3b", - "template": " {{ if .Error }}{{ .Error }}{{ else }}{{ if .Version }}\uf487 {{.Version}}{{ end }}{{ end }} " + "template": " {{ if .Error }}{{ .Error }}{{ else }}{{ if .Version }}\uf487 {{.Version}}{{ end }} {{ if .Name }}{{ .Name }}{{ end }}{{ end }} " } ``` @@ -30,7 +32,7 @@ Supports: :::note default template ``` template -{{ if .Error }}{{ .Error }}{{ else }}{{ if .Version }}\uf487 {{.Version}}{{ end }}{{ end }} + {{ if .Error }}{{ .Error }}{{ else }}{{ if .Version }}\uf487 {{.Version}}{{ end }} {{ if .Name }}{{ .Name }}{{ end }}{{ end }} ``` ::: @@ -38,5 +40,6 @@ Supports: ### Properties - `.Version`: `string` - The version of your project +- `.Name`: `string` - The name of your project [templates]: /docs/config-templates diff --git a/src/go.mod b/src/go.mod index 9f59a9b6..62cd8828 100644 --- a/src/go.mod +++ b/src/go.mod @@ -40,7 +40,7 @@ require ( ) require ( - github.com/BurntSushi/toml v1.0.0 // indirect + github.com/BurntSushi/toml v1.0.0 github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect diff --git a/src/segments/project.go b/src/segments/project.go index 58a0f25a..b269c354 100644 --- a/src/segments/project.go +++ b/src/segments/project.go @@ -4,18 +4,33 @@ import ( "encoding/json" "oh-my-posh/environment" "oh-my-posh/properties" + + "github.com/BurntSushi/toml" ) type ProjectItem struct { Name string File string - Fetcher func(item ProjectItem) string + Fetcher func(item ProjectItem) (string, string) } -type NodePackageJSON struct { - Name string `json:"name"` - Description string `json:"description"` - Version string `json:"version"` +type ProjectData struct { + Version string + Name string +} + +// Rust Cargo package +type CargoTOML struct { + Package ProjectData +} + +// Python Poetry package +type PyProjectTOML struct { + Tool PyProjectToolTOML +} + +type PyProjectToolTOML struct { + Poetry ProjectData } type Project struct { @@ -23,8 +38,9 @@ type Project struct { env environment.Environment projects []*ProjectItem - Version string Error string + + ProjectData } func (n *Project) Enabled() bool { @@ -39,7 +55,7 @@ func (n *Project) Enabled() bool { } func (n *Project) Template() string { - return " {{ if .Error }}{{ .Error }}{{ else }}{{ if .Version }}\uf487 {{.Version}}{{ end }}{{ end }} " + return " {{ if .Error }}{{ .Error }}{{ else }}{{ if .Version }}\uf487 {{.Version}}{{ end }} {{ if .Name }}{{ .Name }}{{ end }}{{ end }} " } func (n *Project) Init(props properties.Properties, env environment.Environment) { @@ -50,14 +66,25 @@ func (n *Project) Init(props properties.Properties, env environment.Environment) { Name: "node", File: "package.json", - Fetcher: n.getNodePackageVersion, + Fetcher: n.getNodePackage, + }, + { + Name: "cargo", + File: "Cargo.toml", + Fetcher: n.getCargoPackage, + }, + { + Name: "poetry", + File: "pyproject.toml", + Fetcher: n.getPoetryPackage, }, } n.Version = "" + n.Name = "" for _, item := range n.projects { if n.hasProjectFile(item) { - n.Version = item.Fetcher(*item) + n.Version, n.Name = item.Fetcher(*item) break } } @@ -67,15 +94,41 @@ func (n *Project) hasProjectFile(p *ProjectItem) bool { return n.env.HasFiles(p.File) } -func (n *Project) getNodePackageVersion(item ProjectItem) string { +func (n *Project) getNodePackage(item ProjectItem) (string, string) { content := n.env.FileContent(item.File) - var data NodePackageJSON + var data ProjectData err := json.Unmarshal([]byte(content), &data) if err != nil { n.Error = err.Error() - return "" + return "", "" } - return data.Version + return data.Version, data.Name +} + +func (n *Project) getCargoPackage(item ProjectItem) (string, string) { + content := n.env.FileContent(item.File) + + var data CargoTOML + _, err := toml.Decode(content, &data) + if err != nil { + n.Error = err.Error() + return "", "" + } + + return data.Package.Version, data.Package.Name +} + +func (n *Project) getPoetryPackage(item ProjectItem) (string, string) { + content := n.env.FileContent(item.File) + + var data PyProjectTOML + _, err := toml.Decode(content, &data) + if err != nil { + n.Error = err.Error() + return "", "" + } + + return data.Tool.Poetry.Version, data.Tool.Poetry.Name } diff --git a/src/segments/project_test.go b/src/segments/project_test.go index 4e096eba..ab1b1451 100644 --- a/src/segments/project_test.go +++ b/src/segments/project_test.go @@ -7,6 +7,8 @@ import ( "testing" "github.com/alecthomas/assert" + + testify_mock "github.com/stretchr/testify/mock" ) type MockData struct { @@ -20,17 +22,36 @@ type MockData struct { func getMockedPackageEnv(tc *MockData) (*mock.MockedEnvironment, properties.Map) { env := new(mock.MockedEnvironment) props := properties.Map{} - env.On("HasFiles", tc.File).Return(true) + env.On("HasFiles", testify_mock.Anything).Run(func(args testify_mock.Arguments) { + for _, c := range env.ExpectedCalls { + if c.Method == "HasFiles" { + c.ReturnArguments = testify_mock.Arguments{args.Get(0).(string) == tc.File} + } + } + }) env.On("FileContent", tc.File).Return(tc.PackageContents) return env, props } func TestPackage(t *testing.T) { cases := []*MockData{ - {Case: "1.0.0", ExpectedString: "\uf487 1.0.0", Name: "node", File: "package.json", PackageContents: "{\"version\":\"1.0.0\"}"}, - {Case: "3.2.1", ExpectedString: "\uf487 3.2.1", Name: "node", File: "package.json", PackageContents: "{\"version\":\"3.2.1\"}"}, - {Case: "No version present", ExpectedString: "", Name: "node", File: "package.json", PackageContents: "{}"}, + {Case: "1.0.0 node.js", ExpectedString: "\uf487 1.0.0 test", Name: "node", File: "package.json", PackageContents: "{\"version\":\"1.0.0\",\"name\":\"test\"}"}, + {Case: "3.2.1 node.js", ExpectedString: "\uf487 3.2.1 test", Name: "node", File: "package.json", PackageContents: "{\"version\":\"3.2.1\",\"name\":\"test\"}"}, + {Case: "1.0.0 cargo", ExpectedString: "\uf487 1.0.0 test", Name: "cargo", File: "Cargo.toml", PackageContents: "[package]\nname=\"test\"\nversion=\"1.0.0\"\n"}, + {Case: "3.2.1 cargo", ExpectedString: "\uf487 3.2.1 test", Name: "cargo", File: "Cargo.toml", PackageContents: "[package]\nname=\"test\"\nversion=\"3.2.1\"\n"}, + {Case: "1.0.0 poetry", ExpectedString: "\uf487 1.0.0 test", Name: "poetry", File: "pyproject.toml", PackageContents: "[tool.poetry]\nname=\"test\"\nversion=\"1.0.0\"\n"}, + {Case: "3.2.1 poetry", ExpectedString: "\uf487 3.2.1 test", Name: "poetry", File: "pyproject.toml", PackageContents: "[tool.poetry]\nname=\"test\"\nversion=\"3.2.1\"\n"}, + {Case: "No version present node.js", ExpectedString: "test", Name: "node", File: "package.json", PackageContents: "{\"name\":\"test\"}"}, + {Case: "No version present cargo", ExpectedString: "test", Name: "cargo", File: "Cargo.toml", PackageContents: "[package]\nname=\"test\"\n"}, + {Case: "No version present poetry", ExpectedString: "test", Name: "poetry", File: "pyproject.toml", PackageContents: "[tool.poetry]\nname=\"test\"\n"}, + {Case: "No name present node.js", ExpectedString: "\uf487 1.0.0", Name: "node", File: "package.json", PackageContents: "{\"version\":\"1.0.0\"}"}, + {Case: "No name present cargo", ExpectedString: "\uf487 1.0.0", Name: "cargo", File: "Cargo.toml", PackageContents: "[package]\nversion=\"1.0.0\"\n"}, + {Case: "No name present poetry", ExpectedString: "\uf487 1.0.0", Name: "poetry", File: "pyproject.toml", PackageContents: "[tool.poetry]\nversion=\"1.0.0\"\n"}, + {Case: "Empty project package node.js", ExpectedString: "", Name: "node", File: "package.json", PackageContents: "{}"}, + {Case: "Empty project package cargo", ExpectedString: "", Name: "cargo", File: "Cargo.toml", PackageContents: ""}, + {Case: "Empty project package poetry", ExpectedString: "", Name: "poetry", File: "pyproject.toml", PackageContents: ""}, {Case: "Invalid json", ExpectedString: "invalid character '}' looking for beginning of value", Name: "node", File: "package.json", PackageContents: "}"}, + {Case: "Invalid toml", ExpectedString: "toml: line 1: unexpected end of table name (table names cannot be empty)", Name: "cargo", File: "Cargo.toml", PackageContents: "["}, } for _, tc := range cases {