mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2024-12-26 19:39:39 -08:00
parent
0cd8bfe6b6
commit
fb698dd20a
|
@ -14,6 +14,7 @@ Supports:
|
|||
- Cargo project (`Cargo.toml`)
|
||||
- Poetry project (`pyproject.toml`)
|
||||
- PHP project (`composer.json`)
|
||||
- Any nuspec based project (`*.nuspec`, first file match info is displayed)
|
||||
|
||||
## Sample Configuration
|
||||
|
||||
|
|
|
@ -2,8 +2,10 @@ package segments
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"oh-my-posh/environment"
|
||||
"oh-my-posh/properties"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
)
|
||||
|
@ -33,6 +35,14 @@ type PyProjectToolTOML struct {
|
|||
Poetry ProjectData
|
||||
}
|
||||
|
||||
type NuSpec struct {
|
||||
XMLName xml.Name `xml:"package"`
|
||||
MetaData struct {
|
||||
Title string `xml:"title"`
|
||||
Version string `xml:"version"`
|
||||
} `xml:"metadata"`
|
||||
}
|
||||
|
||||
type Project struct {
|
||||
props properties.Properties
|
||||
env environment.Environment
|
||||
|
@ -44,14 +54,13 @@ type Project struct {
|
|||
}
|
||||
|
||||
func (n *Project) Enabled() bool {
|
||||
var enabled = false
|
||||
for _, item := range n.projects {
|
||||
if !enabled {
|
||||
enabled = n.hasProjectFile(item)
|
||||
if n.hasProjectFile(item) {
|
||||
n.Version, n.Name = item.Fetcher(*item)
|
||||
return len(n.Version) > 0 || len(n.Name) > 0
|
||||
}
|
||||
}
|
||||
|
||||
return enabled
|
||||
return false
|
||||
}
|
||||
|
||||
func (n *Project) Template() string {
|
||||
|
@ -83,15 +92,11 @@ func (n *Project) Init(props properties.Properties, env environment.Environment)
|
|||
File: "composer.json",
|
||||
Fetcher: n.getNodePackage,
|
||||
},
|
||||
}
|
||||
|
||||
n.Version = ""
|
||||
n.Name = ""
|
||||
for _, item := range n.projects {
|
||||
if n.hasProjectFile(item) {
|
||||
n.Version, n.Name = item.Fetcher(*item)
|
||||
break
|
||||
}
|
||||
{
|
||||
Name: "nuspec",
|
||||
File: "*.nuspec",
|
||||
Fetcher: n.getNuSpecPackage,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,3 +142,24 @@ func (n *Project) getPoetryPackage(item ProjectItem) (string, string) {
|
|||
|
||||
return data.Tool.Poetry.Version, data.Tool.Poetry.Name
|
||||
}
|
||||
|
||||
func (n *Project) getNuSpecPackage(item ProjectItem) (string, string) {
|
||||
files := n.env.LsDir(n.env.Pwd())
|
||||
var content string
|
||||
// get the first match only
|
||||
for _, file := range files {
|
||||
if filepath.Ext(file.Name()) == ".nuspec" {
|
||||
content = n.env.FileContent(file.Name())
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var data NuSpec
|
||||
err := xml.Unmarshal([]byte(content), &data)
|
||||
if err != nil {
|
||||
n.Error = err.Error()
|
||||
return "", ""
|
||||
}
|
||||
|
||||
return data.MetaData.Version, data.MetaData.Title
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
package segments
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"oh-my-posh/mock"
|
||||
"oh-my-posh/properties"
|
||||
"testing"
|
||||
|
@ -11,55 +12,257 @@ import (
|
|||
testify_mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
type MockData struct {
|
||||
Name string
|
||||
Case string
|
||||
ExpectedString string
|
||||
PackageContents string
|
||||
File string
|
||||
type MockDirEntry struct {
|
||||
name string
|
||||
isDir bool
|
||||
fileMode fs.FileMode
|
||||
fileInfo fs.FileInfo
|
||||
err error
|
||||
}
|
||||
|
||||
func getMockedPackageEnv(tc *MockData) (*mock.MockedEnvironment, properties.Map) {
|
||||
env := new(mock.MockedEnvironment)
|
||||
props := properties.Map{}
|
||||
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 (m *MockDirEntry) Name() string {
|
||||
return m.name
|
||||
}
|
||||
|
||||
func (m *MockDirEntry) IsDir() bool {
|
||||
return m.isDir
|
||||
}
|
||||
|
||||
func (m *MockDirEntry) Type() fs.FileMode {
|
||||
return m.fileMode
|
||||
}
|
||||
|
||||
func (m *MockDirEntry) Info() (fs.FileInfo, error) {
|
||||
return m.fileInfo, m.err
|
||||
}
|
||||
|
||||
func TestPackage(t *testing.T) {
|
||||
cases := []*MockData{
|
||||
{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: "1.0.0 php", ExpectedString: "\uf487 1.0.0 test", Name: "php", File: "composer.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: "["},
|
||||
cases := []struct {
|
||||
Name string
|
||||
Case string
|
||||
File string
|
||||
PackageContents string
|
||||
ExpectedString string
|
||||
ExpectedEnabled bool
|
||||
}{
|
||||
{
|
||||
Case: "1.0.0 node.js",
|
||||
ExpectedEnabled: true,
|
||||
ExpectedString: "\uf487 1.0.0 test",
|
||||
Name: "node",
|
||||
File: "package.json",
|
||||
PackageContents: "{\"version\":\"1.0.0\",\"name\":\"test\"}",
|
||||
},
|
||||
{
|
||||
Case: "1.0.0 php",
|
||||
ExpectedEnabled: true,
|
||||
ExpectedString: "\uf487 1.0.0 test",
|
||||
Name: "php",
|
||||
File: "composer.json",
|
||||
PackageContents: "{\"version\":\"1.0.0\",\"name\":\"test\"}",
|
||||
},
|
||||
{
|
||||
Case: "3.2.1 node.js",
|
||||
ExpectedEnabled: true,
|
||||
ExpectedString: "\uf487 3.2.1 test",
|
||||
Name: "node", File: "package.json",
|
||||
PackageContents: "{\"version\":\"3.2.1\",\"name\":\"test\"}",
|
||||
},
|
||||
{
|
||||
Case: "1.0.0 cargo",
|
||||
ExpectedEnabled: true,
|
||||
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",
|
||||
ExpectedEnabled: true,
|
||||
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",
|
||||
ExpectedEnabled: true,
|
||||
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",
|
||||
ExpectedEnabled: true,
|
||||
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",
|
||||
ExpectedEnabled: true,
|
||||
ExpectedString: "test",
|
||||
Name: "node",
|
||||
File: "package.json",
|
||||
PackageContents: "{\"name\":\"test\"}",
|
||||
},
|
||||
{
|
||||
Case: "No version present cargo",
|
||||
ExpectedEnabled: true,
|
||||
ExpectedString: "test",
|
||||
Name: "cargo",
|
||||
File: "Cargo.toml",
|
||||
PackageContents: "[package]\nname=\"test\"\n",
|
||||
},
|
||||
{
|
||||
Case: "No version present poetry",
|
||||
ExpectedEnabled: true,
|
||||
ExpectedString: "test",
|
||||
Name: "poetry",
|
||||
File: "pyproject.toml",
|
||||
PackageContents: "[tool.poetry]\nname=\"test\"\n",
|
||||
},
|
||||
{
|
||||
Case: "No name present node.js",
|
||||
ExpectedEnabled: true,
|
||||
ExpectedString: "\uf487 1.0.0",
|
||||
Name: "node",
|
||||
File: "package.json",
|
||||
PackageContents: "{\"version\":\"1.0.0\"}",
|
||||
},
|
||||
{
|
||||
Case: "No name present cargo",
|
||||
ExpectedEnabled: true,
|
||||
ExpectedString: "\uf487 1.0.0",
|
||||
Name: "cargo",
|
||||
File: "Cargo.toml",
|
||||
PackageContents: "[package]\nversion=\"1.0.0\"\n",
|
||||
},
|
||||
{
|
||||
Case: "No name present poetry",
|
||||
ExpectedEnabled: true,
|
||||
ExpectedString: "\uf487 1.0.0",
|
||||
Name: "poetry",
|
||||
File: "pyproject.toml",
|
||||
PackageContents: "[tool.poetry]\nversion=\"1.0.0\"\n",
|
||||
},
|
||||
{
|
||||
Case: "Empty project package node.js",
|
||||
ExpectedEnabled: false,
|
||||
Name: "node",
|
||||
File: "package.json",
|
||||
PackageContents: "{}",
|
||||
},
|
||||
{
|
||||
Case: "Empty project package cargo",
|
||||
Name: "cargo",
|
||||
File: "Cargo.toml",
|
||||
PackageContents: "",
|
||||
},
|
||||
{
|
||||
Case: "Empty project package poetry",
|
||||
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 {
|
||||
env, props := getMockedPackageEnv(tc)
|
||||
env := new(mock.MockedEnvironment)
|
||||
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)
|
||||
pkg := &Project{}
|
||||
pkg.Init(props, env)
|
||||
assert.True(t, pkg.Enabled(), fmt.Sprintf("Failed in case: %s", tc.Case))
|
||||
assert.Equal(t, tc.ExpectedString, renderTemplate(env, pkg.Template(), pkg), fmt.Sprintf("Failed in case: %s", tc.Case))
|
||||
pkg.Init(properties.Map{}, env)
|
||||
assert.Equal(t, tc.ExpectedEnabled, pkg.Enabled(), tc.Case)
|
||||
if tc.ExpectedEnabled {
|
||||
assert.Equal(t, tc.ExpectedString, renderTemplate(env, pkg.Template(), pkg), tc.Case)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNuspecPackage(t *testing.T) {
|
||||
cases := []struct {
|
||||
Case string
|
||||
HasFiles bool
|
||||
FileName string
|
||||
ExpectedString string
|
||||
ExpectedEnabled bool
|
||||
}{
|
||||
{
|
||||
Case: "valid file",
|
||||
FileName: "../test/valid.nuspec",
|
||||
HasFiles: true,
|
||||
ExpectedEnabled: true,
|
||||
ExpectedString: "\uf487 0.1.0 Az.Compute",
|
||||
},
|
||||
{
|
||||
Case: "invalid file",
|
||||
FileName: "../test/invalid.nuspec",
|
||||
HasFiles: true,
|
||||
ExpectedEnabled: false,
|
||||
},
|
||||
{
|
||||
Case: "no info in file",
|
||||
FileName: "../test/empty.nuspec",
|
||||
HasFiles: true,
|
||||
ExpectedEnabled: false,
|
||||
},
|
||||
{
|
||||
Case: "no files",
|
||||
HasFiles: false,
|
||||
ExpectedEnabled: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
env := new(mock.MockedEnvironment)
|
||||
env.On("HasFiles", testify_mock.Anything).Run(func(args testify_mock.Arguments) {
|
||||
for _, c := range env.ExpectedCalls {
|
||||
if c.Method != "HasFiles" {
|
||||
continue
|
||||
}
|
||||
if args.Get(0).(string) == "*.nuspec" {
|
||||
c.ReturnArguments = testify_mock.Arguments{tc.HasFiles}
|
||||
continue
|
||||
}
|
||||
c.ReturnArguments = testify_mock.Arguments{false}
|
||||
}
|
||||
})
|
||||
env.On("Pwd").Return("posh")
|
||||
env.On("LsDir", "posh").Return([]fs.DirEntry{
|
||||
&MockDirEntry{
|
||||
name: tc.FileName,
|
||||
},
|
||||
})
|
||||
content, _ := ioutil.ReadFile(tc.FileName)
|
||||
env.On("FileContent", tc.FileName).Return(string(content))
|
||||
pkg := &Project{}
|
||||
pkg.Init(properties.Map{}, env)
|
||||
assert.Equal(t, tc.ExpectedEnabled, pkg.Enabled(), tc.Case)
|
||||
if tc.ExpectedEnabled {
|
||||
assert.Equal(t, tc.ExpectedString, renderTemplate(env, pkg.Template(), pkg), tc.Case)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
31
src/test/empty.nuspec
Normal file
31
src/test/empty.nuspec
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Az.Compute</id>
|
||||
<authors>Microsoft Corporation</authors>
|
||||
<owners>Microsoft Corporation</owners>
|
||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||
<licenseUrl>https://aka.ms/azps-license</licenseUrl>
|
||||
<projectUrl>https://github.com/Azure/azure-powershell</projectUrl>
|
||||
<description>Microsoft Azure PowerShell: $(service-name) cmdlets</description>
|
||||
<releaseNotes></releaseNotes>
|
||||
<copyright>Microsoft Corporation. All rights reserved.</copyright>
|
||||
<tags>Azure ResourceManager ARM PSModule $(service-name)</tags>
|
||||
<dependencies>
|
||||
<dependency id="Az.Accounts" version="2.2.3" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="Az.Compute.format.ps1xml" />
|
||||
<file src="Az.Compute.psd1" />
|
||||
<file src="Az.Compute.psm1" />
|
||||
<!-- https://github.com/NuGet/Home/issues/3584 -->
|
||||
<file src="bin/Az.Compute.private.dll" target="bin" />
|
||||
<file src="bin\Az.Compute.private.deps.json" target="bin" />
|
||||
<file src="internal\**\*.*" exclude="internal\README.md" target="internal" />
|
||||
<file src="custom\**\*.*" exclude="custom\README.md;custom\**\*.cs" target="custom" />
|
||||
<file src="docs\**\*.md" exclude="docs\README.md" target="docs" />
|
||||
<file src="exports\**\ProxyCmdletDefinitions.ps1" target="exports" />
|
||||
<file src="utils\**\*.*" target="utils" />
|
||||
</files>
|
||||
</package>
|
1
src/test/invalid.nuspec
Normal file
1
src/test/invalid.nuspec
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
33
src/test/valid.nuspec
Normal file
33
src/test/valid.nuspec
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Az.Compute</id>
|
||||
<title>Az.Compute</title>
|
||||
<version>0.1.0</version>
|
||||
<authors>Microsoft Corporation</authors>
|
||||
<owners>Microsoft Corporation</owners>
|
||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||
<licenseUrl>https://aka.ms/azps-license</licenseUrl>
|
||||
<projectUrl>https://github.com/Azure/azure-powershell</projectUrl>
|
||||
<description>Microsoft Azure PowerShell: $(service-name) cmdlets</description>
|
||||
<releaseNotes></releaseNotes>
|
||||
<copyright>Microsoft Corporation. All rights reserved.</copyright>
|
||||
<tags>Azure ResourceManager ARM PSModule $(service-name)</tags>
|
||||
<dependencies>
|
||||
<dependency id="Az.Accounts" version="2.2.3" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="Az.Compute.format.ps1xml" />
|
||||
<file src="Az.Compute.psd1" />
|
||||
<file src="Az.Compute.psm1" />
|
||||
<!-- https://github.com/NuGet/Home/issues/3584 -->
|
||||
<file src="bin/Az.Compute.private.dll" target="bin" />
|
||||
<file src="bin\Az.Compute.private.deps.json" target="bin" />
|
||||
<file src="internal\**\*.*" exclude="internal\README.md" target="internal" />
|
||||
<file src="custom\**\*.*" exclude="custom\README.md;custom\**\*.cs" target="custom" />
|
||||
<file src="docs\**\*.md" exclude="docs\README.md" target="docs" />
|
||||
<file src="exports\**\ProxyCmdletDefinitions.ps1" target="exports" />
|
||||
<file src="utils\**\*.*" target="utils" />
|
||||
</files>
|
||||
</package>
|
Loading…
Reference in a new issue