pidgin2adium 2.0.1 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,13 @@
1
+ === 2.0.2 / 2009-12-18
2
+ * Much better documentation (more of it, and higher quality too!)
3
+ * Allow user-provided output dir at commandline
4
+ * Cleaner error messages
5
+ * require 'time' for Time.zone_offset (fixes bug)
6
+ * Gracefully handle lack of timezone info
7
+ * Gracefully handle nonexistent output dir
8
+ * Gracefully handle parsing errors
9
+ * Print error messages during *and* after batch converting so they're actually seen
10
+
1
11
  === 2.0.1 / 2009-12-06
2
12
  * Fix timestamps so they show up in Adium chat log viewer
3
13
 
data/README.rdoc CHANGED
@@ -38,8 +38,9 @@ Or:
38
38
 
39
39
  ===Example (using library)
40
40
  The library style allows you to parse a log file and get back a
41
- LogFile instance for easy reading, manipulation, etc.
42
- You can also create log files yourself using Pidgin2Adium.parse_and_generate.
41
+ LogFile[link:classes/Pidgin2Adium/LogFile.html] instance for easy reading, manipulation, etc.
42
+ You can also create log files yourself using Pidgin2Adium.parse_and_generate[link:classes/Pidgin2Adium.html#M000006].
43
+ For batch processing, use LogConverter[link:classes/Pidgin2Adium/LogConverter.html].
43
44
 
44
45
  require 'pidgin2adium'
45
46
  logfile = Pidgin2Adium.parse("/path/to/log/file.html", "gabe,gbw,gabeb-w")
@@ -64,12 +65,35 @@ You can also create log files yourself using Pidgin2Adium.parse_and_generate.
64
65
  # Prints out the message in Adium log format
65
66
  puts message.to_s
66
67
  end
68
+ success = logfile.write_out()
69
+ # To overwrite file if it exists:
70
+ # logfile.write_out(overwrite = true)
71
+ # To specify your own output dir (default = Pidgin2Adium::ADIUM_LOG_DIR):
72
+ # logfile.write_out(false, output_dir = my_dir)
73
+ # Or combine them:
74
+ # logfile.write_out(true, my_dir)
75
+ if success == false
76
+ puts "An error occurred!"
77
+ elsif success == Pidgin2Adium::FILE_EXISTS
78
+ # Not returned if overwrite set to true
79
+ puts "File already exists."
80
+ else
81
+ puts "Successfully wrote out log file!"
82
+ puts "Path to output file: #{success}"
83
+ end
84
+ # This deletes search indexes to Adium re-indexes the new chat logs.
85
+ # Not automatically called after log_file.write_out()
86
+ # If you're converting >1 log, call it after converting all of them, since
87
+ # it takes up a tiny bit of processing power.
88
+ Pidgin2Adium.delete_search_indexes()
67
89
  end
68
90
 
69
91
  ===Example 2 (using library)
70
92
  If you want to output the logfile to an output dir instead of just parsing it, use Pidgin2Adium.parse_and_generate:
71
93
 
72
94
  require 'pidgin2adium'
95
+ # Both options are optional; without :output_dir, writes to Adium log dir
96
+ # (which is usually what you want anyway).
73
97
  opts = {:overwrite => true, :output_dir => "/my/output/dir"}
74
98
  path_to_converted_log = Pidgin2Adium.parse_and_generate("/path/to/log/file.html", "gabe,gbw,gabeb-w", opts)
75
99
 
data/bin/pidgin2adium CHANGED
@@ -15,21 +15,41 @@ automatically recognized.
15
15
  require 'pidgin2adium/log_converter'
16
16
  require 'optparse'
17
17
 
18
+ version = <<EOL
19
+ Pidgin2Adium, version #{Pidgin2Adium::VERSION}
20
+ Written by Gabe Berke-Williams (gbw@rubyforge.org)
21
+ EOL
22
+
18
23
  options = {}
19
24
  oparser = OptionParser.new do |opts|
20
25
  opts.banner = "Usage: #{File.basename($0)} [options]"
21
- opts.on('-i', '--in=IN_DIR', String, 'Specify directory where pidgin logs are stored') do |i|
26
+ opts.on('-i', '--in=IN_DIR', String, 'Directory where pidgin logs are stored') do |i|
22
27
  options[:in] = i
23
28
  end
24
29
  opts.on('-a alias1,alias2', "--aliases alias1,alias2",
25
- "A comma-separated list of your alias(es) so this script knows
26
- which person in a chat is you.", "Whitespace and case do not matter.") do |aliases|
30
+ "A comma-separated list of your alias(es)",
31
+ "so this script knows which person in a chat",
32
+ "is you. Whitespace and case do not matter.") do |aliases|
27
33
  options[:aliases] = aliases
28
34
  end
29
- opts.on('-f', '--force', 'If this is set, then logs in the Adium log folder that have the same name as converted logs will be overwritten.') do |f|
35
+ opts.on('-o', '--out [OUT_DIR]',
36
+ 'The top-level directory under which to',
37
+ 'store the logs (each in its own folder',
38
+ 'by screen name).',
39
+ "Defaults to: #{Pidgin2Adium::ADIUM_LOG_DIR}") do |out|
40
+ options[:output_dir] = out
41
+ end
42
+ opts.on('-f', '--force', 'If this is set, then logs in the Adium log',
43
+ 'folder that have the same name as converted',
44
+ 'logs will be overwritten.') do |f|
30
45
  options[:force] = f
31
46
  end
47
+ opts.on("-v", "--version", "Show version information") do
48
+ puts version
49
+ exit
50
+ end
32
51
  opts.on_tail("-h", "--help", "Show this message") do
52
+ puts version
33
53
  puts opts
34
54
  exit
35
55
  end
@@ -65,8 +85,12 @@ if need_opts
65
85
  exit 1
66
86
  end
67
87
 
88
+ extra_opts = {:overwrite => options[:force]}
89
+ if options.has_key?(:output_dir)
90
+ extra_opts[:output_dir] = options[:output_dir]
91
+ end
92
+
68
93
  log_converter = Pidgin2Adium::LogConverter.new(options[:in],
69
94
  options[:aliases],
70
- {:overwrite => options[:force]}
71
- )
95
+ extra_opts)
72
96
  log_converter.start
