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 }
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 }