Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add flag to set symlink following behavior for uploading directory #591

Merged
merged 5 commits into from
Sep 10, 2024
Merged

Add flag to set symlink following behavior for uploading directory #591

merged 5 commits into from
Sep 10, 2024

Conversation

amonshiz
Copy link
Contributor

@amonshiz amonshiz commented Aug 6, 2024

We would like to be able to use upload_dir in a situation that makes heavy use of symlinks. However, the previous implementation did not respect symlinks and instead resulted in resolving the symlink to the actual path. This is problematic because it means that duplicated data was going to be recreated on a download.

This is solved by introducing a symlink_behavior argument that accepts unspecified (default), preserve, and resolve which map to the SymlinkBehaviorType enum. This allows the caller to specify how to handle symlinks and ensure that later downloads match exactly what the upload was. This also appears to reduce the data uploaded.

Test

bash-5.2$ pwd
/Users/amonshiz/Developer/remote-apis-sdks/go/cmd/remotetool
bash-5.2$ for kind in none unspecified UnspecifiedSymlinkBehavior resolve ResolveSymlink preserve PreserveSymlink; do
    echo "Symlink behavior: $kind"
    dd if=/dev/urandom of=tmp/versions/random_file bs=1024 count=10 &> /dev/null
    ./remotetool_arm64 \
        --operation=upload_dir \
        -service localhost:8980 \
        -service_no_auth \
        -use_rpc_credentials=false \
        -service_no_security \
        --path $(realpath tmp) \
        $([ "$kind" = "none" ] && echo '' || echo "-symlink_behavior=$kind") \
        --json=output.json &> /dev/null
    cat output.json
    echo ""
done
Symlink behavior: none
{
  "InputFiles": 2,
  "InputDirectories": 2,
  "InputSymlinks": 0,
  "TotalInputBytes": 20737,
  "RootDigest": {
    "Hash": "c12e994e2fa5b6e72fc45d66c8a756ec0ac59fc1468e5348ea9b2a3bdfddcf00",
    "Size": 171
  },
  "CountBlobs": 3,
  "CountCacheMisses": 3,
  "BytesTransferred": 10497,
  "BytesCacheMisses": 10497,
  "Error": ""
}
Symlink behavior: unspecified
{
  "InputFiles": 2,
  "InputDirectories": 2,
  "InputSymlinks": 0,
  "TotalInputBytes": 20737,
  "RootDigest": {
    "Hash": "8b0d6b9f687b459dd176909ec244a5139028d695a012ecbcffa2f02b317c988d",
    "Size": 171
  },
  "CountBlobs": 3,
  "CountCacheMisses": 3,
  "BytesTransferred": 10497,
  "BytesCacheMisses": 10497,
  "Error": ""
}
Symlink behavior: UnspecifiedSymlinkBehavior
{
  "InputFiles": 2,
  "InputDirectories": 2,
  "InputSymlinks": 0,
  "TotalInputBytes": 20737,
  "RootDigest": {
    "Hash": "aa29e6cea24a50379fbd03d60f712f1c6124f6ed711b808439f78d6b07197b41",
    "Size": 171
  },
  "CountBlobs": 3,
  "CountCacheMisses": 3,
  "BytesTransferred": 10497,
  "BytesCacheMisses": 10497,
  "Error": ""
}
Symlink behavior: resolve
{
  "InputFiles": 2,
  "InputDirectories": 2,
  "InputSymlinks": 0,
  "TotalInputBytes": 20737,
  "RootDigest": {
    "Hash": "9c5004ba3ec36e502b79dbcbbcf31a8bcd31d06e0cb41e9d4d6bfa30c4434350",
    "Size": 171
  },
  "CountBlobs": 3,
  "CountCacheMisses": 3,
  "BytesTransferred": 10497,
  "BytesCacheMisses": 10497,
  "Error": ""
}
Symlink behavior: ResolveSymlink
{
  "InputFiles": 2,
  "InputDirectories": 2,
  "InputSymlinks": 0,
  "TotalInputBytes": 20737,
  "RootDigest": {
    "Hash": "38a6711760acc6933141cc92ad6f8224fa60c0a61b4fa4f796c48c0a330d9d30",
    "Size": 171
  },
  "CountBlobs": 3,
  "CountCacheMisses": 3,
  "BytesTransferred": 10497,
  "BytesCacheMisses": 10497,
  "Error": ""
}
Symlink behavior: preserve
{
  "InputFiles": 1,
  "InputDirectories": 2,
  "InputSymlinks": 1,
  "TotalInputBytes": 10448,
  "RootDigest": {
    "Hash": "e9cb3d11a60ede62cabaf9dff7e9d9f3817af0d06d3660294504beed1680fcd3",
    "Size": 122
  },
  "CountBlobs": 3,
  "CountCacheMisses": 3,
  "BytesTransferred": 10448,
  "BytesCacheMisses": 10448,
  "Error": ""
}
Symlink behavior: PreserveSymlink
{
  "InputFiles": 1,
  "InputDirectories": 2,
  "InputSymlinks": 1,
  "TotalInputBytes": 10448,
  "RootDigest": {
    "Hash": "d953e212c7db21b1b2e35a54c2f1de293c7d458b2b9daa075ace209a1563de2e",
    "Size": 122
  },
  "CountBlobs": 3,
  "CountCacheMisses": 3,
  "BytesTransferred": 10448,
  "BytesCacheMisses": 10448,
  "Error": ""
}

Copy link
Contributor

@ola-rozenfeld ola-rozenfeld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check go format when done (this is why presubmits are failing). Thank you!

@@ -119,7 +121,7 @@ var RemoteToolOperations = map[OpType]func(ctx context.Context, c *Client){
}
},
uploadDir: func(ctx context.Context, c *Client) {
us, err := c.UploadDirectory(ctx, getPathFlag())
us, err := c.UploadDirectory(ctx, getPathFlag(), getSymlinkBehaviorType())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use the function you added to Command to parse the string as enum.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it okay to add the dependency on command here? I didn't want to introduce a new dep unnecessarily and potentially break some boundaries. Will do!

@@ -71,6 +71,17 @@ func (s SymlinkBehaviorType) String() string {
return fmt.Sprintf("InvalidSymlinkBehaviorType(%d)", s)
}

func SymlinkBehavior(s string) SymlinkBehaviorType {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: the name sounds more like a type. I'd use ParseSymlinkBehavior which is akin to strconv.ParseInt. SymlinkBahaviorFromString is another reasonable name which is akin to uuid.FromString.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I've just noticed there is already a symlinkBehaviorFromProto in this file.

@mrahs
Copy link
Collaborator

mrahs commented Aug 8, 2024

Thank you for the PR and thank you @ola-rozenfeld for the review.

@amonshiz amonshiz requested a review from mrahs September 9, 2024 15:51
@mrahs mrahs merged commit f4821a2 into bazelbuild:master Sep 10, 2024
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants