Blux 0.0.3

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.
@@ -0,0 +1,83 @@
1
+ #
2
+ # Copyright 2010 Louis-Philippe Salin de l'Etoile, aka Louis Salin
3
+ # email: louis.phil@gmail.com
4
+ #
5
+ # This file is part of Blux.
6
+ #
7
+ # Blux is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # Blux is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU General Public License
18
+ # along with Blux. If not, see <http://www.gnu.org/licenses/>.
19
+ class BluxConfigurationReader
20
+ attr_reader :launch_editor_cmd, :html_converter_cmd
21
+ attr_reader :blog, :author_name, :user_name, :password
22
+
23
+ def load_config(blux_rc, verbose = false)
24
+ unless File.exists? blux_rc
25
+ puts "creating #{blux_rc}\n" if verbose
26
+ system "touch #{blux_rc}"
27
+ end
28
+
29
+ line = `grep editor: #{blux_rc}`
30
+ match = line =~ /^editor:\s(.+)$/
31
+ @launch_editor_cmd = $1
32
+
33
+ line = `grep html_converter: #{blux_rc}`
34
+ match = line =~ /^html_converter:\s(.+)$/
35
+ @html_converter_cmd = $1
36
+
37
+ line = `grep blog: #{blux_rc}`
38
+ match = line =~ /^blog:\s(.+)$/
39
+ @blog = $1
40
+
41
+ line = `grep author_name: #{blux_rc}`
42
+ match = line =~ /^author_name:\s(.+)$/
43
+ @author_name = $1
44
+
45
+ line = `grep user_name: #{blux_rc}`
46
+ match = line =~ /^user_name:\s(.+)$/
47
+ @user_name = $1
48
+
49
+ line = `grep password: #{blux_rc}`
50
+ match = line =~ /^password:\s(.+)$/
51
+ @password = $1
52
+
53
+ puts "editor command: #{@launch_editor_cmd}\n" if verbose
54
+ validate
55
+ end
56
+
57
+ private
58
+ def validate
59
+ if (@launch_editor_cmd == nil)
60
+ STDERR.puts "please specify an editor in .bluxrc: editor: [your editor of choice]\n"
61
+ end
62
+
63
+ if (@html_converter_cmd == nil)
64
+ STDERR.puts "please specify an html converter in .bluxrc: html_converter: [your converter command of choice]\n"
65
+ end
66
+
67
+ if (@blog == nil)
68
+ STDERR.puts "please specify your wordpress blog name in .bluxrc: blog: [your blog]\n"
69
+ end
70
+
71
+ if (@author_name == nil)
72
+ STDERR.puts "please specify an author name in .bluxrc: author_name: [your name]\n"
73
+ end
74
+
75
+ if (@user_name == nil)
76
+ STDERR.puts "please specify your wordpress user name in .bluxrc: user_name: [your user name]\n"
77
+ end
78
+
79
+ if (@password == nil)
80
+ STDERR.puts "please specify your wordpress password in .bluxrc: password: [your password]\n"
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,104 @@
1
+ #
2
+ # Copyright 2010 Louis-Philippe Salin de l'Etoile, aka Louis Salin
3
+ # email: louis.phil@gmail.com
4
+ #
5
+ # This file is part of Blux.
6
+ #
7
+ # Blux is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # Blux is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU General Public License
18
+ # along with Blux. If not, see <http://www.gnu.org/licenses/>.
19
+ require 'optparse'
20
+ require 'ostruct'
21
+
22
+ class BluxOptionParser
23
+ def self.parse(args)
24
+ options = OpenStruct.new
25
+ options.verbose = false
26
+ options.list_preview = false
27
+ options.list_details = false
28
+
29
+ opts = OptionParser.new do |opts|
30
+ opts.banner = "Usage: blux <command> [options] [attributes]"
31
+
32
+ opts.on("-n", "--new", "create a new draft") do
33
+ options.command = :new
34
+ end
35
+
36
+ opts.on("-e", "--edit", "edit a draft") do
37
+ options.command = :edit
38
+ end
39
+
40
+ opts.on("-l", "--list", "list drafts") do
41
+ options.command = :list
42
+ end
43
+
44
+ opts.on("-s", "--set", "set an attribute on a draft") do
45
+ options.command = :set
46
+ end
47
+
48
+ opts.on("-c", "--convert", "convert a draft to html") do
49
+ options.command = :convert
50
+ end
51
+
52
+ opts.on("-o", "--out", "dump the content of a draft to stdout") do
53
+ options.command = :out
54
+ end
55
+
56
+ opts.on("-p", "--publish", "publish a draft") do
57
+ options.command = :publish
58
+ end
59
+
60
+ opts.on("-u", "--update", "update a draft") do
61
+ options.command = :update
62
+ end
63
+
64
+ opts.on("--latest", "work on the latest draft") do
65
+ options.use_latest = true
66
+ end
67
+
68
+ opts.on("--title TITLE", "work on a draft with title") do |title|
69
+ options.use_title = true
70
+ options.title = title
71
+ end
72
+
73
+ opts.on("-f", "--file FILENAME", "work on a specific draft file") do |filename|
74
+ options.filename = filename
75
+ end
76
+
77
+ opts.on("--set_edit_url", "sets the edit url, given after publishing") do
78
+ options.command = :set_edit_url
79
+ end
80
+
81
+ opts.on("--with-preview", "show a preview of each draft while listing") do
82
+ options.list_preview = true
83
+ end
84
+
85
+ opts.on("--details", "show all attributes when listing") do
86
+ options.list_details = true
87
+ end
88
+
89
+ opts.on("--verbose", "verbose mode") do
90
+ options.verbose = true
91
+ end
92
+
93
+ opts.on_tail("-h", "--help", "show this message") do
94
+ puts opts
95
+ exit
96
+ end
97
+ end
98
+
99
+ opts.parse!(args)
100
+
101
+ options.attributes = args
102
+ options
103
+ end
104
+ end
@@ -0,0 +1,131 @@
1
+ #
2
+ # Copyright 2010 Louis-Philippe Salin de l'Etoile, aka Louis Salin
3
+ # email: louis.phil@gmail.com
4
+ #
5
+ # This file is part of Blux.
6
+ #
7
+ # Blux is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # Blux is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU General Public License
18
+ # along with Blux. If not, see <http://www.gnu.org/licenses/>.
19
+ require 'tempfile'
20
+ require 'json'
21
+ require 'time'
22
+
23
+ require "#{File.dirname(__FILE__)}/indexer"
24
+
25
+ class DraftManager
26
+ attr_reader :launch_editor_cmd
27
+ attr_reader :temp_dir, :draft_dir
28
+ attr_reader :index
29
+
30
+ include BluxIndexer
31
+
32
+ def setup(editor_cmd, temp_dir, draft_dir, options = {})
33
+ @verbose = options[:verbose] ||= false
34
+
35
+ @launch_editor_cmd = editor_cmd
36
+ @temp_dir = temp_dir
37
+ @draft_dir = draft_dir
38
+ @index_file = "#{@draft_dir}/.draft_index"
39
+
40
+ system "touch #{@index_file}" unless File.exists? @index_file
41
+
42
+ load_index
43
+ end
44
+
45
+ def create_draft
46
+ temp_file = Tempfile.new('draft', @temp_dir)
47
+ temp_file.close
48
+
49
+ puts "created temp file #{temp_file.path}\nlaunching editor\n" if @verbose
50
+
51
+ system "#{@launch_editor_cmd} #{temp_file.path}"
52
+
53
+ puts "editor closed. File size: #{temp_file.size}\n" if @verbose
54
+ if temp_file.size > 0
55
+ system "mv #{temp_file.path} #{@draft_dir}"
56
+
57
+ index_key = File.basename(temp_file.path)
58
+ puts "adding #{index_key} to draft index\n" if @verbose
59
+ @index[index_key] = {:creation_time => Time.now.to_s}
60
+ save_index
61
+ end
62
+ end
63
+
64
+ def edit_draft(filename)
65
+ puts "editing draft #{filename}" if @verbose
66
+
67
+ check_filename(filename) do |draft_filename|
68
+ puts "editing: #{@launch_editor_cmd} #{draft_filename}" if @verbose
69
+
70
+ system "#{@launch_editor_cmd} #{draft_filename}"
71
+ set_attribute(filename, "edited_time", Time.now.to_s)
72
+ end
73
+ end
74
+
75
+ def list
76
+ Dir.entries(@draft_dir).reject {|i| i[0] == '.'}
77
+ end
78
+
79
+ def show_info(filename)
80
+ check_index(filename) do |index|
81
+ index.to_json
82
+ end
83
+ end
84
+
85
+ def show_preview(filename)
86
+ check_filename(filename) do |draft_filename|
87
+ File.open(draft_filename, 'r') do |f|
88
+ if f.eof?
89
+ ''
90
+ else
91
+ line = f.readline.gsub("\n", '')
92
+ line.length > 76 ? line[0..75] + '...' : line
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ def output(filename)
99
+ check_filename(filename) do |draft_filename|
100
+ File.open(draft_filename, 'r') do |f|
101
+ if f.eof?
102
+ ''
103
+ else
104
+ text = ''
105
+ f.each do |l|
106
+ text += l
107
+ end
108
+
109
+ text
110
+ end
111
+ end
112
+ end
113
+ end
114
+
115
+ def get_latest_created_draft
116
+ check_count do
117
+ @index.sort do |a,b|
118
+ Time.parse(a[1]["creation_time"]) <=> Time.parse(b[1]["creation_time"])
119
+ end[-1][0]
120
+ end
121
+ end
122
+
123
+ def get_draft_by_title(title)
124
+ check_count do
125
+ @index.keys.each do |key|
126
+ draft_title = @index[key]["title"]
127
+ return key if draft_title == title
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,98 @@
1
+ #
2
+ # Copyright 2010 Louis-Philippe Salin de l'Etoile, aka Louis Salin
3
+ # email: louis.phil@gmail.com
4
+ #
5
+ # This file is part of Blux.
6
+ #
7
+ # Blux is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # Blux is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU General Public License
18
+ # along with Blux. If not, see <http://www.gnu.org/licenses/>.
19
+ module BluxIndexer
20
+ def check_index(filename)
21
+ check_filename(filename) do
22
+ @index[filename] ||= {}
23
+ yield @index[filename]
24
+ end
25
+ end
26
+
27
+ def check_filename(filename)
28
+ draft_filename = "#{@draft_dir}/#{filename}"
29
+
30
+ if (File.exists?(draft_filename))
31
+ yield draft_filename
32
+ else
33
+ STDERR.puts "draft filename #{filename} does not exist\n"
34
+ end
35
+ end
36
+
37
+ def check_title(filename, attr_key, attr_val)
38
+ return true unless attr_key.to_s == "title"
39
+
40
+ unique_title = true
41
+ @index.keys.reject{|k| k == filename}.each do |key|
42
+ unique_title = false if (@index[key][attr_key.to_s] == attr_val)
43
+ end
44
+
45
+ STDERR.puts "title '#{attr_val}' is not unique\n" unless unique_title
46
+ unique_title
47
+ end
48
+
49
+ def set_attribute(filename, key, val)
50
+ check_index(filename) do |index|
51
+ if check_title(filename, key, val)
52
+ puts "setting attribute #{key} to #{val} in index #{@index_file}" if @verbose
53
+ index[key.to_s] = val
54
+ save_index
55
+ end
56
+ end
57
+ end
58
+
59
+ def delete_attribute(filename, attr_name)
60
+ check_index(filename) do |index|
61
+ index.delete(attr_name.to_s)
62
+ save_index
63
+ end
64
+ end
65
+
66
+ def get_attribute(filename, attribute)
67
+ check_index(filename) do |index|
68
+ index[attribute]
69
+ end
70
+ end
71
+
72
+ def check_count
73
+ if @index.keys.length > 0
74
+ yield
75
+ else
76
+ STDERR.puts "there is currently no saved index\n"
77
+ end
78
+ end
79
+
80
+ def load_index
81
+ puts "creating #{@index_file}\n" if @verbose
82
+ system "touch #{@index_file}" unless File.exists? @index_file
83
+
84
+ str = ''
85
+ File.open(@index_file, 'r') do |f|
86
+ f.each_line {|l| str += l}
87
+ end
88
+
89
+ @index = str.length > 0 ? JSON.parse(str) : {}
90
+ end
91
+
92
+ def save_index
93
+ puts "saving index: #{@index.to_json}\n" if @verbose
94
+ File.open(@index_file, 'w') do |f|
95
+ f.write(@index.to_json) if @index
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,150 @@
1
+ require 'blog_manager.rb'
2
+
3
+ describe BlogManager do
4
+ before :each do
5
+ ENV['HOME'] = File.dirname(__FILE__)
6
+ @blux_rc = "#{File.dirname(__FILE__)}/.bluxrc"
7
+ @blux = "#{File.dirname(__FILE__)}/.blux"
8
+ @blux_dir = "#{File.dirname(__FILE__)}/.blux"
9
+ @draft_dir = "#{@blux_dir}/draft"
10
+
11
+ Dir.mkdir(@blux) unless Dir.exists?(@blux)
12
+
13
+ def STDERR.puts(str) end
14
+
15
+ @draft_mgr = DraftManager.new
16
+ @draft_mgr.stub!(:editor_cmd).and_return('gedit')
17
+ @draft_mgr.stub!(:setup)
18
+
19
+ @manager = BlogManager.new(@draft_mgr)
20
+ end
21
+
22
+ after :each do
23
+ system "rm -Rf #{@blux}"
24
+ system "rm #{@blux_rc}" if File.exists? @blux_rc
25
+ end
26
+
27
+ context "loading with no config file" do
28
+ before :each do
29
+ @manager.load_config
30
+ end
31
+
32
+ it "should create an empty config file it doesn't exist" do
33
+ File.exists?(@blux_rc).should == true
34
+ end
35
+ end
36
+
37
+ context "starting the blog manager" do
38
+ before :each do
39
+ @manager.start
40
+ end
41
+
42
+ it "should read the HOME variable from the environment" do
43
+ @manager.home.should == File.dirname(__FILE__)
44
+ end
45
+
46
+ it "should compute the blux dir" do
47
+ @manager.blux_dir.should == @blux
48
+ end
49
+
50
+ it "should compute the bluxrc file" do
51
+ @manager.blux_rc.should == @blux_rc
52
+ end
53
+
54
+ it "should create a .blux folder in the home dir if it doesn't exist" do
55
+ File.exists?(@blux).should == true
56
+ end
57
+
58
+ it "should create a .tmp folder in the .blux dir if it doesn't exist" do
59
+ File.exists?("#{@blux}/tmp").should == true
60
+ end
61
+
62
+ it "should create a draft folder in the .blux dir if it doesn't exist" do
63
+ File.exists?("#{@blux}/draft").should == true
64
+ end
65
+
66
+ it "should create a published post file in the .blux dir if it doesn't exist" do
67
+ File.exists?("#{@blux}/.published").should == true
68
+ end
69
+ end
70
+
71
+ context "when using the blog manager" do
72
+ before :each do
73
+ File.open("#{@blux}/.published", 'w') do |f|
74
+ f.write('{"draft1.23":{}}')
75
+ end
76
+
77
+ @manager.start
78
+ end
79
+
80
+ it "should load the published post file" do
81
+ @manager.index.key?("draft1.23").should == true
82
+ end
83
+ end
84
+
85
+ context "loading the config and setting up the draft manager" do
86
+ before :each do
87
+ create_config
88
+ @manager.start
89
+ end
90
+
91
+ it "should pass the right configuration to the draft manager" do
92
+ @draft_mgr.should_receive(:setup).with('gedit', @manager.blux_tmp_dir, @manager.draft_dir, {:verbose => false})
93
+
94
+ @manager.load_config
95
+ end
96
+ end
97
+
98
+ context "when publishing" do
99
+ before :each do
100
+ create_config
101
+
102
+ File.open(@manager.index_file, 'w') do |f|
103
+ f.write('{"draft5.67":{"a":1,"b":2}}')
104
+ end
105
+
106
+ @manager.load_config
107
+ @manager.start
108
+ @manager.stub!(:system).and_return(nil)
109
+
110
+ system "touch #{@manager.draft_dir}/draft5.67"
111
+ end
112
+
113
+ it "should send the proper command" do
114
+ @manager.should_receive(:system).with("blux --convert -f draft5.67 | blux_wp_publish -t no title --config #{@blux_rc} | blux --set_edit_url -f draft5.67")
115
+ @manager.publish 'draft5.67'
116
+ end
117
+
118
+ it "should send the command with the title included if it exists" do
119
+ @draft_mgr.stub!(:get_attribute).and_return('bla')
120
+
121
+ @manager.should_receive(:system).with("blux --convert -f draft5.67 | blux_wp_publish -t bla --config #{@blux_rc} | blux --set_edit_url -f draft5.67")
122
+ @manager.publish 'draft5.67'
123
+ end
124
+
125
+ it "should save the record of published drafts to disk" do
126
+ @manager.publish 'draft5.67'
127
+
128
+ lines = ''
129
+ File.open(@manager.index_file, 'r') do |f|
130
+ f.each_line {|l| lines += l}
131
+ end
132
+
133
+ JSON.parse(lines).key?('draft5.67').should == true
134
+ end
135
+
136
+ it "should add the published time to the attributes of that post" do
137
+ time = Time.now.to_s
138
+
139
+ @manager.publish 'draft5.67'
140
+ @manager.index["draft5.67"]["published_time"].to_s.should == time
141
+ end
142
+ end
143
+
144
+ def create_config
145
+ File.open(@blux_rc, 'w') do |f|
146
+ f.puts "editor: gedit"
147
+ f.puts "html_converter: blux_textile_to_html"
148
+ end
149
+ end
150
+ end