data/lib/pidgin2adium.rb CHANGED
@@ -14,17 +14,22 @@ module Pidgin2Adium
14
14
  ADIUM_LOG_DIR = File.expand_path('~/Library/Application Support/Adium 2.0/Users/Default/Logs/') << '/'
15
15
  # These files/directories show up in Dir.entries()
16
16
  BAD_DIRS = %w{. .. .DS_Store Thumbs.db .system}
17
- VERSION = "2.0.1"
17
+ VERSION = "2.0.2"
18
+ # For displaying after we finish converting
19
+ @@oops_messages = []
20
+ @@error_messages = []
18
21
 
19
- def log_msg(str) #:nodoc
22
+ def log_msg(str) #:nodoc:
20
23
  puts str.to_s
21
24
  end
22
25
 
23
- def oops(str) #:nodoc
26
+ def oops(str) #:nodoc:
27
+ @@oops_messages << str
24
28
  warn("Oops: #{str}")
25
29
  end
26
30
 
27
- def error(str) #:nodoc
31
+ def error(str) #:nodoc:
32
+ @@error_messages << str
28
33
  warn("Error: #{str}")
29
34
  end
30
35
 
@@ -43,7 +48,7 @@ module Pidgin2Adium
43
48
  elsif(ext == "txt")
44
49
  parser = TextLogParser.new(logfile_path, my_aliases)
45
50
  else
46
- error("logfile (#{logfile_path}) is not a text or html file. Doing nothing.")
51
+ error("Doing nothing, logfile is not a text or html file. Path: #{logfile_path}.")
47
52
  return false
48
53
  end
49
54
 
@@ -72,14 +77,19 @@ module Pidgin2Adium
72
77
 
73
78
  unless File.directory?(output_dir)
74
79
  puts "Output log directory (#{output_dir}) does not exist or is not a directory."
75
- raise Errno::ENOENT
80
+ begin
81
+ FileUtils.mkdir_p(output_dir)
82
+ rescue Errno::EACCES
83
+ puts "Permission denied, could not create output directory (#{output_dir})"
84
+ return false
85
+ end
76
86
  end
77
87
 
78
88
  logfile_obj = parse(logfile_path, my_aliases)
79
89
  return false if logfile_obj == false
80
90
  dest_file_path = logfile_obj.write_out(overwrite, output_dir)
81
91
  if dest_file_path == false
82
- error("Converting #{logfile_path} failed.")
92
+ error("Successfully parsed file, but failed to write it out. Path: #{logfile_path}.")
83
93
  return false
84
94
  elsif dest_file_path == FILE_EXISTS
85
95
  log_msg("File already exists.")
@@ -109,7 +119,7 @@ module Pidgin2Adium
109
119
  if File.writable?(f)
110
120
  File.delete(f)
111
121
  else
112
- error("#{f} exists but is not writable. Please delete it yourself.")
122
+ error("File exists but is not writable. Please delete it yourself: #{f}")
113
123
  end
114
124
  end
115
125
  end
@@ -53,6 +53,10 @@ module Pidgin2Adium
53
53
  delete_search_indexes()
54
54
 
55
55
  log_msg "Finished converting! Converted #{total_successes} files of #{total_files} total."
56
+ puts "Minor error messages:"
57
+ puts @@oops_messages.join("\n")
58
+ puts "Major error messages:"
59
+ puts @@error_messages.join("\n")
56
60
  end
57
61
 
58
62
  ###########
@@ -1,16 +1,17 @@
1
- # ADD DOCUMENTATION
2
-
3
1
  require 'fileutils'
4
2
 
5
3
  module Pidgin2Adium
6
4
  # A holding object for the result of LogParser.parse. It makes the
7
- # instance variable @chat_lines available, which is an array of objects
8
- # which each have at least the instance variables _sender_, _time_, and
9
- # _buddy_alias_ available. Some objects in @chat_lines have more variables
10
- # available, specifically:
11
- # * XMLMessage, AutoReplyMessage, and Event:: _body_
12
- # * Event:: _event_type_
13
- # * StatusMessage:: _status_
5
+ # instance variable @chat_lines available, which is an array of Message
6
+ # subclass instances (XMLMessage, Event, etc.)
7
+ # Here is a list of the instance variables for each class in @chat_lines:
8
+ #
9
+ # <b>All of these variables are read/write.</b>
10
+ # All:: sender, time, buddy_alias
11
+ # XMLMessage:: body
12
+ # AutoReplyMessage:: body
13
+ # Event:: body, event_type
14
+ # StatusMessage:: status
14
15
  class LogFile
15
16
  include Pidgin2Adium
16
17
  def initialize(chat_lines, service, user_SN, partner_SN, adium_chat_time_start)
@@ -5,6 +5,7 @@
5
5
  # Please use Pidgin2Adium.parse or Pidgin2Adium.parse_and_generate instead of
6
6
  # using these classes directly.
7
7
  require 'parsedate'
8
+ require 'time' # for Time.zone_offset
8
9
 
9
10
  require 'pidgin2adium/balance_tags'
10
11
  require 'pidgin2adium/log_file'
@@ -64,7 +65,7 @@ module Pidgin2Adium
64
65
  @adium_chat_time_start = pre_parse()
65
66
  rescue InvalidFirstLineError
66
67
  @first_line_is_valid = false
67
- error("Parsing of #{@src_path} failed (could not find valid first line).")
68
+ error("Failed to parse, invalid first line: #{@src_path}")
68
69
  return # stop processing
69
70
  end
70
71
 
@@ -143,19 +144,26 @@ module Pidgin2Adium
143
144
  @file_content = cleanup(@file_content).split("\n")
144
145
 
145
146
  @file_content.map! do |line|
147
+ # "next" returns nil which is removed by compact
146
148
  next if line =~ /^\s+$/
147
149
  if line =~ @line_regex
