Commits

m...@mm-laptop  committed ec689d5

Added Some extra features including much better diffing.

  • Participants
  • Parent commits 50d47d8

Comments (0)

Files changed (8)

 
 0.01    Date/time
         First version, released on an unsuspecting world.
+0.10    2009/11/03:1402
+        First release to CPAN,  Added more commands and improved the diffing to be usable. 
 
 lib/Padre/Plugin/HG/ProjectCommit.pm
 lib/Padre/Plugin/HG/StatusTree.pm
 lib/Padre/Plugin/HG/UserPassPrompt.pm
+lib/Padre/Plugin/HG/DiffView.pm
+lib/Padre/Plugin/HG/LogView.pm
 t/00-load.t
-t/pod-coverage.t
 t/pod.t
 Padre-Plugin-HG
 
-The README is used to introduce the module and provide instructions on
-how to install the module, any machine dependencies it may have (for
-example C compilers and installed libraries) and any other information
-that should be provided before the module is installed.
+This module is provided as a plugin to the Padre perl editor.  Padre plugins are installed 
+in the usual way for perl modules.  
 
-A README file is required for CPAN modules since CPAN extracts the README
-file from a module distribution so that people browsing the archive
-can use it to get an idea of the module's uses. It is usually a good idea
-to provide version information here so that people can decide whether
-fixes for the module are worth downloading.
+
 
 
 INSTALLATION

File lib/Padre/Plugin/HG.pm

 use Padre::Plugin::HG::ProjectClone;
 use Padre::Plugin::HG::UserPassPrompt;
 use Padre::Plugin::HG::DiffView;
+use Padre::Plugin::HG::LogView;
 my %projects;
-our $VERSION = '0.01';
+our $VERSION = '0.11';
 our @ISA     = 'Padre::Plugin';
 
 my $VCS = "Mercurial";
-
+# enter the vcs commands here, variables will be evaled in in the sub routines. 
+# was meant as a way to make it more generic.  Not sure it is going to 
+# succeed. 
 my %VCSCommand = ( commit => 'hg commit -A -m"$message" $path ',
 		add => 'hg add $path',
 		status =>'hg status --all $path',
 		root => 'hg root', 
 		diff => 'hg diff $path',
+		diff_revision => 'hg diff -r $revision $path',
 		clone=> 'hg clone $path',
 		pull =>'hg pull --update --noninteractive  ',
-		push =>'hg push $path');
+		push =>'hg push $path',
+		log =>'hg log $path');
 		
-my %HGStatus = ( M => 'File Modified', 
-A => 'File Added not Committed',
-R => 'File Removed',
-C => 'Up to Date',
-'!' => 'Deleted But Still Tracked!',
-'?' => 'Not Tracked',
-I => 'ignored'
-);
+
 
 =pod
 
 
 Padre::Plugin::HG - Mecurial interface for Padre
 
-=head1 SYNOPSIS
+=head1 Instructions
+
+Ensure Mecurial is installed and the hg command is in the path. 
 
 cpan install Padre::Plugin::HG
 
-Access it via Plugin/HG then View Project 
+Either open a file in an existing Mecurial project or choose Plugins > HG > Clone and enter an 
+exisiting repository to clone. 
+ 
+you can clone this project it self with
+"hg clone https://code4pay@bitbucket.org/code4pay/padre-plugin-hg/"
 
+Once you have a file from the project open  got to Plugins > HG > View Project.
+this will display the project tree in the left hand side bar and allow you to 
+perform operations on the files /project via the right mouse button.
+
+Project wide operations like pull are only available by right clicking the project root. 
+ 
 
 =head1 AUTHOR
 
 This program is free software; you can redistribute it and/or modify it
 under the same terms as Perl itself.
 
-=head1 METHODS
+
 
 =cut
 
 	return $self->plugin_name => [
 		'About'             => sub { $self->show_about },
 		'View Project'	    => sub {$self->show_statusTree},
-		'Add'		    => sub {$self->vcs_add},
 		'Clone'		    => sub {$self->show_project_clone},
-		'Commit...' 	    => sub { $self->show_commit_list},
-		'Diff...' 	    => sub { $self->show_diff},
+
 	];
 }
 
 
 	return;
 }
-=pod
 
-=head2 vcs_commit
+#
+#vcs_commit
+#
+# performs the commit 
+# $self->vcs_commit($filename, $dir);
+# will prompt for the commit message.
+# 
 
