func (builder Model) buildableNunitTestProjects(configuration, platform string) ([]project.Model, []string) {
	testProjects := []project.Model{}

	warnings := []string{}

	solutionConfig := utility.ToConfig(configuration, platform)

	for _, proj := range builder.solution.ProjectMap {
		// Check if is nunit test project
		if proj.ProjectType != constants.ProjectTypeNunitTest {
			continue
		}

		// Check if contains config mapping
		_, ok := proj.ConfigMap[solutionConfig]
		if !ok {
			warnings = append(warnings, fmt.Sprintf("project (%s) do not have config for solution config (%s), skipping...", proj.Name, solutionConfig))
			continue
		}

		testProjects = append(testProjects, proj)
	}

	return testProjects, warnings
}
func (builder Model) buildNunitTestProjectCommand(configuration, platform string, proj project.Model, nunitConsolePth string) (tools.Runnable, []string, error) {
	warnings := []string{}

	solutionConfig := utility.ToConfig(configuration, platform)

	projectConfigKey, ok := proj.ConfigMap[solutionConfig]
	if !ok {
		warnings = append(warnings, fmt.Sprintf("project (%s) do not have config for solution config (%s), skipping...", proj.Name, solutionConfig))
	}

	projectConfig, ok := proj.Configs[projectConfigKey]
	if !ok {
		warnings = append(warnings, fmt.Sprintf("project (%s) contains mapping for solution config (%s), but does not have project configuration", proj.Name, solutionConfig))
	}

	command, err := nunit.New(nunitConsolePth)
	if err != nil {
		return tools.EmptyCommand{}, warnings, err
	}

	command.SetProjectPth(proj.Pth)
	command.SetConfig(projectConfig.Configuration)

	return command, warnings, nil
}
func (builder Model) buildableXamarinUITestProjectsAndReferredProjects(configuration, platform string) ([]project.Model, []project.Model, []string) {
	testProjects := []project.Model{}
	referredProjects := []project.Model{}

	warnings := []string{}

	solutionConfig := utility.ToConfig(configuration, platform)

	for _, proj := range builder.solution.ProjectMap {
		// Check if is XamarinUITest project
		if proj.ProjectType != constants.ProjectTypeXamarinUITest {
			continue
		}

		// Check if contains config mapping
		_, ok := proj.ConfigMap[solutionConfig]
		if !ok {
			warnings = append(warnings, fmt.Sprintf("project (%s) do not have config for solution config (%s), skipping...", proj.Name, solutionConfig))
			continue
		}

		// Collect referred projects
		if len(proj.ReferredProjectIDs) == 0 {
			warnings = append(warnings, fmt.Sprintf("no referred projects found for test project: %s, skipping...", proj.Name))
			continue
		}

		for _, projectID := range proj.ReferredProjectIDs {
			referredProj, ok := builder.solution.ProjectMap[projectID]
			if !ok {
				warnings = append(warnings, fmt.Sprintf("project reference exist with project id: %s, but project not found in solution", projectID))
				continue
			}

			if referredProj.ProjectType == constants.ProjectTypeUnknown {
				warnings = append(warnings, fmt.Sprintf("project's (%s) project type is unkown", referredProj.Name))
				continue
			}

			if whitelistAllows(referredProj.ProjectType, builder.projectTypeWhitelist...) {
				referredProjects = append(referredProjects, referredProj)
			}
		}

		if len(referredProjects) == 0 {
			warnings = append(warnings, fmt.Sprintf("test project (%s) does not refers to any project, with project type whitelist (%v), skipping...", proj.Name, builder.projectTypeWhitelist))
			continue
		}

		testProjects = append(testProjects, proj)
	}

	return testProjects, referredProjects, warnings
}
// CollectXamarinUITestProjectOutputs ...
func (builder Model) CollectXamarinUITestProjectOutputs(configuration, platform string) (TestProjectOutputMap, []string, error) {
	testProjectOutputMap := TestProjectOutputMap{}
	warnings := []string{}

	buildableTestProjects, _, _ := builder.buildableXamarinUITestProjectsAndReferredProjects(configuration, platform)

	solutionConfig := utility.ToConfig(configuration, platform)

	for _, testProj := range buildableTestProjects {
		projectConfigKey, ok := testProj.ConfigMap[solutionConfig]
		if !ok {
			continue
		}

		projectConfig, ok := testProj.Configs[projectConfigKey]
		if !ok {
			continue
		}

		if dllPth, err := exportDLL(projectConfig.OutputDir, testProj.AssemblyName); err != nil {
			return TestProjectOutputMap{}, warnings, err
		} else if dllPth != "" {
			referredProjectNames := []string{}
			referredProjectIDs := testProj.ReferredProjectIDs
			for _, referredProjectID := range referredProjectIDs {
				referredProject, ok := builder.solution.ProjectMap[referredProjectID]
				if !ok {
					warnings = append(warnings, fmt.Sprintf("project reference exist with project id: %s, but project not found in solution", referredProjectID))
				}

				referredProjectNames = append(referredProjectNames, referredProject.Name)
			}

			testProjectOutputMap[testProj.Name] = TestProjectOutputModel{
				ProjectType:          testProj.ProjectType,
				ReferredProjectNames: referredProjectNames,
				Output: OutputModel{
					Pth:        dllPth,
					OutputType: constants.OutputTypeDLL,
				},
			}
		}
	}

	return testProjectOutputMap, warnings, nil
}
func (builder Model) buildableProjects(configuration, platform string) ([]project.Model, []string) {
	projects := []project.Model{}
	warnings := []string{}

	solutionConfig := utility.ToConfig(configuration, platform)

	whitelistedProjects := builder.whitelistedProjects()

	for _, proj := range whitelistedProjects {
		//
		// Solution config - project config mapping
		_, ok := proj.ConfigMap[solutionConfig]
		if !ok {
			warnings = append(warnings, fmt.Sprintf("project (%s) do not have config for solution config (%s), skipping...", proj.Name, solutionConfig))
			continue
		}

		if (proj.ProjectType == constants.ProjectTypeIOS ||
			proj.ProjectType == constants.ProjectTypeMacOS ||
			proj.ProjectType == constants.ProjectTypeTvOS) &&
			proj.OutputType != "exe" {
			warnings = append(warnings, fmt.Sprintf("project (%s) does not archivable based on output type (%s), skipping...", proj.Name, proj.OutputType))
			continue
		}
		if proj.ProjectType == constants.ProjectTypeAndroid &&
			!proj.AndroidApplication {
			warnings = append(warnings, fmt.Sprintf("(%s) is not an android application project, skipping...", proj.Name))
			continue
		}

		if proj.ProjectType != constants.ProjectTypeUnknown {
			projects = append(projects, proj)
		}
	}

	return projects, warnings
}
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 (builder Model) buildProjectCommand(configuration, platform string, proj project.Model) ([]tools.Runnable, []string, error) {
	warnings := []string{}

	solutionConfig := utility.ToConfig(configuration, platform)

	projectConfigKey, ok := proj.ConfigMap[solutionConfig]
	if !ok {
		warnings = append(warnings, fmt.Sprintf("project (%s) do not have config for solution config (%s), skipping...", proj.Name, solutionConfig))
	}

	projectConfig, ok := proj.Configs[projectConfigKey]
	if !ok {
		warnings = append(warnings, fmt.Sprintf("project (%s) contains mapping for solution config (%s), but does not have project configuration", proj.Name, solutionConfig))
	}

	// Prepare build commands
	buildCommands := []tools.Runnable{}

	switch proj.ProjectType {
	case constants.ProjectTypeIOS, constants.ProjectTypeTvOS:
		if builder.forceMDTool {
			command, err := mdtool.New(builder.solution.Pth)
			if err != nil {
				return []tools.Runnable{}, warnings, err
			}

			command.SetTarget("build")
			command.SetConfiguration(projectConfig.Configuration)
			command.SetPlatform(projectConfig.Platform)
			command.SetProjectName(proj.Name)

			buildCommands = append(buildCommands, command)

			if isArchitectureArchiveable(projectConfig.MtouchArchs...) {
				command, err := mdtool.New(builder.solution.Pth)
				if err != nil {
					return []tools.Runnable{}, warnings, err
				}

				command.SetTarget("archive")
				command.SetConfiguration(projectConfig.Configuration)
				command.SetPlatform(projectConfig.Platform)
				command.SetProjectName(proj.Name)

				buildCommands = append(buildCommands, command)
			}
		} else {
			command, err := xbuild.New(builder.solution.Pth, "")
			if err != nil {
				return []tools.Runnable{}, warnings, err
			}

			command.SetTarget("Build")
			command.SetConfiguration(configuration)
			command.SetPlatform(platform)

			if isArchitectureArchiveable(projectConfig.MtouchArchs...) {
				command.SetBuildIpa(true)
				command.SetArchiveOnBuild(true)
			}

			buildCommands = append(buildCommands, command)
		}
	case constants.ProjectTypeMacOS:
		if builder.forceMDTool {
			command, err := mdtool.New(builder.solution.Pth)
			if err != nil {
				return []tools.Runnable{}, warnings, err
			}

			command.SetTarget("build")
			command.SetConfiguration(projectConfig.Configuration)
			command.SetPlatform(projectConfig.Platform)
			command.SetProjectName(proj.Name)

			buildCommands = append(buildCommands, command)

			command, err = mdtool.New(builder.solution.Pth)
			if err != nil {
				return []tools.Runnable{}, warnings, err
			}

			command.SetTarget("archive")
			command.SetConfiguration(projectConfig.Configuration)
			command.SetPlatform(projectConfig.Platform)
			command.SetProjectName(proj.Name)

			buildCommands = append(buildCommands, command)
		} else {
			command, err := xbuild.New(builder.solution.Pth, "")
			if err != nil {
				return []tools.Runnable{}, warnings, err
			}

			command.SetTarget("Build")
			command.SetConfiguration(configuration)
			command.SetPlatform(platform)
			command.SetArchiveOnBuild(true)

			buildCommands = append(buildCommands, command)
		}
	case constants.ProjectTypeAndroid:
		command, err := xbuild.New(builder.solution.Pth, proj.Pth)
		if err != nil {
			return []tools.Runnable{}, warnings, err
		}

		if projectConfig.SignAndroid {
			command.SetTarget("SignAndroidPackage")
		} else {
			command.SetTarget("PackageForAndroid")
		}

		command.SetConfiguration(projectConfig.Configuration)

		if !isPlatformAnyCPU(projectConfig.Platform) {
			command.SetPlatform(projectConfig.Platform)
		}

		buildCommands = append(buildCommands, command)
	}

	return buildCommands, warnings, nil
}
// CollectProjectOutputs ...
func (builder Model) CollectProjectOutputs(configuration, platform string) (ProjectOutputMap, error) {
	projectOutputMap := ProjectOutputMap{}

	buildableProjects, _ := builder.buildableProjects(configuration, platform)

	solutionConfig := utility.ToConfig(configuration, platform)

	for _, proj := range buildableProjects {
		projectConfigKey, ok := proj.ConfigMap[solutionConfig]
		if !ok {
			continue
		}

		projectConfig, ok := proj.Configs[projectConfigKey]
		if !ok {
			continue
		}

		projectOutputs, ok := projectOutputMap[proj.Name]
		if !ok {
			projectOutputs = ProjectOutputModel{
				ProjectType: proj.ProjectType,
				Outputs:     []OutputModel{},
			}
		}

		switch proj.ProjectType {
		case constants.ProjectTypeIOS, constants.ProjectTypeTvOS:
			if isArchitectureArchiveable(projectConfig.MtouchArchs...) {
				if xcarchivePth, err := exportLatestXCArchiveFromXcodeArchives(proj.AssemblyName); err != nil {
					return ProjectOutputMap{}, err
				} else if xcarchivePth != "" {
					projectOutputs.Outputs = append(projectOutputs.Outputs, OutputModel{
						Pth:        xcarchivePth,
						OutputType: constants.OutputTypeXCArchive,
					})
				}

				if ipaPth, err := exportLatestIpa(projectConfig.OutputDir, proj.AssemblyName); err != nil {
					return ProjectOutputMap{}, err
				} else if ipaPth != "" {
					projectOutputs.Outputs = append(projectOutputs.Outputs, OutputModel{
						Pth:        ipaPth,
						OutputType: constants.OutputTypeIPA,
					})
				}

				if dsymPth, err := exportAppDSYM(projectConfig.OutputDir, proj.AssemblyName); err != nil {
					return ProjectOutputMap{}, err
				} else if dsymPth != "" {
					projectOutputs.Outputs = append(projectOutputs.Outputs, OutputModel{
						Pth:        dsymPth,
						OutputType: constants.OutputTypeDSYM,
					})
				}
			}

			if appPth, err := exportApp(projectConfig.OutputDir, proj.AssemblyName); err != nil {
				return ProjectOutputMap{}, err
			} else if appPth != "" {
				projectOutputs.Outputs = append(projectOutputs.Outputs, OutputModel{
					Pth:        appPth,
					OutputType: constants.OutputTypeAPP,
				})
			}
		case constants.ProjectTypeMacOS:
			if builder.forceMDTool {
				if xcarchivePth, err := exportLatestXCArchiveFromXcodeArchives(proj.AssemblyName); err != nil {
					return ProjectOutputMap{}, err
				} else if xcarchivePth != "" {
					projectOutputs.Outputs = append(projectOutputs.Outputs, OutputModel{
						Pth:        xcarchivePth,
						OutputType: constants.OutputTypeXCArchive,
					})
				}
			}
			if appPth, err := exportApp(projectConfig.OutputDir, proj.AssemblyName); err != nil {
				return ProjectOutputMap{}, err
			} else if appPth != "" {
				projectOutputs.Outputs = append(projectOutputs.Outputs, OutputModel{
					Pth:        appPth,
					OutputType: constants.OutputTypeAPP,
				})
			}
			if pkgPth, err := exportPKG(projectConfig.OutputDir, proj.AssemblyName); err != nil {
				return ProjectOutputMap{}, err
			} else if pkgPth != "" {
				projectOutputs.Outputs = append(projectOutputs.Outputs, OutputModel{
					Pth:        pkgPth,
					OutputType: constants.OutputTypePKG,
				})
			}
		case constants.ProjectTypeAndroid:
			packageName, err := androidPackageName(proj.ManifestPth)
			if err != nil {
				return ProjectOutputMap{}, err
			}

			if apkPth, err := exportApk(projectConfig.OutputDir, packageName); err != nil {
				return ProjectOutputMap{}, err
			} else if apkPth != "" {
				projectOutputs.Outputs = append(projectOutputs.Outputs, OutputModel{
					Pth:        apkPth,
					OutputType: constants.OutputTypeAPK,
				})
			}
		}

		if len(projectOutputs.Outputs) > 0 {
			projectOutputMap[proj.Name] = projectOutputs
		}
	}

	return projectOutputMap, nil
}
Example #9
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
}