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

feat(iaviewer): Add "data-full" and "hash" commands #959

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

gibson042
Copy link

@gibson042 gibson042 commented Jun 28, 2024

The first three commits are general cleanup that could be pulled out into one or more independent PRs, and the fourth is the motivator of this PR: new iaviewer commands for varying the amount of detail in output.

  • data-full outputs actual values rather than just their SHA-256 digests.
  • hash outputs a tree summary without including details about individual entries.

Summary by CodeRabbit

  • New Features

    • Improved command validation with the addition of a command validation map.
    • Enhanced tree loading to always fetch the latest version with better error handling.
    • Introduced a flag for printing full values in key printing.
    • Added functionality to handle binary data encoding.
  • Bug Fixes

    • Fixed potential issues with error handling and logging across various functions.
    • Improved encoding to manage non-ASCII data correctly.
  • Refactor

    • Restructured command line argument and error handling for better maintainability and readability.
    • Updated function signatures to improve clarity and functionality.

@gibson042 gibson042 requested a review from a team as a code owner June 28, 2024 19:33
Copy link

coderabbitai bot commented Jun 28, 2024

Walkthrough

The recent updates to cmd/iaviewer/main.go focus on refining command line argument handling, enhancing error management, and improving key functions for tree reading and printing. These changes introduce a cmds map for valid commands, restructure the ReadTree function for better error handling, upgrade PrintKeys to work with an ImmutableTree, and improve key encoding.

Changes

Files Change Summary
cmd/iaviewer/main.go Refactored command line argument handling, improved error handling, and restructured key functions (ReadTree, PrintKeys, PrintShape, PrintVersions). Added a cmds map, a new encodeData function, and updated parseWeaveKey.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Main as Main Function
    participant Cmds as Commands Map
    participant ReadTree as ReadTree Function
    participant PrintKeys as PrintKeys Function
    participant ParseWeaveKey as ParseWeaveKey Function

    User->>Main: Input Command
    Main->>Cmds: Validate Command
    alt Valid Command
        Main->>ReadTree: Read Latest Tree Version
        ReadTree-->>Main: Tree Data
        Main->>PrintKeys: Print Tree Keys
        PrintKeys-->>Main: Printed Keys
        Main->>User: Output Result
    else Invalid Command
        Main->>User: Print Usage Message
    end
    Main->>ParseWeaveKey: Parse Key
    ParseWeaveKey-->>Main: Encoded Key
Loading

Poem

In the codebase deep, a rabbit did tweak,
Command lines refined, no errors to sneak.
Trees now immutable, standing so strong,
Keys printed bright, in ASCII or hex long.
With parseWeaveKey improved, data's intact,
Celebrate these changes, in code we trust pact!
🌟🐰✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 0b6f1b6 and 9a884cf.

Files selected for processing (1)
  • cmd/iaviewer/main.go (3 hunks)
Additional comments not posted (2)
cmd/iaviewer/main.go (2)

23-29: Validate command-line arguments using the cmds map.

The cmds map is a good addition for managing command validation. It simplifies the command checking logic and makes it easy to add or remove commands in the future. However, ensure that all commands in the cmds map are actively used and correctly implemented in the switch cases within the main function.

Also applies to: 33-38


64-78: Review switch-case logic for new commands.

The implementation of the data-full and hash commands within a switch-case is efficient. The use of fallthrough for data-full to data is clever, allowing code reuse. However, ensure that the fallthrough behavior is intentional and documented to avoid confusion for future maintainers.