148
150
  create_msg($~.captures)
149
151
  elsif line =~ @line_regex_status
150
- create_status_or_event_msg($~.captures)
152
+ msg = create_status_or_event_msg($~.captures)
153
+ # Error occurred while parsing
154
+ return false if msg == false
151
155
  else
152
156
  error "Could not parse line:"
153
- p line # returns nil which is then removed by compact
154
- exit 1 # if $DEBUG FIXME
157
+ p line
158
+ return false
155
159
  end
156
- end.compact!
160
+ end
161
+ @file_content.compact!
157
162
  return LogFile.new(@file_content, @service, @user_SN, @partner_SN, @adium_chat_time_start)
158
163
  end
164
+ # Prevent parse from being called directly from BasicParser, since
165
+ # it uses subclassing magic.
166
+ protected :parse
159
167
 
160
168
  #################
161
169
  private
@@ -167,7 +175,7 @@ module Pidgin2Adium
167
175
  # 1) the log has an empty start date column in the viewer
168
176
  # 2) The timestamps are all the same for the whole log
169
177
  tz_match = /([-\+]\d+)[A-Z]{3}\.(?:txt|htm|html)/.match(@src_path)
170
- if tz_match[1]
178
+ if tz_match and tz_match[1]
171
179
  tz_offset = tz_match[1]
172
180
  else
173
181
  zone = Time.local(Time.new.year).zone
@@ -296,6 +304,8 @@ module Pidgin2Adium
296
304
  #--
297
305
  # create_status_or_event_msg takes an array of +MatchData+ captures from
298
306
  # matching against @line_regex_status and returns an Event or Status.
307
+ # Returns nil if it's a message that should be ignored, or false if an
308
+ # error occurred.
299
309
  #++
300
310
  def create_status_or_event_msg(matches)
301
311
  # ["22:58:00", "BuddyName logged in."]
@@ -322,10 +332,8 @@ module Pidgin2Adium
322
332
  if @event_map.detect{|regex,event_type| str =~ regex}
323
333
  regex, event_type = $1, $2
324
334
  else
325
- error("Could not match string to status or event!")
326
- error(sprintf("matches: %p", matches))
327
- error(sprintf("str: %p", str))
328
- exit 1
335
+ error(sprintf("Error parsing status or event message, no status or event found: %p", str))
336
+ return false
329
337
  end
330
338
  end
331
339
  if regex and event_type
@@ -367,6 +375,8 @@ module Pidgin2Adium
367
375
  @line_regex_status = /#{@timestamp_rx} ([^:]+)/o
368
376
  end
369
377
 
378
+ public :parse
379
+
370
380
  #################
371
381
  private
372
382
  #################
@@ -407,6 +417,8 @@ module Pidgin2Adium
407
417
  # 1: status message
408
418
  @line_regex_status = /#{@timestamp_rx} ?<b> (.+)<\/b><br ?\/>/o
409
419
  end
420
+
421
+ public :parse
410
422
 
411
423
  #################
412
424
  private
@@ -520,8 +532,12 @@ module Pidgin2Adium
520
532
  # Subclasses: XMLMessage, AutoReplyMessage, StatusMessage, Event.
521
533
  class Message
522
534
  def initialize(sender, time, buddy_alias)
535
+ # The sender's screen name
523
536
  @sender = sender
537
+ # The time the message was sent, in Adium format (e.g.
538
+ # "2008-10-05T22:26:20-0800")
524
539
  @time = time
540
+ # The receiver's alias (NOT screen name)
525
541
  @buddy_alias = buddy_alias
526
542
  end
527
543
  attr_accessor :sender, :time, :buddy_alias
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pidgin2adium
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gabe B-W
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-06 00:00:00 -05:00
12
+ date: 2009-12-18 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -20,7 +20,7 @@ dependencies:
20
20
  requirements:
21
21
  - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: 2.3.3
23
+ version: 2.4.0
24
24
  version:
25
25
  description: |-
26
26
  Pidgin2Adium is a fast, easy way to convert Pidgin (formerly gaim) logs to the