Skip to content

Commit

Permalink
Experimental: Unix Perm add support for SyncManager's download (#7936)
Browse files Browse the repository at this point in the history
* Experimental: Unix Perm add support for SyncManager's download

* Skip tests for now

* Fix deprecation

* CR Fixes

* CR Fixes 2
  • Loading branch information
N-o-Z authored Jul 1, 2024
1 parent 9b1ea5a commit 5463a8e
Show file tree
Hide file tree
Showing 7 changed files with 394 additions and 71 deletions.
12 changes: 6 additions & 6 deletions cmd/lakectl/cmd/local_commit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func getTestClient(t *testing.T, endpoint string) *apigen.ClientWithResponses {
httpClient := &http.Client{
Transport: transport,
}
basicAuthProvider, err := securityprovider.NewSecurityProviderBasicAuth(string(defaultAdminAccessKeyID), string(defaultAdminSecretAccessKey))
basicAuthProvider, err := securityprovider.NewSecurityProviderBasicAuth(defaultAdminAccessKeyID, defaultAdminSecretAccessKey)
require.NoError(t, err)

serverEndpoint, err := apiutil.NormalizeLakeFSEndpoint(endpoint)
Expand Down Expand Up @@ -70,7 +70,7 @@ func TestUncommittedOutsideOfPrefix(t *testing.T) {
w.Header().Set("Content-Type", "application/json")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(res)
require.NoError(t, json.NewEncoder(w).Encode(res))
}),
expectedResult: false,
},
Expand All @@ -88,7 +88,7 @@ func TestUncommittedOutsideOfPrefix(t *testing.T) {
w.Header().Set("Content-Type", "application/json")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(res)
require.NoError(t, json.NewEncoder(w).Encode(res))
}),
expectedResult: true,
},
Expand Down Expand Up @@ -122,7 +122,7 @@ func TestUncommittedOutsideOfPrefix(t *testing.T) {
w.WriteHeader(http.StatusNotFound)
}
require.NotNil(t, res, "Unexpected request")
json.NewEncoder(w).Encode(res)
require.NoError(t, json.NewEncoder(w).Encode(res))
}),
expectedResult: false,
},
Expand Down Expand Up @@ -162,7 +162,7 @@ func TestUncommittedOutsideOfPrefix(t *testing.T) {
}

require.NotNil(t, res, "Unexpected request")
json.NewEncoder(w).Encode(res)
require.NoError(t, json.NewEncoder(w).Encode(res))
}),
expectedResult: true,
},
Expand Down Expand Up @@ -198,7 +198,7 @@ func TestUncommittedOutsideOfPrefix(t *testing.T) {
}

require.NotNil(t, res, "Unexpected request")
json.NewEncoder(w).Encode(res)
require.NoError(t, json.NewEncoder(w).Encode(res))
}),
expectedResult: true,
},
Expand Down
16 changes: 6 additions & 10 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ require (
github.com/hashicorp/go-multierror v1.1.1
github.com/hnlq715/golang-lru v0.3.0
github.com/jamiealquiza/tachymeter v2.0.0+incompatible
github.com/jedib0t/go-pretty/v6 v6.4.8
github.com/jedib0t/go-pretty/v6 v6.5.9
github.com/manifoldco/promptui v0.9.0
github.com/matoous/go-nanoid/v2 v2.0.0
github.com/minio/minio-go/v7 v7.0.63
Expand All @@ -47,7 +47,7 @@ require (
github.com/xitongsys/parquet-go-source v0.0.0-20230607234618-40034c8066df
golang.org/x/crypto v0.18.0
golang.org/x/oauth2 v0.15.0
golang.org/x/term v0.16.0
golang.org/x/term v0.17.0
google.golang.org/api v0.152.0
google.golang.org/protobuf v1.31.0
gopkg.in/natefinch/lumberjack.v2 v2.0.0
Expand All @@ -66,6 +66,8 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v0.3.6
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0
github.com/IBM/pgxpoolprometheus v1.1.1
github.com/Masterminds/sprig/v3 v3.2.3
github.com/NYTimes/gziphandler v1.1.1
github.com/Shopify/go-lua v0.0.0-20221004153744-91867de107cf
github.com/alitto/pond v1.8.3
github.com/antonmedv/expr v1.15.3
Expand Down Expand Up @@ -107,8 +109,6 @@ require (
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.0 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/NYTimes/gziphandler v1.1.1 // indirect
github.com/ahmetb/go-linq/v3 v3.2.0 // indirect
github.com/apache/arrow/go/arrow v0.0.0-20200730104253-651201b0f516 // indirect
github.com/aws/aws-sdk-go v1.48.11 // indirect
Expand Down Expand Up @@ -145,11 +145,8 @@ require (
github.com/imdario/mergo v0.3.12 // indirect
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mattn/go-shellwords v1.0.12 // indirect
github.com/mitchellh/copystructure v1.0.0 // indirect
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
Expand Down Expand Up @@ -188,7 +185,6 @@ require (
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
github.com/VividCortex/ewma v1.1.1 // indirect
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.2.1
github.com/cespare/xxhash/v2 v2.2.0
Expand Down Expand Up @@ -252,9 +248,9 @@ require (
golang.org/x/exp v0.0.0-20231127185646-65229373498e
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.20.0
golang.org/x/sys v0.16.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.17.0 // indirect
golang.org/x/tools v0.17.0
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20231127180814-3a041ad873d4 // indirect
Expand Down
19 changes: 6 additions & 13 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,6 @@ github.com/apache/thrift v0.14.2/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb
github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU=
github.com/apache/thrift v0.19.0 h1:sOqkWPzMj7w6XaYbJQG7m4sGqVolaW/0D28Ln7yPzMk=
github.com/apache/thrift v0.19.0/go.mod h1:SUALL216IiaOw2Oy+5Vs9lboJ/t9g40C+G07Dc0QC1I=
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
Expand Down Expand Up @@ -645,8 +644,6 @@ github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+
github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA=
github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M=
github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/go-uuid v0.0.0-20180228145832-27454136f036/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
Expand Down Expand Up @@ -731,8 +728,8 @@ github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFr
github.com/jamiealquiza/tachymeter v2.0.0+incompatible h1:mGiF1DGo8l6vnGT8FXNNcIXht/YmjzfraiUprXYwJ6g=
github.com/jamiealquiza/tachymeter v2.0.0+incompatible/go.mod h1:Ayf6zPZKEnLsc3winWEXJRkTBhdHo58HODAu1oFJkYU=
github.com/jcmturner/gofork v0.0.0-20180107083740-2aebee971930/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
github.com/jedib0t/go-pretty/v6 v6.4.8 h1:HiNzyMSEpsBaduKhmK+CwcpulEeBrTmxutz4oX/oWkg=
github.com/jedib0t/go-pretty/v6 v6.4.8/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs=
github.com/jedib0t/go-pretty/v6 v6.5.9 h1:ACteMBRrrmm1gMsXe9PSTOClQ63IXDUt03H5U+UV8OU=
github.com/jedib0t/go-pretty/v6 v6.5.9/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
Expand Down Expand Up @@ -849,7 +846,6 @@ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APP
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
Expand Down Expand Up @@ -940,7 +936,6 @@ github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsK
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
Expand Down Expand Up @@ -1048,7 +1043,6 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
Expand Down Expand Up @@ -1416,19 +1410,18 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down
2 changes: 1 addition & 1 deletion pkg/local/progress.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func NewProgressPool() *ProgressPool {
pw := progress.NewWriter()
pw.SetAutoStop(false) // important
pw.SetTrackerLength(progressTrackerLength)
pw.SetMessageWidth(progressTrackerWidth)
pw.SetMessageLength(progressTrackerWidth)
pw.SetSortBy(progress.SortByValue)
pw.SetStyle(progress.StyleDefault)
pw.SetTrackerPosition(progress.PositionRight)
Expand Down
112 changes: 71 additions & 41 deletions pkg/local/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ import (
)

const (
DefaultDirectoryMask = 0o755
ClientMtimeMetadataKey = apiutil.LakeFSMetadataPrefix + "client-mtime"
// DefaultDirectoryPermissions Octal representation of default folder permissions
DefaultDirectoryPermissions = 0o040777
ClientMtimeMetadataKey = apiutil.LakeFSMetadataPrefix + "client-mtime"
)

type SyncFlags struct {
Expand Down Expand Up @@ -95,6 +96,9 @@ func (s *SyncManager) Sync(rootPath string, remote *uri.URI, changeSet <-chan *C
if err := wg.Wait(); err != nil {
return err
}
if s.includePerm { // TODO (niro): Probably need to take care of pruning in deleteLocal flow
return nil // Do not prune directories in this case to preserve directories and permissions
}
_, err := fileutil.PruneEmptyDirectories(rootPath)
return err
}
Expand Down Expand Up @@ -136,41 +140,8 @@ func (s *SyncManager) apply(ctx context.Context, rootPath string, remote *uri.UR
return nil
}

func (s *SyncManager) download(ctx context.Context, rootPath string, remote *uri.URI, path string) error {
if err := fileutil.VerifyRelPath(strings.TrimPrefix(path, uri.PathSeparator), rootPath); err != nil {
return err
}
destination := filepath.Join(rootPath, path)
destinationDirectory := filepath.Dir(destination)
if err := os.MkdirAll(destinationDirectory, DefaultDirectoryMask); err != nil {
return err
}
statResp, err := s.client.StatObjectWithResponse(ctx, remote.Repository, remote.Ref, &apigen.StatObjectParams{
Path: filepath.ToSlash(filepath.Join(remote.GetPath(), path)),
Presign: swag.Bool(s.flags.Presign),
UserMetadata: swag.Bool(true),
})
if err != nil {
return err
}
if statResp.StatusCode() != http.StatusOK {
httpErr := apigen.Error{Message: "no content"}
_ = json.Unmarshal(statResp.Body, &httpErr)
return fmt.Errorf("(stat: HTTP %d, message: %s): %w", statResp.StatusCode(), httpErr.Message, ErrDownloadingFile)
}
// get mtime
mtimeSecs, err := getMtimeFromStats(*statResp.JSON200)
if err != nil {
return err
}

if strings.HasSuffix(path, uri.PathSeparator) {
// Directory marker - skip
return nil
}

lastModified := time.Unix(mtimeSecs, 0)
sizeBytes := swag.Int64Value(statResp.JSON200.SizeBytes)
func (s *SyncManager) downloadFile(ctx context.Context, remote *uri.URI, path, destination string, objStat apigen.ObjectStats) error {
sizeBytes := swag.Int64Value(objStat.SizeBytes)
f, err := os.Create(destination)
if err != nil {
// Sometimes we get a file that is actually a directory marker (Spark loves writing those).
Expand All @@ -188,11 +159,10 @@ func (s *SyncManager) download(ctx context.Context, rootPath string, remote *uri
spinner := s.progressBar.AddSpinner("download " + path)
atomic.AddUint64(&s.tasks.Downloaded, 1)
defer spinner.Done()
} else { // Download file
// make request
} else {
var body io.Reader
if s.flags.Presign {
resp, err := s.httpClient.Get(statResp.JSON200.PhysicalAddress)
resp, err := s.httpClient.Get(objStat.PhysicalAddress)
if err != nil {
return err
}
Expand Down Expand Up @@ -229,15 +199,75 @@ func (s *SyncManager) download(ctx context.Context, rootPath string, remote *uri
b.Done()
}
}()
_, err = io.Copy(f, barReader)

_, err = io.Copy(f, barReader)
if err != nil {
return fmt.Errorf("could not write file '%s': %w", destination, err)
}
}
return nil
}

func (s *SyncManager) download(ctx context.Context, rootPath string, remote *uri.URI, path string) error {
if err := fileutil.VerifyRelPath(strings.TrimPrefix(path, uri.PathSeparator), rootPath); err != nil {
return err
}
destination := fmt.Sprintf("%s%c%s", rootPath, os.PathSeparator, path)
destinationDirectory := filepath.Dir(destination)

if err := os.MkdirAll(destinationDirectory, os.FileMode(DefaultDirectoryPermissions)); err != nil {
return err
}
statResp, err := s.client.StatObjectWithResponse(ctx, remote.Repository, remote.Ref, &apigen.StatObjectParams{
Path: filepath.ToSlash(filepath.Join(remote.GetPath(), path)),
Presign: swag.Bool(s.flags.Presign),
UserMetadata: swag.Bool(true),
})
if err != nil {
return err
}
if statResp.StatusCode() != http.StatusOK {
httpErr := apigen.Error{Message: "no content"}
_ = json.Unmarshal(statResp.Body, &httpErr)
return fmt.Errorf("(stat: HTTP %d, message: %s): %w", statResp.StatusCode(), httpErr.Message, ErrDownloadingFile)
}
objStat := *statResp.JSON200
// get mtime
mtimeSecs, err := getMtimeFromStats(objStat)
if err != nil {
return err
}
lastModified := time.Unix(mtimeSecs, 0)

var unixPerm *UnixPermissions
isDir := strings.HasSuffix(path, uri.PathSeparator)
if s.includePerm { // Optimization - fail on to get permissions from metadata before having to download the entire file
if unixPerm, err = getUnixPermissionFromStats(objStat); err != nil {
return err
}
} else if isDir {
// Directory marker - skip
return nil
}

if !isDir {
if err = s.downloadFile(ctx, remote, path, destination, objStat); err != nil {
return err
}
}
// set mtime to the server returned one
err = os.Chtimes(destination, time.Now(), lastModified) // Explicit to catch in deferred func
if err != nil {
return err
}

// change ownership and permissions
if s.includePerm {
if err = os.Chown(destination, unixPerm.UID, unixPerm.GID); err != nil {
return err
}
err = syscall.Chmod(destination, uint32(unixPerm.Mode))
}
return err
}

Expand Down
Loading

0 comments on commit 5463a8e

Please sign in to comment.