package artifacts import ( "path" "strings" "gitea.maximumdirect.net/eric/narratio/internal/config" ) // S3SessionPrefix builds the canonical S3 session prefix. // Format: {root_prefix}/campaigns/{campaign}/sessions/{session_id}/ func S3SessionPrefix(rootPrefix, campaign, sessionID string) string { prefix := path.Join( cleanS3PathPart(rootPrefix), config.S3CampaignsSegment, cleanS3PathPart(campaign), config.S3SessionsSegment, cleanS3PathPart(sessionID), ) return ensureS3TrailingSlash(prefix) } // S3RunPrefix builds the canonical S3 run prefix. // Format: {session_prefix}/runs/{run_id}/ func S3RunPrefix(sessionPrefix, runID string) string { prefix := path.Join(strings.TrimSuffix(cleanS3Key(sessionPrefix), "/"), config.S3RunsSegment, cleanS3PathPart(runID)) return ensureS3TrailingSlash(prefix) } // S3AudioPrefix builds the session audio prefix from configured audio_s3.prefix. // Format: {session_prefix}/{audio_s3.prefix} func S3AudioPrefix(sessionPrefix, audioPrefix string) string { key := path.Join(strings.TrimSuffix(cleanS3Key(sessionPrefix), "/"), cleanS3Key(audioPrefix)) return ensureS3TrailingSlash(key) } // S3CurrentManifestKey returns the current manifest pointer key. // Format: {session_prefix}/current/manifest.json func S3CurrentManifestKey(sessionPrefix string) string { return path.Join(strings.TrimSuffix(cleanS3Key(sessionPrefix), "/"), config.S3CurrentSegment, config.S3ManifestFile) } // S3CurrentRunPointerKey returns the current run pointer key. // Format: {session_prefix}/current/run_id.txt func S3CurrentRunPointerKey(sessionPrefix string) string { return path.Join(strings.TrimSuffix(cleanS3Key(sessionPrefix), "/"), config.S3CurrentSegment, config.S3RunIDFile) } // S3PromotedArtifactKey returns the destination key for one promoted artifact. // Format: {session_prefix}/{promotion.to} func S3PromotedArtifactKey(sessionPrefix, to string) string { return path.Join(strings.TrimSuffix(cleanS3Key(sessionPrefix), "/"), cleanS3Key(to)) } // S3RunRelativeDestinationKey returns a run-scoped key for a workdir-relative path. // Format: {run_prefix}/{relative_workdir_path} func S3RunRelativeDestinationKey(runPrefix, relativeWorkdirPath string) string { return path.Join(strings.TrimSuffix(cleanS3Key(runPrefix), "/"), cleanS3Key(relativeWorkdirPath)) } func ensureS3TrailingSlash(v string) string { key := cleanS3Key(v) if key == "" { return "" } return strings.TrimSuffix(key, "/") + "/" } func cleanS3PathPart(v string) string { return strings.Trim(strings.ReplaceAll(strings.TrimSpace(v), "\\", "/"), "/") } func cleanS3Key(v string) string { return strings.ReplaceAll(strings.TrimSpace(v), "\\", "/") }