Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
8aa16e09
Commit
8aa16e09
authored
Feb 02, 2017
by
ymqytw
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
support generic 3-way json merge patch
parent
9805b0bd
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
188 additions
and
20 deletions
+188
-20
patch.go
.../src/k8s.io/apimachinery/pkg/util/jsonmergepatch/patch.go
+144
-0
patch_test.go
...k8s.io/apimachinery/pkg/util/jsonmergepatch/patch_test.go
+0
-0
patch.go
.../src/k8s.io/apimachinery/pkg/util/strategicpatch/patch.go
+14
-14
patch_test.go
...k8s.io/apimachinery/pkg/util/strategicpatch/patch_test.go
+6
-6
BUILD
vendor/BUILD
+24
-0
No files found.
staging/src/k8s.io/apimachinery/pkg/util/jsonmergepatch/patch.go
0 → 100644
View file @
8aa16e09
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package
jsonmergepatch
import
(
"fmt"
"reflect"
"k8s.io/apimachinery/pkg/util/json"
"github.com/evanphx/json-patch"
"k8s.io/apimachinery/pkg/util/strategicpatch"
)
// Create a 3-way merge patch based-on JSON merge patch.
// Calculate addition-and-change patch between current and modified.
// Calculate deletion patch between original and modified.
func
CreateThreeWayJSONMergePatch
(
original
,
modified
,
current
[]
byte
,
fns
...
strategicpatch
.
PreconditionFunc
)
([]
byte
,
error
)
{
if
len
(
original
)
==
0
{
original
=
[]
byte
(
`{}`
)
}
if
len
(
modified
)
==
0
{
modified
=
[]
byte
(
`{}`
)
}
if
len
(
current
)
==
0
{
current
=
[]
byte
(
`{}`
)
}
addAndChangePatch
,
err
:=
jsonpatch
.
CreateMergePatch
(
current
,
modified
)
if
err
!=
nil
{
return
nil
,
err
}
// Only keep addition and changes
addAndChangePatch
,
addAndChangePatchObj
,
err
:=
keepOrDeleteNullInJsonPatch
(
addAndChangePatch
,
false
)
if
err
!=
nil
{
return
nil
,
err
}
deletePatch
,
err
:=
jsonpatch
.
CreateMergePatch
(
original
,
modified
)
if
err
!=
nil
{
return
nil
,
err
}
// Only keep deletion
deletePatch
,
deletePatchObj
,
err
:=
keepOrDeleteNullInJsonPatch
(
deletePatch
,
true
)
if
err
!=
nil
{
return
nil
,
err
}
hasConflicts
,
err
:=
strategicpatch
.
HasConflicts
(
addAndChangePatchObj
,
deletePatchObj
)
if
err
!=
nil
{
return
nil
,
err
}
if
hasConflicts
{
return
nil
,
strategicpatch
.
NewErrConflict
(
strategicpatch
.
ToYAMLOrError
(
addAndChangePatchObj
),
strategicpatch
.
ToYAMLOrError
(
deletePatchObj
))
}
patch
,
err
:=
jsonpatch
.
MergePatch
(
deletePatch
,
addAndChangePatch
)
if
err
!=
nil
{
return
nil
,
err
}
var
patchMap
map
[
string
]
interface
{}
err
=
json
.
Unmarshal
(
patch
,
&
patchMap
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"Failed to unmarshal patch for precondition check: %s"
,
patch
)
}
meetPreconditions
,
err
:=
meetPreconditions
(
patchMap
,
fns
...
)
if
err
!=
nil
{
return
nil
,
err
}
if
!
meetPreconditions
{
return
nil
,
strategicpatch
.
NewErrPreconditionFailed
(
patchMap
)
}
return
patch
,
nil
}
// keepOrDeleteNullInJsonPatch takes a json-encoded byte array and a boolean.
// It returns a filtered object and its corresponding json-encoded byte array.
// It is a wrapper of func keepOrDeleteNullInObj
func
keepOrDeleteNullInJsonPatch
(
patch
[]
byte
,
keepNull
bool
)
([]
byte
,
map
[
string
]
interface
{},
error
)
{
var
patchMap
map
[
string
]
interface
{}
err
:=
json
.
Unmarshal
(
patch
,
&
patchMap
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
filteredMap
,
err
:=
keepOrDeleteNullInObj
(
patchMap
,
keepNull
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
o
,
err
:=
json
.
Marshal
(
filteredMap
)
return
o
,
filteredMap
,
err
}
// keepOrDeleteNullInObj will keep only the null value and delete all the others,
// if keepNull is true. Otherwise, it will delete all the null value and keep the others.
func
keepOrDeleteNullInObj
(
m
map
[
string
]
interface
{},
keepNull
bool
)
(
map
[
string
]
interface
{},
error
)
{
filteredMap
:=
make
(
map
[
string
]
interface
{})
var
err
error
for
key
,
val
:=
range
m
{
switch
{
case
keepNull
&&
val
==
nil
:
filteredMap
[
key
]
=
nil
case
val
!=
nil
:
switch
typedVal
:=
val
.
(
type
)
{
case
map
[
string
]
interface
{}
:
filteredMap
[
key
],
err
=
keepOrDeleteNullInObj
(
typedVal
,
keepNull
)
if
err
!=
nil
{
return
nil
,
err
}
case
[]
interface
{},
string
,
float64
,
bool
,
int
,
int64
,
nil
:
// Lists are always replaced in Json, no need to check each entry in the list.
if
!
keepNull
{
filteredMap
[
key
]
=
val
}
default
:
return
nil
,
fmt
.
Errorf
(
"unknown type: %v"
,
reflect
.
TypeOf
(
typedVal
))
}
}
}
return
filteredMap
,
nil
}
func
meetPreconditions
(
patchObj
map
[
string
]
interface
{},
fns
...
strategicpatch
.
PreconditionFunc
)
(
bool
,
error
)
{
// Apply the preconditions to the patch, and return an error if any of them fail.
for
_
,
fn
:=
range
fns
{
if
!
fn
(
patchObj
)
{
return
false
,
fmt
.
Errorf
(
"precondition failed for: %v"
,
patchObj
)
}
}
return
true
,
nil
}
staging/src/k8s.io/apimachinery/pkg/util/jsonmergepatch/patch_test.go
0 → 100644
View file @
8aa16e09
This diff is collapsed.
Click to expand it.
staging/src/k8s.io/apimachinery/pkg/util/strategicpatch/patch.go
View file @
8aa16e09
...
@@ -58,40 +58,40 @@ type JSONMap map[string]interface{}
...
@@ -58,40 +58,40 @@ type JSONMap map[string]interface{}
// IsPreconditionFailed returns true if the provided error indicates
// IsPreconditionFailed returns true if the provided error indicates
// a precondition failed.
// a precondition failed.
func
IsPreconditionFailed
(
err
error
)
bool
{
func
IsPreconditionFailed
(
err
error
)
bool
{
_
,
ok
:=
err
.
(
e
rrPreconditionFailed
)
_
,
ok
:=
err
.
(
E
rrPreconditionFailed
)
return
ok
return
ok
}
}
type
e
rrPreconditionFailed
struct
{
type
E
rrPreconditionFailed
struct
{
message
string
message
string
}
}
func
newErrPreconditionFailed
(
target
map
[
string
]
interface
{})
e
rrPreconditionFailed
{
func
NewErrPreconditionFailed
(
target
map
[
string
]
interface
{})
E
rrPreconditionFailed
{
s
:=
fmt
.
Sprintf
(
"precondition failed for: %v"
,
target
)
s
:=
fmt
.
Sprintf
(
"precondition failed for: %v"
,
target
)
return
e
rrPreconditionFailed
{
s
}
return
E
rrPreconditionFailed
{
s
}
}
}
func
(
err
e
rrPreconditionFailed
)
Error
()
string
{
func
(
err
E
rrPreconditionFailed
)
Error
()
string
{
return
err
.
message
return
err
.
message
}
}
type
e
rrConflict
struct
{
type
E
rrConflict
struct
{
message
string
message
string
}
}
func
newErrConflict
(
patch
,
current
string
)
e
rrConflict
{
func
NewErrConflict
(
patch
,
current
string
)
E
rrConflict
{
s
:=
fmt
.
Sprintf
(
"patch:
\n
%s
\n
conflicts with changes made from original to current:
\n
%s
\n
"
,
patch
,
current
)
s
:=
fmt
.
Sprintf
(
"patch:
\n
%s
\n
conflicts with changes made from original to current:
\n
%s
\n
"
,
patch
,
current
)
return
e
rrConflict
{
s
}
return
E
rrConflict
{
s
}
}
}
func
(
err
e
rrConflict
)
Error
()
string
{
func
(
err
E
rrConflict
)
Error
()
string
{
return
err
.
message
return
err
.
message
}
}
// IsConflict returns true if the provided error indicates
// IsConflict returns true if the provided error indicates
// a conflict between the patch and the current configuration.
// a conflict between the patch and the current configuration.
func
IsConflict
(
err
error
)
bool
{
func
IsConflict
(
err
error
)
bool
{
_
,
ok
:=
err
.
(
e
rrConflict
)
_
,
ok
:=
err
.
(
E
rrConflict
)
return
ok
return
ok
}
}
...
@@ -187,7 +187,7 @@ func CreateTwoWayMergeMapPatch(original, modified JSONMap, dataStruct interface{
...
@@ -187,7 +187,7 @@ func CreateTwoWayMergeMapPatch(original, modified JSONMap, dataStruct interface{
// Apply the preconditions to the patch, and return an error if any of them fail.
// Apply the preconditions to the patch, and return an error if any of them fail.
for
_
,
fn
:=
range
fns
{
for
_
,
fn
:=
range
fns
{
if
!
fn
(
patchMap
)
{
if
!
fn
(
patchMap
)
{
return
nil
,
n
ewErrPreconditionFailed
(
patchMap
)
return
nil
,
N
ewErrPreconditionFailed
(
patchMap
)
}
}
}
}
...
@@ -1340,7 +1340,7 @@ func CreateThreeWayMergePatch(original, modified, current []byte, dataStruct int
...
@@ -1340,7 +1340,7 @@ func CreateThreeWayMergePatch(original, modified, current []byte, dataStruct int
// Apply the preconditions to the patch, and return an error if any of them fail.
// Apply the preconditions to the patch, and return an error if any of them fail.
for
_
,
fn
:=
range
fns
{
for
_
,
fn
:=
range
fns
{
if
!
fn
(
patchMap
)
{
if
!
fn
(
patchMap
)
{
return
nil
,
n
ewErrPreconditionFailed
(
patchMap
)
return
nil
,
N
ewErrPreconditionFailed
(
patchMap
)
}
}
}
}
...
@@ -1358,14 +1358,14 @@ func CreateThreeWayMergePatch(original, modified, current []byte, dataStruct int
...
@@ -1358,14 +1358,14 @@ func CreateThreeWayMergePatch(original, modified, current []byte, dataStruct int
}
}
if
hasConflicts
{
if
hasConflicts
{
return
nil
,
newErrConflict
(
toYAMLOrError
(
patchMap
),
t
oYAMLOrError
(
changedMap
))
return
nil
,
NewErrConflict
(
ToYAMLOrError
(
patchMap
),
T
oYAMLOrError
(
changedMap
))
}
}
}
}
return
json
.
Marshal
(
patchMap
)
return
json
.
Marshal
(
patchMap
)
}
}
func
t
oYAMLOrError
(
v
interface
{})
string
{
func
T
oYAMLOrError
(
v
interface
{})
string
{
y
,
err
:=
toYAML
(
v
)
y
,
err
:=
toYAML
(
v
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
.
Error
()
return
err
.
Error
()
...
...
staging/src/k8s.io/apimachinery/pkg/util/strategicpatch/patch_test.go
View file @
8aa16e09
...
@@ -266,7 +266,7 @@ func TestSortMergeLists(t *testing.T) {
...
@@ -266,7 +266,7 @@ func TestSortMergeLists(t *testing.T) {
sorted
:=
testObjectToJSONOrFail
(
t
,
c
.
Sorted
,
c
.
Description
)
sorted
:=
testObjectToJSONOrFail
(
t
,
c
.
Sorted
,
c
.
Description
)
if
!
reflect
.
DeepEqual
(
original
,
sorted
)
{
if
!
reflect
.
DeepEqual
(
original
,
sorted
)
{
t
.
Errorf
(
"error in test case: %s
\n
cannot sort object:
\n
%s
\n
expected:
\n
%s
\n
got:
\n
%s
\n
"
,
t
.
Errorf
(
"error in test case: %s
\n
cannot sort object:
\n
%s
\n
expected:
\n
%s
\n
got:
\n
%s
\n
"
,
c
.
Description
,
toYAMLOrError
(
c
.
Original
),
t
oYAMLOrError
(
c
.
Sorted
),
jsonToYAMLOrError
(
original
))
c
.
Description
,
ToYAMLOrError
(
c
.
Original
),
T
oYAMLOrError
(
c
.
Sorted
),
jsonToYAMLOrError
(
original
))
}
}
}
}
}
}
...
@@ -2037,7 +2037,7 @@ func testTwoWayPatch(t *testing.T, c StrategicMergePatchTestCase) {
...
@@ -2037,7 +2037,7 @@ func testTwoWayPatch(t *testing.T, c StrategicMergePatchTestCase) {
actualPatch
,
err
:=
CreateTwoWayMergePatch
(
original
,
modified
,
mergeItem
)
actualPatch
,
err
:=
CreateTwoWayMergePatch
(
original
,
modified
,
mergeItem
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Errorf
(
"error: %s
\n
in test case: %s
\n
cannot create two way patch: %s:
\n
%s
\n
"
,
t
.
Errorf
(
"error: %s
\n
in test case: %s
\n
cannot create two way patch: %s:
\n
%s
\n
"
,
err
,
c
.
Description
,
original
,
t
oYAMLOrError
(
c
.
StrategicMergePatchTestCaseData
))
err
,
c
.
Description
,
original
,
T
oYAMLOrError
(
c
.
StrategicMergePatchTestCaseData
))
return
return
}
}
...
@@ -2087,13 +2087,13 @@ func testThreeWayPatch(t *testing.T, c StrategicMergePatchTestCase) {
...
@@ -2087,13 +2087,13 @@ func testThreeWayPatch(t *testing.T, c StrategicMergePatchTestCase) {
if
err
!=
nil
{
if
err
!=
nil
{
if
!
IsConflict
(
err
)
{
if
!
IsConflict
(
err
)
{
t
.
Errorf
(
"error: %s
\n
in test case: %s
\n
cannot create three way patch:
\n
%s
\n
"
,
t
.
Errorf
(
"error: %s
\n
in test case: %s
\n
cannot create three way patch:
\n
%s
\n
"
,
err
,
c
.
Description
,
t
oYAMLOrError
(
c
.
StrategicMergePatchTestCaseData
))
err
,
c
.
Description
,
T
oYAMLOrError
(
c
.
StrategicMergePatchTestCaseData
))
return
return
}
}
if
!
strings
.
Contains
(
c
.
Description
,
"conflict"
)
{
if
!
strings
.
Contains
(
c
.
Description
,
"conflict"
)
{
t
.
Errorf
(
"unexpected conflict: %s
\n
in test case: %s
\n
cannot create three way patch:
\n
%s
\n
"
,
t
.
Errorf
(
"unexpected conflict: %s
\n
in test case: %s
\n
cannot create three way patch:
\n
%s
\n
"
,
err
,
c
.
Description
,
t
oYAMLOrError
(
c
.
StrategicMergePatchTestCaseData
))
err
,
c
.
Description
,
T
oYAMLOrError
(
c
.
StrategicMergePatchTestCaseData
))
return
return
}
}
...
@@ -2101,7 +2101,7 @@ func testThreeWayPatch(t *testing.T, c StrategicMergePatchTestCase) {
...
@@ -2101,7 +2101,7 @@ func testThreeWayPatch(t *testing.T, c StrategicMergePatchTestCase) {
actual
,
err
:=
CreateThreeWayMergePatch
(
original
,
modified
,
current
,
mergeItem
,
true
)
actual
,
err
:=
CreateThreeWayMergePatch
(
original
,
modified
,
current
,
mergeItem
,
true
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Errorf
(
"error: %s
\n
in test case: %s
\n
cannot force three way patch application:
\n
%s
\n
"
,
t
.
Errorf
(
"error: %s
\n
in test case: %s
\n
cannot force three way patch application:
\n
%s
\n
"
,
err
,
c
.
Description
,
t
oYAMLOrError
(
c
.
StrategicMergePatchTestCaseData
))
err
,
c
.
Description
,
T
oYAMLOrError
(
c
.
StrategicMergePatchTestCaseData
))
return
return
}
}
...
@@ -2114,7 +2114,7 @@ func testThreeWayPatch(t *testing.T, c StrategicMergePatchTestCase) {
...
@@ -2114,7 +2114,7 @@ func testThreeWayPatch(t *testing.T, c StrategicMergePatchTestCase) {
if
strings
.
Contains
(
c
.
Description
,
"conflict"
)
||
len
(
c
.
Result
)
<
1
{
if
strings
.
Contains
(
c
.
Description
,
"conflict"
)
||
len
(
c
.
Result
)
<
1
{
t
.
Errorf
(
"error in test case: %s
\n
expected conflict did not occur:
\n
%s
\n
"
,
t
.
Errorf
(
"error in test case: %s
\n
expected conflict did not occur:
\n
%s
\n
"
,
c
.
Description
,
t
oYAMLOrError
(
c
.
StrategicMergePatchTestCaseData
))
c
.
Description
,
T
oYAMLOrError
(
c
.
StrategicMergePatchTestCaseData
))
return
return
}
}
...
...
vendor/BUILD
View file @
8aa16e09
...
@@ -14192,3 +14192,27 @@ go_library(
...
@@ -14192,3 +14192,27 @@ go_library(
"//vendor:k8s.io/client-go/tools/clientcmd",
"//vendor:k8s.io/client-go/tools/clientcmd",
],
],
)
)
go_test(
name = "k8s.io/apimachinery/pkg/util/jsonmergepatch_test",
srcs = ["k8s.io/apimachinery/pkg/util/jsonmergepatch/patch_test.go"],
library = ":k8s.io/apimachinery/pkg/util/jsonmergepatch",
tags = ["automanaged"],
deps = [
"//vendor:github.com/davecgh/go-spew/spew",
"//vendor:github.com/evanphx/json-patch",
"//vendor:github.com/ghodss/yaml",
"//vendor:k8s.io/apimachinery/pkg/util/json",
],
)
go_library(
name = "k8s.io/apimachinery/pkg/util/jsonmergepatch",
srcs = ["k8s.io/apimachinery/pkg/util/jsonmergepatch/patch.go"],
tags = ["automanaged"],
deps = [
"//vendor:github.com/evanphx/json-patch",
"//vendor:k8s.io/apimachinery/pkg/util/json",
"//vendor:k8s.io/apimachinery/pkg/util/strategicpatch",
],
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment