laskoviymishka commented on code in PR #1961:
URL: https://github.com/apache/iceberg-go/pull/1961#discussion_r3890695581


##########
io/gocloud/blobfs/blob.go:
##########
@@ -274,7 +284,7 @@ func (bfs *BlobFileIO) Open(path string) (icebergio.File, 
error) {
        return &blobOpenFile{Reader: r, name: name, key: key, b: bfs, ctx: 
bfs.ctx}, nil
 }
 
-func (bfs *BlobFileIO) Remove(name string) error {
+func (bfs *FileIO) Remove(name string) error {
        var err error
        name, err = bfs.preprocess(name)

Review Comment:
   While we're moving this into a public package, worth fixing: `Remove` 
reassigns `name` with the preprocessed key, so when `preprocess` fails and 
returns `""`, the `&fs.PathError{Path: name}` below reports an empty path 
instead of the caller's original.
   
   `Open` already guards against this with `originalPath := path`. Same gap in 
`WriteFile` and `NewWriter`. I'd take a separate `key` variable and leave 
`name`/`path` intact:
   
   ```go
   key, err := bfs.preprocess(name)
   if err != nil {
       return &fs.PathError{Op: "remove", Path: name, Err: err}
   }
   ```



##########
io/gocloud/compat_test.go:
##########
@@ -0,0 +1,100 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package gocloud_test
+
+import (
+       "context"
+       "testing"
+
+       "github.com/apache/iceberg-go/io"
+       "github.com/apache/iceberg-go/io/gocloud"
+       "github.com/apache/iceberg-go/io/gocloud/blobfs"
+       "github.com/apache/iceberg-go/io/gocloud/gcs"
+       "github.com/apache/iceberg-go/io/gocloud/s3"
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+// For callers who still have not migrated
+var (
+       _ *blobfs.FileIO      = (*gocloud.BlobFileIO)(nil)

Review Comment:
   The compat shim's whole contract is that blank-importing `io/gocloud` still 
registers all nine schemes, but this test only checks the type aliases and the 
wrapper functions.
   
   If a future edit drops one of the sub-package imports from `gocloud.go`, the 
aliases still compile (they live in `blobfs`) and this test stays green, but 
the registration side effect silently disappears. I'd add an assertion that 
`io.GetRegisteredSchemes()` contains all nine cloud schemes after importing 
`io/gocloud`, mirroring the per-backend `TestRegistersOnlyItsOwnSchemes`.
   
   While we're at it, the flip side of the `catalog/hadoop` change has no test 
either. A small case in `catalog/hadoop` that imports it without any backend 
and asserts `LoadFS(ctx, nil, "s3://...")` returns `ErrIOSchemeNotFound` would 
lock in whatever we decide above.



##########
io/gocloud/blobfs/blob.go:
##########
@@ -323,7 +333,7 @@ func (bfs *BlobFileIO) WriteFile(name string, content 
[]byte) error {
 //
 // The caller must call Close on the returned Writer, even if the write is
 // aborted.
-func (bfs *BlobFileIO) NewWriter(ctx context.Context, path string, overwrite 
bool, opts *blob.WriterOptions) (w *blobWriteFile, err error) {
+func (bfs *FileIO) NewWriter(ctx context.Context, path string, overwrite bool, 
opts *blob.WriterOptions) (w *blobWriteFile, err error) {

Review Comment:
   `NewWriter` is exported on an exported type but returns `*blobWriteFile`, 
which callers outside the package can't name. It's valid Go and predates the 
split, but the rename makes it public surface now, so I'd either return an 
exported `Writer` interface or export the concrete type.



##########
io/gocloud/blobfs/blob.go:
##########
@@ -83,18 +86,18 @@ var ErrEmptyObjectKey = errors.New("object key is empty")
 // URI to access it; this backend does not route across authorities.
 var ErrUnsupportedObjectAuthority = errors.New("object URI authority is not 
supported by this FileIO")
 
-type objectLocation struct {
+type ObjectLocation struct {

Review Comment:
   Now that `ObjectLocation` is exported, its fields are all still unexported 
and the only constructor is `NewObjectLocation`. An external package writing a 
custom `ObjectLocationExtractor` can build one but can't read 
`scheme`/`authority`/`key` back off a value it's handed, which limits how far a 
custom extractor can route.
   
   I'd either add `Scheme()`/`Authority()`/`Key()` accessors, or, if it's meant 
to be opaque, say so in a doc comment and point people at 
`KeyExtractorFromObjectLocation`. Either way these newly-exported symbols 
(`ObjectLocation`, `NewObjectLocation`, `ObjectLocationExtractor`, 
`KeyExtractorFromObjectLocation`, `DefaultObjectLocationExtractor`) are the 
extension surface for custom backends and none of them have doc comments yet.



##########
io/gocloud/blobfs/utils.go:
##########
@@ -15,11 +15,11 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package gocloud
+package blobfs
 
 import "strings"
 
-func propertiesWithPrefix(props map[string]string, prefix string) 
map[string]string {
+func PropertiesWithPrefix(props map[string]string, prefix string) 
map[string]string {

Review Comment:
   This is a generic map-prefix helper with no relationship to blob FS, and its 
only caller is `azure.go`. Exporting it from `blobfs` makes it permanent public 
API.
   
   I'd keep it unexported (the azure package can hold its own two-line copy) or 
move it to an `internal/` helper, rather than committing to it as public 
surface. If it does stay exported, it needs a doc comment on what it matches 
and whether the prefix is stripped from the keys.



##########
catalog/hadoop/io.go:
##########
@@ -19,7 +19,7 @@ package hadoop
 
 import (
        icebergio "github.com/apache/iceberg-go/io"
-       "github.com/apache/iceberg-go/io/gocloud"
+       "github.com/apache/iceberg-go/io/gocloud/blobfs"

Review Comment:
   I'd hold on this import swap until we decide what happens to scheme 
registration for `catalog/hadoop` users.
   
   Today the value import of `io/gocloud` pulls in that package's `init()`, so 
anyone importing `catalog/hadoop` gets all nine cloud schemes registered for 
free. Swapping to `blobfs` (which has no registration `init()`) means a program 
that imports only `catalog/hadoop` and talks to s3/gcs/azure will now build 
fine and then fail at the first `LoadFS` with `ErrIOSchemeNotFound`. That's a 
silent runtime regression on `go get -u`, with no compile-time signal.
   
   I think the split itself is right, so I wouldn't want to re-link all three 
SDKs into hadoop just to preserve the old behavior. But we shouldn't let it 
break silently either. Either keep a blank import of `io/gocloud` here, or 
treat this as an intentional break and call it out loudly in the CHANGELOG and 
package doc (the website config page alone won't reach someone upgrading). wdyt?



##########
internal/schemes/schemes.go:
##########
@@ -0,0 +1,42 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package schemes
+
+import "slices"
+
+var (
+       S3    = []string{"s3", "s3a", "s3n", "oss"}
+       GCS   = []string{"gs"}
+       Azure = []string{"abfs", "abfss", "wasb", "wasbs"}
+)
+
+var byBackend = map[string][]string{

Review Comment:
   One subtle thing here: `byBackend` copies the `S3`/`GCS`/`Azure` slice 
headers at package load. Since these are exported mutable vars, if anything 
ever appends to one past its capacity, `byBackend` keeps pointing at the old 
backing array and `BackendFor` silently returns `""` for the new scheme.
   
   It's internal so the blast radius is small, but adding a scheme alias looks 
like a harmless one-liner. I'd at least add a doc comment noting these are 
read-only, or build `byBackend` lazily so it can't drift.



##########
io/gocloud/s3/register_test.go:
##########
@@ -0,0 +1,52 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package s3_test
+
+import (
+       "context"
+       "testing"
+
+       "github.com/apache/iceberg-go/internal/schemes"
+       "github.com/apache/iceberg-go/io"
+       _ "github.com/apache/iceberg-go/io/gocloud/s3"
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+func TestRegistersOnlyItsOwnSchemes(t *testing.T) {
+       assert.ElementsMatch(t, append([]string{"file", "", "mem"}, 
schemes.S3...), io.GetRegisteredSchemes())

Review Comment:
   The `"mem"` here comes from a transitive import rather than anything in this 
package, so if that dependency changes this fails with no obvious reason. A 
one-line comment naming where `mem` gets registered would save the next person 
the hunt.
   
   The exact-set match via `ElementsMatch` also means any newly-registered 
legit scheme breaks all three of these. `assert.Subset` for the cloud schemes 
you actually care about would be less brittle. Same pattern in the gcs and 
azure register tests.



##########
internal/schemes/schemes.go:
##########
@@ -0,0 +1,42 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package schemes
+
+import "slices"
+
+var (
+       S3    = []string{"s3", "s3a", "s3n", "oss"}

Review Comment:
   Worth a doc comment on this slice: `oss` routes through the AWS S3 SDK here, 
which works via OSS's S3-compatible API but diverges from Java (dedicated 
`OSSFileIO`) and means OSS users configure `s3.*` credential keys, not `oss.*`. 
Easy to trip over otherwise.



##########
io/gocloud/azure/register_test.go:
##########
@@ -0,0 +1,52 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package azure_test
+
+import (
+       "context"
+       "testing"
+
+       "github.com/apache/iceberg-go/internal/schemes"
+       "github.com/apache/iceberg-go/io"
+       _ "github.com/apache/iceberg-go/io/gocloud/azure"
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+func TestRegistersOnlyItsOwnSchemes(t *testing.T) {
+       assert.ElementsMatch(t, append([]string{"file", "", "mem"}, 
schemes.Azure...), io.GetRegisteredSchemes())
+}
+
+func TestOtherCloudSchemesRemainUnregistered(t *testing.T) {
+       ctx := context.Background()
+
+       for _, tt := range []struct {
+               location string
+               errValue string

Review Comment:
   Small consistency thing: the s3 and gcs register tests call this field 
`wantHint`; only azure uses `errValue`. I'd rename to `wantHint` to match.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to