github.com/jfrog/jfrog-cli-go@v1.22.1-0.20200318093948-4826ef344ffd/artifactory/utils/nuget/solution/solution.go (about)

     1  package solution
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"github.com/jfrog/jfrog-cli-go/artifactory/utils/nuget/solution/project"
     7  	"github.com/jfrog/jfrog-client-go/artifactory/buildinfo"
     8  	"github.com/jfrog/jfrog-client-go/utils"
     9  	"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
    10  	"github.com/jfrog/jfrog-client-go/utils/log"
    11  	"io/ioutil"
    12  	"path/filepath"
    13  	"regexp"
    14  	"strings"
    15  )
    16  
    17  type Solution interface {
    18  	BuildInfo(module string) (*buildinfo.BuildInfo, error)
    19  	Marshal() ([]byte, error)
    20  	GetProjects() []project.Project
    21  }
    22  
    23  var projectRegExp *regexp.Regexp
    24  
    25  func Load(solutionPath, slnFile string) (Solution, error) {
    26  	solution := &solution{path: solutionPath, slnFile: slnFile}
    27  	err := solution.loadProjects()
    28  	return solution, err
    29  }
    30  
    31  type solution struct {
    32  	path string
    33  	// If there are more then one sln files in the directory,
    34  	// the user must specify as arguments the sln file that should be used.
    35  	slnFile  string
    36  	projects []project.Project
    37  }
    38  
    39  func (solution *solution) BuildInfo(module string) (*buildinfo.BuildInfo, error) {
    40  	buildInfo := &buildinfo.BuildInfo{}
    41  	var modules []buildinfo.Module
    42  	for _, project := range solution.projects {
    43  		// Get All project dependencies
    44  		dependencies, err := project.Extractor().AllDependencies()
    45  		if err != nil {
    46  			return nil, err
    47  		}
    48  		var projectDependencies []buildinfo.Dependency
    49  
    50  		for _, dep := range dependencies {
    51  			projectDependencies = append(projectDependencies, *dep)
    52  		}
    53  		module := buildinfo.Module{Id: getModuleId(module, project.Name()), Dependencies: projectDependencies}
    54  		modules = append(modules, module)
    55  	}
    56  	buildInfo.Modules = modules
    57  	return buildInfo, nil
    58  }
    59  
    60  func getModuleId(customModuleID, projectName string) string {
    61  	if customModuleID != "" {
    62  		return customModuleID
    63  	}
    64  	return projectName
    65  }
    66  
    67  func (solution *solution) Marshal() ([]byte, error) {
    68  	return json.Marshal(&struct {
    69  		Projects []project.Project `json:"projects,omitempty"`
    70  	}{
    71  		Projects: solution.projects,
    72  	})
    73  }
    74  
    75  func (solution *solution) GetProjects() []project.Project {
    76  	return solution.projects
    77  }
    78  
    79  func (solution *solution) loadProjects() error {
    80  	allProjects, err := solution.getProjectsFromSlns()
    81  	if err != nil {
    82  		return err
    83  	}
    84  
    85  	for _, projectLine := range allProjects {
    86  		projectName, csprojPath, err := parseProject(projectLine, solution.path)
    87  		if err != nil {
    88  			log.Error(err)
    89  			continue
    90  		}
    91  		proj, err := project.Load(projectName, filepath.Dir(csprojPath), csprojPath)
    92  		if err != nil {
    93  			log.Error(err)
    94  			continue
    95  		}
    96  		if proj.Extractor() != nil {
    97  			solution.projects = append(solution.projects, proj)
    98  		}
    99  	}
   100  	return nil
   101  }
   102  
   103  // Finds all the projects by reading the content of the the sln files. If sln file is not provided,
   104  // finds all sln files in the directory.
   105  // Returns a slice with all the projects in the solution.
   106  func (solution *solution) getProjectsFromSlns() ([]string, error) {
   107  	var allProjects []string
   108  	if solution.slnFile == "" {
   109  		slnFiles, err := fileutils.ListFilesWithExtension(solution.path, ".sln")
   110  		if err != nil {
   111  			return nil, err
   112  		}
   113  		for _, slnFile := range slnFiles {
   114  			projects, err := parseSlnFile(slnFile)
   115  			if err != nil {
   116  				return nil, err
   117  			}
   118  			allProjects = append(allProjects, projects...)
   119  		}
   120  	} else {
   121  		projects, err := parseSlnFile(filepath.Join(solution.path, solution.slnFile))
   122  		if err != nil {
   123  			return nil, err
   124  		}
   125  		allProjects = append(allProjects, projects...)
   126  	}
   127  	return allProjects, nil
   128  }
   129  
   130  // Parses the project line for the project name and path information.
   131  // Returns the name and path to csproj
   132  func parseProject(projectLine, path string) (projectName, csprojPath string, err error) {
   133  	parsedLine := strings.Split(projectLine, "=")
   134  	if len(parsedLine) <= 1 {
   135  		return "", "", errors.New("Unexpected project line format: " + projectLine)
   136  	}
   137  
   138  	projectInfo := strings.Split(parsedLine[1], ",")
   139  	if len(projectInfo) <= 2 {
   140  		return "", "", errors.New("Unexpected project information format: " + parsedLine[1])
   141  	}
   142  	projectName = removeQuotes(projectInfo[0])
   143  	csprojPath = filepath.Join(path, removeQuotes(projectInfo[1]))
   144  	return
   145  }
   146  
   147  // Parse the sln file according to project regular expression and returns all the founded lines by the regex
   148  func parseSlnFile(slnFile string) ([]string, error) {
   149  	var err error
   150  	if projectRegExp == nil {
   151  		projectRegExp, err = utils.GetRegExp(`Project\("(.*)\nEndProject`)
   152  		if err != nil {
   153  			return nil, err
   154  		}
   155  	}
   156  
   157  	content, err := ioutil.ReadFile(slnFile)
   158  	if err != nil {
   159  		return nil, err
   160  	}
   161  	projects := projectRegExp.FindAllString(string(content), -1)
   162  	return projects, nil
   163  }
   164  
   165  func removeQuotes(value string) string {
   166  	return strings.Trim(strings.TrimSpace(value), "\"")
   167  }