Blux 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +1 -0
- data/Blux.gemspec +57 -0
- data/COPYING +674 -0
- data/Manifest +15 -0
- data/README.markdown +81 -0
- data/Rakefile +19 -0
- data/bin/blux +107 -0
- data/bin/blux_textile_to_html +25 -0
- data/bin/blux_wp_publish +142 -0
- data/lib/blog_manager.rb +99 -0
- data/lib/blux_config_reader.rb +83 -0
- data/lib/blux_option_parser.rb +104 -0
- data/lib/draft_manager.rb +131 -0
- data/lib/indexer.rb +98 -0
- data/spec/blog_manager_spec.rb +150 -0
- data/spec/blux_config_reader_spec.rb +81 -0
- data/spec/draft_manager_spec.rb +363 -0
- metadata +236 -0
- metadata.gz.sig +1 -0
data/Manifest
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
COPYING
|
2
|
+
Manifest
|
3
|
+
README.markdown
|
4
|
+
Rakefile
|
5
|
+
bin/blux
|
6
|
+
bin/blux_textile_to_html
|
7
|
+
bin/blux_wp_publish
|
8
|
+
lib/blog_manager.rb
|
9
|
+
lib/blux_config_reader.rb
|
10
|
+
lib/blux_option_parser.rb
|
11
|
+
lib/draft_manager.rb
|
12
|
+
lib/indexer.rb
|
13
|
+
spec/blog_manager_spec.rb
|
14
|
+
spec/blux_config_reader_spec.rb
|
15
|
+
spec/draft_manager_spec.rb
|
data/README.markdown
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
# Blux
|
2
|
+
Blux is an offline blog manager that lets you manage your blog posts offline and publish them to any blog engine that supports AtomPub.
|
3
|
+
|
4
|
+
## install
|
5
|
+
gem install Blux
|
6
|
+
|
7
|
+
That's it!
|
8
|
+
|
9
|
+
## configuration
|
10
|
+
Blux reads its configuration info from ~/.bluxrc. The first time you run blux, it will create this file for you, but will immediately complain about missing configuration items. Use the following configuration example for a Wordpress blog and edit each line as needed:
|
11
|
+
|
12
|
+
editor: vim
|
13
|
+
html_converter: blux_textile_to_html
|
14
|
+
|
15
|
+
blog: myWordpressBlog
|
16
|
+
author_name: Mr. Author
|
17
|
+
user_name: my_user_id
|
18
|
+
password: my_password
|
19
|
+
|
20
|
+
**editor:** this is the shell command that will be executed to launch your editor of choice
|
21
|
+
|
22
|
+
**html_converter:** Blux will use this shell command to convert your blog draft to html. In the example above, Blux will use the blux_textile_to_html script, which is included with this application. The script will transform your post, written in the textile markup language, and convert it to html.
|
23
|
+
|
24
|
+
**blog:** this is your Wordpress blog ID
|
25
|
+
|
26
|
+
**author_name:** the name of the author
|
27
|
+
|
28
|
+
**user_name:** your Wordpress user name that Blux will use to publish your posts
|
29
|
+
|
30
|
+
**password:** your Wordpress password
|
31
|
+
|
32
|
+
## Blux from command line
|
33
|
+
|
34
|
+
Blux is a command line tool that currently operates without a GUI of any sort. Here are a few of the commands you can use:
|
35
|
+
|
36
|
+
> $ blux -n (--new)
|
37
|
+
|
38
|
+
this command launches your text editor. As soon as you quit the editor, it will create a draft in the Blux draft folder in ~/.blux/draft
|
39
|
+
|
40
|
+
> $ blux -s (--set) --latest title "a title"
|
41
|
+
|
42
|
+
this command sets a title on the latest created draft
|
43
|
+
|
44
|
+
> $ blux -s -f draft1.23 title "a title"
|
45
|
+
|
46
|
+
the -f <filename> option can be used to tell Blux to operate on a specific draft by use the draft's filename (without the path)
|
47
|
+
|
48
|
+
> $ blux -s --title "old title" title "new title"
|
49
|
+
|
50
|
+
use --title <title> to tell Blux to operate on a draft with a specific title. In this case, blux will change the title of the "old title" draft to "new title"
|
51
|
+
|
52
|
+
> $ blux -l (--list)
|
53
|
+
|
54
|
+
this command will list all your drafts, showing each draft by filename
|
55
|
+
|
56
|
+
> $ blux -l --with-preview
|
57
|
+
|
58
|
+
use --with-preview when you want to show a small snippet of each draft during the listing
|
59
|
+
|
60
|
+
> $ blux -l --details -f draft1.23
|
61
|
+
|
62
|
+
user --details to see each draft filename followed by the drafts attributes in JSON format when listing
|
63
|
+
|
64
|
+
> $ blux -o (--out) -f draft1.23
|
65
|
+
|
66
|
+
this command will output the content of your draft to stdin
|
67
|
+
|
68
|
+
> $ blux -c (--convert) --latest
|
69
|
+
|
70
|
+
this command will invoke the specified converter to convert your post to html
|
71
|
+
|
72
|
+
> $ blux -e (--edit) --title "title 1"
|
73
|
+
|
74
|
+
use this command to edit a draft
|
75
|
+
|
76
|
+
> $ blux -e -f draft1.23 --verbose
|
77
|
+
|
78
|
+
when using the --verbose option, Blux will output a lot of extra information to the screen as it works
|
79
|
+
|
80
|
+
## community
|
81
|
+
feel free to post your comments or questions to the Blux Google group here: blux_manager@googlegroups.com
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'echoe'
|
4
|
+
|
5
|
+
Echoe.new('Blux', '0.0.3') do |p|
|
6
|
+
p.description = 'An offline blog manager'
|
7
|
+
p.url = 'http://github.com/louissalin/blux'
|
8
|
+
p.author = 'Louis Salin'
|
9
|
+
p.email = 'louis.phil@gmail.com'
|
10
|
+
p.ignore_pattern = ["tags", "TODO", "plan", "gem-public_cert.pem"]
|
11
|
+
p.development_dependencies = ["OptionParser >=0.5.1",
|
12
|
+
"atom-tools >=2.0.5",
|
13
|
+
"json >=1.4.6",
|
14
|
+
"RedCloth >=4.2.3"]
|
15
|
+
p.runtime_dependencies = ["OptionParser >=0.5.1",
|
16
|
+
"atom-tools >=2.0.5",
|
17
|
+
"json >=1.4.6",
|
18
|
+
"RedCloth >=4.2.3"]
|
19
|
+
end
|
data/bin/blux
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Copyright 2010 Louis-Philippe Salin de l'Etoile, aka Louis Salin
|
4
|
+
# email: louis.phil@gmail.com
|
5
|
+
#
|
6
|
+
# This file is part of Blux.
|
7
|
+
#
|
8
|
+
# Blux is free software: you can redistribute it and/or modify
|
9
|
+
# it under the terms of the GNU General Public License as published by
|
10
|
+
# the Free Software Foundation, either version 3 of the License, or
|
11
|
+
# (at your option) any later version.
|
12
|
+
#
|
13
|
+
# Blux is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
# GNU General Public License for more details.
|
17
|
+
#
|
18
|
+
# You should have received a copy of the GNU General Public License
|
19
|
+
# along with Blux. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
|
21
|
+
require "#{File.dirname(__FILE__)}/../lib/blux_option_parser.rb"
|
22
|
+
require "#{File.dirname(__FILE__)}/../lib/blog_manager.rb"
|
23
|
+
|
24
|
+
def validate_command(options)
|
25
|
+
if (options.command != nil)
|
26
|
+
yield options
|
27
|
+
else
|
28
|
+
STDERR << "No command specified. Use -h for a list of possible commands\n"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def validate_set_options(options)
|
33
|
+
if options.attributes.length.modulo(2) == 0
|
34
|
+
yield options.attributes[0], options.attributes[1]
|
35
|
+
else
|
36
|
+
STDERR << "Attribute error: you must specify an attribute name and a value."
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def check_filename(options, blog_manager)
|
41
|
+
filename = blog_manager.draft_manager.get_latest_created_draft if options.use_latest
|
42
|
+
filename = blog_manager.draft_manager.get_draft_by_title(options.title) if options.use_title
|
43
|
+
filename = options.filename || filename
|
44
|
+
|
45
|
+
puts "check_filename: #{filename}" if options.verbose
|
46
|
+
if filename != nil
|
47
|
+
yield filename
|
48
|
+
else
|
49
|
+
STDERR << "Please specify the draft file you want to work with. If you want to work with the latest created/edited draft, use the --latest option. You can also tell blux to get a draft with a specific title with --title."
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
validate_command(BluxOptionParser.parse(ARGV)) do |options|
|
54
|
+
puts "#{options}" if options.verbose
|
55
|
+
|
56
|
+
draft_manager = DraftManager.new
|
57
|
+
mgr = BlogManager.new(draft_manager, :verbose => options.verbose)
|
58
|
+
mgr.load_config
|
59
|
+
mgr.start
|
60
|
+
|
61
|
+
case options.command
|
62
|
+
when :new
|
63
|
+
mgr.draft_manager.create_draft
|
64
|
+
when :edit
|
65
|
+
check_filename(options, mgr) do |filename|
|
66
|
+
mgr.draft_manager.edit_draft filename
|
67
|
+
end
|
68
|
+
when :list
|
69
|
+
mgr.draft_manager.list.each do |item|
|
70
|
+
break if options.filename != nil && options.filename != item
|
71
|
+
puts "#{item}"
|
72
|
+
puts " #{mgr.draft_manager.show_info(item)}" if options.list_details
|
73
|
+
puts " #{mgr.draft_manager.show_preview(item)}" if options.list_preview
|
74
|
+
end
|
75
|
+
when :set
|
76
|
+
check_filename(options, mgr) do |filename|
|
77
|
+
validate_set_options(options) do |attribute, value|
|
78
|
+
mgr.draft_manager.set_attribute(filename, attribute, value)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
when :out
|
82
|
+
check_filename(options, mgr) do |filename|
|
83
|
+
STDOUT.puts(mgr.draft_manager.output filename)
|
84
|
+
end
|
85
|
+
when :convert
|
86
|
+
check_filename(options, mgr) do |filename|
|
87
|
+
system "blux --out -f #{filename} | #{mgr.config.html_converter_cmd}"
|
88
|
+
end
|
89
|
+
when :publish
|
90
|
+
check_filename(options, mgr) do |filename|
|
91
|
+
puts "publishing" if options.verbose
|
92
|
+
mgr.publish filename
|
93
|
+
end
|
94
|
+
when :update
|
95
|
+
check_filename(options, mgr) do |filename|
|
96
|
+
puts "updating" if options.verbose
|
97
|
+
mgr.update filename
|
98
|
+
end
|
99
|
+
when :set_edit_url
|
100
|
+
check_filename(options, mgr) do |filename|
|
101
|
+
ARGF.each do |url|
|
102
|
+
mgr.set_attribute(filename, 'edit_url', url.strip)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Copyright 2010 Louis-Philippe Salin de l'Etoile, aka Louis Salin
|
4
|
+
# email: louis.phil@gmail.com
|
5
|
+
#
|
6
|
+
# This file is part of Blux.
|
7
|
+
#
|
8
|
+
# Blux is free software: you can redistribute it and/or modify
|
9
|
+
# it under the terms of the GNU General Public License as published by
|
10
|
+
# the Free Software Foundation, either version 3 of the License, or
|
11
|
+
# (at your option) any later version.
|
12
|
+
#
|
13
|
+
# Blux is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
# GNU General Public License for more details.
|
17
|
+
#
|
18
|
+
# You should have received a copy of the GNU General Public License
|
19
|
+
# along with Blux. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
|
21
|
+
require 'redcloth'
|
22
|
+
|
23
|
+
ARGF.each do |line|
|
24
|
+
STDOUT.puts RedCloth.new(line).to_html
|
25
|
+
end
|
data/bin/blux_wp_publish
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
## Copyright (c) 2007 John Mettraux
|
3
|
+
## Released under the MIT license
|
4
|
+
## http://www.opensource.org/licenses/mit-license.php
|
5
|
+
##
|
6
|
+
## Modifications by Louis Salin, October 2010
|
7
|
+
## => reading blog information from the configuration file
|
8
|
+
|
9
|
+
require 'optparse'
|
10
|
+
require 'net/http'
|
11
|
+
require 'atom/entry' # sudo gem install atom-tools
|
12
|
+
require 'atom/collection'
|
13
|
+
require "#{File.dirname(__FILE__)}/../lib/blux_config_reader"
|
14
|
+
|
15
|
+
|
16
|
+
#
|
17
|
+
# parse options
|
18
|
+
|
19
|
+
tags = []
|
20
|
+
title = nil
|
21
|
+
type = 'html'
|
22
|
+
bluxrc = nil
|
23
|
+
command = :post
|
24
|
+
entry_id = nil
|
25
|
+
|
26
|
+
opts = OptionParser.new
|
27
|
+
opts.banner = "Usage: post.rb [options]"
|
28
|
+
opts.separator ""
|
29
|
+
opts.separator "options :"
|
30
|
+
|
31
|
+
opts.on(
|
32
|
+
"-c",
|
33
|
+
"--categories {list}",
|
34
|
+
"comma separated list of tags/categories") do |v|
|
35
|
+
|
36
|
+
tags = v.split ","
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.on(
|
40
|
+
"-t",
|
41
|
+
"--title {title}",
|
42
|
+
"title for the post") do |v|
|
43
|
+
|
44
|
+
title = v
|
45
|
+
end
|
46
|
+
|
47
|
+
opts.on(
|
48
|
+
"-T",
|
49
|
+
"--type {html|xhtml|text}",
|
50
|
+
"type of the content. ('html' is the default).") do |v|
|
51
|
+
|
52
|
+
type = v
|
53
|
+
end
|
54
|
+
|
55
|
+
opts.on(
|
56
|
+
"--config {config_file}",
|
57
|
+
"blux config file path") do |f|
|
58
|
+
bluxrc = f
|
59
|
+
end
|
60
|
+
|
61
|
+
opts.on(
|
62
|
+
"--update {entry_id}",
|
63
|
+
"update an existing post") do |id|
|
64
|
+
command = :put
|
65
|
+
entry_id = id
|
66
|
+
end
|
67
|
+
|
68
|
+
opts.on(
|
69
|
+
"-h",
|
70
|
+
"--help",
|
71
|
+
"displays this help") do
|
72
|
+
|
73
|
+
puts
|
74
|
+
puts opts.to_s
|
75
|
+
puts
|
76
|
+
exit 0
|
77
|
+
end
|
78
|
+
|
79
|
+
opts.parse ARGV
|
80
|
+
|
81
|
+
raise "please specify a title for the post with the -t option" unless title
|
82
|
+
|
83
|
+
# a great thanks to the devs of all the libs used here
|
84
|
+
#
|
85
|
+
# some info about you and your blog
|
86
|
+
|
87
|
+
config = BluxConfigurationReader.new
|
88
|
+
config.load_config bluxrc
|
89
|
+
|
90
|
+
blog = config.blog
|
91
|
+
authorname = config.author_name
|
92
|
+
username = config.user_name
|
93
|
+
password = config.password
|
94
|
+
|
95
|
+
bloguri = "http://#{blog}.wordpress.com"
|
96
|
+
base = "https://#{blog}.wordpress.com/wp-app.php"
|
97
|
+
|
98
|
+
#
|
99
|
+
# gather content
|
100
|
+
|
101
|
+
content = ""
|
102
|
+
loop do
|
103
|
+
line = STDIN.gets
|
104
|
+
break unless line
|
105
|
+
content += line
|
106
|
+
end
|
107
|
+
|
108
|
+
# create entry
|
109
|
+
|
110
|
+
entry = Atom::Entry.new
|
111
|
+
entry.title = title
|
112
|
+
entry.updated!
|
113
|
+
|
114
|
+
author = Atom::Author.new
|
115
|
+
author.name = authorname
|
116
|
+
author.uri = bloguri
|
117
|
+
entry.authors << author
|
118
|
+
|
119
|
+
tags.each do |t|
|
120
|
+
c = Atom::Category.new
|
121
|
+
c["scheme"] = bloguri
|
122
|
+
c["term"] = t.strip
|
123
|
+
entry.categories << c
|
124
|
+
end
|
125
|
+
|
126
|
+
entry.content = content
|
127
|
+
entry.content["type"] = type if type
|
128
|
+
|
129
|
+
h = Atom::HTTP.new
|
130
|
+
h.user = username
|
131
|
+
h.pass = password
|
132
|
+
h.always_auth = :basic
|
133
|
+
|
134
|
+
c = Atom::Collection.new(base + "/posts", h)
|
135
|
+
if command == :post
|
136
|
+
res = c.post! entry
|
137
|
+
puts Atom::Entry.parse(res.read_body).edit_url
|
138
|
+
elsif command == :put
|
139
|
+
entry.edit_url = entry_id
|
140
|
+
res = c.put! entry
|
141
|
+
end
|
142
|
+
|
data/lib/blog_manager.rb
ADDED
@@ -0,0 +1,99 @@
|
|
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 "#{File.dirname(__FILE__)}/draft_manager"
|
20
|
+
require "#{File.dirname(__FILE__)}/blux_config_reader"
|
21
|
+
require "#{File.dirname(__FILE__)}/indexer"
|
22
|
+
|
23
|
+
class BlogManager
|
24
|
+
attr_accessor :home, :blux_dir, :blux_rc, :blux_tmp_dir, :draft_dir
|
25
|
+
attr_accessor :draft_manager
|
26
|
+
attr_accessor :config
|
27
|
+
attr_accessor :index
|
28
|
+
attr_accessor :index_file
|
29
|
+
|
30
|
+
include BluxIndexer
|
31
|
+
|
32
|
+
def initialize(draft_manager, options = {})
|
33
|
+
@options = options
|
34
|
+
@verbose = options[:verbose] ||= false
|
35
|
+
|
36
|
+
@home = ENV['HOME']
|
37
|
+
@blux_dir = "#{@home}/.blux"
|
38
|
+
@draft_dir = "#{@blux_dir}/draft"
|
39
|
+
@blux_tmp_dir = "#{@blux_dir}/tmp"
|
40
|
+
@blux_rc = "#{@home}/.bluxrc"
|
41
|
+
@index_file = "#{@blux_dir}/.published"
|
42
|
+
|
43
|
+
@draft_manager = draft_manager
|
44
|
+
end
|
45
|
+
|
46
|
+
def start
|
47
|
+
unless Dir.exists?(@blux_dir)
|
48
|
+
puts "creating #{@blux_dir}\n" if @verbose
|
49
|
+
Dir.mkdir(@blux_dir)
|
50
|
+
end
|
51
|
+
|
52
|
+
unless Dir.exists?(@draft_dir)
|
53
|
+
puts "creating #{@draft_dir}\n" if @verbose
|
54
|
+
Dir.mkdir(@draft_dir)
|
55
|
+
end
|
56
|
+
|
57
|
+
unless Dir.exists?(@blux_tmp_dir)
|
58
|
+
puts "creating #{@blux_tmp_dir}\n" if @verbose
|
59
|
+
Dir.mkdir(@blux_tmp_dir)
|
60
|
+
end
|
61
|
+
|
62
|
+
load_index
|
63
|
+
end
|
64
|
+
|
65
|
+
def load_config
|
66
|
+
@config = BluxConfigurationReader.new
|
67
|
+
@config.load_config @blux_rc, @verbose
|
68
|
+
|
69
|
+
@draft_manager.setup(@config.launch_editor_cmd, @blux_tmp_dir, @draft_dir, @options)
|
70
|
+
end
|
71
|
+
|
72
|
+
def publish(filename)
|
73
|
+
title = @draft_manager.get_attribute(filename, "title") || 'no title'
|
74
|
+
|
75
|
+
cmd = "blux --convert -f #{filename} | blux_wp_publish -t #{title} --config #{@blux_rc} | blux --set_edit_url -f #{filename}"
|
76
|
+
cmd = cmd + " --verbose" if @verbose
|
77
|
+
|
78
|
+
puts cmd if @verbose
|
79
|
+
system cmd
|
80
|
+
|
81
|
+
load_index
|
82
|
+
set_attribute(filename, :published_time, Time.now)
|
83
|
+
end
|
84
|
+
|
85
|
+
def update(filename)
|
86
|
+
title = @draft_manager.get_attribute(filename, "title") || 'no title'
|
87
|
+
url = get_attribute(filename, "edit_url")
|
88
|
+
|
89
|
+
raise "couldn't find an edit url for the draft: #{filename}" unless url
|
90
|
+
|
91
|
+
cmd = "blux --convert -f #{filename} | blux_wp_publish.rb -t #{title} --update #{url} --config #{@blux_rc}"
|
92
|
+
|
93
|
+
puts cmd if @verbose
|
94
|
+
system cmd
|
95
|
+
|
96
|
+
set_attribute(filename, :published_time, Time.now)
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|