pidgin2adium 2.0.1 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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