├── .gitignore
├── README.textile
├── rsyncdiff.gemspec
└── bin
└── rsyncdiff
/.gitignore:
--------------------------------------------------------------------------------
1 | *.swp
2 |
--------------------------------------------------------------------------------
/README.textile:
--------------------------------------------------------------------------------
1 | This is a simple tool for running diffs against local and remote code. It uses rysnc so it can get all the creations, deletions and updates.
2 |
3 | Run it like this:
4 |
5 | rsyncdiff server:/u/apps/myapp/current/app app/
6 |
7 | !http://dl.getdropbox.com/u/221414/github/rsync_diff.png!
8 |
9 | It'll use colordiff if it's installed.
10 |
11 | h3. Installation
12 |
13 | This gem is hosted on "gemcutter":http://gemcutter.org
14 |
15 | Install with:
16 |
17 | gem install rsyncdiff
18 |
--------------------------------------------------------------------------------
/rsyncdiff.gemspec:
--------------------------------------------------------------------------------
1 | Gem::Specification.new do |s|
2 | s.name = %q{rsyncdiff}
3 | s.version = "0.0.3"
4 |
5 | s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6 | s.authors = ["Alex R. Young"]
7 | s.date = %q{2009-09-16}
8 | s.description = %q{rsyncdiff is a tool for comparing local and remote code. It displays changes, deletions and diffs.}
9 | s.email = %q{alex@alexyoung.org}
10 | s.files = %w{README.textile bin/rsyncdiff}
11 | s.has_rdoc = false
12 | s.bindir = 'bin'
13 | s.executables = ['rsyncdiff']
14 | s.default_executable = 'bin/rsyncdiff'
15 | s.homepage = %q{http://github.com/alexyoung/rsyncdiff}
16 | s.summary = %q{rsyncdiff is a tool for comparing local and remote code.}
17 | end
18 |
19 |
--------------------------------------------------------------------------------
/bin/rsyncdiff:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # This script uses rsync to compare remote and local files.
4 | # It will display new files that would have been uploaded
5 | # and displays a diff for ones that have changes.
6 |
7 | begin
8 | remote_path = ARGV[0]
9 | path = ARGV[1]
10 | host, remote_path = remote_path.split(':')
11 | path = path + '/' if path[-1].chr != '/'
12 | rescue
13 | puts "Provide two arguments: [remote path] [local path]\n\n"
14 | puts "For example:"
15 | puts "\trsyncdiff server:/u/apps/myapp/current/app app/"
16 | exit 1
17 | end
18 |
19 | def colorize(text, color_code)
20 | "#{color_code}#{text}#{27.chr}[0m"
21 | end
22 |
23 | def red(text); colorize(text, "#{27.chr}[31m"); end
24 | def green(text); colorize(text, "#{27.chr}[32m"); end
25 |
26 | def use_colordiff?
27 | not `which colordiff`.empty?
28 | end
29 |
30 | class RemoteChange
31 | attr_reader :file
32 |
33 | def initialize(string, file)
34 | @string = string
35 | @file = file
36 | end
37 |
38 | def to_s
39 | change_type = if new?
40 | "[#{green 'CREATE'}]"
41 | elsif include?('new')
42 | "[#{green 'CREATE'}] #{output.first}"
43 | elsif change?
44 | "[#{green 'UPDATE'}] #{output[1]}"
45 | elsif delete?
46 | "[#{red 'DELETE'}] #{output[1]}"
47 | end
48 |
49 | "#{change_type}\t#{@file}"
50 | end
51 |
52 | def new?
53 | include?('uploaded') and include?('new')
54 | end
55 |
56 | def change?
57 | include?('uploaded') and include?('size')
58 | end
59 |
60 | def delete?
61 | include? 'deleted'
62 | end
63 |
64 | def output
65 | @results ||= parse
66 | end
67 |
68 | def include?(item)
69 | output.include? item
70 | end
71 |
72 | def interesting_deletion?
73 | @string.match /^\*deleting/ and !@string.match /\.svn/
74 | end
75 |
76 | def parse
77 | return @results unless @results.nil?
78 | @string ||= ''
79 |
80 | @results = if interesting_deletion?
81 | ['deleted']
82 | else
83 | @string.split('').collect do |c|
84 | identify c
85 | end
86 | end
87 | @results.compact
88 | end
89 |
90 | def identify(c)
91 | case c
92 | when '<'
93 | 'uploaded'
94 | when '>'
95 | 'downloaded'
96 | when 'c'
97 | 'local change/creation'
98 | when 'h'
99 | 'hard link'
100 | when '*'
101 | when 'f'
102 | 'file'
103 | when 'L'
104 | 'symlink'
105 | when '+'
106 | 'new'
107 | when '.'
108 | 'no change'
109 | when 's'
110 | 'size'
111 | end
112 | end
113 | end
114 |
115 | rsync_command = "rsync -rvv --itemize-changes --delete --dry-run #{path} #{host}:#{remote_path}"
116 | rsync_output = %x(#{rsync_command})
117 |
118 | items = {}
119 | items[:creations] = []
120 | items[:updates] = []
121 | items[:deletions] = []
122 |
123 | rsync_output.split("\n").each do |line|
124 | changes, file = line.gsub(/[ ]+/, ' ').split(' ')
125 |
126 | # ignore dot files
127 | next if file.nil? or file[0].chr == '.' or file.match('/\.')
128 |
129 | item = RemoteChange.new changes, file
130 |
131 | if item.change?
132 | items[:updates] << item
133 | elsif item.new?
134 | items[:creations] << item
135 | elsif item.delete?
136 | items[:deletions] << item
137 | end
138 | end
139 |
140 | items[:deletions].each do |item|
141 | puts item
142 | end
143 |
144 | puts
145 |
146 | items[:creations].each do |item|
147 | puts item
148 | end
149 |
150 | puts
151 |
152 | items[:updates].each do |item|
153 | puts item
154 | ssh_diff_command = "ssh #{host} cat \"#{File.join(remote_path, item.file)}\" | diff \"#{path}#{item.file}\" -"
155 |
156 | if use_colordiff?
157 | ssh_diff_command += ' | colordiff'
158 | end
159 |
160 | system(ssh_diff_command)
161 | puts
162 | end
163 |
--------------------------------------------------------------------------------