- performs the commit 
- $self->vcs_commit($filename, $dir);
- will prompt for the commit message.
- 
-=cut
 
 sub vcs_commit {
 	my ($self, $path, $dir ) = @_;
 	return;	
 }
 
-=pod
 
-=head2 vcs_add
+#
+#vcs_add
+#
+# Adds the file to the repository
+# $self->vcs_add($filename, $dir);
+# will prompt for the commit message.
+# 
 
- Adds the file to the repository
- $self->vcs_add($filename, $dir);
- will prompt for the commit message.
- 
-=cut
 
 sub vcs_add {
 	my ($self, $path, $dir) = @_;
 	return;	
 }
 
-=pod
+#
+# vcs_diff
+#
+# compare the file to the repository tip
+# $self->vcs_diff($filename, $dir);
+# provides some basic diffing the current file agains the tip
 
-=head2 vcs_add
-
- Adds the file to the repository
- $self->vcs_diff($filename, $dir);
- provides some basic diffing the current file agains the tip
-
-=cut
 sub vcs_diff {
 	my ($self, $path, $dir) = @_;
 	
 	return $result;
 }
 
-=pod
+# vcs_diff_revision
+#
+# compare the file to a repository revision 
+# $self->vcs_diff($filename, $dir, $revision);
+# Revision for HG is the changeset id. 
 
-=head2 clone_project
 
- Adds the file to the repository
- $self->vcs_diff($repository, $destination_dir);
- Will clone a repository and place it in the destination dir
- 
-=cut
+sub vcs_diff_revision {
+	my ($self, $path, $dir, $revision) = @_;
+	
+	my $main = Padre->ide->wx->main;
+	my $command = eval "qq\0$VCSCommand{diff_revision}\0";
+	return $main->error('File not in a $VCS Project', "Padre $VCS" ) if not $self->_project_root($path);
+	my $result = $self->vcs_execute($command, $dir);
+	return $result;
+}
+
+
+
+# vcs_log
+#
+# show the commit history of the passed file. 
+# $self->vcs_commit($filename, $dir);
+# returns a string containing the log history
+
+
+sub vcs_log {
+	my ($self, $path, $dir) = @_;
+	
+	my $main = Padre->ide->wx->main;
+	my $command = eval "qq\0$VCSCommand{log} $path\0";
+	return $main->error('File not in a $VCS Project', "Padre $VCS" ) if not $self->_project_root($path);
+	my $result = $self->vcs_execute($command, $dir);
+	return $result;
+}
+
+
+#
+#clone_project
+#
+# Adds the file to the repository
+# $self->vcs_diff($repository, $destination_dir);
+# Will clone a repository and place it in the destination dir
+# 
+
 sub clone_project
 {
 	my ($self, $path, $dir) = @_;
 	$main->message( $result, "$VCS Cloning $path" );
 	return;
 }
-=pod
 
-=head2 pull_update_project
+#
+# pull_update_project
+#
+# Pulls updates to a project. 
+# It will perform an update automatically on the repository
+# $self->pull_update_project($file, $projectdir);
+# Only pulls changes from the default repository, which is normally
+# the one you cloned from.
 
- Pulls updates to a project. 
- It will perform an update automatically on the repository
- $self->pull_update_project($file, $projectdir);
- Only pulls changes from the default repository, which is normally
- the one you cloned from.
-
-=cut
 sub pull_update_project
 {
 	my ($self, $path, $dir) = @_;
 	$main->message( $result, "$VCS Cloning $path" );
 	return;
 }
-=pod
 
-=head2 push_project
 
- Pushes updates to a remote repository. 
- Prompts for the username and password. 
- $self->push_project($file, $projectdir);
- Only pushes changes to the default remote repository, which is normally
- the one you cloned from.
+# Pushes updates to a remote repository. 
+# Prompts for the username and password. 
+# $self->push_project($file, $projectdir);
+# Only pushes changes to the default remote repository, which is normally
+# the one you cloned from.
 
-=cut
+
 sub push_project
 {
 	my ($self, $path, $dir) = @_;
 	return;
 }
 
-=pod
 
-=head2 vcs_execute
 
- Executes a command after changing to the appropriate dir.
- $self->vcs_execute($command, $dir);
- All output is captured and returned as a string.
+# vcs_execute
+#
+# Executes a command after changing to the appropriate dir.
+# $self->vcs_execute($command, $dir);
+# All output is captured and returned as a string.
 
