Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

packages.config resolver #114

Merged
merged 8 commits into from
Sep 28, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 23 additions & 11 deletions internal/resolution/pm/nuget/cmd_factory.go
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ import (
"os/exec"
"path/filepath"
"regexp"
"sort"
"strings"
)

@@ -27,10 +28,6 @@ func (ExecPath) LookPath(file string) (string, error) {
return exec.LookPath(file)
}

type CmdFactory struct {
execPath IExecPath
}

var packagesConfigTemplate = `
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
@@ -44,17 +41,31 @@ var packagesConfigTemplate = `
</Project>
`

type CmdFactory struct {
execPath IExecPath
packageConfgRegex string
packagesConfigTemplate string
}

func NewCmdFactory(execPath IExecPath) CmdFactory {
return CmdFactory{
execPath: execPath,
packageConfgRegex: PackagesConfigRegex,
packagesConfigTemplate: packagesConfigTemplate,
}
}

func (cmdf CmdFactory) MakeInstallCmd(command string, file string) (*exec.Cmd, error) {

// If the file is a packages.config file, convert it to a .csproj file
// check regex with PackagesConfigRegex
packageConfig, err := regexp.Compile(PackagesConfigRegex)
packageConfig, err := regexp.Compile(cmdf.packageConfgRegex)
if err != nil {
return nil, err
}

if packageConfig.MatchString(file) {
file, err = convertPackagesConfigToCsproj(file)
file, err = cmdf.convertPackagesConfigToCsproj(file)
if err != nil {
return nil, err
}
@@ -92,14 +103,14 @@ type Package struct {
// that enables debricked to parse out transitive dependencies.
// This may add some additional framework dependencies that will not show up if
// we only scan the packages.config file.
func convertPackagesConfigToCsproj(filePath string) (string, error) {
func (cmdf CmdFactory) convertPackagesConfigToCsproj(filePath string) (string, error) {
packages, err := parsePackagesConfig(filePath)
if err != nil {
return "", err
}

targetFrameworksStr := collectUniqueTargetFrameworks(packages.Packages)
csprojContent, err := createCsprojContentWithTemplate(targetFrameworksStr, packages.Packages, packagesConfigTemplate)
csprojContent, err := cmdf.createCsprojContentWithTemplate(targetFrameworksStr, packages.Packages)
if err != nil {
return "", err
}
@@ -147,11 +158,12 @@ func collectUniqueTargetFrameworks(packages []Package) string {
}
}

sort.Strings(targetFrameworks) // Sort the targetFrameworks slice

return strings.Join(targetFrameworks, ";")
}

func createCsprojContentWithTemplate(targetFrameworksStr string, packages []Package, tmpl string) (string, error) {
tmplParsed, err := template.New("csproj").Parse(tmpl)
func (cmdf CmdFactory) createCsprojContentWithTemplate(targetFrameworksStr string, packages []Package) (string, error) {
tmplParsed, err := template.New("csproj").Parse(cmdf.packagesConfigTemplate)
if err != nil {
return "", err
}
153 changes: 124 additions & 29 deletions internal/resolution/pm/nuget/cmd_factory_test.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package nuget

import (
"errors"
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
)

func TestMakeInstallCmd(t *testing.T) {
nugetCommand := "dotnet"
cmd, err := CmdFactory{
execPath: ExecPath{},
}.MakeInstallCmd(nugetCommand, "file")
cmd, err := NewCmdFactory(
ExecPath{},
).MakeInstallCmd(nugetCommand, "file")
assert.NoError(t, err)
assert.NotNil(t, cmd)
args := cmd.Args
@@ -21,9 +23,9 @@ func TestMakeInstallCmd(t *testing.T) {

func TestMakeInstallCmdPackagsConfig(t *testing.T) {
nugetCommand := "dotnet"
cmd, err := CmdFactory{
execPath: ExecPath{},
}.MakeInstallCmd(nugetCommand, "testdata/valid/packages.config")
cmd, err := NewCmdFactory(
ExecPath{},
).MakeInstallCmd(nugetCommand, "testdata/valid/packages.config")
assert.NoError(t, err)
assert.NotNil(t, cmd)
args := cmd.Args
@@ -127,28 +129,6 @@ func TestWriteContentToCsprojFile(t *testing.T) {
}
}

func TestConvertPackagesConfigToCsproj(t *testing.T) {
tests := []struct {
filePath string
wantError bool
}{
{"testdata/valid/packages.config", false},
{"testdata/invalid/packages.config", true},
}

for _, tt := range tests {
_, err := convertPackagesConfigToCsproj(tt.filePath)
if (err != nil) != tt.wantError {
t.Errorf("convertPackagesConfigToCsproj(%q) = %v, want error: %v", tt.filePath, err, tt.wantError)
}
}

// Cleanup: Remove the created .csproj file
if err := os.Remove("testdata/valid/packages.config.csproj"); err != nil {
t.Fatalf("Failed to remove test file: %v", err)
}
}

func TestWriteContentToCsprojFileErr(t *testing.T) {
tests := []struct {
name string
@@ -264,10 +244,125 @@ func TestCreateCsprojContent(t *testing.T) {

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
_, err := createCsprojContentWithTemplate(test.targetFrameworksStr, test.packages, test.tmpl)
cmd := CmdFactory{
execPath: ExecPath{},
packageConfgRegex: PackagesConfigRegex,
packagesConfigTemplate: test.tmpl,
}
_, err := cmd.createCsprojContentWithTemplate(test.targetFrameworksStr, test.packages)
if (err != nil) != test.shouldFail {
t.Errorf("createCsprojContentWithTemplate() error = %v, shouldFail = %v", err, test.shouldFail)
}
})
}
}

func TestMakeInstallCmdBadPackagesConfigRegex(t *testing.T) {
nugetCommand := "dotnet"
cmd, err := CmdFactory{
execPath: ExecPath{},
packageConfgRegex: "[",
}.MakeInstallCmd(nugetCommand, "file")

assert.Error(t, err)
assert.Nil(t, cmd)
}

func TestMakeInstallCmdNotAccessToFile(t *testing.T) {
nugetCommand := "dotnet"
tempDir, err := os.MkdirTemp("", "TestMakeInstallCmdNotAccessToFile")
if err != nil {
panic(err)
}
defer os.RemoveAll(tempDir)

filePath := filepath.Join(tempDir, "packages.config")

file, err := os.Create(filePath)
if err != nil {
panic(err)
}
defer file.Close()

file.Chmod(0222) // write-only permissions

_, err = NewCmdFactory(
ExecPath{},
).MakeInstallCmd(nugetCommand, file.Name())

assert.Error(t, err)
}

type ExecPathErr struct {
}

func (ExecPathErr) LookPath(file string) (string, error) {
return "", errors.New("error")
}

func TestMakeInstallCmdExecPathError(t *testing.T) {
nugetCommand := "dotnet"
cmd, err := CmdFactory{
execPath: ExecPathErr{},
packageConfgRegex: PackagesConfigRegex,
}.MakeInstallCmd(nugetCommand, "file")

assert.Error(t, err)
assert.Nil(t, cmd)
}

func TestConvertPackagesConfigToCsproj(t *testing.T) {
tests := []struct {
name string
filePath string
wantError bool
packagesConfigTemplate string
setup func() string // function to set up the test environment
teardown func() // function to clean up after the test
}{
{"Valid packages config", "testdata/valid/packages.config", false, packagesConfigTemplate, nil, nil},
{"Invalid packages config", "testdata/invalid/packages.config", true, packagesConfigTemplate, nil, nil},
{"Bad template", "testdata/valid/packages.config", true, "{{.TargetFramewo", nil, nil},
{"File without write premisions", "testdata/valid/packages.config", true, packagesConfigTemplate,
func() string {
filename := "testdata/valid/packages.config.csproj"
file, err := os.Create(filename)
if err != nil {
t.Fatal(err)
}
defer file.Close()
file.Chmod(0222) // write-only permissions
return file.Name()
},
nil,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.setup != nil {
tt.setup() // set up the environment for the test
}

if tt.teardown != nil {
defer tt.teardown() // clean up after the test
}

cmd := CmdFactory{
execPath: ExecPath{},
packageConfgRegex: PackagesConfigRegex,
packagesConfigTemplate: tt.packagesConfigTemplate,
}
_, err := cmd.convertPackagesConfigToCsproj(tt.filePath)
if (err != nil) != tt.wantError {
t.Errorf("convertPackagesConfigToCsproj(%q) = %v, want error: %v", tt.filePath, err, tt.wantError)
}

})
}

// Cleanup: Remove the created .csproj file
if err := os.Remove("testdata/valid/packages.config.csproj"); err != nil {
t.Fatalf("Failed to remove test file: %v", err)
}
}
4 changes: 1 addition & 3 deletions internal/resolution/pm/nuget/strategy.go
Original file line number Diff line number Diff line change
@@ -14,9 +14,7 @@ func (s Strategy) Invoke() ([]job.IJob, error) {
jobs = append(jobs, NewJob(
file,
true,
CmdFactory{
execPath: ExecPath{},
},
NewCmdFactory(ExecPath{}),
),
)
}