Blux 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig CHANGED
Binary file
@@ -2,18 +2,18 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{Blux}
5
- s.version = "0.0.4"
5
+ s.version = "0.0.5"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Louis Salin"]
9
9
  s.cert_chain = ["/home/louis/Documents/gem_keys/gem-public_cert.pem"]
10
- s.date = %q{2010-10-23}
10
+ s.date = %q{2010-11-06}
11
11
  s.default_executable = %q{blux}
12
12
  s.description = %q{An offline blog manager}
13
13
  s.email = %q{louis.phil@gmail.com}
14
14
  s.executables = ["blux"]
15
- s.extra_rdoc_files = ["COPYING", "README.markdown", "bin/blux", "lib/textile_to_html.rb", "lib/wp_publish.rb", "lib/blog_manager.rb", "lib/blux_config_reader.rb", "lib/blux_option_parser.rb", "lib/draft_manager.rb", "lib/indexer.rb"]
16
- s.files = ["COPYING", "Manifest", "README.markdown", "Rakefile", "bin/blux", "lib/textile_to_html.rb", "lib/wp_publish.rb", "lib/blog_manager.rb", "lib/blux_config_reader.rb", "lib/blux_option_parser.rb", "lib/draft_manager.rb", "lib/indexer.rb", "spec/blog_manager_spec.rb", "spec/blux_config_reader_spec.rb", "spec/draft_manager_spec.rb", "Blux.gemspec"]
15
+ s.extra_rdoc_files = ["COPYING", "README.markdown", "bin/blux", "lib/textile_to_html.rb", "lib/blog_manager.rb", "lib/blux_config_reader.rb", "lib/blux_option_parser.rb", "lib/draft_manager.rb", "lib/indexer.rb", "lib/publishing/wp_publish.rb", "lib/publishing/wp_options.rb"]
16
+ s.files = ["COPYING", "Manifest", "README.markdown", "Rakefile", "bin/blux", "lib/textile_to_html.rb", "lib/blog_manager.rb", "lib/blux_config_reader.rb", "lib/blux_option_parser.rb", "lib/draft_manager.rb", "lib/indexer.rb", "lib/publishing/wp_publish.rb", "lib/publishing/wp_options.rb", "spec/blog_manager_spec.rb", "spec/blux_config_reader_spec.rb", "spec/draft_manager_spec.rb", "Blux.gemspec"]
17
17
  s.homepage = %q{http://github.com/louissalin/blux}
18
18
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Blux", "--main", "README.markdown"]
19
19
  s.require_paths = ["lib"]
data/Manifest CHANGED
@@ -4,12 +4,13 @@ README.markdown
4
4
  Rakefile
5
5
  bin/blux
6
6
  lib/textile_to_html.rb
7
- lib/wp_publish.rb
8
7
  lib/blog_manager.rb
9
8
  lib/blux_config_reader.rb
10
9
  lib/blux_option_parser.rb
11
10
  lib/draft_manager.rb
12
11
  lib/indexer.rb
12
+ lib/publishing/wp_publish.rb
13
+ lib/publishing/wp_options.rb
13
14
  spec/blog_manager_spec.rb
14
15
  spec/blux_config_reader_spec.rb
15
16
  spec/draft_manager_spec.rb
@@ -74,5 +74,17 @@ use this command to edit a draft
74
74
 
75
75
  when using the --verbose option, Blux will output a lot of extra information to the screen as it works
76
76
 
77
+ > $ blux -p (--publish) [--latest, --title <a title>, --file <filename>]
78
+
79
+ this command will publish your draft. It will publish either the latest draft, or a draft with a specific title, or a draft with a specific filename, as specified in the command.
80
+
81
+ > $ blux -u (--update) [--latest, --title <a title>, --file <filename>]
82
+
83
+ this command will update an exisiting published blog post. It will update either the latest draft, or a draft with a specific title, or a draft with a specific filename, as specified in the command.
84
+
85
+ > $ blux -d (--delete) [--latest, --title <a title>, --file <filename>]
86
+
87
+ this command will delete a published blog post and mark the associated draft as deleted. The draft will still exist, but Blux will not take it into consideration anymore.
88
+
77
89
  ## community
78
90
  feel free to post your comments or questions to the Blux Google group here: blux_manager@googlegroups.com
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'rubygems'
2
2
  require 'rake'
3
3
  require 'echoe'
4
4
 
5
- Echoe.new('Blux', '0.0.4') do |p|
5
+ Echoe.new('Blux', '0.0.5') do |p|
6
6
  p.description = 'An offline blog manager'
7
7
  p.url = 'http://github.com/louissalin/blux'
8
8
  p.author = 'Louis Salin'
data/bin/blux CHANGED
@@ -57,6 +57,43 @@ def check_filename(options, blog_manager)
57
57
  end
58
58
  end
59
59
 
60
+ def build_post_info(options)
61
+ switch = nil
62
+ entry = Array.new
63
+ response = Array.new
64
+ url = ""
65
+
66
+ ARGF.each do |line|
67
+ if line == "--entry--\n"
68
+ switch = :entry
69
+ next
70
+ elsif line == "--response--\n"
71
+ switch = :response
72
+ next
73
+ elsif line == "--url--\n"
74
+ switch = :url
75
+ next
76
+ end
77
+
78
+ case (switch)
79
+ when :entry
80
+ entry << line
81
+ when :response
82
+ response << line
83
+ when :url
84
+ url = line
85
+ end
86
+ end
87
+
88
+ entry_text = entry.join
89
+ response_text = response.join
90
+
91
+ msg = "Error communicating with the publishing script. Exiting..."
92
+ raise RuntimeError, msg if response.length == 0
93
+
94
+ return entry, response, url
95
+ end
96
+
60
97
  begin
61
98
  validate_command(BluxOptionParser.parse(ARGV)) do |options|
62
99
  draft_manager = DraftManager.new
@@ -84,6 +121,10 @@ begin
84
121
  mgr.draft_manager.set_attribute(filename, attribute, value)
85
122
  end
86
123
  end
124
+ when :unset
125
+ check_filename(options, mgr) do |filename|
126
+ mgr.draft_manager.delete_attribute(filename, options.attribute)
127
+ end
87
128
  when :out
88
129
  check_filename(options, mgr) do |filename|
89
130
  STDOUT.puts(mgr.draft_manager.output filename)
@@ -103,47 +144,42 @@ begin
103
144
  puts "updating" if options.verbose
104
145
  mgr.update filename
105
146
  end
106
- when :set_edit_url
147
+ when :delete
107
148
  check_filename(options, mgr) do |filename|
108
- switch = nil
109
- entry = Array.new
110
- response = Array.new
111
- url = ""
112
-
113
- ARGF.each do |line|
114
- if line == "--entry--\n"
115
- switch = :entry
116
- next
117
- elsif line == "--response--\n"
118
- switch = :response
119
- next
120
- elsif line == "--url--\n"
121
- switch = :url
122
- next
123
- end
124
-
125
- case (switch)
126
- when :entry
127
- entry << line
128
- when :response
129
- response << line
130
- when :url
131
- url = line
132
- end
149
+ puts "deleting" if options.verbose
150
+ mgr.delete filename
151
+ end
152
+ when :show_post_info
153
+ entry, response, url = build_post_info(options)
154
+ if options.verbose
155
+ puts "entry:"
156
+ puts entry
157
+
158
+ puts "response:"
159
+ puts response
160
+
161
+ puts "edit url:"
162
+ puts url
133
163
  end
164
+ when :set_edit_url
165
+ check_filename(options, mgr) do |filename|
166
+ entry, response, url = build_post_info(options)
167
+
168
+ if options.verbose
169
+ puts "entry:"
170
+ puts entry
134
171
 
135
- entry_text = entry.join
136
- puts "entry:" if options.verbose
137
- puts entry_text if options.verbose
172
+ puts "response:"
173
+ puts response
174
+
175
+ puts "edit url:"
176
+ puts url
177
+ end
138
178
 
139
- response_text = response.join
140
- puts "response:" if options.verbose
141
- puts response_text if options.verbose
142
-
143
- mgr.set_attribute(filename, 'edit_url', url.strip)
179
+ mgr.draft_manager.set_attribute(filename, 'edit_url', url.strip)
144
180
  end
145
181
  when :version
146
- puts "0.0.4"
182
+ puts "0.0.5"
147
183
  end
148
184
  end
149
185
  rescue
@@ -19,13 +19,12 @@
19
19
  require "#{File.dirname(__FILE__)}/draft_manager"
20
20
  require "#{File.dirname(__FILE__)}/blux_config_reader"
21
21
  require "#{File.dirname(__FILE__)}/indexer"
22
+ require 'timeout'
22
23
 
23
24
  class BlogManager
24
25
  attr_accessor :home, :blux_dir, :blux_rc, :blux_tmp_dir, :draft_dir
25
26
  attr_accessor :draft_manager
26
27
  attr_accessor :config
27
- attr_accessor :index
28
- attr_accessor :index_file
29
28
 
30
29
  include BluxIndexer
31
30
 
@@ -38,7 +37,6 @@ class BlogManager
38
37
  @draft_dir = "#{@blux_dir}/draft"
39
38
  @blux_tmp_dir = "#{@blux_dir}/tmp"
40
39
  @blux_rc = "#{@home}/.bluxrc"
41
- @index_file = "#{@blux_dir}/.published"
42
40
 
43
41
  @draft_manager = draft_manager
44
42
  end
@@ -55,10 +53,6 @@ class BlogManager
55
53
  unless Dir.exists?(@blux_tmp_dir)
56
54
  Dir.mkdir(@blux_tmp_dir)
57
55
  end
58
-
59
- load_index
60
- puts "blog index:\n" if @verbose
61
- print_index if @verbose
62
56
  end
63
57
 
64
58
  def load_config
@@ -69,48 +63,71 @@ class BlogManager
69
63
  end
70
64
 
71
65
  def publish(filename)
66
+ raise "this draft has already been published" if published?(filename)
67
+
72
68
  title = @draft_manager.get_attribute(filename, "title") || 'no title'
69
+ categories = @draft_manager.get_attribute(filename, "categories")
73
70
 
74
71
  convert_cmd = "blux --convert -f #{filename}"
75
- publish_cmd = "ruby #{File.dirname(__FILE__)}/wp_publish.rb -t \"#{title}\" --config #{@blux_rc}"
72
+ categories_cmd = categories ? "-c \"#{categories}\"" : ""
73
+ publish_cmd = "ruby #{File.dirname(__FILE__)}/publishing/wp_publish.rb -t \"#{title}\" --config #{@blux_rc} #{categories_cmd}"
76
74
  set_url_cmd = "blux --set_edit_url -f #{filename}"
77
75
 
78
76
  cmd = "#{convert_cmd} | #{publish_cmd} | #{set_url_cmd}"
79
77
  cmd = cmd + " --verbose" if @verbose
80
78
 
81
- if system cmd
82
- load_index
83
- set_attribute(filename, :published_time, Time.now)
84
- else
85
- msg = "failed to publish...\n"
86
- msg = msg + ' use the --verbose option for more information' if !@verbose
87
-
88
- raise SystemExit, msg
79
+ send_publish_command(cmd, filename, "failed to publish...") do
80
+ @draft_manager.set_attribute(filename, "published_time", Time.now)
89
81
  end
90
-
91
- puts "blog index:\n" if @verbose
92
- print_index if @verbose
93
82
  end
94
83
 
95
84
  def update(filename)
96
85
  title = @draft_manager.get_attribute(filename, "title") || 'no title'
97
- url = get_attribute(filename, "edit_url")
86
+ categories = @draft_manager.get_attribute(filename, "categories")
87
+ url = @draft_manager.get_attribute(filename, "edit_url")
88
+
89
+ raise "couldn't find an edit url for the draft: #{filename}" unless url
90
+
91
+ publish_cmd = "ruby #{File.dirname(__FILE__)}/publishing/wp_publish.rb"
92
+ categories_cmd = categories ? "-c \"#{categories}\"" : ""
93
+ post_cmd = "blux --post-cmd"
94
+ cmd = "blux --convert -f #{filename} | #{publish_cmd} -t \"#{title}\" --update #{url} --config #{@blux_rc} #{categories_cmd} | #{post_cmd}"
95
+ cmd = cmd + " --verbose" if @verbose
98
96
 
97
+ send_publish_command(cmd, filename, "failed to update...") do
98
+ @draft_manager.set_attribute(filename, "published_time", Time.now)
99
+ end
100
+ end
101
+
102
+ def delete(filename)
103
+ url = @draft_manager.get_attribute(filename, "edit_url")
99
104
  raise "couldn't find an edit url for the draft: #{filename}" unless url
100
105
 
101
- publish_cmd = "ruby #{File.dirname(__FILE__)}/wp_publish.rb"
102
- cmd = "blux --convert -f #{filename} | #{publish_cmd} -t \"#{title}\" --update #{url} --config #{@blux_rc}"
106
+ publish_cmd = "ruby #{File.dirname(__FILE__)}/publishing/wp_publish.rb"
107
+ post_cmd = "blux --post-cmd"
108
+ cmd = "#{publish_cmd} --delete #{url} --config #{@blux_rc} | #{post_cmd}"
109
+ cmd = cmd + " --verbose" if @verbose
103
110
 
104
- if system cmd
105
- set_attribute(filename, :published_time, Time.now)
111
+ send_publish_command(cmd, filename, "failed to delete...") do
112
+ @draft_manager.delete_draft(filename)
113
+ end
114
+ end
115
+
116
+ private
117
+
118
+ def published?(filename)
119
+ @draft_manager.get_attribute(filename, "published_time") != nil
120
+ end
121
+
122
+ def send_publish_command(cmd, filename, error_msg)
123
+ status = Timeout::timeout(10) { system cmd }
124
+ if status
125
+ yield
106
126
  else
107
- msg = "failed to update...\n"
127
+ msg = "#{error_msg}\n"
108
128
  msg = msg + ' use the --verbose option for more information' if !@verbose
109
129
 
110
130
  raise SystemExit, msg
111
131
  end
112
-
113
- puts "blog index:\n" if @verbose
114
- print_index if @verbose
115
132
  end
116
133
  end
@@ -44,6 +44,11 @@ class BluxOptionParser
44
44
  opts.on("-s", "--set", "set an attribute on a draft") do
45
45
  options.command = :set
46
46
  end
47
+
48
+ opts.on("--unset ATTR", "delete an attribute on a draft") do |attr|
49
+ options.command = :unset
50
+ options.attribute = attr
51
+ end
47
52
 
48
53
  opts.on("-c", "--convert", "convert a draft to html") do
49
54
  options.command = :convert
@@ -61,6 +66,10 @@ class BluxOptionParser
61
66
  options.command = :update
62
67
  end
63
68
 
69
+ opts.on("-d", "--delete", "mark a draft as deleted") do
70
+ options.command = :delete
71
+ end
72
+
64
73
  opts.on("--latest", "work on the latest draft") do
65
74
  options.use_latest = true
66
75
  end
@@ -78,6 +87,10 @@ class BluxOptionParser
78
87
  options.command = :set_edit_url
79
88
  end
80
89
 
90
+ opts.on("--post-cmd", "shows post publishing info: request & response") do
91
+ options.command = :show_post_info
92
+ end
93
+
81
94
  opts.on("--with-preview", "show a preview of each draft while listing") do
82
95
  options.list_preview = true
83
96
  end
@@ -25,7 +25,6 @@ require "#{File.dirname(__FILE__)}/indexer"
25
25
  class DraftManager
26
26
  attr_reader :launch_editor_cmd
27
27
  attr_reader :temp_dir, :draft_dir
28
- attr_reader :index
29
28
  attr_reader :index_file
30
29
 
31
30
  include BluxIndexer
@@ -42,7 +41,6 @@ class DraftManager
42
41
  value = system "touch #{@index_file}" unless File.exists? @index_file
43
42
 
44
43
  if value
45
- load_index
46
44
  print_index if @verbose
47
45
  else
48
46
  msg = 'could not create the draft index file'
@@ -69,8 +67,7 @@ class DraftManager
69
67
  def move_temp_file(tempfile)
70
68
  if system "mv #{tempfile} #{@draft_dir}"
71
69
  index_key = File.basename(tempfile)
72
- @index[index_key] = {:creation_time => Time.now.to_s}
73
- save_index
70
+ set_attribute(index_key, "creation_time", Time.now.to_s)
74
71
  else
75
72
  msg = "failed to move the temp file to the draft folder"
76
73
  raise RuntimeError, msg
@@ -90,12 +87,24 @@ class DraftManager
90
87
  print_index if @verbose
91
88
  end
92
89
 
90
+ def delete_draft(filename)
91
+ set_attribute(filename, "deleted", Time.now.to_s)
92
+ print_index if @verbose
93
+ end
94
+
93
95
  def list
94
- Dir.entries(@draft_dir).reject {|i| i[0] == '.'}
96
+ block = Enumerator.new do |g|
97
+ index = load_index
98
+ index.keys.each do |k|
99
+ g << k if index[k]["deleted"] == nil
100
+ end
101
+ end
102
+
103
+ block
95
104
  end
96
105
 
97
106
  def show_info(filename)
98
- check_index(filename) do |index|
107
+ check_index(filename) do |full_index, index|
99
108
  index.to_json
100
109
  end
101
110
  end
@@ -114,6 +123,7 @@ class DraftManager
114
123
  end
115
124
 
116
125
  def output(filename)
126
+ ensure_not_deleted filename
117
127
  check_filename(filename) do |draft_filename|
118
128
  File.open(draft_filename, 'r') do |f|
119
129
  if f.eof?
@@ -132,7 +142,10 @@ class DraftManager
132
142
 
133
143
  def get_latest_created_draft
134
144
  check_count do
135
- @index.sort do |a,b|
145
+ index = load_index
146
+ index.reject do |key, val|
147
+ val["deleted"] != nil
148
+ end.sort do |a,b|
136
149
  Time.parse(a[1]["creation_time"]) <=> Time.parse(b[1]["creation_time"])
137
150
  end[-1][0]
138
151
  end
@@ -140,8 +153,9 @@ class DraftManager
140
153
 
141
154
  def get_draft_by_title(title)
142
155
  check_count do
143
- @index.keys.each do |key|
144
- draft_title = @index[key]["title"]
156
+ index = load_index
157
+ index.keys.each do |key|
158
+ draft_title = index[key]["title"]
145
159
  return key if draft_title == title
146
160
  end
147
161
  end
@@ -19,11 +19,12 @@
19
19
  module BluxIndexer
20
20
  def check_index(filename)
21
21
  check_filename(filename) do
22
- @index[filename] ||= {}
23
- yield @index[filename]
22
+ full_index = load_index
23
+ full_index[filename] ||= {}
24
+ yield full_index, full_index[filename]
24
25
  end
25
26
  end
26
-
27
+
27
28
  def check_filename(filename)
28
29
  draft_filename = "#{self.draft_dir}/#{filename}"
29
30
 
@@ -35,48 +36,80 @@ module BluxIndexer
35
36
  end
36
37
  end
37
38
 
38
- def check_title(filename, attr_key, attr_val)
39
- return true unless attr_key.to_s == "title"
40
-
41
- unique_title = true
42
- @index.keys.reject{|k| k == filename}.each do |key|
43
- unique_title = false if (@index[key][attr_key.to_s] == attr_val)
44
- end
45
-
46
- STDERR << "warning: title '#{attr_val}' is not unique\n" unless unique_title
47
- true
48
- end
49
-
50
39
  def set_attribute(filename, key, val)
51
- check_index(filename) do |index|
52
- if check_title(filename, key, val)
40
+ check_index(filename) do |full_index, index|
41
+ case key
42
+ when "title"
43
+ unique_title = true
44
+ full_index.keys.reject{|k| k == filename}.each do |other_key|
45
+ unique_title = false if (full_index[other_key.to_s][key] == val)
46
+ end
47
+
48
+ STDERR << "warning: title '#{val}' is not unique\n" unless unique_title
49
+
50
+ index[key.to_s] = val
51
+ when "categories"
52
+ values = Array.new
53
+ values << index[key.to_s] unless index[key.to_s] == nil
54
+ values << val
55
+
56
+ index[key.to_s] = values.join(',')
57
+ else
53
58
  index[key.to_s] = val
54
- save_index
55
59
  end
60
+
61
+ save_index(full_index)
56
62
  end
57
63
  end
58
64
 
59
65
  def delete_attribute(filename, attr_name)
60
- check_index(filename) do |index|
61
- index.delete(attr_name.to_s)
62
- save_index
66
+ check_index(filename) do |full_index, index|
67
+ case attr_name
68
+ when "categories"
69
+ if block_given?
70
+ categories = yield
71
+ categories_to_remove = categories.split(',')
72
+
73
+ values = index[attr_name.to_s].split(',')
74
+
75
+ new_values = values.reject{|i| categories_to_remove.include?(i)}.join(',')
76
+
77
+ if new_values.length > 0
78
+ index[attr_name.to_s] = new_values
79
+ else
80
+ index.delete(attr_name.to_s)
81
+ end
82
+ else
83
+ index.delete(attr_name.to_s)
84
+ end
85
+ else
86
+ index.delete(attr_name.to_s)
87
+ end
88
+
89
+ save_index(full_index)
63
90
  end
64
91
  end
65
92
 
66
93
  def get_attribute(filename, attribute)
67
- check_index(filename) do |index|
94
+ check_index(filename) do |full_index, index|
68
95
  index[attribute]
69
96
  end
70
97
  end
71
98
 
72
99
  def check_count
73
- if @index.keys.length > 0
100
+ index = load_index
101
+ if index.keys.length > 0
74
102
  yield
75
103
  else
76
104
  msg = "there is currently no saved index"
77
105
  raise RuntimeError, msg
78
106
  end
79
107
  end
108
+
109
+ def delete_index(filename)
110
+ index = load_index
111
+ save_index if index.delete filename
112
+ end
80
113
 
81
114
  def load_index
82
115
  system "touch #{@index_file}" unless File.exists? @index_file
@@ -86,16 +119,24 @@ module BluxIndexer
86
119
  f.each_line {|l| str += l}
87
120
  end
88
121
 
89
- @index = str.length > 0 ? JSON.parse(str) : {}
122
+ return str.length > 0 ? JSON.parse(str) : {}
90
123
  end
91
124
 
92
- def save_index
125
+ def save_index(index)
93
126
  File.open(@index_file, 'w') do |f|
94
- f.write(@index.to_json) if @index
127
+ f.write(index.to_json) if index
95
128
  end
96
129
  end
97
130
 
98
131
  def print_index
99
- puts @index.to_json + "\n" if @verbose
132
+ index = load_index
133
+ puts index.to_json + "\n" if @verbose
134
+ end
135
+
136
+ def ensure_not_deleted(filename)
137
+ check_index(filename) do |full_index, index|
138
+ msg = "draft filename #{filename} has been deleted"
139
+ raise RuntimeError, msg if index["deleted"]
140
+ end
100
141
  end
101
142
  end