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.
- 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
|