~ubuntu-branches/ubuntu/saucy/padre/saucy-proposed

« back to all changes in this revision

Viewing changes to lib/Padre/Task/Diff.pm

  • Committer: Package Import Robot
  • Author(s): Dominique Dumont, gregor herrmann, Dominique Dumont
  • Date: 2012-01-04 12:04:20 UTC
  • mfrom: (1.3.3)
  • Revision ID: package-import@ubuntu.com-20120104120420-i5oybqwf91m1d3il
Tags: 0.92.ds1-1
[ gregor herrmann ]
* Remove debian/source/local-options; abort-on-upstream-changes
  and unapply-patches are default in dpkg-source since 1.16.1.
* Swap order of alternative (build) dependencies after the perl
  5.14 transition.

[ Dominique Dumont ]
* Imported Upstream version 0.92.ds1
* removed fix-spelling patch (applied upstream)
* lintian-override: use wildcard to avoid listing a gazillion files
* updated size of some 'not-real-man-page' entries
* rules: remove dekstop cruft (replaced by a file provided in debian
  directory)
* control: removed Breaks statement. Add /me to uploaders. Updated
  dependencies
* rules: make sure that non-DFSG file (i.e. the cute butterfly, sigh)
  is not distributed

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package Padre::Task::Diff;
 
2
 
 
3
use 5.008005;
 
4
use strict;
 
5
use warnings;
 
6
use Padre::Task     ();
 
7
use Padre::Util     ();
 
8
use Algorithm::Diff ();
 
9
use Encode          ();
 
10
use File::Basename  ();
 
11
use File::Spec      ();
 
12
use File::Which     ();
 
13
use File::Temp      ();
 
14
use Params::Util    ();
 
15
use Padre::Logger qw(TRACE);
 
16
 
 
17
our $VERSION = '0.92';
 
18
our @ISA     = 'Padre::Task';
 
19
 
 
20
######################################################################
 
21
# Constructor
 
22
 
 
23
sub new {
 
24
        my $self = shift->SUPER::new(@_);
 
25
 
 
26
        # Just convert the document to text for now.
 
27
        # Later, we'll suck in more data from the project and
 
28
        # other related documents to do differences calculation more awesomely.
 
29
        unless ( Params::Util::_INSTANCE( $self->{document}, 'Padre::Document' ) ) {
 
30
                die "Failed to provide a document to the diff task\n";
 
31
        }
 
32
 
 
33
        # Remove the document entirely as we do this,
 
34
        # as it won't be able to survive serialisation.
 
35
        my $document = delete $self->{document};
 
36
 
 
37
        # Obtain document full filename
 
38
        my $file = $document->{file};
 
39
        $self->{filename} = $file ? $file->filename : undef;
 
40
 
 
41
        # Obtain project's Version Control System (VCS)
 
42
        $self->{vcs} = $document->project->vcs;
 
43
 
 
44
        # Obtain document text
 
45
        $self->{text} = $document->text_get;
 
46
 
 
47
        # Obtain document encoding scheme
 
48
        $self->{encoding} = $document->encoding;
 
49
 
 
50
        # Obtain document project dir
 
51
        $self->{project_dir} = $document->project_dir;
 
52
 
 
53
        return $self;
 
54
}
 
55
 
 
56
 
 
57
 
 
58
 
 
59
 
 
60
######################################################################
 
61
# Padre::Task Methods
 
62
 
 
63
sub run {
 
64
        my $self = shift;
 
65
 
 
66
        # Pull the text off the task so we won't need to serialize
 
67
        # it back up to the parent Wx thread at the end of the task.
 
68
        my $text        = delete $self->{text};
 
69
        my $vcs         = delete $self->{vcs};
 
70
        my $filename    = delete $self->{filename};
 
71
        my $project_dir = delete $self->{project_dir};
 
72
        my $encoding    = delete $self->{encoding};
 
73
 
 
74
        # Compare between VCS and local buffer document
 
75
        my $data;
 
76
        $data = $self->_find_vcs_diff( $vcs, $project_dir, $filename, $text, $encoding ) if $vcs;
 
77
        unless ($data) {
 
78
 
 
79
                # Compare between saved and current buffer document
 
80
                $data = $self->_find_local_diff( $text, $filename, $encoding );
 
81
        }
 
82
        $self->{data} = $data;
 
83
 
 
84
        return 1;
 
85
}
 
86
 
 
87
# Find local differences between current unsaved document and saved document
 
88
sub _find_local_diff {
 
89
        my ( $self, $text, $filename, $encoding ) = @_;
 
90
 
 
91
        my $content = $filename ? _slurp( $filename, $encoding ) : undef;
 
92
        my $data = [];
 
93
        if ( $content and $text ) {
 
94
                $data = $self->_find_diffs( $$content, $text );
 
95
        }
 
96
 
 
97
        return $data;
 
98
}
 