-=cut
 sub vcs_execute
 {
 	my ($self, $command, $dir) = @_;
 	return $result;
 }
 
-=pod
 
-=head2 show_statusTree
 
- Displays a Project Browser in the side pane. The Browser shows the status of the
- files in HG and gives menu options to perform actions. 
+# show_statusTree
+#
+# Displays a Project Browser in the side pane. The Browser shows the status of the
+# files in HG and gives menu options to perform actions. 
 
-=cut
+
 sub show_statusTree
 {	
 	my ($self) = @_;
 	}
 }
 
-=pod
+#
+#
+#show_commit_list
+#
+# Displays a list of all the files that are awaiting commiting. It will include
+# not added and deleted files adding and removing them as required. 
 
-=head2 show_commit_list
 
- Displays a list of all the files that are awaiting commiting. It will include
- not added and deleted files adding and removing them as required. 
-
-=cut
 sub show_commit_list
 {	
 	my ($self) = @_;
 
 }
 
-=pod
 
-=head2 show_diff
+#
+# show_diff
+#
+# Displays a list of all the files that are awaiting commiting. It will include
+# not added and deleted files adding and removing them as required. 
 
- Displays a list of all the files that are awaiting commiting. It will include
- not added and deleted files adding and removing them as required. 
 
-=cut
 sub show_diff
 {	
 	my ($self, $file, $path) = @_;
 	 $self->{project_path} = $self->_project_root($file);
         my $full_path = File::Spec->catdir(($path,$file));
 	return $main->error("Not a $VCS Project") if ! $self->{project_path} ;
+ 	Padre::Plugin::HG::DiffView->showDiff($self,$full_path );	
+	
+
+}
+
+#show_diff_revision
+#
+# Displays a list of all the revisions for the selected file. 
+# Allowing you to choose one to diff the current selection to.  
+
+sub show_diff_revision
+{	
+	my ($self, $file, $path) = @_;
+	my $main = Padre->ide->wx->main;
+	 $self->{project_path} = $self->_project_root($file);
+        my $full_path = File::Spec->catdir(($path,$file));
+	return $main->error("Not a $VCS Project") if ! $self->{project_path} ;
+ 	my $changeset = Padre::Plugin::HG::LogView->showList($self,$full_path);
+ 	my $differences = $self->vcs_diff_revision($file, $path, $changeset);	
+	Padre::Plugin::HG::DiffView->showDiff($self,$differences);	
+
+
+}
+
+#show_commit_list
+#
+# Displays a list of all the files that are awaiting commiting. It will include
+# not added and deleted files adding and removing them as required. 
+
+sub show_log
+{	
+	my ($self) = @_;
+	my $main = Padre->ide->wx->main;
+	 $self->{project_path} = $self->_project_root(current_filename());
+
+	return $main->error("Not a $VCS Project") if ! $self->{project_path} ;
  
-	my $obj = Padre::Plugin::HG::DiffView->showList($self,$full_path );	
+	my $obj = Padre::Plugin::HG::LogView->showList($self,current_filename());	
 	$obj = undef;
 
 }
 
-=pod
 
-=head2 show_project_clone
 
- Dialog for project cloning
 
