@@ -22,6 +22,7 @@ import (
22
22
"fmt"
23
23
"net/http"
24
24
"net/url"
25
+ "slices"
25
26
"time"
26
27
27
28
"github.com/minio/minio-go/v7/pkg/s3utils"
@@ -421,20 +422,17 @@ func (c *Client) listObjectVersions(ctx context.Context, bucketName string, opts
421
422
var (
422
423
keyMarker = ""
423
424
versionIDMarker = ""
425
+ preName = ""
426
+ preKey = ""
427
+ perVersions []Version
428
+ numVersions int
424
429
)
425
-
426
- for {
427
- // Get list of objects a maximum of 1000 per request.
428
- result , err := c .listObjectVersionsQuery (ctx , bucketName , opts , keyMarker , versionIDMarker , delimiter )
429
- if err != nil {
430
- sendObjectInfo (ObjectInfo {
431
- Err : err ,
432
- })
433
- return
430
+ send := func (vers []Version ) {
431
+ if opts .WithVersions && opts .ReverseVersions {
432
+ slices .Reverse (vers )
433
+ numVersions = len (vers )
434
434
}
435
-
436
- // If contents are available loop through and send over channel.
437
- for _ , version := range result .Versions {
435
+ for _ , version := range vers {
438
436
info := ObjectInfo {
439
437
ETag : trimEtag (version .ETag ),
440
438
Key : version .Key ,
@@ -448,6 +446,7 @@ func (c *Client) listObjectVersions(ctx context.Context, bucketName string, opts
448
446
UserTags : version .UserTags ,
449
447
UserMetadata : version .UserMetadata ,
450
448
Internal : version .Internal ,
449
+ NumVersions : numVersions ,
451
450
}
452
451
select {
453
452
// Send object version info.
@@ -457,6 +456,38 @@ func (c *Client) listObjectVersions(ctx context.Context, bucketName string, opts
457
456
return
458
457
}
459
458
}
459
+ }
460
+ for {
461
+ // Get list of objects a maximum of 1000 per request.
462
+ result , err := c .listObjectVersionsQuery (ctx , bucketName , opts , keyMarker , versionIDMarker , delimiter )
463
+ if err != nil {
464
+ sendObjectInfo (ObjectInfo {
465
+ Err : err ,
466
+ })
467
+ return
468
+ }
469
+ if opts .WithVersions && opts .ReverseVersions {
470
+ for _ , version := range result .Versions {
471
+ if preName == "" {
472
+ preName = result .Name
473
+ preKey = version .Key
474
+ }
475
+ if result .Name == preName && preKey == version .Key {
476
+ // If the current name is same as previous name,
477
+ // we need to append the version to the previous version.
478
+ perVersions = append (perVersions , version )
479
+ continue
480
+ }
481
+ // Send the file versions.
482
+ send (perVersions )
483
+ perVersions = perVersions [:0 ]
484
+ perVersions = append (perVersions , version )
485
+ preName = result .Name
486
+ preKey = version .Key
487
+ }
488
+ } else {
489
+ send (result .Versions )
490
+ }
460
491
461
492
// Send all common prefixes if any.
462
493
// NOTE: prefixes are only present if the request is delimited.
@@ -480,10 +511,20 @@ func (c *Client) listObjectVersions(ctx context.Context, bucketName string, opts
480
511
versionIDMarker = result .NextVersionIDMarker
481
512
}
482
513
514
+ // If context is canceled, return here.
515
+ if contextCanceled (ctx ) {
516
+ return
517
+ }
518
+
483
519
// Listing ends result is not truncated, return right here.
484
520
if ! result .IsTruncated {
521
+ // sent the lasted file with versions
522
+ if opts .ReverseVersions && len (perVersions ) > 0 {
523
+ send (perVersions )
524
+ }
485
525
return
486
526
}
527
+
487
528
}
488
529
}(resultCh )
489
530
return resultCh
@@ -683,6 +724,8 @@ func (c *Client) listObjectsQuery(ctx context.Context, bucketName, objectPrefix,
683
724
684
725
// ListObjectsOptions holds all options of a list object request
685
726
type ListObjectsOptions struct {
727
+ // ReverseVersions - reverse the order of the object versions
728
+ ReverseVersions bool
686
729
// Include objects versions in the listing
687
730
WithVersions bool
688
731
// Include objects metadata in the listing
0 commit comments