@@ -12,6 +12,7 @@ import (
1212 "net/url"
1313 "os"
1414 "path/filepath"
15+ "strings"
1516
1617 "github.com/ARM-software/embedded-development-services-client-utils/utils/api"
1718 paginationUtils "github.com/ARM-software/embedded-development-services-client-utils/utils/pagination"
@@ -24,6 +25,8 @@ import (
2425 "github.com/ARM-software/golang-utils/utils/safeio"
2526)
2627
28+ const relativePathKey = "Relative Path"
29+
2730type (
2831 // GetArtefactManagersFirstPageFunc defines the function which can retrieve the first page of artefact managers.
2932 GetArtefactManagersFirstPageFunc = func (ctx context.Context , job string ) (* client.ArtefactManagerCollection , * http.Response , error )
@@ -35,6 +38,44 @@ type (
3538 GetArtefactContentFunc = func (ctx context.Context , job , artefactID string ) (* os.File , * http.Response , error )
3639)
3740
41+ func determineArtefactDestination (outputDir string , maintainTree bool , item * client.ArtefactManagerItem ) (artefactFileName string , destinationDir string , err error ) {
42+ if item == nil {
43+ err = fmt .Errorf ("%w: missing artefact item" , commonerrors .ErrUndefined )
44+ return
45+ }
46+ artefactManagerName := item .GetName ()
47+ if artefactManagerName == "" {
48+ err = fmt .Errorf ("%w: missing artefact name" , commonerrors .ErrUndefined )
49+ return
50+ }
51+ rawFileName := artefactManagerName
52+ if item .HasTitle () {
53+ rawFileName = item .GetTitle ()
54+ }
55+ artefactFileName = rawFileName
56+ if unescapedName , err := url .PathUnescape (rawFileName ); err == nil {
57+ artefactFileName = unescapedName
58+ }
59+ destinationDir = filepath .Clean (outputDir )
60+ if ! maintainTree {
61+ return
62+ }
63+
64+ if item .HasExtraMetadata () {
65+ m := item .GetExtraMetadata ()
66+ treePath , ok := m [relativePathKey ]
67+ if ! ok {
68+ return
69+ }
70+ treePath = strings .TrimSpace (treePath )
71+ if strings .HasSuffix (treePath , rawFileName ) || strings .HasSuffix (treePath , artefactFileName ) {
72+ treePath = filepath .Dir (treePath )
73+ }
74+ destinationDir = filepath .Clean (filepath .Join (outputDir , treePath ))
75+ }
76+ return
77+ }
78+
3879type ArtefactManager struct {
3980 getArtefactManagerFunc GetArtefactManagerFunc
4081 getArtefactContentFunc GetArtefactContentFunc
@@ -51,8 +92,11 @@ func NewArtefactManager(getArtefactManagersFirstPage GetArtefactManagersFirstPag
5192 getArtefactManagersFollowLinkFunc : getArtefactsManagersPage ,
5293 }
5394}
54-
5595func (m * ArtefactManager ) DownloadJobArtefact (ctx context.Context , jobName string , outputDirectory string , artefactManager * client.ArtefactManagerItem ) (err error ) {
96+ return m .DownloadJobArtefactWithTree (ctx , jobName , false , outputDirectory , artefactManager )
97+ }
98+
99+ func (m * ArtefactManager ) DownloadJobArtefactWithTree (ctx context.Context , jobName string , maintainTreeLocation bool , outputDirectory string , artefactManager * client.ArtefactManagerItem ) (err error ) {
56100 err = parallelisation .DetermineContextError (ctx )
57101 if err != nil {
58102 return
@@ -83,14 +127,6 @@ func (m *ArtefactManager) DownloadJobArtefact(ctx context.Context, jobName strin
83127 return
84128 }
85129
86- artefactFilename := artefactManagerName
87- if artefactManager .HasTitle () {
88- artefactFilename = artefactManager .GetTitle ()
89- }
90- if unescapedName , err := url .PathUnescape (artefactFilename ); err == nil {
91- artefactFilename = unescapedName
92- }
93-
94130 expectedSizePtr , ok := artefactManager .GetSizeOk ()
95131 if ! ok {
96132 err = fmt .Errorf ("%w: could not fetch artefact's size from artefact's manager [%v]" , commonerrors .ErrUndefined , artefactManagerName )
@@ -105,6 +141,16 @@ func (m *ArtefactManager) DownloadJobArtefact(ctx context.Context, jobName strin
105141 }
106142 expectedHash := * expectedHashPtr
107143
144+ artefactFilename , artefactDestDir , err := determineArtefactDestination (outputDirectory , maintainTreeLocation , artefactManager )
145+ if err != nil {
146+ return
147+ }
148+ err = filesystem .MkDir (artefactDestDir )
149+ if err != nil {
150+ err = fmt .Errorf ("%w: failed creating the output directory [%v] for job artefact: %v" , commonerrors .ErrUnexpected , artefactDestDir , err .Error ())
151+ return
152+ }
153+
108154 artefact , resp , apierr := m .getArtefactContentFunc (ctx , jobName , artefactManagerName )
109155 defer func () {
110156 if resp != nil {
@@ -120,7 +166,7 @@ func (m *ArtefactManager) DownloadJobArtefact(ctx context.Context, jobName strin
120166 return
121167 }
122168
123- destination , err := filesystem .CreateFile (filepath .Join (outputDirectory , artefactFilename ))
169+ destination , err := filesystem .CreateFile (filepath .Join (artefactDestDir , artefactFilename ))
124170 if err != nil {
125171 err = fmt .Errorf ("%w: could not create a location to store generated artefact [%v]: %v" , commonerrors .ErrUnexpected , artefactFilename , err .Error ())
126172 return
@@ -161,8 +207,11 @@ func (m *ArtefactManager) DownloadJobArtefact(ctx context.Context, jobName strin
161207 return
162208
163209}
210+ func (m * ArtefactManager ) DownloadJobArtefactFromLink (ctx context.Context , jobName string , outputDirectory string , artefactManagerItemLink * client.HalLinkData ) error {
211+ return m .DownloadJobArtefactFromLinkWithTree (ctx , jobName , false , outputDirectory , artefactManagerItemLink )
212+ }
164213
165- func (m * ArtefactManager ) DownloadJobArtefactFromLink (ctx context.Context , jobName string , outputDirectory string , artefactManagerItem * client.HalLinkData ) (err error ) {
214+ func (m * ArtefactManager ) DownloadJobArtefactFromLinkWithTree (ctx context.Context , jobName string , maintainTreeLocation bool , outputDirectory string , artefactManagerItemLink * client.HalLinkData ) (err error ) {
166215 err = parallelisation .DetermineContextError (ctx )
167216 if err != nil {
168217 return
@@ -171,12 +220,12 @@ func (m *ArtefactManager) DownloadJobArtefactFromLink(ctx context.Context, jobNa
171220 err = fmt .Errorf ("%w: function to retrieve an artefact manager was not properly defined" , commonerrors .ErrUndefined )
172221 return
173222 }
174- if artefactManagerItem == nil {
223+ if artefactManagerItemLink == nil {
175224 err = fmt .Errorf ("%w: missing artefact link" , commonerrors .ErrUndefined )
176225 return
177226 }
178227
179- artefactManagerName := artefactManagerItem .GetName ()
228+ artefactManagerName := artefactManagerItemLink .GetName ()
180229 artefactManager , resp , apierr := m .getArtefactManagerFunc (ctx , jobName , artefactManagerName )
181230 defer func () {
182231 if resp != nil {
@@ -190,7 +239,7 @@ func (m *ArtefactManager) DownloadJobArtefactFromLink(ctx context.Context, jobNa
190239 if resp != nil {
191240 _ = resp .Body .Close ()
192241 }
193- err = m .DownloadJobArtefact (ctx , jobName , outputDirectory , artefactManager )
242+ err = m .DownloadJobArtefactWithTree (ctx , jobName , maintainTreeLocation , outputDirectory , artefactManager )
194243 return
195244}
196245
@@ -263,7 +312,11 @@ func (m *ArtefactManager) fetchJobArtefactsNextPage(ctx context.Context, current
263312 return
264313}
265314
266- func (m * ArtefactManager ) DownloadAllJobArtefacts (ctx context.Context , jobName string , outputDirectory string ) (err error ) {
315+ func (m * ArtefactManager ) DownloadAllJobArtefacts (ctx context.Context , jobName string , outputDirectory string ) error {
316+ return m .DownloadAllJobArtefactsWithTree (ctx , jobName , false , outputDirectory )
317+ }
318+
319+ func (m * ArtefactManager ) DownloadAllJobArtefactsWithTree (ctx context.Context , jobName string , maintainTreeStructure bool , outputDirectory string ) (err error ) {
267320 err = parallelisation .DetermineContextError (ctx )
268321 if err != nil {
269322 return
@@ -290,7 +343,7 @@ func (m *ArtefactManager) DownloadAllJobArtefacts(ctx context.Context, jobName s
290343 }
291344 artefactLink , ok := item .(* client.HalLinkData )
292345 if ok {
293- subErr = m .DownloadJobArtefactFromLink (ctx , jobName , outputDirectory , artefactLink )
346+ subErr = m .DownloadJobArtefactFromLinkWithTree (ctx , jobName , maintainTreeStructure , outputDirectory , artefactLink )
294347 if subErr != nil {
295348 err = subErr
296349 return
@@ -299,7 +352,7 @@ func (m *ArtefactManager) DownloadAllJobArtefacts(ctx context.Context, jobName s
299352 } else {
300353 artefactManager , ok := item .(* client.ArtefactManagerItem )
301354 if ok {
302- subErr = m .DownloadJobArtefact (ctx , jobName , outputDirectory , artefactManager )
355+ subErr = m .DownloadJobArtefactWithTree (ctx , jobName , maintainTreeStructure , outputDirectory , artefactManager )
303356 if subErr != nil {
304357 err = subErr
305358 return
0 commit comments