99
 
 
100
# Find differences between VCS versioned document and current document
 
101
sub _find_vcs_diff {
 
102
        my ( $self, $vcs, $project_dir, $filename, $text, $encoding ) = @_;
 
103
 
 
104
        return $self->_find_svn_diff( $filename, $text, $encoding ) if $vcs eq Padre::Constant::SUBVERSION;
 
105
        return $self->_find_git_diff( $project_dir, $filename, $text, $encoding ) if $vcs eq Padre::Constant::GIT;
 
106
 
 
107
        #TODO implement the rest of the VCS like mercurial, bazaar
 
108
        TRACE("Unhandled $vcs") if DEBUG;
 
109
 
 
110
        return;
 
111
}
 
112
 
 
113
# Generate a fast diff between the editor buffer and the original
 
114
# file in the .svn folder
 
115
# Contributed by submersible_toaster
 
116
sub _find_svn_diff {
 
117
        my ( $self, $filename, $text, $encoding ) = @_;
 
118
 
 
119
        my $local_cheat = File::Spec->catfile(
 
120
                File::Basename::dirname($filename),
 
121
                '.svn', 'text-base',
 
122
                File::Basename::basename($filename) . '.svn-base'
 
123
        );
 
124
        my $origin = _slurp( $local_cheat, $encoding );
 
125
        return $origin ? $self->_find_diffs( $$origin, $text ) : undef;
 
126
}
 
127
 
 
128
# Reads the contents of a file, and decode it using document encoding scheme
 
129
sub _slurp {
 
130
        my ( $file, $encoding ) = @_;
 
131
 
 
132
        open my $fh, '<', $file or return '';
 
133
        binmode $fh;
 
134
        local $/ = undef;
 
135
        my $content = <$fh>;
 
136
        close $fh;
 
137
 
 
138
        # Decode the content
 
139
        $content = Encode::decode( $encoding, $content );
 
140
 
 
141
        return \$content;
 
142
}
 
143
 
 
144
# Find differences between git versioned document and current document
 
145
sub _find_git_diff {
 
146
        my ( $self, $project_dir, $filename, $text, $encoding ) = @_;
 
147
 
 
148
        # Create a temporary file for standard output redirection
 
149
        my $out = File::Temp->new( UNLINK => 1 );
 
150
        $out->close;
 
151
 
 
152
        # Create a temporary file for standard error redirection
 
153
        my $err = File::Temp->new( UNLINK => 1 );
 
154
        $err->close;
 
155
 
 
156
        # Find the git command line
 
157
        my $git = File::Which::which('git') or return;
 
158
 
 
159
        # Handle spaces in git executable path under win32
 
160
        $git = qq{"$git"} if Padre::Constant::WIN32;
 
161
 
 
162
        # 'git --no-pager show' command
 
163
        my $path = File::Spec->abs2rel( $filename, $project_dir );
 
164
        $path =~ s/\\/\//g if Padre::Constant::WIN32;
 
165
        my @cmd = (
 
166
                $git,
 
167
                '--no-pager',
 
168
                'show',
 
169
                "HEAD:" . $path,
 
170
                '1>' . $out->filename,
 
171
                '2>' . $err->filename,
 
172
        );
 
173
 
 
174
        # We need shell redirection (list context does not give that)
 
175
        # Run command in directory
 
176
        Padre::Util::run_in_directory( join( ' ', @cmd ), $project_dir );
 
177
 
 
178
        # Slurp git command standard input and output
 
179
        my $stdout = _slurp( $out->filename, $encoding );
 
180
        my $stderr = _slurp( $err->filename, $encoding );
 
181
 
 
182
        if ( defined($stderr) and ( $$stderr eq '' ) and defined($stdout) ) {
 
183
                return $self->_find_diffs( $$stdout, $text );
 
184
        }
 
185
 
 
186
        return;
 
187
}
 
188
 
 
189
# Find differences between original text and unsaved text
 
190
sub _find_diffs {
 
191
        my ( $self, $original_text, $unsaved_text ) = @_;
 
192
 
 
193
        my @original_seq = split /^/, $original_text;
 
194
        my @unsaved_seq  = split /^/, $unsaved_text;
 
195
        my @diff = Algorithm::Diff::diff( \@original_seq, \@unsaved_seq );
 
196
        return \@diff;
 
197
}
 
198
 
 
199
1;
 
200
 
 
201
# Copyright 2008-2011 The Padre development team as listed in Padre.pm.
 
202
# LICENSE
 
203
# This program is free software; you can redistribute it and/or
 
204
# modify it under the same terms as Perl 5 itself.