package main // playing with gemini to do simple tasks. it kicked this out import ( "bufio" "errors" "fmt" "os" "path/filepath" "strings" ) // ParsedGitConfig represents the structure of a .gitconfig file, // which is a map of section names to a map of their key-value pairs. // For example: // // { // "user": { // "name": "John Doe", // "email": "john.doe@example.com", // }, // "core": { // "editor": "vim", // }, // } type ParsedGitConfig map[string]map[string]string // ParseGlobalGitConfig finds and parses the global .gitconfig file for the current user. // It is platform-agnostic and works on Windows, macOS, and Linux. // It returns the parsed configuration or an error if the file cannot be found or read. func ParseGlobalGitConfig() (ParsedGitConfig, error) { // os.UserHomeDir() is the platform-agnostic way to get the user's home directory. homeDir, err := os.UserHomeDir() if err != nil { return nil, fmt.Errorf("could not get user home directory: %w", err) } // filepath.Join correctly constructs the path for the current OS. gitConfigPath := filepath.Join(homeDir, ".gitconfig") file, err := os.Open(gitConfigPath) if err != nil { if errors.Is(err, os.ErrNotExist) { return nil, fmt.Errorf(".gitconfig file not found at %s", gitConfigPath) } return nil, fmt.Errorf("could not open .gitconfig file: %w", err) } defer file.Close() config := make(ParsedGitConfig) var currentSection string scanner := bufio.NewScanner(file) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) // Ignore empty lines and comments if line == "" || line[0] == '#' || line[0] == ';' { continue } // Check for a new section if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") { sectionName := line[1 : len(line)-1] // Handle subsections like [remote "origin"] by splitting them. // For simplicity, we'll just use the full string as the key. // A more complex parser might create nested maps. currentSection = strings.TrimSpace(sectionName) if _, exists := config[currentSection]; !exists { config[currentSection] = make(map[string]string) } continue } // Parse key-value pairs within a section if currentSection != "" { // Split by "=". Use SplitN to handle values that might contain "=". parts := strings.SplitN(line, "=", 2) if len(parts) == 2 { key := strings.TrimSpace(parts[0]) value := strings.TrimSpace(parts[1]) config[currentSection][key] = value } } } if err := scanner.Err(); err != nil { return nil, fmt.Errorf("error reading .gitconfig file: %w", err) } return config, nil } // GetValue retrieves a specific value from the parsed git config. // It takes the section and key as input (e.g., "user", "name"). // It returns the value and a boolean indicating if the key was found. func (c ParsedGitConfig) GetValue(section, key string) (string, bool) { if sectionMap, ok := c[section]; ok { if value, ok := sectionMap[key]; ok { return value, true } } return "", false } /* // main function to demonstrate the usage of ParseGlobalGitConfig. func main() { config, err := ParseGlobalGitConfig() if err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } fmt.Println("Successfully parsed global .gitconfig file.") fmt.Println("-----------------------------------------") // Example of using GetValue to retrieve the user's name and email. userName, found := config.GetValue("user", "name") if found { fmt.Printf("User Name: %s\n", userName) } else { fmt.Println("User name not found.") } userEmail, found := config.GetValue("user", "email") if found { fmt.Printf("User Email: %s\n", userEmail) } else { fmt.Println("User email not found.") } fmt.Println("\nFull configuration:") // Print out the full parsed configuration for section, keys := range config { fmt.Printf("[%s]\n", section) for key, value := range keys { fmt.Printf(" %s = %s\n", key, value) } } } */