@@ -14,7 +14,9 @@ import (
1414 "path/filepath"
1515
1616 "github.com/ARM-software/embedded-development-services-client-utils/utils/api"
17+ paginationUtils "github.com/ARM-software/embedded-development-services-client-utils/utils/pagination"
1718 "github.com/ARM-software/embedded-development-services-client/client"
19+ "github.com/ARM-software/golang-utils/utils/collection/pagination"
1820 "github.com/ARM-software/golang-utils/utils/commonerrors"
1921 "github.com/ARM-software/golang-utils/utils/filesystem"
2022 "github.com/ARM-software/golang-utils/utils/hashing"
@@ -23,47 +25,68 @@ import (
2325)
2426
2527type (
26- getArtefactManagerFunc = func (ctx context.Context , job , artefact string ) (* client.ArtefactManagerItem , * http.Response , error )
27- getArtefactContentFunc = func (ctx context.Context , job , artefactID string ) (* os.File , * http.Response , error )
28+ // GetArtefactManagersFirstPageFunc defines the function which can retrieve the first page of artefact managers.
29+ GetArtefactManagersFirstPageFunc = func (ctx context.Context , job string ) (* client.ArtefactManagerCollection , * http.Response , error )
30+ // FollowLinkToArtefactManagersPageFunc is a function able to follow a link to an artefact manager page.
31+ FollowLinkToArtefactManagersPageFunc = func (ctx context.Context , href string ) (* client.ArtefactManagerCollection , * http.Response , error )
32+ // GetArtefactManagerFunc is a function which retrieves information about an artefact manager.
33+ GetArtefactManagerFunc = func (ctx context.Context , job , artefact string ) (* client.ArtefactManagerItem , * http.Response , error )
34+ // GetArtefactContentFunc is a function able to return the content of any artefact managers.
35+ GetArtefactContentFunc = func (ctx context.Context , job , artefactID string ) (* os.File , * http.Response , error )
2836)
2937
3038type ArtefactManager struct {
31- getArtefactManagerFunc getArtefactManagerFunc
32- getArtefactContentFunc getArtefactContentFunc
39+ getArtefactManagerFunc GetArtefactManagerFunc
40+ getArtefactContentFunc GetArtefactContentFunc
41+ getArtefactManagersFirstPageFunc GetArtefactManagersFirstPageFunc
42+ getArtefactManagersFollowLinkFunc FollowLinkToArtefactManagersPageFunc
3343}
3444
35- func NewArtefactManager (getArtefactManager getArtefactManagerFunc , getOutputArtefact getArtefactContentFunc ) * ArtefactManager {
45+ // NewArtefactManager returns an artefact manager.
46+ func NewArtefactManager (getArtefactManagersFirstPage GetArtefactManagersFirstPageFunc , getArtefactsManagersPage FollowLinkToArtefactManagersPageFunc , getArtefactManager GetArtefactManagerFunc , getOutputArtefact GetArtefactContentFunc ) IArtefactManager {
3647 return & ArtefactManager {
37- getArtefactManagerFunc : getArtefactManager ,
38- getArtefactContentFunc : getOutputArtefact ,
48+ getArtefactManagerFunc : getArtefactManager ,
49+ getArtefactContentFunc : getOutputArtefact ,
50+ getArtefactManagersFirstPageFunc : getArtefactManagersFirstPage ,
51+ getArtefactManagersFollowLinkFunc : getArtefactsManagersPage ,
3952 }
4053}
4154
42- func (m * ArtefactManager ) DownloadJobArtefact (ctx context.Context , jobName string , outputDirectory string , artefactManagerItem client.HalLinkData ) (err error ) {
55+ func (m * ArtefactManager ) DownloadJobArtefact (ctx context.Context , jobName string , outputDirectory string , artefactManager * client.ArtefactManagerItem ) (err error ) {
4356 err = parallelisation .DetermineContextError (ctx )
4457 if err != nil {
4558 return
4659 }
60+ if m .getArtefactManagerFunc == nil || m .getArtefactContentFunc == nil {
61+ err = fmt .Errorf ("%w: function to retrieve an artefact manager was not properly defined" , commonerrors .ErrUndefined )
62+ return
63+ }
4764
48- artefactManagerName := artefactManagerItem .GetName ()
49- artefactManager , resp , apierr := m .getArtefactManagerFunc (ctx , jobName , artefactManagerName )
50- defer func () {
51- if resp != nil {
52- _ = resp .Body .Close ()
53- }
54- }()
55- err = api .CheckAPICallSuccess (ctx , fmt .Sprintf ("cannot fetch artefact's manager [%v]" , artefactManager ), resp , apierr )
65+ err = filesystem .MkDir (outputDirectory )
5666 if err != nil {
67+ err = fmt .Errorf ("%w: failed creating the output directory [%v] for job artefact: %v" , commonerrors .ErrUnexpected , outputDirectory , err .Error ())
5768 return
5869 }
5970
60- artefactFilenamePtr , ok := artefactManager .GetTitleOk ()
61- if ! ok {
62- err = fmt .Errorf ("%w: could not fetch artefact's title from artefact's manager [%v]" , commonerrors .ErrUndefined , artefactManagerName )
71+ fileHasher , err := filesystem .NewFileHash (hashing .HashSha256 )
72+ if err != nil {
73+ return
74+ }
75+ if artefactManager == nil {
76+ err = fmt .Errorf ("%w: missing artefact manager" , commonerrors .ErrUndefined )
77+ return
78+ }
79+
80+ artefactManagerName := artefactManager .GetName ()
81+ if artefactManagerName == "" {
82+ err = fmt .Errorf ("%w: missing artefact name" , commonerrors .ErrUndefined )
6383 return
6484 }
6585
66- artefactFilename := * artefactFilenamePtr
86+ artefactFilename := artefactManagerName
87+ if artefactManager .HasTitle () {
88+ artefactFilename = artefactManager .GetTitle ()
89+ }
6790 if unescapedName , err := url .PathUnescape (artefactFilename ); err == nil {
6891 artefactFilename = unescapedName
6992 }
@@ -82,14 +105,7 @@ func (m *ArtefactManager) DownloadJobArtefact(ctx context.Context, jobName strin
82105 }
83106 expectedHash := * expectedHashPtr
84107
85- artefactNamePtr , ok := artefactManager .GetNameOk ()
86- if ! ok {
87- err = fmt .Errorf ("%w: could not fetch artefact's name from artefact's manager [%v]" , commonerrors .ErrUndefined , artefactManagerName )
88- return
89- }
90- artefactName := * artefactNamePtr
91-
92- artefact , resp , apierr := m .getArtefactContentFunc (ctx , jobName , artefactName )
108+ artefact , resp , apierr := m .getArtefactContentFunc (ctx , jobName , artefactManagerName )
93109 defer func () {
94110 if resp != nil {
95111 _ = resp .Body .Close ()
@@ -111,11 +127,6 @@ func (m *ArtefactManager) DownloadJobArtefact(ctx context.Context, jobName strin
111127 }
112128 defer func () { _ = destination .Close () }()
113129
114- fileHasher , err := filesystem .NewFileHash (hashing .HashSha256 )
115- if err != nil {
116- return
117- }
118-
119130 actualSize , err := safeio .CopyDataWithContext (ctx , artefact , destination )
120131 if err != nil {
121132 err = fmt .Errorf ("%w: failed to copy artefact [%v]: %v" , commonerrors .ErrUnexpected , artefactFilename , err .Error ())
@@ -148,4 +159,152 @@ func (m *ArtefactManager) DownloadJobArtefact(ctx context.Context, jobName strin
148159
149160 err = parallelisation .DetermineContextError (ctx )
150161 return
162+
163+ }
164+
165+ func (m * ArtefactManager ) DownloadJobArtefactFromLink (ctx context.Context , jobName string , outputDirectory string , artefactManagerItem * client.HalLinkData ) (err error ) {
166+ err = parallelisation .DetermineContextError (ctx )
167+ if err != nil {
168+ return
169+ }
170+ if m .getArtefactManagerFunc == nil || m .getArtefactContentFunc == nil {
171+ err = fmt .Errorf ("%w: function to retrieve an artefact manager was not properly defined" , commonerrors .ErrUndefined )
172+ return
173+ }
174+ if artefactManagerItem == nil {
175+ err = fmt .Errorf ("%w: missing artefact link" , commonerrors .ErrUndefined )
176+ return
177+ }
178+
179+ artefactManagerName := artefactManagerItem .GetName ()
180+ artefactManager , resp , apierr := m .getArtefactManagerFunc (ctx , jobName , artefactManagerName )
181+ defer func () {
182+ if resp != nil {
183+ _ = resp .Body .Close ()
184+ }
185+ }()
186+ err = api .CheckAPICallSuccess (ctx , fmt .Sprintf ("cannot fetch artefact's manager [%+v]" , artefactManager ), resp , apierr )
187+ if err != nil {
188+ return
189+ }
190+ if resp != nil {
191+ _ = resp .Body .Close ()
192+ }
193+ err = m .DownloadJobArtefact (ctx , jobName , outputDirectory , artefactManager )
194+ return
195+ }
196+
197+ func (m * ArtefactManager ) ListJobArtefacts (ctx context.Context , jobName string ) (pagination.IPaginatorAndPageFetcher , error ) {
198+ err := parallelisation .DetermineContextError (ctx )
199+ if err != nil {
200+ return nil , err
201+ }
202+ return pagination .NewStaticPagePaginator (ctx , func (context.Context ) (pagination.IStaticPage , error ) {
203+ return m .fetchJobArtefactsFirstPage (ctx , jobName )
204+ }, m .fetchJobArtefactsNextPage )
205+ }
206+
207+ func (m * ArtefactManager ) fetchJobArtefactsFirstPage (ctx context.Context , jobName string ) (page pagination.IStaticPage , err error ) {
208+ if m .getArtefactManagersFirstPageFunc == nil {
209+ err = fmt .Errorf ("%w: function to retrieve artefact managers was not properly defined" , commonerrors .ErrUndefined )
210+ return
211+ }
212+ clientPage , resp , apierr := m .getArtefactManagersFirstPageFunc (ctx , jobName )
213+ if resp != nil {
214+ _ = resp .Body .Close ()
215+ }
216+ err = api .CheckAPICallSuccess (ctx , fmt .Sprintf ("could not list artefact managers for job [%v]" , jobName ), resp , apierr )
217+ if err == nil {
218+ page = paginationUtils .ToPage (clientPage )
219+ }
220+ return
221+ }
222+
223+ func (m * ArtefactManager ) fetchJobArtefactsNextPage (ctx context.Context , currentPage pagination.IStaticPage ) (nextPage pagination.IStaticPage , err error ) {
224+ err = parallelisation .DetermineContextError (ctx )
225+ if err != nil {
226+ return
227+ }
228+ if currentPage == nil {
229+ return
230+ }
231+ if m .getArtefactManagersFollowLinkFunc == nil {
232+ err = fmt .Errorf ("%w: function to retrieve artefact managers was not properly defined" , commonerrors .ErrUndefined )
233+ return
234+ }
235+ page , ok := paginationUtils .ToClientPage (currentPage ).(* client.BuildJobCollection )
236+ if ! ok {
237+ err = fmt .Errorf ("%w: returned build job page [%T] is not of the expected type [%v]" , commonerrors .ErrUnexpected , currentPage , "*BuildJobCollection" )
238+ return
239+ }
240+ links , has := page .GetLinksOk ()
241+ if ! has {
242+ err = fmt .Errorf ("%w: returned page of build jobs has no links" , commonerrors .ErrUnexpected )
243+ return
244+ }
245+ if ! links .HasNext () {
246+ err = fmt .Errorf ("%w: returned page of build job has no `next` link" , commonerrors .ErrUnexpected )
247+ return
248+ }
249+ link := links .GetNext ()
250+ clientPage , resp , apierr := m .getArtefactManagersFollowLinkFunc (ctx , link .GetHref ())
251+ if resp != nil {
252+ _ = resp .Body .Close ()
253+ }
254+ err = api .CheckAPICallSuccess (ctx , fmt .Sprintf ("could not follow `next` link [%v]" , link ), resp , apierr )
255+ if err == nil {
256+ nextPage = paginationUtils .ToPage (clientPage )
257+ }
258+ return
259+ }
260+
261+ func (m * ArtefactManager ) DownloadAllJobArtefacts (ctx context.Context , jobName string , outputDirectory string ) (err error ) {
262+ err = parallelisation .DetermineContextError (ctx )
263+ if err != nil {
264+ return
265+ }
266+ err = filesystem .MkDir (outputDirectory )
267+ if err != nil {
268+ err = fmt .Errorf ("%w: failed creating the output directory [%v] for job artefacts: %v" , commonerrors .ErrUnexpected , outputDirectory , err .Error ())
269+ return
270+ }
271+ paginator , err := m .ListJobArtefacts (ctx , jobName )
272+ if err != nil {
273+ return
274+ }
275+ stop := paginator .Stop ()
276+ defer stop ()
277+ for {
278+ if ! paginator .HasNext () {
279+ return
280+ }
281+ item , subErr := paginator .GetNext ()
282+ if subErr != nil {
283+ err = fmt .Errorf ("%w: failed getting information about job artefacts: %v" , commonerrors .ErrUnexpected , subErr .Error ())
284+ return
285+ }
286+ artefactLink , ok := item .(* client.HalLinkData )
287+ if ok {
288+ subErr = m .DownloadJobArtefactFromLink (ctx , jobName , outputDirectory , artefactLink )
289+ if subErr != nil {
290+ err = subErr
291+ return
292+ }
293+
294+ } else {
295+ artefactManager , ok := item .(* client.ArtefactManagerItem )
296+ if ok {
297+ subErr = m .DownloadJobArtefact (ctx , jobName , outputDirectory , artefactManager )
298+ if subErr != nil {
299+ err = subErr
300+ return
301+ }
302+ } else {
303+ err = fmt .Errorf ("%w: the type of the response from service cannot be interpreted" , commonerrors .ErrMarshalling )
304+ return
305+ }
306+
307+ }
308+
309+ }
151310}
0 commit comments