Ticket #1444: padre-vcs-tobyink-20120604.diff
| File padre-vcs-tobyink-20120604.diff, 16.0 KB (added by bowtie, 10 months ago) |
|---|
-
Padre/Padre.fbp
25546 25546 <property name="permission">protected</property> 25547 25547 <property name="pos"></property> 25548 25548 <property name="size"></property> 25549 <property name="style">wxLC_REPORT |wxLC_SINGLE_SEL</property>25549 <property name="style">wxLC_REPORT</property> 25550 25550 <property name="subclass"></property> 25551 25551 <property name="tooltip"></property> 25552 25552 <property name="validator_data_type"></property> -
Padre/lib/Padre/Wx/VCS.pm
178 178 my $self = shift; 179 179 my $current = shift or return; 180 180 my $command = shift || Padre::Task::VCS::VCS_STATUS; 181 my $files = shift || []; 182 my %extra = %{ shift || +{} }; 181 183 182 184 my $document = $current->document; 183 185 … … 206 208 } 207 209 208 210 # Not supported VCS check 209 if ( $vcs ne Padre::Constant::SUBVERSION and $vcs ne Padre::Constant::GIT ) {211 if ( $vcs ne Padre::Constant::SUBVERSION and $vcs ne Padre::Constant::GIT and $vcs ne Padre::Constant::MERCURIAL ) { 210 212 $self->{status}->SetValue( sprintf( Wx::gettext('%s version control is not currently available'), $vcs ) ); 211 213 return; 212 214 } 213 215 214 215 216 # Start a background VCS status task 216 217 $self->task_request( 217 218 task => 'Padre::Task::VCS', 218 219 command => $command, 219 220 document => $document, 221 files => $files, 222 %extra, 220 223 ); 221 224 222 225 return 1; … … 265 268 '?' => { name => Wx::gettext('Unversioned') }, 266 269 ); 267 270 268 my %vcs_status = $self->{vcs} eq Padre::Constant:: SUBVERSION ? %SVN_STATUS : %GIT_STATUS;271 my %vcs_status = $self->{vcs} eq Padre::Constant::GIT ? %GIT_STATUS : %SVN_STATUS; 269 272 270 273 # Add a zero count key for VCS status hash 271 274 $vcs_status{$_}->{count} = 0 for keys %vcs_status; … … 484 487 $self->render; 485 488 } 486 489 490 my @default_message = map { Wx::gettext($_) } 491 ( 492 q[DAAAAHUUUUUT!!!!], 493 q[Reverse the polarity of the neutron flow.], 494 q[Increase shareholder value.], 495 q[This patch fixes all known and future bugs in everything ever.], 496 q[I updated some code. Yay for me!], 497 ); 498 487 499 # Called when "Commit" button is clicked 488 500 sub on_commit_click { 489 501 my $self = shift; 490 502 my $main = $self->main; 503 504 my @files = $self->_get_selected or return; 491 505 492 506 return 493 507 unless $main->yes_no( 508 sprintf( Wx::gettext('Commit %s to repository?'), $self->_display_selected(@files) ), 494 509 Wx::gettext("Do you want to commit?"), 495 Wx::gettext('Commit file/directory to repository?')496 510 ); 511 512 my $message = $main->simple_prompt( 513 Wx::gettext("Commit message"), 514 Wx::gettext("Please provide a description of the changes for the commit log."), 515 $default_message[ rand(@default_message) ], 516 ) or return; 497 517 498 $main->vcs->refresh( $self->current, Padre::Task::VCS::VCS_COMMIT );518 $main->vcs->refresh( $self->current, Padre::Task::VCS::VCS_COMMIT, \@files, { commit_message => $message } ); 499 519 } 500 520 501 521 # Called when "Add" button is clicked 502 522 sub on_add_click { 503 523 my $self = shift; 524 my $main = $self->main; 504 525 505 my $main = $self->main; 506 my $list = $self->{list}; 507 my $selected_index = $list->GetNextItem( -1, Wx::LIST_NEXT_ALL, Wx::LIST_STATE_SELECTED ); 508 return if $selected_index == -1; 509 my $rec = $self->{model}->[ $list->GetItemData($selected_index) ] or return; 510 my $filename = $rec->{fullpath}; 526 my @files = $self->_get_selected or return; 511 527 512 528 return 513 529 unless $main->yes_no( 514 sprintf( Wx::gettext("Do you want to add '%s' to your repository"), $filename),515 Wx::gettext('Add fileto repository?')530 sprintf( Wx::gettext("Do you want to add %s to your repository?"), $self->_display_selected(@files) ), 531 Wx::gettext('Add to repository?') 516 532 ); 517 533 518 $main->vcs->refresh( $self->current, Padre::Task::VCS::VCS_ADD );534 $main->vcs->refresh( $self->current, Padre::Task::VCS::VCS_ADD, \@files ); 519 535 } 520 536 521 537 # Called when "Delete" checkbox is clicked 522 538 sub on_delete_click { 523 539 my $self = shift; 524 540 my $main = $self->main; 525 my $list = $self->{list};526 my $selected_index = $list->GetNextItem( -1, Wx::LIST_NEXT_ALL, Wx::LIST_STATE_SELECTED );527 return if $selected_index == -1;528 my $rec = $self->{model}->[ $list->GetItemData($selected_index) ] or return;529 my $filename = $rec->{fullpath};530 541 542 my @files = $self->_get_selected or return; 543 531 544 return 532 545 unless $main->yes_no( 533 sprintf( Wx::gettext("Do you want to delete '%s' from your repository"), $filename),534 Wx::gettext('Delete f ile from repository??')546 sprintf( Wx::gettext("Do you want to delete %s from your repository?"), $self->_display_selected(@files) ), 547 Wx::gettext('Delete from repository??') 535 548 ); 536 549 537 $main->vcs->refresh( $self->current, Padre::Task::VCS::VCS_DELETE );550 $main->vcs->refresh( $self->current, Padre::Task::VCS::VCS_DELETE, \@files ); 538 551 } 539 552 540 553 # Called when "Update" button is clicked … … 549 562 sub on_revert_click { 550 563 my $self = shift; 551 564 my $main = $self->main; 552 my $list = $self->{list};553 my $selected_index = $list->GetNextItem( -1, Wx::LIST_NEXT_ALL, Wx::LIST_STATE_SELECTED );554 return if $selected_index == -1;555 my $rec = $self->{model}->[ $list->GetItemData($selected_index) ] or return;556 my $filename = $rec->{fullpath};557 565 566 my @files = $self->_get_selected or return; 567 558 568 return 559 569 unless $main->yes_no( 560 sprintf( Wx::gettext("Do you want to revert changes to '%s'"), $filename),570 sprintf( Wx::gettext("Do you want to revert changes to %s?"), $self->_display_selected(@files) ), 561 571 Wx::gettext('Revert changes?') 562 572 ); 563 573 564 $main->vcs->refresh( $self->current, Padre::Task::VCS::VCS_REVERT );574 $main->vcs->refresh( $self->current, Padre::Task::VCS::VCS_REVERT, \@files ); 565 575 } 566 576 577 sub _display_selected 578 { 579 my ($self, @files) = @_; 580 if (@files == 1) { 581 return qq{'$files[0]'}; 582 } 583 else { 584 sprintf( Wx::gettext("%d files"), scalar(@files) ), 585 } 586 } 587 588 sub _get_selected 589 { 590 my $self = shift; 591 my $list = $self->{list}; 592 593 my @files; 594 my $last = -1; 595 596 while ( 597 (my $selected_index = $list->GetNextItem($last, Wx::LIST_NEXT_ALL, Wx::LIST_STATE_SELECTED)) 598 >= 0 599 ) { 600 my $rec = $self->{model}->[ $list->GetItemData($selected_index) ] or return @files; 601 push @files, $rec->{fullpath}; 602 $last = $selected_index; 603 } 604 605 return @files; 606 } 607 567 608 1; 568 609 569 610 # Copyright 2008-2012 The Padre development team as listed in Padre.pm. -
Padre/lib/Padre/Wx/FBP/VCS.pm
156 156 -1, 157 157 Wx::DefaultPosition, 158 158 Wx::DefaultSize, 159 Wx::LC_REPORT | Wx::LC_SINGLE_SEL,159 Wx::LC_REPORT, 160 160 ); 161 161 162 162 Wx::Event::EVT_LIST_COL_CLICK( -
Padre/lib/Padre/Task/VCS.pm
72 72 return unless $self->{project_dir}; 73 73 my $project_dir = delete $self->{project_dir}; 74 74 75 # bail out if a version control system is not currently supported76 return unless ( $vcs eq Padre::Constant::SUBVERSION or $vcs eq Padre::Constant::GIT);75 # # bail out if a version control system is not currently supported 76 # return unless ( $vcs eq Padre::Constant::SUBVERSION or $vcs eq Padre::Constant::GIT or $vcs eq Padre::Constant::MERCURIAL ); 77 77 78 78 if ( $command eq VCS_STATUS ) { 79 79 if ( $vcs eq Padre::Constant::SUBVERSION ) { 80 80 $self->{model} = $self->_find_svn_status($project_dir); 81 81 } elsif ( $vcs eq Padre::Constant::GIT ) { 82 82 $self->{model} = $self->_find_git_status($project_dir); 83 } elsif ( $vcs eq Padre::Constant::MERCURIAL ) { 84 $self->{model} = $self->_find_hg_status($project_dir); 83 85 } else { 84 die VCS_STATUS . " is not supported for $vcs\n"; 86 warn VCS_STATUS . " is not supported for $vcs\n"; 87 return; 85 88 } 86 } else { 89 } 90 elsif ( $command eq VCS_ADD ) { 91 if ( $vcs eq Padre::Constant::SUBVERSION ) { 92 $self->{model} = $self->_svn_add_files($project_dir, $self->{files}); 93 } elsif ( $vcs eq Padre::Constant::MERCURIAL ) { 94 $self->{model} = $self->_hg_add_files($project_dir, $self->{files}); 95 } else { 96 warn VCS_ADD . " is not supported for $vcs\n"; 97 return; 98 } 99 } 100 elsif ( $command eq VCS_DELETE ) { 101 if ( $vcs eq Padre::Constant::SUBVERSION ) { 102 $self->{model} = $self->_svn_delete_files($project_dir, $self->{files}); 103 } elsif ( $vcs eq Padre::Constant::MERCURIAL ) { 104 $self->{model} = $self->_hg_delete_files($project_dir, $self->{files}); 105 } else { 106 warn VCS_DELETE . " is not supported for $vcs\n"; 107 return; 108 } 109 } 110 elsif ( $command eq VCS_COMMIT ) { 111 if ( $vcs eq Padre::Constant::SUBVERSION ) { 112 $self->{model} = $self->_svn_commit_files($project_dir, $self->{files}, $self->{commit_message}); 113 } elsif ( $vcs eq Padre::Constant::MERCURIAL ) { 114 $self->{model} = $self->_hg_commit_files($project_dir, $self->{files}, $self->{commit_message}); 115 } else { 116 warn VCS_COMMIT . " is not supported for $vcs\n"; 117 return; 118 } 119 } 120 elsif ( $command eq VCS_REVERT ) { 121 if ( $vcs eq Padre::Constant::SUBVERSION ) { 122 $self->{model} = $self->_svn_revert_files($project_dir, $self->{files}); 123 } elsif ( $vcs eq Padre::Constant::MERCURIAL ) { 124 $self->{model} = $self->_hg_revert_files($project_dir, $self->{files}); 125 } else { 126 warn VCS_REVERT . " is not supported for $vcs\n"; 127 return; 128 } 129 } 130 else { 87 131 die "$command is not currently supported\n"; 88 132 } 89 133 90 134 return 1; 91 135 } 92 136 93 sub _find_svn_status { 94 my ( $self, $project_dir ) = @_; 137 # function, not method! 138 sub __quote_arg { 139 my $r = shift; 140 $r =~ s/[\\\"]/\\$1/; 141 qq{'$r'}; 142 } 95 143 96 my @model = (); 97 144 sub _vcs_exec { 145 my ($self, $vcs, $project_dir, @args) = @_; 146 98 147 # Create a temporary file for standard output redirection 99 148 my $out = File::Temp->new( UNLINK => 1 ); 100 149 $out->close; … … 103 152 my $err = File::Temp->new( UNLINK => 1 ); 104 153 $err->close; 105 154 106 # Find the svncommand line107 my $ svn = File::Which::which('svn') or return \@model;155 # Find the hg command line 156 my $executable = File::Which::which($vcs) or return; 108 157 109 158 # Handle spaces in executable path under win32 110 $ svn = qq{"$svn"} if Padre::Constant::WIN32;159 $executable = qq{"$executable"} if Padre::Constant::WIN32; 111 160 112 # run 'svn --no-ignore --verbose status' command113 161 my @cmd = ( 114 $svn, 115 '--no-ignore', 116 '--verbose', 117 'status', 162 $executable => @args, 118 163 '1>' . $out->filename, 119 164 '2>' . $err->filename, 120 165 ); 121 166 122 167 # We need shell redirection (list context does not give that) 123 168 # Run command in directory 124 Padre::Util::run_in_directory( join( ' ', @cmd ), $project_dir ); 169 Padre::Util::run_in_directory( join(' ', @cmd), $project_dir ); 170 # Note - above is insane! The system() command accepts arguments 171 # as a list, so you don't need to worry about quoting. Joining them 172 # as a string is a disaster waiting to happen. 125 173 126 # Slurp command standard input and output 127 my $stdout = Padre::Util::slurp $out->filename; 174 if (wantarray) { 175 my $stdout = Padre::Util::slurp $out->filename; 176 my $stderr = Padre::Util::slurp $err->filename; 177 return ($stdout, $stderr); 178 } 179 elsif (defined wantarray) { 180 # Slurp command standard input and output 181 my $stdout = Padre::Util::slurp $out->filename; 182 return $stdout; 183 } 184 } 128 185 129 #TODO parse Standard error? 130 #my $stderr = Padre::Util::slurp $err->filename; 186 sub _hg_exec { 187 my ($self, @args) = @_; 188 $self->_vcs_exec(hg => @args); 189 } 131 190 132 if ($stdout) { 133 for my $line ( split /^/, $$stdout ) { 191 sub _svn_exec { 192 my ($self, @args) = @_; 193 $self->_vcs_exec(hg => @args); 194 } 134 195 135 # Remove newlines and an extra CR (carriage return) 136 chomp($line); 137 $line =~ s/\r//g; 138 if ( $line =~ /^(\?|I)\s+(.+?)$/ ) { 196 sub _find_hg_status { 197 my ($self, $project_dir) = @_; 198 my @model; 199 200 my $stdout = $self->_hg_exec($project_dir, qw( status --all )) 201 or return \@model; 202 203 # Map hg codes to subversion. 204 # This saves adding hg-specific stuff to Padre::Wx::VCS. 205 my $lookup = { 206 'M' => 'M', 207 'A' => 'A', 208 'R' => 'D', 209 'C' => ' ', 210 '!' => '!', 211 '?' => '?', 212 'I' => 'I', 213 }; 139 214 140 # Handle unversioned and ignored objects 141 push @model, 142 { 143 status => $1, 144 revision => '', 145 author => '', 146 path => $2, 147 fullpath => File::Spec->catfile( $project_dir, $2 ), 148 }; 149 } elsif ( $line =~ /^(.)\s+\d+\s+(\d+)\s+(\w+)\s+(.+?)$/ ) { 215 for my $line ( split /^/, $$stdout ) { 216 # Remove newlines and an extra CR (carriage return) 217 chomp($line); 218 $line =~ s/\r//g; 219 220 if ( $line =~ /^([MARC!?I])\s+(.+?)$/ ) { 221 push @model, 222 { 223 status => $lookup->{$1}, 224 revision => '', 225 author => '', 226 path => $2, 227 fullpath => File::Spec->catfile($project_dir, $2), 228 }; 229 } else { 230 # Log the event but do not do anything drastic 231 # about it 232 TRACE("Cannot understand '$line'") if DEBUG; 233 } 234 } 150 235 151 # Handle other cases 152 push @model, 153 { 154 status => $1, 155 revision => $2, 156 author => $3, 157 path => $4, 158 fullpath => File::Spec->catfile( $project_dir, $4 ), 159 }; 160 } else { 236 return \@model; 237 } 161 238 162 # Log the event but do not do anything drastic 163 # about it 164 TRACE("Cannot understand '$line'") if DEBUG; 165 } 239 sub _hg_add_files 240 { 241 my ($self, $project_dir, $files) = @_; 242 $self->_hg_exec($project_dir, add => (map { __quote_arg($_) } @$files)); 243 return $self->_find_hg_status($project_dir); 244 } 245 246 sub _hg_delete_files 247 { 248 my ($self, $project_dir, $files) = @_; 249 $self->_hg_exec($project_dir, remove => (map { __quote_arg($_) } @$files)); 250 return $self->_find_hg_status($project_dir); 251 } 252 253 sub _hg_commit_files 254 { 255 my ($self, $project_dir, $files, $message) = @_; 256 $self->_hg_exec($project_dir, commit => (map { __quote_arg($_) } @$files), -m => __quote_arg($message)); 257 return $self->_find_hg_status($project_dir); 258 } 259 260 sub _hg_revert_files 261 { 262 my ($self, $project_dir, $files) = @_; 263 $self->_hg_exec($project_dir, revert => (map { __quote_arg($_) } @$files)); 264 return $self->_find_hg_status($project_dir); 265 } 266 267 sub _find_svn_status { 268 my ($self, $project_dir) = @_; 269 my @model; 270 271 my $stdout = $self->_hg_exec($project_dir, qw( --no-ignore --verbose status )) 272 or return \@model; 273 274 for my $line ( split /^/, $$stdout ) { 275 276 # Remove newlines and an extra CR (carriage return) 277 chomp($line); 278 $line =~ s/\r//g; 279 if ( $line =~ /^(\?|I)\s+(.+?)$/ ) { 280 281 # Handle unversioned and ignored objects 282 push @model, 283 { 284 status => $1, 285 revision => '', 286 author => '', 287 path => $2, 288 fullpath => File::Spec->catfile( $project_dir, $2 ), 289 }; 290 } elsif ( $line =~ /^(.)\s+\d+\s+(\d+)\s+(\w+)\s+(.+?)$/ ) { 291 292 # Handle other cases 293 push @model, 294 { 295 status => $1, 296 revision => $2, 297 author => $3, 298 path => $4, 299 fullpath => File::Spec->catfile( $project_dir, $4 ), 300 }; 301 } else { 302 303 # Log the event but do not do anything drastic 304 # about it 305 TRACE("Cannot understand '$line'") if DEBUG; 166 306 } 167 307 } 168 308 169 309 return \@model; 170 310 } 171 311 312 sub _svn_add_files 313 { 314 my ($self, $project_dir, $files) = @_; 315 $self->_svn_exec($project_dir, add => (map { __quote_arg($_) } @$files)); 316 return $self->_find_svn_status($project_dir); 317 } 318 319 sub _svn_delete_files 320 { 321 my ($self, $project_dir, $files) = @_; 322 $self->_svn_exec($project_dir, remove => (map { __quote_arg($_) } @$files)); 323 return $self->_find_svn_status($project_dir); 324 } 325 326 sub _svn_commit_files 327 { 328 my ($self, $project_dir, $files, $message) = @_; 329 $self->_svn_exec($project_dir, commit => (map { __quote_arg($_) } @$files), -m => __quote_arg($message)); 330 return $self->_find_svn_status($project_dir); 331 } 332 333 sub _svn_revert_files 334 { 335 my ($self, $project_dir, $files) = @_; 336 $self->_svn_exec($project_dir, revert => (map { __quote_arg($_) } @$files)); 337 return $self->_find_svn_status($project_dir); 338 } 339 172 340 sub _find_git_status { 173 341 my ( $self, $project_dir ) = @_; 174 342
