diff options
| author | Sadeep Madurange <sadeep@asciimx.com> | 2026-04-03 18:12:38 +0800 |
|---|---|---|
| committer | Sadeep Madurange <sadeep@asciimx.com> | 2026-04-03 18:32:40 +0800 |
| commit | 2203cfea1a05c274da879301e2cc48bd748bb05c (patch) | |
| tree | dc75461726e3f230b4ea1e4bc0d9d7b7abe44a2f | |
| parent | 1231e1b6d7a74aca4af6a40dddf50c603d6c11c7 (diff) | |
| download | cvn-2203cfea1a05c274da879301e2cc48bd748bb05c.tar.gz | |
Empty file as pointer to tree and built-in compare().
| -rw-r--r-- | vcx | 88 |
1 files changed, 36 insertions, 52 deletions
@@ -5,6 +5,7 @@ use warnings; use File::Path qw(make_path); use File::Copy qw(copy); use File::Find; +use File::Compare; use File::Basename; use File::Glob qw(:bsd_glob); use File::Spec; @@ -12,18 +13,15 @@ use Digest::SHA qw(sha1_hex); use POSIX qw(strftime); use constant VCX_DIR => '.vcx'; +use constant HEAD => VCX_DIR . '/head'; # Current commit ID use constant OBJ_DIR => VCX_DIR . '/objs'; # Latest version of a file use constant REV_DIR => VCX_DIR . '/revs'; # Commits -use constant TREE_DIR => VCX_DIR . '/trees'; # Trees -use constant HEAD_FILE => VCX_DIR . '/head'; # Current commit ID # Staging area use constant TMP_DIR => VCX_DIR . '/index'; use constant TMP_TREE => TMP_DIR . '/tree'; use constant TMP_DIFF => TMP_DIR . '/deltas'; - -use constant TMP_META_FILE => VCX_DIR . '/meta'; -use constant TMP_TREE_FILE => VCX_DIR . '/tree'; +use constant TMP_META_FILE => TMP_DIR . '/meta'; my $cmd = shift @ARGV // ''; my @args = @ARGV; @@ -48,33 +46,32 @@ if ($cmd eq 'init') { } sub run_init { - make_path(OBJ_DIR, REV_DIR, TREE_DIR); + make_path(OBJ_DIR, REV_DIR); my $initial_hex = to_hex_id(0); my $rev0_dir = File::Spec->catfile(REV_DIR, $initial_hex); make_path($rev0_dir); - write_file(HEAD_FILE, "$initial_hex\n"); + write_file(HEAD, "$initial_hex\n"); # Baseline tree (empty) my $empty_tree_hash = sha1_hex(""); - write_file(File::Spec->catfile($rev0_dir, "tree"), "$empty_tree_hash\n"); - make_path(File::Spec->catdir(TREE_DIR, $empty_tree_hash)); + my $empty_tree_file = File::Spec->catfile($rev0_dir, "tree-$empty_tree_hash"); + open my $fh, '>', $empty_tree_file or die $!; close $fh; + make_path(File::Spec->catdir(OBJ_DIR, $empty_tree_hash)); open my $mfh, '>', File::Spec->catfile($rev0_dir, "message"); close $mfh; - print "Initialized repository.\n"; } sub run_status { - open my $fh, '<', HEAD_FILE or die "VCX not initialized.\n"; + open my $fh, '<', HEAD or die "VCX not initialized.\n"; my $head = <$fh>; chomp $head; close $fh; print "On revision [$head]\n"; - my $tree_hash_path = File::Spec->catfile(REV_DIR, $head, "tree"); - open my $tp_fh, '<', $tree_hash_path or die $!; - my $tree_hash = <$tp_fh>; chomp $tree_hash; close $tp_fh; - my $latest_tree_dir = File::Spec->catdir(TREE_DIR, $tree_hash); + my ($tree_ptr) = bsd_glob(File::Spec->catfile(REV_DIR, $head, "tree-*")); + my ($tree_hash) = $tree_ptr =~ /tree-([a-f0-9]{40})$/; + my $latest_tree_dir = File::Spec->catdir(OBJ_DIR, $tree_hash); # Pass 1: Workspace -> History (Detects New and Modified) find({ @@ -89,7 +86,7 @@ sub run_status { if (-e $base_in_tree || -l $base_in_tree) { my $obj_in_store = readlink($base_in_tree); - if (!compare_files($File::Find::name, $obj_in_store)) { + if (compare($_, $obj_in_store) != 0) { my $staged = check_staged_status($rel, 'M') ? " (staged)" : ""; print "[M] $rel$staged\n"; } @@ -147,15 +144,15 @@ sub check_staged_status { sub run_add { my @targets = @_; - make_path(TMP_TREE, TMP_DIFF); - open my $fh_h, '<', HEAD_FILE or die $!; + make_path(TMP_TREE); + + open my $fh_h, '<', HEAD or die $!; my $head = <$fh_h>; chomp $head; close $fh_h; - my $latest_tree_hash_path = File::Spec->catfile(REV_DIR, $head, "tree"); - open my $tp_fh, '<', $latest_tree_hash_path or die $!; - my $latest_tree_hash = <$tp_fh>; chomp $latest_tree_hash; close $tp_fh; - my $latest_tree_dir = File::Spec->catdir(TREE_DIR, $latest_tree_hash); + my ($latest_tree_ptr) = bsd_glob(File::Spec->catfile(REV_DIR, $head, "tree-*")); + my ($latest_tree_hash) = $latest_tree_ptr =~ /tree-([a-f0-9]{40})$/; + my $latest_tree_dir = File::Spec->catdir(OBJ_DIR, $latest_tree_hash); my $next_id_hex = to_hex_id(from_hex_id($head) + 1); @@ -183,12 +180,12 @@ sub run_add { my $prev_link = File::Spec->catfile($latest_tree_dir, $rel); # CASE 1: Regular File - if (-f $File::Find::name && !-l $File::Find::name) { + if (-f $_ && !-l _) { return if -e $staged_path; # Already staged if (-l $prev_link) { my $obj_in_head = readlink($prev_link); - return if compare_files($File::Find::name, $obj_in_head); + return if compare($_, $obj_in_head) == 0; } # Generate deltas if modified @@ -198,8 +195,10 @@ sub run_add { if (-e $obj_path) { my $p_path = File::Spec->catfile(TMP_DIFF, "$obj_name.$next_id_hex.patch"); if (-T $_) { - system("diff -u '$obj_path' '$_' > '$p_path'") - if system("diff -q '$obj_path' '$_' > /dev/null") != 0; + if (compare($_, $obj_path) != 0) { + unless (-d TMP_DIFF) { make_path(TMP_DIFF); } + system("diff -u '$obj_path' '$_' > '$p_path'"); + } } else { make_bin_patch($_, $obj_path, $p_path); } @@ -232,16 +231,18 @@ sub run_add { my $tree_data = join("\n", sort @entries); my $tree_hash = sha1_hex($tree_data); - write_file(TMP_TREE_FILE, $tree_hash); + my $tree_file = File::Spec->catfile(TMP_DIR, "tree-$tree_hash"); + open my $fh, '>', $tree_file or die $!; close $fh; } sub run_commit { my ($message) = @_; my $content_changed = -s TMP_META_FILE; - open my $th_fh, '<', TMP_TREE_FILE or die $!; - my $staged_hash = <$th_fh>; chomp $staged_hash; close $th_fh; - my $tree_path = File::Spec->catdir(TREE_DIR, $staged_hash); + + my ($staged_tree_ptr) = bsd_glob(File::Spec->catfile(TMP_DIR, "tree-*")); + my ($tree_hash) = $staged_tree_ptr =~ /tree-([a-f0-9]{40})$/; + my $tree_path = File::Spec->catdir(OBJ_DIR, $tree_hash); my $tree_exists = -d $tree_path; if ($tree_exists && !$content_changed) { @@ -256,7 +257,7 @@ sub run_commit { } # Prepare IDs - open my $fh_h, '<', HEAD_FILE or die "Not a repository.\n"; + open my $fh_h, '<', HEAD or die "Not a repository.\n"; my $old_head = <$fh_h>; chomp $old_head; close $fh_h; my $next_id_hex = to_hex_id(from_hex_id($old_head) + 1); my $rev_dir = File::Spec->catfile(REV_DIR, $next_id_hex); @@ -280,7 +281,7 @@ sub run_commit { rename(TMP_TREE, $tree_path) or die "Failed to save directories: $!"; } - rename(TMP_TREE_FILE, File::Spec->catfile($rev_dir, "tree")) + rename($staged_tree_ptr, File::Spec->catfile($rev_dir, "tree-$tree_hash")) or die "Failed to save tree pointer to revision: $!"; # Move deltas @@ -291,7 +292,7 @@ sub run_commit { } write_file(File::Spec->catfile($rev_dir, "message"), "$message\n"); - write_file(HEAD_FILE, "$next_id_hex\n"); # Update head + write_file(HEAD, "$next_id_hex\n"); # Update head File::Path::remove_tree(TMP_DIR) if -d TMP_DIR; @@ -300,7 +301,7 @@ sub run_commit { } sub run_log { - open my $fh_h, '<', HEAD_FILE or die "Not a repository.\n"; + open my $fh_h, '<', HEAD or die "Not a repository.\n"; my $head = <$fh_h>; chomp $head; close $fh_h; # Setup pager @@ -370,7 +371,7 @@ sub stage_link { sub stage_deletions { my ($target) = @_; - open my $fh, '<', HEAD_FILE or die "Not a repository.\n"; + open my $fh, '<', HEAD or die "Not a repository.\n"; my $head = <$fh>; chomp $head; close $fh; my $latest_tree = File::Spec->catfile(REV_DIR, $head, "tree"); @@ -457,23 +458,6 @@ sub apply_bin_patch { close $ptch_fh; } -sub compare_files { - my ($file1, $file2) = @_; - return 0 unless -s $file1 == -s $file2; - - open my $fh1, '<:raw', $file1 or return 0; - open my $fh2, '<:raw', $file2 or return 0; - - my $blk_size = 4096; - while (1) { - my $read1 = sysread($fh1, my $buf1, $blk_size); - my $read2 = sysread($fh2, my $buf2, $blk_size); - return 0 if $buf1 ne $buf2; - last if $read1 == 0; - } - return 1; -} - # Convert decimal to a padded 7-char hex string sub to_hex_id { sprintf("%07x", $_[0]) } |
