@@ -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,45 @@ 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+ artefactFileName = rawFileName
53+ if item .HasTitle () {
54+ rawFileName = item .GetTitle ()
55+ }
56+ artefactFileName = rawFileName
57+ if unescapedName , err := url .PathUnescape (rawFileName ); err == nil {
58+ artefactFileName = unescapedName
59+ }
60+ destinationDir = filepath .Clean (outputDir )
61+ if ! maintainTree {
62+ return
63+ }
64+
65+ if item .HasExtraMetadata () {
66+ m := item .GetExtraMetadata ()
67+ treePath , ok := m [relativePathKey ]
68+ if ! ok {
69+ return
70+ }
71+ treePath = strings .TrimSpace (treePath )
72+ if strings .HasSuffix (treePath , rawFileName ) || strings .HasSuffix (treePath , artefactFileName ) {
73+ treePath = filepath .Dir (treePath )
74+ }
75+ destinationDir = filepath .Clean (filepath .Join (outputDir , treePath ))
76+ }
77+ return
78+ }
79+
3880type ArtefactManager struct {
3981 getArtefactManagerFunc GetArtefactManagerFunc
4082 getArtefactContentFunc GetArtefactContentFunc
@@ -51,8 +93,11 @@ func NewArtefactManager(getArtefactManagersFirstPage GetArtefactManagersFirstPag
5193 getArtefactManagersFollowLinkFunc : getArtefactsManagersPage ,
5294 }
5395}
54-
5596func (m * ArtefactManager ) DownloadJobArtefact (ctx context.Context , jobName string , outputDirectory string , artefactManager * client.ArtefactManagerItem ) (err error ) {
97+ return m .DownloadJobArtefactWithTree (ctx , jobName , false , outputDirectory , artefactManager )
98+ }
99+
100+ func (m * ArtefactManager ) DownloadJobArtefactWithTree (ctx context.Context , jobName string , maintainTreeLocation bool , outputDirectory string , artefactManager * client.ArtefactManagerItem ) (err error ) {
56101 err = parallelisation .DetermineContextError (ctx )
57102 if err != nil {
58103 return
@@ -83,14 +128,6 @@ func (m *ArtefactManager) DownloadJobArtefact(ctx context.Context, jobName strin
83128 return
84129 }
85130
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-
94131 expectedSizePtr , ok := artefactManager .GetSizeOk ()
95132 if ! ok {
96133 err = fmt .Errorf ("%w: could not fetch artefact's size from artefact's manager [%v]" , commonerrors .ErrUndefined , artefactManagerName )
@@ -105,6 +142,16 @@ func (m *ArtefactManager) DownloadJobArtefact(ctx context.Context, jobName strin
105142 }
106143 expectedHash := * expectedHashPtr
107144
145+ artefactFilename , artefactDestDir , err := determineArtefactDestination (outputDirectory , maintainTreeLocation , artefactManager )
146+ if err != nil {
147+ return
148+ }
149+ err = filesystem .MkDir (artefactDestDir )
150+ if err != nil {
151+ err = fmt .Errorf ("%w: failed creating the output directory [%v] for job artefact: %v" , commonerrors .ErrUnexpected , artefactDestDir , err .Error ())
152+ return
153+ }
154+
108155 artefact , resp , apierr := m .getArtefactContentFunc (ctx , jobName , artefactManagerName )
109156 defer func () {
110157 if resp != nil {
@@ -120,7 +167,7 @@ func (m *ArtefactManager) DownloadJobArtefact(ctx context.Context, jobName strin
120167 return
121168 }
122169
123- destination , err := filesystem .CreateFile (filepath .Join (outputDirectory , artefactFilename ))
170+ destination , err := filesystem .CreateFile (filepath .Join (artefactDestDir , artefactFilename ))
124171 if err != nil {
125172 err = fmt .Errorf ("%w: could not create a location to store generated artefact [%v]: %v" , commonerrors .ErrUnexpected , artefactFilename , err .Error ())
126173 return
@@ -161,8 +208,11 @@ func (m *ArtefactManager) DownloadJobArtefact(ctx context.Context, jobName strin
161208 return
162209
163210}
211+ func (m * ArtefactManager ) DownloadJobArtefactFromLink (ctx context.Context , jobName string , outputDirectory string , artefactManagerItemLink * client.HalLinkData ) error {
212+ return m .DownloadJobArtefactFromLinkWithTree (ctx , jobName , false , outputDirectory , artefactManagerItemLink )
213+ }
164214
165- func (m * ArtefactManager ) DownloadJobArtefactFromLink (ctx context.Context , jobName string , outputDirectory string , artefactManagerItem * client.HalLinkData ) (err error ) {
215+ func (m * ArtefactManager ) DownloadJobArtefactFromLinkWithTree (ctx context.Context , jobName string , maintainTreeLocation bool , outputDirectory string , artefactManagerItemLink * client.HalLinkData ) (err error ) {
166216 err = parallelisation .DetermineContextError (ctx )
167217 if err != nil {
168218 return
@@ -171,12 +221,12 @@ func (m *ArtefactManager) DownloadJobArtefactFromLink(ctx context.Context, jobNa
171221 err = fmt .Errorf ("%w: function to retrieve an artefact manager was not properly defined" , commonerrors .ErrUndefined )
172222 return
173223 }
174- if artefactManagerItem == nil {
224+ if artefactManagerItemLink == nil {
175225 err = fmt .Errorf ("%w: missing artefact link" , commonerrors .ErrUndefined )
176226 return
177227 }
178228
179- artefactManagerName := artefactManagerItem .GetName ()
229+ artefactManagerName := artefactManagerItemLink .GetName ()
180230 artefactManager , resp , apierr := m .getArtefactManagerFunc (ctx , jobName , artefactManagerName )
181231 defer func () {
182232 if resp != nil {
@@ -190,7 +240,7 @@ func (m *ArtefactManager) DownloadJobArtefactFromLink(ctx context.Context, jobNa
190240 if resp != nil {
191241 _ = resp .Body .Close ()
192242 }
193- err = m .DownloadJobArtefact (ctx , jobName , outputDirectory , artefactManager )
243+ err = m .DownloadJobArtefactWithTree (ctx , jobName , maintainTreeLocation , outputDirectory , artefactManager )
194244 return
195245}
196246
@@ -263,7 +313,11 @@ func (m *ArtefactManager) fetchJobArtefactsNextPage(ctx context.Context, current
263313 return
264314}
265315
266- func (m * ArtefactManager ) DownloadAllJobArtefacts (ctx context.Context , jobName string , outputDirectory string ) (err error ) {
316+ func (m * ArtefactManager ) DownloadAllJobArtefacts (ctx context.Context , jobName string , outputDirectory string ) error {
317+ return m .DownloadAllJobArtefactsWithTree (ctx , jobName , false , outputDirectory )
318+ }
319+
320+ func (m * ArtefactManager ) DownloadAllJobArtefactsWithTree (ctx context.Context , jobName string , maintainTreeStructure bool , outputDirectory string ) (err error ) {
267321 err = parallelisation .DetermineContextError (ctx )
268322 if err != nil {
269323 return
@@ -290,7 +344,7 @@ func (m *ArtefactManager) DownloadAllJobArtefacts(ctx context.Context, jobName s
290344 }
291345 artefactLink , ok := item .(* client.HalLinkData )
292346 if ok {
293- subErr = m .DownloadJobArtefactFromLink (ctx , jobName , outputDirectory , artefactLink )
347+ subErr = m .DownloadJobArtefactFromLinkWithTree (ctx , jobName , maintainTreeStructure , outputDirectory , artefactLink )
294348 if subErr != nil {
295349 err = subErr
296350 return
@@ -299,7 +353,7 @@ func (m *ArtefactManager) DownloadAllJobArtefacts(ctx context.Context, jobName s
299353 } else {
300354 artefactManager , ok := item .(* client.ArtefactManagerItem )
301355 if ok {
302- subErr = m .DownloadJobArtefact (ctx , jobName , outputDirectory , artefactManager )
356+ subErr = m .DownloadJobArtefactWithTree (ctx , jobName , maintainTreeStructure , outputDirectory , artefactManager )
303357 if subErr != nil {
304358 err = subErr
305359 return
0 commit comments