Comment on lines +178 to +188
// parseWeaveKey returns a string representation of a key, splitting on the first ":"
// into a prefix (presumably an all-ASCII type label) followed by a possibly-binary suffix.
func parseWeaveKey(key []byte) string {
cut := bytes.IndexRune(key, ':')
if cut == -1 {
return encodeID(key)
return encodeData(key)
}
prefix := key[:cut]
id := key[cut+1:]
return fmt.Sprintf("%s:%s", encodeID(prefix), encodeID(id))
return fmt.Sprintf("%s:%s", encodeData(prefix), encodeData(id))
Copy link

Choose a reason for hiding this comment

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

Optimize and clarify parseWeaveKey function.

The parseWeaveKey function now handles potentially binary data, which enhances its robustness. However, the function could be optimized by avoiding multiple calls to encodeData. Consider caching the result or restructuring the logic to minimize redundancy.

-	return fmt.Sprintf("%s:%s", encodeData(prefix), encodeData(id))
+	encodedPrefix := encodeData(prefix)
+	encodedId := encodeData(id)
+	return fmt.Sprintf("%s:%s", encodedPrefix, encodedId)
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// parseWeaveKey returns a string representation of a key, splitting on the first ":"
// into a prefix (presumably an all-ASCII type label) followed by a possibly-binary suffix.
func parseWeaveKey(key []byte) string {
cut := bytes.IndexRune(key, ':')
if cut == -1 {
return encodeID(key)
return encodeData(key)
}
prefix := key[:cut]
id := key[cut+1:]
return fmt.Sprintf("%s:%s", encodeID(prefix), encodeID(id))
return fmt.Sprintf("%s:%s", encodeData(prefix), encodeData(id))
// parseWeaveKey returns a string representation of a key, splitting on the first ":"
// into a prefix (presumably an all-ASCII type label) followed by a possibly-binary suffix.
func parseWeaveKey(key []byte) string {
cut := bytes.IndexRune(key, ':')
if cut == -1 {
return encodeData(key)
}
prefix := key[:cut]
id := key[cut+1:]
encodedPrefix := encodeData(prefix)
encodedId := encodeData(id)
return fmt.Sprintf("%s:%s", encodedPrefix, encodedId)

Comment on lines 49 to 63
mutableTree, latestVersion, err := ReadTree(args[1], []byte(args[2]))
assertNoError(err, "Error reading database")

if args[0] == "versions" {
PrintVersions(mutableTree)
return
}

if version == 0 {
version = int(latestVersion)
}
tree, err := mutableTree.GetImmutable(int64(version))
assertNoError(err, "Error reading target version")
fmt.Printf("Got version: %d\n", tree.Version())
Copy link

Choose a reason for hiding this comment

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

Tip

Codebase Verification

Missing Tests for ReadTree Function

The ReadTree function is not currently tested, which affects the reliability and maintainability of the code. Comprehensive tests should be added to cover the new functionality of the ReadTree function.

  • Ensure that unit tests are created for the ReadTree function.
  • Consider adding integration tests to verify its behavior in different scenarios.
Analysis chain

Refactor ReadTree function usage.

The ReadTree function now returns an ImmutableTree and the latest version, which aligns with the new functionality of loading the latest tree version. This is a significant improvement for error handling and flexibility. However, ensure that the ReadTree function is robustly tested, especially since it now handles more logic with version management.

Consider separating the version fetching logic to a different function for better separation of concerns and readability.

Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify robustness of the `ReadTree` function.

# Test: Search for the function usage and related unit tests. Expect: Comprehensive tests covering new functionality.
rg --type go $'ReadTree'

Length of output: 343



Script:

#!/bin/bash
# Description: Search for test files that use the `ReadTree` function and inspect their coverage.

# Find all Go test files
test_files=$(fd --type f --extension go --exec grep -l 'ReadTree')

# Search for ReadTree function usage in the test files
if [ -n "$test_files" ]; then
  echo "$test_files" | xargs rg 'ReadTree'
else
  echo "No test files found using ReadTree"
fi

Length of output: 432



Script:

#!/bin/bash
# Description: Search for all test files in the repository and check if `ReadTree` is tested indirectly.

# Find all Go test files
test_files=$(fd --type f --extension go --exec grep -l '_test.go')

# If test files are found, search for ReadTree function usage within them
if [ -n "$test_files" ]; then
  echo "$test_files" | xargs rg 'ReadTree'
else
  echo "No test files found in the repository"
fi

Length of output: 168

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 9a884cf and 54c925b.

Files selected for processing (1)
  • cmd/iaviewer/main.go (3 hunks)
Files skipped from review as they are similar to previous changes (1)
  • cmd/iaviewer/main.go

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 54c925b and b891ecd.

Files selected for processing (1)
  • cmd/iaviewer/main.go (4 hunks)
Additional comments not posted (8)
cmd/iaviewer/main.go (8)

23-29: Good use of map for command validation.

Using a map simplifies the validation of command line arguments, making the code cleaner and more maintainable.


33-38: Clear and concise argument validation.

The validation logic is well-implemented. Consider adding a bit more detail to the usage instructions for clarity.

- <prefix> is the prefix of db, and the iavl tree of different modules in cosmos-sdk uses
+ <prefix> is the database prefix. Each module in the cosmos-sdk, such as "gov", uses a unique prefix to identify its iavl tree.

43-46: Proper handling of version parsing and error checking.

The error handling using assertNoError is clean and reduces code duplication.


52-78: Well-structured command routing and error handling.

The switch-case structure is effectively used to manage different commands. Consistent error handling enhances the robustness of the application.


81-84: Effective centralization of error handling.

Centralizing error handling in assertNoError function simplifies the code and enhances maintainability.


139-157: Robust implementation of tree loading with comprehensive error handling.

The function is well-implemented with clear error handling. Consider adding a comment explaining the use of DefaultCacheSize.

+ // DefaultCacheSize is used here to specify the cache size for the iavl tree.

178-187: Optimize and clarify parseWeaveKey function.

The parseWeaveKey function now handles potentially binary data, which enhances its robustness. However, the function could be optimized by avoiding multiple calls to encodeData. Consider caching the result or restructuring the logic to minimize redundancy.

-	return fmt.Sprintf("%s:%s", encodeData(prefix), encodeData(id))
+	encodedPrefix := encodeData(prefix)
+	encodedId := encodeData(id)
+	return fmt.Sprintf("%s:%s", encodedPrefix, encodedId)

190-210: Well-implemented data encoding function.

The function handles various cases effectively. Consider adding more comments to explain the logic behind decisions like hexConfusable and forceQuotes.

+ // hexConfusable is used to determine if the data should be represented in hexadecimal to avoid confusion.
+ // forceQuotes is used to ensure that certain characters are quoted to prevent misinterpretation.

}

func PrintShape(tree *iavl.MutableTree) {
func PrintShape(tree *iavl.ImmutableTree) {
Copy link

Choose a reason for hiding this comment

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

Handle errors explicitly in PrintShape.

The function currently ignores errors silently. It's a good practice to handle errors explicitly to avoid hidden bugs.

- shape, _ := tree.RenderShape("  ", nodeEncoder)
+ shape, err := tree.RenderShape("  ", nodeEncoder)
+ if err != nil {
+     fmt.Fprintf(os.Stderr, "Error rendering tree shape: %s\n", err)
+     return
+ }
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func PrintShape(tree *iavl.ImmutableTree) {
func PrintShape(tree *iavl.ImmutableTree) {
shape, err := tree.RenderShape(" ", nodeEncoder)
if err != nil {
fmt.Fprintf(os.Stderr, "Error rendering tree shape: %s\n", err)
return
}
fmt.Println(shape)
}

Comment on lines +160 to +174
func PrintKeys(tree *iavl.ImmutableTree, fullValues bool) {
valuesLabel := "hashed values"
valueToString := func(value []byte) string {
return fmt.Sprintf("%X", sha256.Sum256(value))
}
if fullValues {
valuesLabel = "values"
valueToString = encodeData
}
fmt.Printf("Printing all keys with %s (to detect diff)\n", valuesLabel)
tree.Iterate(func(key []byte, value []byte) bool {
keyStr := parseWeaveKey(key)
valueStr := valueToString(value)
fmt.Printf(" %s\n %s\n", keyStr, valueStr)
Copy link

Choose a reason for hiding this comment

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

Tip

Codebase Verification

Unit tests for PrintKeys function are missing.

The search did not find any unit tests covering the PrintKeys function. Please add unit tests to ensure both modes of operation (hashed values and full values) are verified.

  • Location: cmd/iaviewer/main.go lines 160-173
Analysis chain

Flexible implementation of key printing with mode switching.

The use of a function pointer to switch between hashed and full values is a clever design choice. Ensure that this function is covered by unit tests to verify both modes of operation.

Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify unit tests for `PrintKeys` function.

# Test: Search for unit tests covering both `hashed values` and `full values`. Expect: Tests validating both modes.
rg --type go $'PrintKeys'

Length of output: 156



Script:

#!/bin/bash
# Description: Find test files and check for tests covering `PrintKeys` function.

# Step 1: Find all Go test files
test_files=$(fd --type f --extension go '_test.go')

# Step 2: Search for `PrintKeys` function usage within the test files
if [ -n "$test_files" ]; then
  echo "$test_files" | xargs rg 'PrintKeys'
else
  echo "No test files found."
fi

Length of output: 2183

@cool-develope
Copy link
Collaborator

lgtm! @gibson042 could you please resolve conflicts?

@gibson042 gibson042 force-pushed the 2024-06-more-iaviewer-commands branch from b891ecd to 0370eb1 Compare October 9, 2024 19:29
@gibson042
Copy link
Author

@cool-develope Done.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between b891ecd and 0370eb1.

📒 Files selected for processing (1)
  • cmd/iaviewer/main.go (2 hunks)
🧰 Additional context used
🔇 Additional comments (8)
cmd/iaviewer/main.go (8)

24-31: Efficient command validation with 'cmds' map

The initialization of the cmds map provides an efficient way to validate supported commands.


34-39: Updated usage message includes new commands

The usage message now reflects the addition of data-full and hash commands, providing users with accurate information.


43-47: Proper parsing of version argument

The use of strconv.ParseInt ensures the version number is correctly parsed into an int64.


50-52: Improved 'ReadTree' function usage

The updated call to ReadTree now retrieves the latest version, enhancing functionality.


58-60: Default to latest version when unspecified

The code correctly defaults to the latest version if none is provided, ensuring expected behavior.


61-64: Retrieve immutable tree for specified version

The call to GetImmutable retrieves the tree for the desired version, with proper error handling.


82-85: Consistent error handling with 'assertNoError' function

The assertNoError function provides a unified approach to error checking, improving code maintainability.


191-211: Robust data encoding in 'encodeData' function

The encodeData function effectively converts byte slices into human-readable strings, handling non-printable characters and avoiding misinterpretation.

Comment on lines +65 to +79
fullValues := false
switch args[0] {
case "data-full":
fullValues = true
fallthrough
case "data":
PrintKeys(tree)
PrintKeys(tree, fullValues)
fallthrough
case "hash":
hash := tree.Hash()
fmt.Printf("Hash: %X\n", hash)
fmt.Printf("Size: %X\n", tree.Size())
case "shape":
PrintShape(tree)
case "versions":
PrintVersions(tree)
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Potential unintended command execution due to 'fallthrough'

The use of fallthrough statements causes commands "data", "data-full", and "hash" to execute sequentially. This means that when the "data" or "data-full" command is specified, the "hash" command's logic is also executed. If this behavior is unintended, consider removing the fallthrough statements to prevent unexpected command execution.

Apply this diff to remove unintended fallthroughs:

switch args[0] {
case "data-full":
	fullValues = true
-	fallthrough
case "data":
	PrintKeys(tree, fullValues)
-	fallthrough
case "hash":
	hash := tree.Hash()
	fmt.Printf("Hash: %X\n", hash)
	fmt.Printf("Size: %X\n", tree.Size())
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fullValues := false
switch args[0] {
case "data-full":
fullValues = true
fallthrough
case "data":
PrintKeys(tree)
PrintKeys(tree, fullValues)
fallthrough
case "hash":
hash := tree.Hash()
fmt.Printf("Hash: %X\n", hash)
fmt.Printf("Size: %X\n", tree.Size())
case "shape":
PrintShape(tree)
case "versions":
PrintVersions(tree)
}
fullValues := false
switch args[0] {
case "data-full":
fullValues = true
PrintKeys(tree, fullValues)
case "data":
PrintKeys(tree, fullValues)
case "hash":
hash := tree.Hash()
fmt.Printf("Hash: %X\n", hash)
fmt.Printf("Size: %X\n", tree.Size())
case "shape":
PrintShape(tree)
}

Copy link

@alpe alpe left a comment

Choose a reason for hiding this comment

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

Nice work! 🌻
The changes look good.

os.Exit(1)
}

version := 0
if len(args) == 4 {
version := int64(0)
Copy link

Choose a reason for hiding this comment

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

personal preference: a more verbose name would be more readable.

Suggested change
version := int64(0)
wantVersion := int64(0)

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.

4 participants