@@ -75,6 +75,7 @@ func UnmarshalStruct(args []string, data interface{}) error {
7575 // Loop through all arguments
7676 for _ , kv := range argsSlice {
7777 argName , argValue := kv [0 ], kv [1 ]
78+ argNameWords := strings .Split (argName , "." )
7879
7980 // Make sure argument name is correct.
8081 // We enforce this check to avoid not well formatted argument name to work by "accident"
@@ -102,10 +103,30 @@ func UnmarshalStruct(args []string, data interface{}) error {
102103 Err : & DuplicateArgError {},
103104 }
104105 }
106+
107+ // We check that we did not already handle an argument value set on a child or a parent
108+ // Example `cluster=premium cluster.volume.size=12` cannot be valid as both args are in conflict.
109+ // Example `cluster.volume.size=12 cluster=premium` should also be invalid.
110+ for processedArgName := range processedArgNames {
111+ // We put the longest argName in long and the shortest in short.
112+ short , long := argName , processedArgName
113+ if len (long ) < len (short ) {
114+ short , long = long , short
115+ }
116+
117+ // We check if the longest starts with short+"."
118+ // If it does this mean we have a conflict.
119+ if strings .HasPrefix (long , short + "." ) {
120+ return & ConflictArgError {
121+ ArgName1 : processedArgName ,
122+ ArgName2 : argName ,
123+ }
124+ }
125+ }
105126 processedArgNames [argName ] = true
106127
107128 // Set will recursively find the correct field to set.
108- err := set (dest , strings . Split ( argName , "." ) , argValue )
129+ err := set (dest , argNameWords , argValue )
109130 if err != nil {
110131 return & UnmarshalArgError {
111132 ArgName : argName ,
@@ -172,19 +193,27 @@ func set(dest reflect.Value, argNameWords []string, value string) error {
172193 dest .Set (reflect .New (dest .Type ().Elem ()))
173194 }
174195
196+ // When:
197+ // - dest is a pointer to a slice
198+ // - there is no more argNameWords left
199+ // - value == none
200+ // we let the slice empty and return
201+ if dest .Elem ().Kind () == reflect .Slice && len (argNameWords ) == 0 && value == emptySliceValue {
202+ return nil
203+ }
204+
175205 // Call set with the pointer.Elem()
176206 return set (dest .Elem (), argNameWords , value )
177207
178208 case reflect .Slice :
179209 // If type is a slice:
180- // We check if argNameWords[0] is an number to handle cases like keys.0.value=12
181210
182211 // We cannot handle slice without an index notation.
183212 if len (argNameWords ) == 0 {
184213 return & MissingIndexOnArrayError {}
185214 }
186215
187- // Make sure index is a positive integer.
216+ // We check if argNameWords[0] is a positive integer to handle cases like keys.0.value=12
188217 index , err := strconv .ParseUint (argNameWords [0 ], 10 , 64 )
189218 if err != nil {
190219 return & InvalidIndexError {Index : argNameWords [0 ]}
0 commit comments