func scanXamarinProject(cmd *cobra.Command, args []string) error { absExportOutputDirPath, err := initExportOutputDir() if err != nil { return printXamarinScanFinishedWithError("Failed to prepare Export directory: %s", err) } logOutput := "" xamarinCmd := xamarin.CommandModel{} if paramXamarinOutputLogFilePath != "" { xamLog, err := fileutil.ReadStringFromFile(paramXamarinOutputLogFilePath) if err != nil { return printXamarinScanFinishedWithError("Failed to read log from the specified log file, error: %s", err) } logOutput = xamLog } else { // --- Inputs --- // Xamarin Solution Path xamarinCmd.SolutionFilePath = paramXamarinSolutionFilePath if xamarinCmd.SolutionFilePath == "" { askText := `Please drag-and-drop your Xamarin Solution (` + colorstring.Green(".sln") + `) file here, and then hit Enter` fmt.Println() projpth, err := goinp.AskForPath(askText) if err != nil { return printXamarinScanFinishedWithError("Failed to read input: %s", err) } xamarinCmd.SolutionFilePath = projpth } log.Debugf("xamSolutionPth: %s", xamarinCmd.SolutionFilePath) xamSln, err := solution.New(xamarinCmd.SolutionFilePath, true) if err != nil { return printXamarinScanFinishedWithError("Failed to analyze Xamarin solution: %s", err) } log.Debugf("xamSln: %#v", xamSln) // filter only the iOS "app"" projects xamarinProjectsToChooseFrom := []project.Model{} for _, aXamarinProject := range xamSln.ProjectMap { switch aXamarinProject.ProjectType { case constants.ProjectTypeIOS, constants.ProjectTypeTvOS, constants.ProjectTypeMacOS: if aXamarinProject.OutputType == "exe" { // possible project xamarinProjectsToChooseFrom = append(xamarinProjectsToChooseFrom, aXamarinProject) } default: continue } } log.Debugf("len(xamarinProjectsToChooseFrom): %#v", len(xamarinProjectsToChooseFrom)) log.Debugf("xamarinProjectsToChooseFrom: %#v", xamarinProjectsToChooseFrom) // Xamarin Project selectedXamarinProject := project.Model{} { if len(xamarinProjectsToChooseFrom) < 1 { return printXamarinScanFinishedWithError( "No acceptable Project found in the provided Solution, or none can be used for iOS Archive.", ) } if paramXamarinProjectName != "" { // project specified via flag/param for _, aProj := range xamarinProjectsToChooseFrom { if paramXamarinProjectName == aProj.Name { selectedXamarinProject = aProj break } } if selectedXamarinProject.Name == "" { return printXamarinScanFinishedWithError( `Invalid Project specified (%s), either not found in the provided Solution or it can't be used for iOS "Archive for Publishing".`, paramXamarinProjectName) } } else { // no project CLI param specified if len(xamarinProjectsToChooseFrom) == 1 { selectedXamarinProject = xamarinProjectsToChooseFrom[0] } else { projectNames := []string{} for _, aProj := range xamarinProjectsToChooseFrom { projectNames = append(projectNames, aProj.Name) } fmt.Println() answerValue, err := goinp.SelectFromStrings( `Select the Project Name you use for "Archive for Publishing" (usually ends with ".iOS", e.g.: MyProject.iOS)?`, projectNames, ) if err != nil { return printXamarinScanFinishedWithError("Failed to select Project: %s", err) } log.Debugf("selected project: %v", answerValue) for _, aProj := range xamarinProjectsToChooseFrom { if answerValue == aProj.Name { selectedXamarinProject = aProj break } } } } } xamarinCmd.ProjectName = selectedXamarinProject.Name log.Debugf("xamarinCmd.ProjectName: %s", xamarinCmd.ProjectName) log.Debugf("selectedXamarinProject.Configs: %#v", selectedXamarinProject.Configs) // Xamarin Configuration Name selectedXamarinConfigurationName := "" { acceptableConfigs := []string{} for configName, aConfig := range selectedXamarinProject.Configs { if aConfig.Platform == "iPhone" { if aConfig.Configuration == "Release" { // ios & tvOS app acceptableConfigs = append(acceptableConfigs, configName) } } else if aConfig.Platform == "x86" { if aConfig.Configuration == "Release" || aConfig.Configuration == "Debug" { // MacOS app acceptableConfigs = append(acceptableConfigs, configName) } } } if len(acceptableConfigs) < 1 { return printXamarinScanFinishedWithError( `No acceptable Configuration found in the provided Solution and Project, or none can be used for iOS "Archive for Publishing".`, ) } if paramXamarinConfigurationName != "" { // configuration specified via flag/param for _, aConfigName := range acceptableConfigs { if paramXamarinConfigurationName == aConfigName { selectedXamarinConfigurationName = aConfigName break } } if selectedXamarinConfigurationName == "" { return printXamarinScanFinishedWithError( "Invalid Configuration specified (%s), either not found in the provided Solution and Project or it can't be used for iOS Archive.", paramXamarinConfigurationName) } } else { // no configuration CLI param specified if len(acceptableConfigs) == 1 { selectedXamarinConfigurationName = acceptableConfigs[0] } else { fmt.Println() answerValue, err := goinp.SelectFromStrings( `Select the Configuration Name you use for "Archive for Publishing" (usually Release|iPhone)?`, acceptableConfigs, ) if err != nil { return printXamarinScanFinishedWithError("Failed to select Configuration: %s", err) } log.Debugf("selected configuration: %v", answerValue) selectedXamarinConfigurationName = answerValue } } } if selectedXamarinConfigurationName == "" { return printXamarinScanFinishedWithError( `No acceptable Configuration found (it was empty) in the provided Solution and Project, or none can be used for iOS "Archive for Publishing".`, ) } xamarinCmd.ConfigurationName = selectedXamarinConfigurationName fmt.Println() fmt.Println() log.Println(`🔦 Running a Build, to get all the required code signing settings...`) xamLogOut, err := xamarinCmd.GenerateLog() logOutput = xamLogOut // save the xamarin output into a debug log file logOutputFilePath := filepath.Join(absExportOutputDirPath, "xamarin-build-output.log") { log.Infof(" 💡 "+colorstring.Yellow("Saving xamarin output into file")+": %s", logOutputFilePath) if logWriteErr := fileutil.WriteStringToFile(logOutputFilePath, logOutput); logWriteErr != nil { log.Errorf("Failed to save xamarin build output into file (%s), error: %s", logOutputFilePath, logWriteErr) } else if err != nil { log.Infoln(colorstring.Yellow("Please check the logfile (" + logOutputFilePath + ") to see what caused the error")) log.Infoln(colorstring.Red(`and make sure that you can "Archive for Publishing" this project from Xamarin!`)) fmt.Println() log.Infoln("Open the project: ", xamarinCmd.SolutionFilePath) log.Infoln(`And do "Archive for Publishing", after selecting the Configuration: `, xamarinCmd.ConfigurationName) fmt.Println() } } if err != nil { return printXamarinScanFinishedWithError("Failed to run xamarin build command: %s", err) } } codeSigningSettings, err := xamarinCmd.ScanCodeSigningSettings(logOutput) if err != nil { return printXamarinScanFinishedWithError("Failed to detect code signing settings: %s", err) } log.Debugf("codeSigningSettings: %#v", codeSigningSettings) return exportCodeSigningFiles("Xamarin Studio", absExportOutputDirPath, codeSigningSettings) }
func scanXcodeProject(cmd *cobra.Command, args []string) error { absExportOutputDirPath, err := initExportOutputDir() if err != nil { return printXcodeScanFinishedWithError("Failed to prepare Export directory: %s", err) } xcodebuildOutput := "" xcodeCmd := xcode.CommandModel{} if paramXcodebuildOutputLogFilePath != "" { xcLog, err := fileutil.ReadStringFromFile(paramXcodebuildOutputLogFilePath) if err != nil { return printXcodeScanFinishedWithError("Failed to read log from the specified log file, error: %s", err) } xcodebuildOutput = xcLog } else { projectPath := paramXcodeProjectFilePath if projectPath == "" { askText := `Please drag-and-drop your Xcode Project (` + colorstring.Green(".xcodeproj") + `) or Workspace (` + colorstring.Green(".xcworkspace") + `) file, the one you usually open in Xcode, then hit Enter. (Note: if you have a Workspace file you should most likely use that)` fmt.Println() projpth, err := goinp.AskForPath(askText) if err != nil { return printXcodeScanFinishedWithError("Failed to read input: %s", err) } projectPath = projpth } log.Debugf("projectPath: %s", projectPath) xcodeCmd.ProjectFilePath = projectPath schemeToUse := paramXcodeScheme if schemeToUse == "" { fmt.Println() fmt.Println() log.Println("🔦 Scanning Schemes ...") schemes, err := xcodeCmd.ScanSchemes() if err != nil { return printXcodeScanFinishedWithError("Failed to scan Schemes: %s", err) } log.Debugf("schemes: %v", schemes) fmt.Println() selectedScheme, err := goinp.SelectFromStrings("Select the Scheme you usually use in Xcode", schemes) if err != nil { return printXcodeScanFinishedWithError("Failed to select Scheme: %s", err) } log.Debugf("selected scheme: %v", selectedScheme) schemeToUse = selectedScheme } xcodeCmd.Scheme = schemeToUse fmt.Println() fmt.Println() log.Println("🔦 Running an Xcode Archive, to get all the required code signing settings...") xcLog, err := xcodeCmd.GenerateLog() xcodebuildOutput = xcLog // save the xcodebuild output into a debug log file xcodebuildOutputFilePath := filepath.Join(absExportOutputDirPath, "xcodebuild-output.log") { log.Infof(" 💡 "+colorstring.Yellow("Saving xcodebuild output into file")+": %s", xcodebuildOutputFilePath) if logWriteErr := fileutil.WriteStringToFile(xcodebuildOutputFilePath, xcodebuildOutput); logWriteErr != nil { log.Errorf("Failed to save xcodebuild output into file (%s), error: %s", xcodebuildOutputFilePath, logWriteErr) } else if err != nil { log.Infoln(colorstring.Yellow("Please check the logfile (" + xcodebuildOutputFilePath + ") to see what caused the error")) log.Infoln(colorstring.Red("and make sure that you can Archive this project from Xcode!")) fmt.Println() log.Infoln("Open the project:", xcodeCmd.ProjectFilePath) log.Infoln("and Archive, using the Scheme:", xcodeCmd.Scheme) fmt.Println() } } if err != nil { return printXcodeScanFinishedWithError("Failed to run Xcode Archive: %s", err) } } codeSigningSettings, err := xcodeCmd.ScanCodeSigningSettings(xcodebuildOutput) if err != nil { return printXcodeScanFinishedWithError("Failed to detect code signing settings: %s", err) } log.Debugf("codeSigningSettings: %#v", codeSigningSettings) return exportCodeSigningFiles("Xcode", absExportOutputDirPath, codeSigningSettings) }