-
Notifications
You must be signed in to change notification settings - Fork 47
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 target-diff #664
base: main
Are you sure you want to change the base?
Add target-diff #664
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not review the whole PR, just added some small flow.record
quality of life suggestions since the merge of fox-it/flow.record#115
Available in flow.record==3.15
.
131e6b5
to
aac31af
Compare
Thanks for your suggestions on the |
We understand this PR will take some time to review, but we do think it might be worthwhile to incorporate the changes to What we could do is move the Do you agree with this approach? |
I am working slowly through the backlog of long outstanding PRs but had not gotten to this yet. Your proposal of splitting it up sounds like a good idea though, it's always nice if we can split of large PRs into separate smaller ones. I won't complain either if you pick up some of the mentioned improvements along the way 😄. I've just merged #716 for your convenience so feel free to do with that as you please 😉. |
* `--hex` can be used to diff binary files in a readable way. * `--only-changed` can be used to omit unchanged records when comparing plugin outputs
7f1b27d
to
8a0c6af
Compare
Fix a test and update ls and completedefault to how target-shell does it.
I will check if someone from the dissect team can review this. |
type=int, | ||
help="How many bytes to compare before assuming a file is left unchanged (0 for no limit)", | ||
) | ||
subparsers = parser.add_subparsers(help="Mode for differentiating targets", dest="mode") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
subparsers = parser.add_subparsers(help="Mode for differentiating targets", dest="mode") | |
subparsers = parser.add_subparsers(help="Mode for differentiating targets", dest="mode", required=True) |
shell_mode.add_argument("targets", metavar="TARGETS", nargs="*", help="Targets to differentiate between") | ||
|
||
fs_mode = subparsers.add_parser("fs", help="Yield records about differences between target filesystems.") | ||
fs_mode.add_argument("targets", metavar="TARGETS", nargs="*", help="Targets to differentiate between") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fs_mode.add_argument("targets", metavar="TARGETS", nargs="*", help="Targets to differentiate between") | |
fs_mode.add_argument("targets", metavar="TARGETS", nargs="+", help="Targets to differentiate between") |
subparsers = parser.add_subparsers(help="Mode for differentiating targets", dest="mode") | ||
|
||
shell_mode = subparsers.add_parser("shell", help="Open an interactive shell to compare two or more targets.") | ||
shell_mode.add_argument("targets", metavar="TARGETS", nargs="*", help="Targets to differentiate between") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shell_mode.add_argument("targets", metavar="TARGETS", nargs="*", help="Targets to differentiate between") | |
shell_mode.add_argument("targets", metavar="TARGETS", nargs="+", help="Targets to differentiate between") |
) | ||
|
||
query_mode = subparsers.add_parser("query", help="Differentiate plugin outputs between two or more targets.") | ||
query_mode.add_argument("targets", metavar="TARGETS", nargs="*", help="Targets to differentiate between") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
query_mode.add_argument("targets", metavar="TARGETS", nargs="*", help="Targets to differentiate between") | |
query_mode.add_argument("targets", metavar="TARGETS", nargs="+", help="Targets to differentiate between") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to avoid errors when invoking target-diff
without targets or mode
|
||
args = parser.parse_args() | ||
process_generic_arguments(args) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if len(args.targets) < 2: | |
print("At least two targets are required for diff.") | |
exit(1) | |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #664 +/- ##
==========================================
- Coverage 76.75% 76.63% -0.13%
==========================================
Files 315 316 +1
Lines 27126 27678 +552
==========================================
+ Hits 20820 21210 +390
- Misses 6306 6468 +162
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
exclude=args.exclude, | ||
) | ||
elif args.mode == "query": | ||
iterator = differentiate_target_plugin_outputs( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
iterator = differentiate_target_plugin_outputs( | |
if args.deep: | |
log.warning("--deep parameter ignored for query mode.") | |
iterator = differentiate_target_plugin_outputs( |
self._select_source_and_dest(0, 1) | ||
if len(self.targets) > 2: | ||
# Some help may be nice if you are diffing more than 2 targets at once | ||
self.do_help(arg=None) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this line should be moved after the super().__init__()
otherwise you get an error:
AttributeError: 'DifferentialCli' object has no attribute 'stdout'
return self._write_entry_contents_to_stdout(entry.dst_target_entry, stdout) | ||
print(f"File {name} not found.") | ||
return False | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@arg("path", nargs="?") | |
@alias("xxd") | |
def cmd_hexdump(self, args: argparse.Namespace, stdout: TextIO) -> bool: | |
setattr(args, "hex", True) | |
return self.cmd_diff(args, stdout) |
"""Given a list of targets, compare targets against one another and yield File[Created|Modified|Deleted]Records | ||
indicating the differences between them.""" | ||
if len(targets) < 2: | ||
raise ValueError("Provide two or more targets to differentiate between.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is true for all modes right? maybe move it to a more generic place? - see my relevant corresponding suggestion...
type=int, | ||
help="How many bytes to compare before assuming a file is left unchanged (0 for no limit)", | ||
) | ||
subparsers = parser.add_subparsers(help="Mode for differentiating targets", dest="mode") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might be an interesting idea to split the subparsers into multiple different functions for readability...
This PR adds the command
target-diff
, which can be used to compare two or more targets against one another:fs
mode outputs records denoting filesystem changes from one target to the other:Using
query
mode, you can compare plugin outputs from one target to the other:In
shell
mode, you can browse the target filesystems like intarget-shell
, where directory listings will show which files / directories have been changed, added or deleted. Using theplugin
command, plugin outputs can be compared from within the shell context.target-diff
depends on fox-it/flow.record#107. To allow tests to run for this PR we've temporarily bumped flow.record to3.15.dev10
inpyproject.toml
When three or more targets are provided, you can choose between treating every target as a 'delta' or compare every target against one 'absolute' target. Treating targets as 'deltas' is useful if you have multiple snapshots of the same target from different points in time. Treating targets as 'absolutes' can be useful in situations where you have a 'golden image' that you want to compare different targets against.
To keep code duplication low between
tools/diff.py
andtools/shell.py
, this PR adds a superclassExtendedCmd
toshell.py
that contains most of the functionality that is shared between the two. BothTargetCmd
andDifferentialCli
inherit from this class.