package config import ( "fmt" "path/filepath" "strings" "gitea.maximumdirect.net/eric/narratio/internal/fileops" ) const maxPartyDocumentBytes = 8 << 20 func resolvePartyInput(input ResolvedInputFile) (ResolvedParty, error) { configuredPath := strings.TrimSpace(input.Path) if configuredPath == "" { return ResolvedParty{}, fmt.Errorf("party input path is required") } configPath := strings.TrimSpace(input.ConfigPath) if configPath == "" { return ResolvedParty{}, fmt.Errorf("party input %q has no declaring configuration path", configuredPath) } path := configuredPath if !filepath.IsAbs(path) { path = filepath.Join(filepath.Dir(configPath), path) } path = filepath.Clean(path) raw, err := fileops.ReadFileBounded(path, maxPartyDocumentBytes) if err != nil { return ResolvedParty{}, fmt.Errorf("read party input %q: %w", path, err) } party, err := ParseParty(raw) if err != nil { return ResolvedParty{}, fmt.Errorf("parse party input %q: %w", path, err) } return ResolvedParty{ Source: PartySource{ Path: path, ConfigPath: configPath, Source: input.Source, }, Canonical: party, }, nil } func campaignPartyInput(campaignPath string, campaign *CampaignConfig) (ResolvedInputFile, error) { if campaign == nil { return ResolvedInputFile{}, fmt.Errorf("campaign config is required") } if strings.TrimSpace(campaign.Inputs.PartyFile) == "" { return ResolvedInputFile{}, fmt.Errorf("campaign.inputs.party_file is required") } return ResolvedInputFile{ Path: campaign.Inputs.PartyFile, ConfigPath: campaignPath, Source: "campaign_config", }, nil } func resolveCampaignParty(campaignPath string, campaign *CampaignConfig) (ResolvedParty, error) { input, err := campaignPartyInput(campaignPath, campaign) if err != nil { return ResolvedParty{}, err } return resolvePartyInput(input) }