func analyzeSolution(pth string, analyzeProjects bool) (Model, error) {
	absPth, err := pathutil.AbsPath(pth)
	if err != nil {
		return Model{}, fmt.Errorf("Failed to expand path (%s), error: %s", pth, err)
	}

	fileName := filepath.Base(absPth)
	ext := filepath.Ext(absPth)
	fileName = strings.TrimSuffix(fileName, ext)

	solution := Model{
		Pth:        absPth,
		Name:       fileName,
		ConfigMap:  map[string]string{},
		ProjectMap: map[string]project.Model{},
	}

	isSolutionConfigurationPlatformsSection := false
	isProjectConfigurationPlatformsSection := false

	solutionDir := filepath.Dir(absPth)

	content, err := fileutil.ReadStringFromFile(absPth)
	if err != nil {
		return Model{}, fmt.Errorf("failed to read solution (%s), error: %s", absPth, err)
	}

	scanner := bufio.NewScanner(strings.NewReader(content))
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())

		// Projects
		if matches := regexp.MustCompile(solutionProjectsPattern).FindStringSubmatch(line); len(matches) == 5 {
			ID := strings.ToUpper(matches[1])
			projectName := matches[2]
			projectID := strings.ToUpper(matches[4])
			projectRelativePth := utility.FixWindowsPath(matches[3])
			projectPth := filepath.Join(solutionDir, projectRelativePth)

			if strings.HasSuffix(projectPth, constants.CSProjExt) ||
				strings.HasSuffix(projectPth, constants.SHProjExt) ||
				strings.HasSuffix(projectPth, constants.FSProjExt) {

				project := project.Model{
					ID:   projectID,
					Name: projectName,
					Pth:  projectPth,

					ConfigMap: map[string]string{},
					Configs:   map[string]project.ConfigurationPlatformModel{},
				}
				solution.ProjectMap[projectID] = project
			}

			solution.ID = ID

			continue
		}

		// GlobalSection(SolutionConfigurationPlatforms) = preSolution
		if isSolutionConfigurationPlatformsSection {
			if match := regexp.MustCompile(solutionConfigurationPlatformsSectionEndPattern).FindString(line); match != "" {
				isSolutionConfigurationPlatformsSection = false
				continue
			}
		}

		if match := regexp.MustCompile(solutionConfigurationPlatformsSectionStartPattern).FindString(line); match != "" {
			isSolutionConfigurationPlatformsSection = true
			continue
		}

		if isSolutionConfigurationPlatformsSection {
			if matches := regexp.MustCompile(solutionConfigurationPlatformPattern).FindStringSubmatch(line); len(matches) == 5 {
				configuration := matches[1]
				platform := matches[2]

				mappedConfiguration := matches[3]
				mappedPlatform := matches[4]

				solution.ConfigMap[utility.ToConfig(configuration, platform)] = utility.ToConfig(mappedConfiguration, mappedPlatform)

				continue
			}
		}

		// GlobalSection(ProjectConfigurationPlatforms) = postSolution
		if isProjectConfigurationPlatformsSection {
			if match := regexp.MustCompile(projectConfigurationPlatformsSectionEndPattern).FindString(line); match != "" {
				isProjectConfigurationPlatformsSection = false
				continue
			}
		}

		if match := regexp.MustCompile(projectConfigurationPlatformsSectionStartPattern).FindString(line); match != "" {
			isProjectConfigurationPlatformsSection = true
			continue
		}

		if isProjectConfigurationPlatformsSection {
			if matches := regexp.MustCompile(projectConfigurationPlatformPattern).FindStringSubmatch(line); len(matches) == 6 {
				projectID := strings.ToUpper(matches[1])
				solutionConfiguration := matches[2]
				solutionPlatform := matches[3]
				projectConfiguration := matches[4]
				projectPlatform := matches[5]
				if projectPlatform == "Any CPU" {
					projectPlatform = "AnyCPU"
				}

				project, found := solution.ProjectMap[projectID]
				if !found {
					return Model{}, fmt.Errorf("no project found with ID: %s", projectID)
				}

				project.ConfigMap[utility.ToConfig(solutionConfiguration, solutionPlatform)] = utility.ToConfig(projectConfiguration, projectPlatform)

				solution.ProjectMap[projectID] = project

				continue
			}
		}
	}
	if err := scanner.Err(); err != nil {
		return Model{}, err
	}

	if analyzeProjects {
		projectMap := map[string]project.Model{}

		for projectID, proj := range solution.ProjectMap {
			projectDefinition, err := project.New(proj.Pth)
			if err != nil {
				return Model{}, fmt.Errorf("failed to analyze project (%s), error: %s", proj.Pth, err)
			}

			projectDefinition.Name = proj.Name
			projectDefinition.Pth = proj.Pth
			projectDefinition.ConfigMap = proj.ConfigMap

			projectMap[projectID] = projectDefinition
		}

		solution.ProjectMap = projectMap
	}

	return solution, nil
}
Пример #2
0
func analyzeTargetDefinition(project Model, pth string) (Model, error) {
	configurationPlatform := ConfigurationPlatformModel{}

	isPropertyGroupSection := false
	isProjectReferenceSection := false

	projectDir := filepath.Dir(pth)

	projectDefinitionFileContent, err := fileutil.ReadStringFromFile(pth)
	if err != nil {
		return Model{}, fmt.Errorf("failed to read project (%s), error: %s", pth, err)
	}

	scanner := bufio.NewScanner(strings.NewReader(projectDefinitionFileContent))
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())

		// Target definition
		if matches := regexp.MustCompile(targetDefinitionPattern).FindStringSubmatch(line); len(matches) == 2 {
			targetDefinitionRelativePth := utility.FixWindowsPath(matches[1])

			if !strings.Contains(targetDefinitionRelativePth, "$(MSBuild") {
				targetDefinitionPth := filepath.Join(projectDir, targetDefinitionRelativePth)

				if exist, err := pathutil.IsPathExists(targetDefinitionPth); err != nil {
					return Model{}, err
				} else if exist {
					proj, err := analyzeTargetDefinition(project, targetDefinitionPth)
					if err != nil {
						return Model{}, err
					}
					project = proj
				}
			}

			continue
		}

		// ProjectGuid
		if matches := regexp.MustCompile(guidPattern).FindStringSubmatch(line); len(matches) == 2 {
			project.ID = matches[1]
			continue
		}

		// OutputType
		if matches := regexp.MustCompile(outputTpyePattern).FindStringSubmatch(line); len(matches) == 2 {
			project.OutputType = strings.ToLower(matches[1])
			continue
		}

		// AssemblyName
		if matches := regexp.MustCompile(assemblyNamePattern).FindStringSubmatch(line); len(matches) == 2 {
			project.AssemblyName = matches[1]
			continue
		}

		// AndroidManifest
		if matches := regexp.MustCompile(manifestPattern).FindStringSubmatch(line); len(matches) == 2 {
			manifestRelativePth := utility.FixWindowsPath(matches[1])

			project.ManifestPth = filepath.Join(projectDir, manifestRelativePth)
			continue
		}

		// AndroidApplication
		if match := regexp.MustCompile(androidApplicationPattern).FindString(line); match != "" {
			project.AndroidApplication = true
			continue
		}

		//
		// PropertyGroups

		if isPropertyGroupSection {
			if match := regexp.MustCompile(propertyGroupEndPattern).FindString(line); match != "" {
				project.Configs[utility.ToConfig(configurationPlatform.Configuration, configurationPlatform.Platform)] = configurationPlatform

				configurationPlatform = ConfigurationPlatformModel{}

				isPropertyGroupSection = false
				continue
			}
		}

		// PropertyGroup with Condition (Configuration & Platform)
		if matches := regexp.MustCompile(propertyGroupWithConditionConfigurationAndPlatformPattern).FindStringSubmatch(line); len(matches) == 3 {
			platform := matches[2]
			/*
				if platform == "AnyCPU" {
					platform = "Any CPU"
				}
			*/

			configurationPlatform = ConfigurationPlatformModel{
				Configuration: matches[1],
				Platform:      platform,
			}

			isPropertyGroupSection = true
			continue
		}

		// PropertyGroup with Condition (Configuration)
		if matches := regexp.MustCompile(propertyGroupWithConditionConfigurationPattern).FindStringSubmatch(line); len(matches) == 2 {
			configurationPlatform = ConfigurationPlatformModel{
				Configuration: matches[1],
			}

			isPropertyGroupSection = true
			continue
		}

		// PropertyGroup with Condition (Platform)
		if matches := regexp.MustCompile(propertyGroupWithConditionPlatformPattern).FindStringSubmatch(line); len(matches) == 2 {
			platform := matches[2]
			/*
				if platform == "AnyCPU" {
					platform = "Any CPU"
				}
			*/

			configurationPlatform = ConfigurationPlatformModel{
				Platform: platform,
			}

			isPropertyGroupSection = true
			continue
		}

		if isPropertyGroupSection {
			// OutputPath
			if matches := regexp.MustCompile(outputPathPattern).FindStringSubmatch(line); len(matches) == 2 {
				outputRelativePth := utility.FixWindowsPath(matches[1])
				strings.Replace(outputRelativePth, "$(Configuration)", configurationPlatform.Configuration, -1)
				strings.Replace(outputRelativePth, "$(Platform)", configurationPlatform.Platform, -1)

				configurationPlatform.OutputDir = filepath.Join(projectDir, outputRelativePth)
				continue
			}

			// MtouchArch
			if matches := regexp.MustCompile(mtouchArchPattern).FindStringSubmatch(line); len(matches) == 2 {
				configurationPlatform.MtouchArchs = utility.SplitAndStripList(matches[1], ",")
				continue
			}

			// AndroidKeyStore
			if match := regexp.MustCompile(androidKeystorePattern).FindString(line); match != "" {
				configurationPlatform.SignAndroid = true
				continue
			}

			/*
				// IpaPackageName
				if match := regexp.MustCompile(ipaPackageNamePattern).FindString(line); match != "" {
					configurationPlatform.IpaPackage = true
					continue
				}
			*/

			// BuildIpa ...
			if match := regexp.MustCompile(buildIpaPattern).FindString(line); match != "" {
				configurationPlatform.BuildIpa = true
				continue
			}
		}

		//
		// API

		// ProjectTypeGuids
		if matches := regexp.MustCompile(typeGUIDsPattern).FindStringSubmatch(line); len(matches) == 2 {
			projectType := constants.ProjectTypeUnknown
			projectTypeList := strings.Split(matches[1], ";")
			for _, guid := range projectTypeList {
				guid = strings.TrimPrefix(guid, "{")
				guid = strings.TrimSuffix(guid, "}")

				projectType, err = constants.ParseProjectTypeGUID(guid)
				if err == nil {
					break
				}
			}

			project.ProjectType = projectType
			continue
		}

		if match := regexp.MustCompile(referenceXamarinUITestPattern).FindString(line); match != "" {
			project.TestFramworks = append(project.TestFramworks, constants.XamarinUITest)
			continue
		}

		if match := regexp.MustCompile(referenceNunitFramework).FindString(line); match != "" {
			project.TestFramworks = append(project.TestFramworks, constants.NunitTest)
			continue
		}

		if match := regexp.MustCompile(referenceNunitLiteFramework).FindString(line); match != "" {
			project.TestFramworks = append(project.TestFramworks, constants.NunitLiteTest)
			continue
		}

		//
		// ProjectReference

		if isProjectReferenceSection {
			if match := regexp.MustCompile(projectRefernceEndPattern).FindString(line); match != "" {
				isProjectReferenceSection = false
			}
		}

		// ProjectReference
		if matches := regexp.MustCompile(projectRefernceStartPattern).FindStringSubmatch(line); len(matches) == 2 {
			/*
				projectRelativePth := fixWindowsPath(matches[1])
				projectPth := filepath.Join(projectDir, projectRelativePth)
			*/

			isProjectReferenceSection = true
			continue
		}

		if isProjectReferenceSection {
			if matches := regexp.MustCompile(referredProjectIDPattern).FindStringSubmatch(line); len(matches) == 2 {
				project.ReferredProjectIDs = append(project.ReferredProjectIDs, matches[1])
			}
			continue
		}

	}
	if err := scanner.Err(); err != nil {
		return Model{}, err
	}

	return project, nil
}