@@ -2,31 +2,121 @@ package artifact
22
33import (
44 "context"
5+ "fmt"
6+ "io"
7+ "net/url"
58 "strings"
69
710 "cloud.google.com/go/storage"
811 "google.golang.org/api/iterator"
912)
1013
14+ // URL contains the information needed to identify the location of an object
15+ // located in Google Cloud Storage.
16+ type URL struct {
17+ // Bucket is the name of the Google Cloud Storage bucket where the object
18+ // is located.
19+ Bucket string
20+
21+ // Object is the name and or path of the object stored in the bucket. It
22+ // should not start with a forward slash.
23+ Object string
24+ }
25+
1126type Service interface {
27+ ParseURL (gsURL string ) (* URL , error )
28+
29+ ReadArtifact (ctx context.Context , url string ) ([]byte , error )
30+ WriteArtifact (ctx context.Context , url string , content []byte ) error
1231 DeleteArtifact (ctx context.Context , url string ) error
1332}
1433
1534type GcsArtifactClient struct {
1635 API * storage.Client
1736}
1837
38+ func NewGcsArtifactClient (api * storage.Client ) Service {
39+ return & GcsArtifactClient {
40+ API : api ,
41+ }
42+ }
43+
44+ // Parse parses a Google Cloud Storage string into a URL struct. The expected
45+ // format of the string is gs://[bucket-name]/[object-path]. If the provided
46+ // URL is formatted incorrectly an error will be returned.
47+ func (gac * GcsArtifactClient ) ParseURL (gsURL string ) (* URL , error ) {
48+ u , err := url .Parse (gsURL )
49+ if err != nil {
50+ return nil , err
51+ }
52+ if u .Scheme != "gs" {
53+ return nil , err
54+ }
55+
56+ bucket , object := u .Host , strings .TrimLeft (u .Path , "/" )
57+
58+ if bucket == "" {
59+ return nil , err
60+ }
61+
62+ if object == "" {
63+ return nil , err
64+ }
65+
66+ return & URL {
67+ Bucket : bucket ,
68+ Object : object ,
69+ }, nil
70+ }
71+
72+ func (gac * GcsArtifactClient ) ReadArtifact (ctx context.Context , url string ) ([]byte , error ) {
73+ u , err := gac .ParseURL (url )
74+ if err != nil {
75+ return nil , err
76+ }
77+
78+ reader , err := gac .API .Bucket (u .Bucket ).Object (u .Object ).NewReader (ctx )
79+ if err != nil {
80+ return nil , err
81+ }
82+ defer reader .Close () //nolint:errcheck
83+
84+ bytes , err := io .ReadAll (reader )
85+ if err != nil {
86+ return nil , err
87+ }
88+ return bytes , nil
89+ }
90+
91+ func (gac * GcsArtifactClient ) WriteArtifact (ctx context.Context , url string , content []byte ) error {
92+ u , err := gac .ParseURL (url )
93+ if err != nil {
94+ return err
95+ }
96+ w := gac .API .Bucket (u .Bucket ).Object (u .Object ).NewWriter (ctx )
97+
98+ if _ , err := fmt .Fprintf (w , "%s" , content ); err != nil {
99+ return err
100+ }
101+
102+ if err := w .Close (); err != nil {
103+ return err
104+ }
105+
106+ return nil
107+ }
108+
19109func (gac * GcsArtifactClient ) DeleteArtifact (ctx context.Context , url string ) error {
20- // Get bucket name and gcsPrefix
21- // the [5:] is to remove the "gs://" on the artifact uri
22- // ex : gs://bucketName/path → bucketName/path
23- gcsBucket , gcsLocation := gac . getGcsBucketAndLocation ( url [ 5 :])
110+ u , err := gac . ParseURL ( url )
111+ if err != nil {
112+ return err
113+ }
24114
25115 // Sets the name for the bucket.
26- bucket := gac .API .Bucket (gcsBucket )
116+ bucket := gac .API .Bucket (u . Bucket )
27117
28118 it := bucket .Objects (ctx , & storage.Query {
29- Prefix : gcsLocation ,
119+ Prefix : u . Object ,
30120 })
31121 for {
32122 attrs , err := it .Next ()
@@ -43,25 +133,24 @@ func (gac *GcsArtifactClient) DeleteArtifact(ctx context.Context, url string) er
43133 return nil
44134}
45135
46- func (gac * GcsArtifactClient ) getGcsBucketAndLocation (str string ) (string , string ) {
47- // Split string using delimiter
48- // ex : bucketName/path/path1/item → (bucketName , path/path1/item)
49- splitStr := strings .SplitN (str , "/" , 2 )
50- return splitStr [0 ], splitStr [1 ]
136+ type NopArtifactClient struct {}
137+
138+ func NewNopArtifactClient () Service {
139+ return & NopArtifactClient {}
51140}
52141
53- func NewGcsArtifactClient (api * storage.Client ) Service {
54- return & GcsArtifactClient {
55- API : api ,
56- }
142+ func (nac * NopArtifactClient ) ParseURL (gsURL string ) (* URL , error ) {
143+ return nil , nil
57144}
58145
59- type NopArtifactClient struct {}
146+ func (nac * NopArtifactClient ) ReadArtifact (ctx context.Context , url string ) ([]byte , error ) {
147+ return nil , nil
148+ }
60149
61- func (nac * NopArtifactClient ) DeleteArtifact (ctx context.Context , url string ) error {
150+ func (nac * NopArtifactClient ) WriteArtifact (ctx context.Context , url string , content [] byte ) error {
62151 return nil
63152}
64153
65- func NewNopArtifactClient () Service {
66- return & NopArtifactClient {}
154+ func ( nac * NopArtifactClient ) DeleteArtifact ( ctx context. Context , url string ) error {
155+ return nil
67156}
0 commit comments