package toolingplan import ( "context" "fmt" "strings" toml "github.com/pelletier/go-toml" ) type rustDetector struct{} func (rustDetector) detect(_ context.Context, repoRoot string, managedTools map[string]struct{}) detectionResult { if alreadyManaged("rust", managedTools) { return detectionResult{Skips: []SkipNote{{Target: "rust", Reason: "already managed by repo mise declarations"}}} } if version, ok, reason := parseRustToolchainToml(repoRoot); ok { return detectionResult{Steps: []InstallStep{{Tool: "rust", Version: version, Source: "rust-toolchain.toml", Reason: "exact toolchain channel"}}} } else if reason != "" { return detectionResult{Skips: []SkipNote{{Target: "rust", Reason: reason}}} } value, ok, err := readRepoFile(repoRoot, "rust-toolchain") if err != nil { return detectionResult{Skips: []SkipNote{{Target: "rust", Reason: fmt.Sprintf("could not read rust-toolchain: %v", err)}}} } if !ok { return detectionResult{Skips: []SkipNote{{Target: "rust", Reason: "no rust-toolchain or rust-toolchain.toml"}}} } version := firstMeaningfulLine(value) if normalized, ok := normalizeExactVersion(version); ok { return detectionResult{Steps: []InstallStep{{Tool: "rust", Version: normalized, Source: "rust-toolchain", Reason: "exact toolchain channel"}}} } return detectionResult{Skips: []SkipNote{{Target: "rust", Reason: "rust-toolchain does not pin an exact version"}}} } func parseRustToolchainToml(repoRoot string) (version string, ok bool, reason string) { data, found, err := readRepoFile(repoRoot, "rust-toolchain.toml") if err != nil { return "", false, fmt.Sprintf("could not read rust-toolchain.toml: %v", err) } if !found { return "", false, "" } tree, err := toml.Load(data) if err != nil { return "", false, fmt.Sprintf("could not parse rust-toolchain.toml: %v", err) } channelValue := tree.GetDefault("toolchain.channel", "") channel, _ := channelValue.(string) channel = strings.TrimSpace(channel) if channel == "" { return "", false, "rust-toolchain.toml has no toolchain.channel" } version, ok = normalizeExactVersion(channel) if !ok { return "", false, "rust-toolchain.toml channel is not an exact version" } return version, true, "" } func firstMeaningfulLine(value string) string { for _, line := range strings.Split(value, "\n") { trimmed := strings.TrimSpace(line) if trimmed == "" || strings.HasPrefix(trimmed, "#") { continue } return trimmed } return "" }