@@ -12,7 +12,6 @@ import (
1212 "github.com/MakeNowJust/heredoc/v2"
1313 "github.com/OctopusDeploy/cli/pkg/output"
1414 "github.com/OctopusDeploy/cli/pkg/question"
15- "github.com/OctopusDeploy/cli/pkg/util"
1615 octopusApiClient "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/client"
1716 "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/feeds"
1817 "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/releases"
@@ -193,19 +192,19 @@ type PackageVersionOverride struct {
193192func (p * PackageVersionOverride ) ToPackageOverrideString () string {
194193 components := make ([]string , 0 , 3 )
195194
196- // stepNameOrPackageID always comes first if we have it
195+ // stepNameOrPackageID always comes first if we have it; escape delimiter chars so the server can parse correctly
197196 if p .PackageID != "" {
198- components = append (components , p .PackageID )
197+ components = append (components , escapePackageDelimiters ( p .PackageID ) )
199198 } else if p .ActionName != "" { // can't have both PackageID and ActionName; PackageID wins
200- components = append (components , p .ActionName )
199+ components = append (components , escapePackageDelimiters ( p .ActionName ) )
201200 }
202201
203202 // followed by package reference name if we have it
204203 if p .PackageReferenceName != "" {
205204 if len (components ) == 0 { // if we have an explicit packagereference but no packageId or action, we need to express it with *:ref:version
206205 components = append (components , "*" )
207206 }
208- components = append (components , p .PackageReferenceName )
207+ components = append (components , escapePackageDelimiters ( p .PackageReferenceName ) )
209208 }
210209
211210 if len (components ) == 0 { // the server can't deal with just a number by itself; if we want to override everything we must pass *:Version
@@ -216,12 +215,62 @@ func (p *PackageVersionOverride) ToPackageOverrideString() string {
216215 return strings .Join (components , ":" )
217216}
218217
219- // splitPackageOverrideString splits the input string into components based on delimiter characters.
220- // we want to pick up empty entries here; so "::5" and ":pterm:5" should both return THREE components, rather than one or two
221- // and we want to allow for multiple different delimeters.
222- // neither the builtin golang strings.Split or strings.FieldsFunc support this. Logic borrowed from strings.FieldsFunc with heavy modifications
218+ // splitPackageOverrideString splits the input string into components based on delimiter characters (:, /, =).
219+ // Supports escaping delimiters with a backslash (e.g. \: for a literal colon in Maven package IDs).
220+ // Empty entries are preserved; "::5" and ":pterm:5" both return THREE components.
223221func splitPackageOverrideString (s string ) []string {
224- return util .SplitString (s , []int32 {':' , '/' , '=' })
222+ type span struct {
223+ start int
224+ end int
225+ }
226+ spans := make ([]span , 0 , 3 )
227+ start := 0
228+ escaped := false
229+
230+ for idx , ch := range s {
231+ if ch == '\\' && ! escaped {
232+ escaped = true
233+ continue
234+ }
235+ if (ch == ':' || ch == '/' || ch == '=' ) && ! escaped {
236+ spans = append (spans , span {start , idx })
237+ start = idx + 1
238+ } else {
239+ escaped = false
240+ }
241+ }
242+ spans = append (spans , span {start , len (s )})
243+
244+ a := make ([]string , len (spans ))
245+ for i , span := range spans {
246+ a [i ] = unescapePackageString (s [span .start :span .end ])
247+ }
248+ return a
249+ }
250+
251+ func unescapePackageString (s string ) string {
252+ result := make ([]rune , 0 , len (s ))
253+ escaped := false
254+ for _ , ch := range s {
255+ if ch == '\\' && ! escaped {
256+ escaped = true
257+ continue
258+ }
259+ result = append (result , ch )
260+ escaped = false
261+ }
262+ return string (result )
263+ }
264+
265+ func escapePackageDelimiters (s string ) string {
266+ var result strings.Builder
267+ for _ , ch := range s {
268+ if ch == ':' || ch == '/' || ch == '=' || ch == '\\' {
269+ result .WriteRune ('\\' )
270+ }
271+ result .WriteRune (ch )
272+ }
273+ return result .String ()
225274}
226275
227276// AmbiguousPackageVersionOverride tells us that we want to set the version of some package to `Version`
0 commit comments