-=cut
+#show_project_clone
+#
+# Dialog for project cloning
+#
 
 sub show_project_clone
 {	
 	{
 		$clone->choose_destination();
 	}
-	
+
 	if ($clone->project_url()  and $clone->destination_dir())
 	{
 		$self->clone_project(
 
 
 
-=pod
 
-=head2 _project_root
+#
+# _project_root
+#
+# $self->_project_root($filename);
+# Calculates the project root.  if the file is not in a project it 
+# will return 0 
+# otherwise it returns the fully qualified path to the project. 
 
- $self->_project_root($filename);
- Calculates the project root.  if the file is not in a project it 
- will return 0 
- otherwise it returns the fully qualified path to the project. 
-
-=cut
 
 sub _project_root
 {
 	return $project_root;
 }
 
-=pod
 
-=head2 _get_hg_files
+# _get_hg_files
+#
+# $self->_get_hg_files(@hgStatus);
+#  Pass the output of hg status and it will give back an array
+#  each element of the array is [$status, $filename]
 
- $self->_get_hg_files(@hgStatus);
-  Pass the output of hg status and it will give back an array
-  each element of the array is [$status, $filename]
 
-=cut
 
 sub _get_hg_files
 {
 	return @files;
 }
 
-=pod
 
-=head2 current_filename
+#current_filename 
+#
+# $self->current_filename();
+#  returns the path of the file with the current attention 
+#  in the ide.
 
- $self->current_filename();
-  returns the path of the file with the current attention 
-  in the ide.
 
-=cut
 
 
 sub current_filename {
         return ($filename); 
 }
 
-=pod
+#parse_log
+#
+# $self->parse_log($log);;
+# Pass it the output of the hg log command and it will 
+# return an array of hashes with each array element 
+# being  a  hash of the commit values. 
+# eg changeset, user, date ...
+#
 
-=head2 object_for_testing
 
- creates a blessed object so we can run our tests. 
 
-=cut
+sub parse_log {
+	my ($self,$log) = @_;
+	
+	# log output looks like
+	# 
+	#changeset:   3:80d72b2a4751
+	#user:        bill@microsoft.com
+	#date:        Fri Oct 16 07:05:27 2009 +1100
+	#summary:     Added files for CPAN distribution
+	#
+	#changeset:   3:80d72b2a4751
+	#user:        bill@microsoft.com
+	#date:        Fri Oct 16 07:05:27 2009 +1100
+	#summary:     Tricky Comment summary: CPAN distribution
+	
+	#split the output at blank lines
+	my @commits = split(/\n{2,}/, $log);
+	my $i = 0;
+	my @result;
+	foreach my $commit (@commits)
+	{
+		
+		
+		$result[$i] = {
+			changeset=>$commit =~ /^changeset:\s+(.*)/m,
+			user=>$commit=~ /^user:\s+(.*)/m,
+			date=>$commit=~ /^date:\s+(.*)/m, 
+			summary=>$commit=~ /^summary:\s+(.*)/m,
+		} ;
+		$i++;
+	} 
+	
+	return @result;
+}
+
+
+
+# object_for_testing
+#
+# creates a blessed object so we can run our tests. 
+#
+
 
 sub object_for_testing
 {

File lib/Padre/Plugin/HG/LogView.pm

+=pod
+
+=head1  NAME
+
+Padre::Plugin::HG::LogView
+Displays a list of commits for the passed file. 
+
+=head1 SYNOPSIS
+
+ my $changeset = Padre::Plugin::HG::LogView->showList($self, $file);
+ 
+=head1 DESCRIPTION
+
+This module displays the list of commits that have occured for the passed file. 
+it returns the changeset number. 
+=head1 METHODS
+
+=cut
+
+
 package Padre::Plugin::HG::LogView;
 use strict;
 use Padre::Wx;
         #insert the HG data
         chdir ($self->{hg}->{project_path});
         my $hgdata = $self->{hg}->vcs_log($file, $self->{hg}->{project_path});
+        
         $self->_populate_list( $hgdata);
 
 	
 	# Change the contents of $self->{txt}
 	
 	my $changeset;
-	#$self->{txt}->SetLabel("The button was clicked!"); 
+	
 	my $item = -1;
 	 while ( 1 ==1 )
 	{
  my @commits = $self->{hg}->parse_log($log);
  
  if (!$log) {return}
+ #build the list headers
  $self->{list_box}->InsertColumn(0,'changeset');
  $self->{list_box}->InsertColumn(1,'user');
  $self->{list_box}->InsertColumn(2,'date');

File lib/Padre/Plugin/HG/ProjectClone.pm

 
 =head2 new
 
-  my $object = Module::Name->new(
-      foo => 'bar',
-  );
-
-The C<new> constructor lets you create a new B<Module::Install> object.
-
-So no big surprises there...
-
-Returns a new B<Module::Install> or dies on error.
+ create a new ProjectClone object. 
+ 
 
 =cut
 
     my ($class, $hg) = @_; 
     my $self       = $class->SUPER::new( Padre::Current->main);
     $self->{hg} = $hg;
-
-    
-  
     return $self;
 }
 
 {
     my ($self) = @_;
     my $dialog = Wx::DirDialog->new($self, 'Choose a Destination Directory');
-    $dialog->ShowModal();
-    $self->{destination_dir} = $dialog->GetPath();
-    return $self->{destination_dir};
+    my $choice = $dialog->ShowModal();
+    if ($choice == Wx::wxID_CANCEL)
+    {   
+        $self->{destination_dir} = undef();
+        return;
+    }
+    else
+    {
+        $self->{destination_dir} = $dialog->GetPath();
+        return $self->{destination_dir};
+    }
 }
 
 sub project_url

File lib/Padre/Plugin/HG/StatusTree.pm

 {
   my ($class, $hg, $root) = @_;
   $project_name = $root;
-  $HG = $hg;
+
 
   my $self       = $class->SUPER::new( Padre::Current->main->left );
   my $box        = Wx::BoxSizer->new(Wx::wxVERTICAL);
   my $treectrl = Wx::TreeCtrl->new( $self, -1 );
   $treectrl->AssignImageList($images);
-
+  
+  $HG = $hg; #assign this the hg object. 
+ 
   $self->drawTree($treectrl);
   Wx::Event::EVT_TREE_ITEM_MENU(
          $treectrl, $treectrl,
 =head2 _on_tree_item_activated
 
         Performs actions when the users double clicks on a tree node
+        at the moment opens a file when it is double clicked. 
         
  
 =cut
 	
 	my ( $self, $event,$me ) = @_;
 	my $node      = $event->GetItem;
+            
         my $node_data = $self->GetPlData($node);
 	my $selected_path  = $node_data->{path};
         my $selected_file = $node_data->{name};
         my $selected_type = $node_data->{type};
         my $full_path = File::Spec->catdir(($project_name,$selected_path));
-
+        
         if ($selected_type ne 'dir' and $selected_type ne 'root')
         {
                 open_file($full_path);
                        $self, $diff,
                        sub { $HG->show_diff($selected_file, $parent_dir);}
                );  
+               #diff to a revision  
+               my $diff = $menu->Append(
+                         -1,
+                       Wx::gettext( 'Diff to Revision' ));
+                    
+                Wx::Event::EVT_MENU(
+                       $self, $diff,
+                       sub { $HG->show_diff_revision($selected_file, $parent_dir);}
+               );  
                
                #open 
                my $open = $menu->Append(
 use strict;
 use warnings;
 use File::Spec;
-use Test::More tests => 8;
+use Test::More tests => 19;
 use Cwd;   
+chdir ('/home/mm/Padre-Plugin-HG/');
 
-use lib ("../lib");
+use lib ("./lib");
 use_ok ('Padre::Plugin::HG');
 my $hg = Padre::Plugin::HG->object_for_testing();
 ok (`hg`, 'Found hg');
 my $root = File::Spec->catdir((getcwd(), 't','hg_test_dir'));
 is($hg->_project_root($hg_file ),$root, 'Determined Project root');
 
+#Parse the history log
 
+my $log_string = q !changeset:   14:f9a3b28f269c
+user:        mm@mm-laptop
+date:        Fri Oct 30 08:41:24 2009 +1100
+summary:     Implement Better Diff Viewing
 
+changeset:   3:80d72b2a4751
+user:        bill@microsoft.com
+date:        Fri Oct 16 07:05:27 2009 +1100
+summary:     Added files for CPAN distribution
+
+changeset:   3:80d72b2a4751
+user:        bill@microsoft.com
+date:        Fri Oct 16 07:05:27 2009 +1100
+summary:     Tricky Comment summary: CPAN distribution
+
+changeset:   3:80d72b2a4751
+user:        bill@microsoft.com
+date:        Fri Oct 16 07:05:27 2009 +1100
+summary:     
+
+!;
+
+my @log;
+ok ( @log = $hg->parse_log($log_string), 'Parse the Log String');
+
+is ($log[0]->{user}, 'mm@mm-laptop', 'first User Log');
+is ($log[0]->{changeset}, '14:f9a3b28f269c', 'first changeset Log');
+is ($log[0]->{date}, 'Fri Oct 30 08:41:24 2009 +1100', 'first date Log');
+is ($log[0]->{summary}, 'Implement Better Diff Viewing', 'first summary Log');
+is ($log[1]->{user}, 'bill@microsoft.com', 'Second User Log');
+is ($log[1]->{changeset}, '3:80d72b2a4751', 'Second chageset Log');
+is ($log[1]->{date}, 'Fri Oct 16 07:05:27 2009 +1100', 'Second date Log');
+is ($log[1]->{summary}, 'Added files for CPAN distribution', 'Second summary Log');
+
+is ($log[2]->{summary}, 'Tricky Comment summary: CPAN distribution', 'Tricky summary Log');
+
+is ($log[3]->{summary}, '', 'Blank');
+
+