diff options
| author | Sadeep Madurange <sadeep@asciimx.com> | 2026-04-18 10:10:04 +0800 |
|---|---|---|
| committer | Sadeep Madurange <sadeep@asciimx.com> | 2026-04-18 10:10:04 +0800 |
| commit | a4258d636fec97688f3db95bd5d1cdf0bd1344f7 (patch) | |
| tree | 98f507d95fbc9ce44f03c0ce5b23b523beae22ec /vcx | |
| parent | e9b0bd8e247c4f0e63acde2e898771527708fd2b (diff) | |
| download | urn-a4258d636fec97688f3db95bd5d1cdf0bd1344f7.tar.gz | |
Show command.
Diffstat (limited to 'vcx')
| -rw-r--r-- | vcx | 79 |
1 files changed, 79 insertions, 0 deletions
@@ -46,6 +46,12 @@ if ($cmd eq 'init') { run_commit($m); } elsif ($cmd eq 'log') { run_log(); +} elsif ($cmd eq 'show') { + # Usage: vcx show HEAD main.c + my $rev = shift @args; + my $file = shift @args; + die "Usage: $0 show <rev_id|HEAD> <file_path>\n" unless defined $rev && defined $file; + run_show($rev, $file); } else { print "Usage: $0 [init|status|add|commit|log]\n"; exit 1; @@ -429,6 +435,79 @@ sub run_log { select($old_fh); } +sub run_show { + my ($rev_id, $file_path) = @_; + + if (!defined $rev_id || lc($rev_id) eq 'head') { + $rev_id = read_head(); + } + + die "Usage: $0 show <rev_id|HEAD> <file_path>\n" unless $rev_id && $file_path; + + my $rev_file = File::Spec->catfile(REV_DIR, $rev_id); + die "Error: Revision $rev_id not found.\n" unless -f $rev_file; + + # Extract metadata from revision + my ($tree_hash, $patch_bundle_hash) = ("", ""); + open my $rfh, '<', $rev_file or die $!; + while (<$rfh>) { + if (/^tree:(.*)$/) { $tree_hash = $1; } + elsif (/^patch:(.*)$/) { $patch_bundle_hash = $1; } + } + close $rfh; + + # Locate file in tree + my $it = stream_tree_file($tree_hash); + my $target_node; + while (my $node = $it->()) { + if ($node->{path} eq $file_path) { + $target_node = $node; + last; + } + } + die "Error: File '$file_path' not found in revision $rev_id.\n" unless $target_node; + + my $obj_path = get_obj_path($target_node->{hash}); + die "Error: Object $target_node->{hash} missing.\n" unless -f $obj_path; + + my $content = read_file($obj_path); + + # Apply patch + if ($patch_bundle_hash) { + my $bundle_path = get_obj_path($patch_bundle_hash); + if (-f $bundle_path) { + open my $bfh, '<:raw', $bundle_path or die $!; + my $raw_bundle = do { local $/; <$bfh> }; + close $bfh; + + # Handle magic bytes (1f 8b = Gzip) + my $tar_data = (substr($raw_bundle, 0, 2) eq "\x1f\x8b") + ? Compress::Zlib::uncompress($raw_bundle) + : $raw_bundle; + + my $tar = Archive::Tar->new; + $tar->read($tar_data); + + my $patch_name = "$file_path.patch"; + if ($tar->contains_file($patch_name)) { + my $patch_data = $tar->get_content($patch_name); + if ($patch_data =~ /^\d+(?:,\d+)?[adc]\d+/) { + my ($tfh, $tpath) = tempfile(DIR => TMP_DIR, UNLINK => 1); + binmode $tfh, ":raw"; + print $tfh $content; + close $tfh; + $content = qx(patch -s -f $tpath -o - <<'EOF'\n$patch_data\nEOF\n); + } else { + $content = apply_bin_patch($content, $patch_data); + } + } + } + } + + binmode STDOUT, ":raw"; + print $content; +} + sub make_bin_patch { my ($new_file, $old_file) = @_; |
