1
1
package app
2
2
3
3
import (
4
+ "encoding/json"
5
+ "os"
6
+ "path/filepath"
7
+ "strings"
8
+
9
+ "github.com/opcr-io/policy/pkg/oci"
4
10
"github.com/opcr-io/policy/pkg/parser"
11
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
5
12
"github.com/pkg/errors"
6
- "oras.land/oras-go/pkg/content"
7
13
)
8
14
9
15
func (c * PolicyApp ) Rm (existingRef string , force bool ) error {
@@ -30,35 +36,108 @@ func (c *PolicyApp) Rm(existingRef string, force bool) error {
30
36
return nil
31
37
}
32
38
33
- ociStore , err := content .NewOCI (c .Configuration .PoliciesRoot ())
39
+ ociClient , err := oci .NewOCI (c . Context , c . Logger , c . getHosts , c .Configuration .PoliciesRoot ())
34
40
if err != nil {
35
41
return err
36
42
}
37
- err = ociStore .LoadIndex ()
43
+
44
+ existingRefs , err := ociClient .ListReferences ()
38
45
if err != nil {
39
46
return err
40
47
}
41
48
42
- existingRefs := ociStore .ListReferences ()
43
-
44
- _ , ok := existingRefs [existingRefParsed ]
49
+ ref , ok := existingRefs [existingRefParsed ]
45
50
if ! ok {
46
51
return errors .Errorf ("ref [%s] not found in the local store" , existingRef )
47
52
}
53
+ // attach ref name annotation for comparisson.
54
+ ref .Annotations = make (map [string ]string )
55
+ ref .Annotations [ocispec .AnnotationRefName ] = existingRefParsed
48
56
49
- ociStore .DeleteReference (existingRefParsed )
57
+ err = c .removeFromIndex (ref )
58
+ if err != nil {
59
+ return err
60
+ }
61
+
62
+ // Reload ociClient with refreshed index to update reference list.
63
+ ociClient , err = oci .NewOCI (c .Context , c .Logger , c .getHosts , c .Configuration .PoliciesRoot ())
64
+ if err != nil {
65
+ return err
66
+ }
50
67
51
- // TODO: if there are no references left to the policy, perhaps delete the descriptor?
52
- // or implement a cleanup command.
68
+ updatedRefs , err := ociClient .ListReferences ()
69
+ if err != nil {
70
+ return err
71
+ }
72
+ // Check if existing images use same digest.
73
+ removeBlob := true
74
+ for _ , v := range updatedRefs {
75
+ if v .Digest == ref .Digest {
76
+ removeBlob = false
77
+ break
78
+ }
79
+ }
80
+ // only remove the blob if not used by another reference.
81
+ if removeBlob {
82
+ // Hack to remove the existing digest until ocistore deleter is implemented
83
+ // https://github.com/oras-project/oras-go/issues/454
84
+ digestPath := filepath .Join (strings .Split (ref .Digest .String (), ":" )... )
85
+ blob := filepath .Join (c .Configuration .PoliciesRoot (), "blobs" , digestPath )
86
+ err = os .Remove (blob )
87
+ if err != nil {
88
+ return err
89
+ }
90
+ }
53
91
54
92
c .UI .Normal ().
55
93
WithStringValue ("reference" , existingRef ).
56
94
Msg ("Removed reference." )
57
95
58
- err = ociStore .SaveIndex ()
96
+ return nil
97
+ }
98
+
99
+ func (c * PolicyApp ) removeFromIndex (ref ocispec.Descriptor ) error {
100
+
101
+ type index struct {
102
+ Version int `json:"schemaVersion"`
103
+ Manifests []ocispec.Descriptor `json:"manifests"`
104
+ }
105
+
106
+ var localIndex index
107
+ indexPath := filepath .Join (c .Configuration .PoliciesRoot (), "index.json" )
108
+ indexBytes , err := os .ReadFile (indexPath )
109
+ if err != nil {
110
+ return err
111
+ }
112
+
113
+ err = json .Unmarshal (indexBytes , & localIndex )
114
+ if err != nil {
115
+ return err
116
+ }
117
+
118
+ localIndex .Manifests = removeFromManifests (localIndex .Manifests , ref )
119
+
120
+ newIndexBytes , err := json .Marshal (localIndex )
59
121
if err != nil {
60
122
return err
61
123
}
62
124
125
+ err = os .WriteFile (indexPath , newIndexBytes , 0664 )
126
+ if err != nil {
127
+ return err
128
+ }
63
129
return nil
64
130
}
131
+
132
+ func removeFromManifests (manifests []ocispec.Descriptor , ref ocispec.Descriptor ) []ocispec.Descriptor {
133
+ newarray := make ([]ocispec.Descriptor , len (manifests )- 1 )
134
+ k := 0
135
+ for i := 0 ; i < len (manifests ); i ++ {
136
+ if manifests [i ].Digest == ref .Digest && manifests [i ].Annotations [ocispec .AnnotationRefName ] == ref .Annotations [ocispec .AnnotationRefName ] {
137
+ continue
138
+ }
139
+ newarray [k ] = manifests [i ]
140
+ k ++
141
+ }
142
+ return newarray
143
+ }
0 commit comments