hobix 0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +18 -0
- data/README +18 -0
- data/Rakefile +96 -0
- data/bin/hobix +94 -0
- data/contrib/blosxom-to-hobix.rb +253 -0
- data/contrib/txp-to-hobix.rb +56 -0
- data/contrib/webrick-all-mine.rb +20 -0
- data/doc/CHANGELOG +285 -0
- data/doc/rdoc/classes/Hobix/API.html +382 -0
- data/doc/rdoc/classes/Hobix/Article.html +111 -0
- data/doc/rdoc/classes/Hobix/BaseContent.html +692 -0
- data/doc/rdoc/classes/Hobix/BaseEntry.html +218 -0
- data/doc/rdoc/classes/Hobix/BaseFacet.html +205 -0
- data/doc/rdoc/classes/Hobix/BaseOutput.html +122 -0
- data/doc/rdoc/classes/Hobix/BasePlugin.html +201 -0
- data/doc/rdoc/classes/Hobix/BaseProperties/ClassMethods.html +243 -0
- data/doc/rdoc/classes/Hobix/BaseProperties.html +218 -0
- data/doc/rdoc/classes/Hobix/BasePublish.html +157 -0
- data/doc/rdoc/classes/Hobix/BaseStorage.html +417 -0
- data/doc/rdoc/classes/Hobix/BixWik/Entry.html +196 -0
- data/doc/rdoc/classes/Hobix/BixWik/IndexEntry.html +170 -0
- data/doc/rdoc/classes/Hobix/BixWik/WikiRedCloth.html +111 -0
- data/doc/rdoc/classes/Hobix/BixWik.html +418 -0
- data/doc/rdoc/classes/Hobix/BixWikPlugin.html +158 -0
- data/doc/rdoc/classes/Hobix/CommandLine.html +1970 -0
- data/doc/rdoc/classes/Hobix/Comment.html +113 -0
- data/doc/rdoc/classes/Hobix/Config.html +212 -0
- data/doc/rdoc/classes/Hobix/DataMarsh.html +667 -0
- data/doc/rdoc/classes/Hobix/Entry.html +178 -0
- data/doc/rdoc/classes/Hobix/EntryEnum.html +162 -0
- data/doc/rdoc/classes/Hobix/Enumerable.html +170 -0
- data/doc/rdoc/classes/Hobix/Facets/WikiEdit.html +180 -0
- data/doc/rdoc/classes/Hobix/Facets.html +111 -0
- data/doc/rdoc/classes/Hobix/LinkList.html +182 -0
- data/doc/rdoc/classes/Hobix/Out/Quick.html +412 -0
- data/doc/rdoc/classes/Hobix/Out.html +119 -0
- data/doc/rdoc/classes/Hobix/Page.html +381 -0
- data/doc/rdoc/classes/Hobix/Trackback.html +113 -0
- data/doc/rdoc/classes/Hobix/UriStr.html +198 -0
- data/doc/rdoc/classes/Hobix/WebApp/QueryString.html +207 -0
- data/doc/rdoc/classes/Hobix/WebApp/QueryValidationFailure.html +111 -0
- data/doc/rdoc/classes/Hobix/WebApp.html +1383 -0
- data/doc/rdoc/classes/Hobix/Weblog/AuthorNotFound.html +111 -0
- data/doc/rdoc/classes/Hobix/Weblog.html +2082 -0
- data/doc/rdoc/classes/Hobix.html +399 -0
- data/doc/rdoc/classes/Kernel.html +139 -0
- data/doc/rdoc/classes/Regexp.html +154 -0
- data/doc/rdoc/classes/YAML/Omap.html +144 -0
- data/doc/rdoc/classes/YAML.html +111 -0
- data/doc/rdoc/created.rid +1 -0
- data/doc/rdoc/files/COPYING.html +129 -0
- data/doc/rdoc/files/README.html +131 -0
- data/doc/rdoc/files/doc/CHANGELOG.html +101 -0
- data/doc/rdoc/files/lib/hobix/api_rb.html +119 -0
- data/doc/rdoc/files/lib/hobix/article_rb.html +126 -0
- data/doc/rdoc/files/lib/hobix/base_rb.html +128 -0
- data/doc/rdoc/files/lib/hobix/bixwik_rb.html +126 -0
- data/doc/rdoc/files/lib/hobix/commandline_rb.html +140 -0
- data/doc/rdoc/files/lib/hobix/comments_rb.html +126 -0
- data/doc/rdoc/files/lib/hobix/config_rb.html +125 -0
- data/doc/rdoc/files/lib/hobix/datamarsh_rb.html +108 -0
- data/doc/rdoc/files/lib/hobix/entry_rb.html +118 -0
- data/doc/rdoc/files/lib/hobix/linklist_rb.html +127 -0
- data/doc/rdoc/files/lib/hobix/publisher_rb.html +126 -0
- data/doc/rdoc/files/lib/hobix/trackbacks_rb.html +128 -0
- data/doc/rdoc/files/lib/hobix/webapp_rb.html +127 -0
- data/doc/rdoc/files/lib/hobix/weblog_rb.html +135 -0
- data/doc/rdoc/files/lib/hobix_rb.html +127 -0
- data/doc/rdoc/fr_class_index.html +67 -0
- data/doc/rdoc/fr_file_index.html +44 -0
- data/doc/rdoc/fr_method_index.html +307 -0
- data/doc/rdoc/index.html +24 -0
- data/doc/rdoc/rdoc-style.css +208 -0
- data/git_hobix_update.php +13 -0
- data/lib/hobix/api.rb +91 -0
- data/lib/hobix/article.rb +22 -0
- data/lib/hobix/base.rb +480 -0
- data/lib/hobix/bixwik.rb +200 -0
- data/lib/hobix/commandline.rb +677 -0
- data/lib/hobix/comments.rb +98 -0
- data/lib/hobix/config.rb +39 -0
- data/lib/hobix/datamarsh.rb +110 -0
- data/lib/hobix/entry.rb +84 -0
- data/lib/hobix/facets/comments.rb +99 -0
- data/lib/hobix/facets/publisher.rb +314 -0
- data/lib/hobix/facets/trackbacks.rb +80 -0
- data/lib/hobix/linklist.rb +81 -0
- data/lib/hobix/out/atom.rb +101 -0
- data/lib/hobix/out/erb.rb +64 -0
- data/lib/hobix/out/okaynews.rb +55 -0
- data/lib/hobix/out/quick.rb +314 -0
- data/lib/hobix/out/rdf.rb +97 -0
- data/lib/hobix/out/redrum.rb +26 -0
- data/lib/hobix/out/rss.rb +128 -0
- data/lib/hobix/plugin/akismet.rb +196 -0
- data/lib/hobix/plugin/bloglines.rb +73 -0
- data/lib/hobix/plugin/calendar.rb +212 -0
- data/lib/hobix/plugin/flickr.rb +110 -0
- data/lib/hobix/plugin/recent_comments.rb +84 -0
- data/lib/hobix/plugin/sections.rb +91 -0
- data/lib/hobix/plugin/tags.rb +60 -0
- data/lib/hobix/publish/ping.rb +53 -0
- data/lib/hobix/publish/replicate.rb +283 -0
- data/lib/hobix/publisher.rb +18 -0
- data/lib/hobix/search/dictionary.rb +141 -0
- data/lib/hobix/search/porter_stemmer.rb +203 -0
- data/lib/hobix/search/simple.rb +209 -0
- data/lib/hobix/search/vector.rb +100 -0
- data/lib/hobix/storage/filesys.rb +408 -0
- data/lib/hobix/trackbacks.rb +93 -0
- data/lib/hobix/util/objedit.rb +193 -0
- data/lib/hobix/util/patcher.rb +155 -0
- data/lib/hobix/webapp/cli.rb +195 -0
- data/lib/hobix/webapp/htmlform.rb +107 -0
- data/lib/hobix/webapp/message.rb +177 -0
- data/lib/hobix/webapp/urigen.rb +141 -0
- data/lib/hobix/webapp/webrick-servlet.rb +90 -0
- data/lib/hobix/webapp.rb +723 -0
- data/lib/hobix/weblog.rb +893 -0
- data/lib/hobix.rb +230 -0
- data/share/default-blog/hobix.yaml +16 -0
- data/share/default-blog/htdocs/site.css +174 -0
- data/share/default-blog/skel/entry.html.quick +0 -0
- data/share/default-blog/skel/index.atom.atom +0 -0
- data/share/default-blog/skel/index.html.quick-summary +0 -0
- data/share/default-blog/skel/index.xml.rss +0 -0
- data/share/default-blog/skel/index.yaml.okaynews +0 -0
- data/share/default-blog/skel/monthly.html.quick-archive +0 -0
- data/share/default-blog/skel/section.html.quick-archive +0 -0
- data/share/default-blog/skel/yearly.html.quick-archive +0 -0
- data/share/default-blog-modes.yaml +7 -0
- data/share/default-blog.apache-cgi.patch +8 -0
- data/share/default-blog.apache-ssi.patch +38 -0
- data/share/default-blog.apache2-ssi.patch +3 -0
- data/share/default-blog.cgi.patch +8 -0
- data/share/default-blog.comments.patch +5 -0
- data/share/default-blog.prototype.patch +766 -0
- data/share/default-blog.publisher.patch +5 -0
- data/share/default-blog.wiki.patch +29 -0
- data/share/publisher/css/control.css +90 -0
- data/share/publisher/css/form.css +238 -0
- data/share/publisher/css/form.import.css +72 -0
- data/share/publisher/css/main-menu.css +134 -0
- data/share/publisher/i/hobix-emblazen-1.png +0 -0
- data/share/publisher/i/hobix-emblazen-2.png +0 -0
- data/share/publisher/i/hobix-emblazen-3.png +0 -0
- data/share/publisher/i/hobix-emblazen-4.png +0 -0
- data/share/publisher/i/hobix-emblazen-5.png +0 -0
- data/share/publisher/i/hobix-emblazen-6.png +0 -0
- data/share/publisher/i/hobix-emblazen-7.png +0 -0
- data/share/publisher/index.erb +66 -0
- data/share/publisher/js/controls.js +261 -0
- data/share/publisher/js/dragdrop.js +476 -0
- data/share/publisher/js/effects.js +570 -0
- data/share/publisher/js/prototype.js +1011 -0
- metadata +230 -0
@@ -0,0 +1,677 @@
|
|
1
|
+
#
|
2
|
+
# = hobix/commandline.rb
|
3
|
+
#
|
4
|
+
# Hobix command-line weblog system.
|
5
|
+
#
|
6
|
+
# Copyright (c) 2003-2004 why the lucky stiff
|
7
|
+
# Copyright (c) 2005 MenTaLguY
|
8
|
+
#
|
9
|
+
# Written & maintained by why the lucky stiff <why@ruby-lang.org>
|
10
|
+
# Additional bits by MenTaLguY <mental@rydia.net>
|
11
|
+
#
|
12
|
+
# This program is free software, released under a BSD license.
|
13
|
+
# See COPYING for details.
|
14
|
+
#
|
15
|
+
#--
|
16
|
+
# $Id$
|
17
|
+
#++
|
18
|
+
require 'hobix'
|
19
|
+
require 'tempfile'
|
20
|
+
|
21
|
+
module Hobix
|
22
|
+
module CommandLine
|
23
|
+
##
|
24
|
+
## Locate RC
|
25
|
+
##
|
26
|
+
[
|
27
|
+
[ENV['HOME'], ENV['HOME']],
|
28
|
+
[ENV['APPDATA'], File.join( ENV['APPDATA'] || "", 'Hobix' )]
|
29
|
+
].each do |home_top, home_dir|
|
30
|
+
next unless home_top
|
31
|
+
if File.exists? home_top
|
32
|
+
File.makedirs( home_dir )
|
33
|
+
HOME_DIR = home_dir
|
34
|
+
break
|
35
|
+
end
|
36
|
+
end
|
37
|
+
RC = File.join( HOME_DIR, '.hobixrc' )
|
38
|
+
|
39
|
+
def CommandLine.extended( o )
|
40
|
+
#
|
41
|
+
# When extended we should get all required plugin for the
|
42
|
+
# whole Hobix stuff
|
43
|
+
#
|
44
|
+
return unless File.exists? RC
|
45
|
+
|
46
|
+
config = YAML::load( File.open( RC ) )
|
47
|
+
|
48
|
+
#
|
49
|
+
# Add a new instance variable to o
|
50
|
+
#
|
51
|
+
o.instance_variable_set( :@config, config )
|
52
|
+
|
53
|
+
#
|
54
|
+
# Eventually add user specified path
|
55
|
+
#
|
56
|
+
if config['libs']
|
57
|
+
config['libs'].each do |p|
|
58
|
+
if File.exists?( p ) && File.directory?( p )
|
59
|
+
$LOAD_PATH << p
|
60
|
+
else
|
61
|
+
warn "#{p} not loaded. Either inexistant or not a directory"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# And system wide path too
|
68
|
+
#
|
69
|
+
if File.exists?( Hobix::SHARE_PATH )
|
70
|
+
$LOAD_PATH << File.join(Hobix::SHARE_PATH,"lib")
|
71
|
+
end
|
72
|
+
|
73
|
+
#
|
74
|
+
# Load plugins if necessary
|
75
|
+
#
|
76
|
+
if config['requires']
|
77
|
+
config['requires'].each do |req|
|
78
|
+
Hobix::BasePlugin::start( req, self )
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
def gets; $stdin.gets; end
|
85
|
+
def puts( *args ); $stdin.puts( *args ); end
|
86
|
+
|
87
|
+
def login( config = nil )
|
88
|
+
config ||= RC
|
89
|
+
@config = File.open( config ) { |f| YAML::load( f ) } if File.exists? RC
|
90
|
+
setup unless @config
|
91
|
+
setup_personal unless @config['personal']
|
92
|
+
end
|
93
|
+
|
94
|
+
def config
|
95
|
+
@config
|
96
|
+
end
|
97
|
+
|
98
|
+
def save_config
|
99
|
+
File.open( RC, "w" ) do |f|
|
100
|
+
f.write @config.to_yaml
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Update your Hobix setup
|
105
|
+
def upgrade_app_explain; "Check for updates to Hobix."; end
|
106
|
+
def upgrade_app_args; []; end
|
107
|
+
def upgrade_app( config )
|
108
|
+
require 'rbconfig'
|
109
|
+
require 'open-uri'
|
110
|
+
c = ::Config::CONFIG.merge( config )
|
111
|
+
eval(open("http://go.hobix.com/").read)
|
112
|
+
|
113
|
+
|
114
|
+
# Now look at all blogs and delete entries/index.{hobix,search}
|
115
|
+
if @config['weblogs'].respond_to? :sort
|
116
|
+
blogs = @config['weblogs'].sort
|
117
|
+
blogs.each do |e|
|
118
|
+
weblog = Hobix::Weblog.load( e[1] )
|
119
|
+
puts "Removing index.search and index.hobix from #{weblog.entry_path}"
|
120
|
+
File.safe_unlink( File.join(weblog.entry_path, "index.search"),
|
121
|
+
File.join(weblog.entry_path, "index.hobix"))
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# List all your weblogs
|
127
|
+
def blogs_weblog_explain; "List your weblogs."; end
|
128
|
+
def blogs_weblog_args; []; end
|
129
|
+
def blogs_weblog
|
130
|
+
if @config['weblogs'].respond_to?( :sort ) && !@config['weblogs'].empty?
|
131
|
+
blogs = @config['weblogs'].sort
|
132
|
+
name_width = blogs.collect { |b| b[0].length }.max
|
133
|
+
tabular( blogs, [[-name_width, 0, 'weblog-name'], [-40, 1, 'path']] )
|
134
|
+
else
|
135
|
+
puts "** You have no blogs set up. Use `hobix setup_blogs' to get started."
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def load_patchsets
|
140
|
+
File.open( "#{ Hobix::SHARE_PATH }/default-blog-modes.yaml" ) { |f| YAML::load( f ) }
|
141
|
+
end
|
142
|
+
|
143
|
+
# Create a new skeleton for a weblog
|
144
|
+
def create_weblog_explain; "Create a brand new weblog."; end
|
145
|
+
def create_weblog_args; ['weblog-name', '/path/to/']; end
|
146
|
+
def create_weblog( name, path )
|
147
|
+
@config['weblogs'] ||= {}
|
148
|
+
if @config['weblogs'][name]
|
149
|
+
print "*** Blog '#{ name }' exists already! Overwrite?? [y/N]: "
|
150
|
+
if gets.strip.upcase != 'Y'
|
151
|
+
puts "*** Creation of weblog `#{ name }' aborted."
|
152
|
+
return
|
153
|
+
end
|
154
|
+
end
|
155
|
+
path = File.expand_path( path )
|
156
|
+
puts <<-NOTE
|
157
|
+
|*** Creation of weblog `#{ name }' will add the following directory"
|
158
|
+
| structure to directory #{ path }"
|
159
|
+
|
|
160
|
+
| #{ path }
|
161
|
+
| hobix.yaml <- configuration
|
162
|
+
|
|
163
|
+
| entries/ <- edit and organize
|
164
|
+
| your news items,
|
165
|
+
| articles and so on.
|
166
|
+
|
|
167
|
+
| skel/ <- contains your
|
168
|
+
| templates
|
169
|
+
|
|
170
|
+
| htdocs/ <- html is created here,
|
171
|
+
| store all your images here,
|
172
|
+
| this is your viewable
|
173
|
+
| websyht
|
174
|
+
|
|
175
|
+
| lib/ <- extra hobix libraries
|
176
|
+
| (plugins) go here
|
177
|
+
|
|
178
|
+
NOTE
|
179
|
+
print "Create this structure? [y/N]: "
|
180
|
+
if gets.strip.upcase != 'Y'
|
181
|
+
puts "*** Creation of weblog `#{ name }' aborted."
|
182
|
+
return
|
183
|
+
end
|
184
|
+
|
185
|
+
modes = load_patchsets
|
186
|
+
|
187
|
+
puts "The default blog is available in the following modes:"
|
188
|
+
puts " #{ modes.keys.join( ', ' ) }"
|
189
|
+
puts
|
190
|
+
mode = nil
|
191
|
+
loop do
|
192
|
+
print "Modes: [Comma between each mode or Enter for none] "
|
193
|
+
mode = gets.strip.downcase
|
194
|
+
m = mode
|
195
|
+
break if mode.empty? or not mode.split( /,/ ).detect { |m| m.strip!; not modes.has_key?( m ) }
|
196
|
+
puts "*** No `#{ m }' mode available."
|
197
|
+
end
|
198
|
+
|
199
|
+
require 'fileutils'
|
200
|
+
FileUtils.makedirs path
|
201
|
+
FileUtils.cp_r Dir.glob( "#{ Hobix::SHARE_PATH }/default-blog/*" ), path
|
202
|
+
|
203
|
+
# apply any patches
|
204
|
+
patchlist = mode.split( /,/ ).map { |m| modes[m.strip] }.flatten.uniq
|
205
|
+
require 'hobix/util/patcher'
|
206
|
+
patchlist.collect! { |p| "#{ Hobix::SHARE_PATH }/default-blog.#{ p }.patch" }
|
207
|
+
patcher = Hobix::Util::Patcher[ *patchlist ]
|
208
|
+
patcher.apply( path )
|
209
|
+
|
210
|
+
hobix_yaml = File.join( path, "hobix.yaml" )
|
211
|
+
join_as_author( name, hobix_yaml )
|
212
|
+
weblog = Hobix::Weblog.load( hobix_yaml )
|
213
|
+
weblog.setup
|
214
|
+
edit_action( weblog )
|
215
|
+
end
|
216
|
+
|
217
|
+
# Add a weblog to local config
|
218
|
+
def add_weblog_explain; "Adds a pre-existing hobix weblog to your list."; end
|
219
|
+
def add_weblog_args; ['weblog-name', '/path/to/hobix.yaml']; end
|
220
|
+
def add_weblog( name, path )
|
221
|
+
@config['weblogs'] ||= {}
|
222
|
+
path = File.expand_path( path )
|
223
|
+
puts "*** Checking for existence of blog."
|
224
|
+
require 'hobix/weblog'
|
225
|
+
if File.directory? path
|
226
|
+
path = File.join( path, 'hobix.yaml' )
|
227
|
+
puts "*** Path is a directory, using `#{ path }'."
|
228
|
+
end
|
229
|
+
unless File.exists? path
|
230
|
+
puts "*** No file `#{ path }' found! Aborting."
|
231
|
+
return
|
232
|
+
end
|
233
|
+
join_as_author( name, path )
|
234
|
+
end
|
235
|
+
|
236
|
+
def join_as_author( name, path )
|
237
|
+
weblog = Hobix::Weblog.load( path )
|
238
|
+
puts "*** Joining blog `#{ weblog.title }', adding you as author."
|
239
|
+
weblog.authors[@config['username']] = @config['personal']
|
240
|
+
weblog.save( path )
|
241
|
+
@config['weblogs'][name] = path
|
242
|
+
save_config
|
243
|
+
end
|
244
|
+
|
245
|
+
# Update the site
|
246
|
+
def upgen_action_explain; "Update site with only the latest changes."; end
|
247
|
+
def upgen_action_args; ['weblog-name']; end
|
248
|
+
def upgen_action( weblog )
|
249
|
+
weblog.regenerate( :update )
|
250
|
+
end
|
251
|
+
|
252
|
+
# Regenerate the site
|
253
|
+
def regen_action_explain; "Regenerate the all the pages throughout the site."; end
|
254
|
+
def regen_action_args; ['weblog-name']; end
|
255
|
+
def regen_action( weblog )
|
256
|
+
weblog.regenerate
|
257
|
+
end
|
258
|
+
|
259
|
+
# Edit a weblog from local config
|
260
|
+
def edit_action_explain; "Edit weblog's configuration"; end
|
261
|
+
def edit_action_args; ['weblog-name']; end
|
262
|
+
def edit_action( weblog )
|
263
|
+
path = weblog.hobix_yaml
|
264
|
+
weblog = aorta( weblog )
|
265
|
+
return if weblog.nil?
|
266
|
+
weblog.save( path )
|
267
|
+
end
|
268
|
+
|
269
|
+
# Delete a weblog from local config
|
270
|
+
def del_weblog_explain; "Remove weblog from your list."; end
|
271
|
+
def del_weblog_args; ['weblog-name']; end
|
272
|
+
def del_weblog( name )
|
273
|
+
@config['weblogs'] ||= {}
|
274
|
+
@config['weblogs'].delete( name )
|
275
|
+
save_config
|
276
|
+
end
|
277
|
+
|
278
|
+
# Run a DRuby daemon for blogs in your configuration
|
279
|
+
def druby_weblog_explain; "Start the DRuby daemon for weblogs in your config."; end
|
280
|
+
def druby_weblog_args; []; end
|
281
|
+
def druby_weblog
|
282
|
+
if @config['weblogs']
|
283
|
+
unless @config['druby']
|
284
|
+
@config['druby'] = 'druby://:4081'
|
285
|
+
puts "** No drb url found, using #{ @config['druby'] }"
|
286
|
+
end
|
287
|
+
require 'drb'
|
288
|
+
blogs = {}
|
289
|
+
@config['weblogs'].each do |name, path|
|
290
|
+
blogs[name] = Hobix::Weblog.load path
|
291
|
+
end
|
292
|
+
require 'hobix/api'
|
293
|
+
api = Hobix::API.new blogs
|
294
|
+
DRb.start_service @config['druby'], api
|
295
|
+
DRb.thread.join
|
296
|
+
else
|
297
|
+
puts "** No blogs found in the configuration."
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
# Patch a weblog
|
302
|
+
def patch_action_explain; "Applies a patch to a weblog."; end
|
303
|
+
def patch_action_args; ['weblog-name', 'patch-name']; end
|
304
|
+
def patch_action( weblog, patch )
|
305
|
+
require 'hobix/util/patcher'
|
306
|
+
modes = load_patchsets
|
307
|
+
patchlist = modes[patch.strip].map { |p| "#{ Hobix::SHARE_PATH }/default-blog.#{ p }.patch" }
|
308
|
+
patcher = Hobix::Util::Patcher[ *patchlist ]
|
309
|
+
patcher.apply( weblog.path )
|
310
|
+
end
|
311
|
+
|
312
|
+
# List entries
|
313
|
+
def list_action_explain; "List all posts within a given path."; end
|
314
|
+
def list_action_args; ['weblog-name', 'search/path']; end
|
315
|
+
def list_action( weblog, inpath = '' )
|
316
|
+
entries = weblog.storage.find( :all => true, :inpath => inpath )
|
317
|
+
if entries.empty?
|
318
|
+
puts "** No posts found in the weblog for path '#{inpath}'."
|
319
|
+
else
|
320
|
+
tabular_entries( entries )
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
# Search (disabled in 0.4)
|
325
|
+
# def search_action_explain; "Search for words within posts of a given path."; end
|
326
|
+
# def search_action_args; ['weblog-name', 'word1,word2', 'search/path']; end
|
327
|
+
# def search_action( weblog, words, inpath = '' )
|
328
|
+
# entries = weblog.storage.find( :all => true, :inpath => inpath, :search => words.split( ',' ) )
|
329
|
+
# if entries.empty?
|
330
|
+
# puts "** No posts found in the weblog for path '#{inpath}'."
|
331
|
+
# else
|
332
|
+
# tabular_entries( entries )
|
333
|
+
# end
|
334
|
+
# end
|
335
|
+
|
336
|
+
# Post a new entry
|
337
|
+
def post_action_explain; "Add or edit a post with identifier 'shortName'.\n" +
|
338
|
+
"(You can use full paths. 'blog/weddings/anotherPatheticWedding')\n" +
|
339
|
+
"'type' specifies the type of entry to create if the entry does not\n" +
|
340
|
+
"already exist." ; end
|
341
|
+
def post_action_args; ['weblog-name', '[type]', 'shortName']; end
|
342
|
+
def post_action( weblog, *args )
|
343
|
+
if args.size == 1
|
344
|
+
entry_type = nil
|
345
|
+
entry_id = args[0]
|
346
|
+
elsif args.size == 2
|
347
|
+
( entry_type, entry_id ) = args
|
348
|
+
else
|
349
|
+
raise ArgumentError, "Wrong number of arguments"
|
350
|
+
end
|
351
|
+
|
352
|
+
entry_class = weblog.entry_class(entry_type)
|
353
|
+
begin
|
354
|
+
entry = weblog.storage.load_entry( entry_id )
|
355
|
+
if entry_type and not entry.instance_of? entry_class
|
356
|
+
raise TypeError, "#{entry_id} already exists with a different type (#{entry.class})"
|
357
|
+
end
|
358
|
+
rescue Errno::ENOENT
|
359
|
+
entry = entry_class.new
|
360
|
+
entry.author = @config['username']
|
361
|
+
entry.title = entry_id.split( '/' ).
|
362
|
+
last.
|
363
|
+
gsub( /^\w|\W\w|_\w|[A-Z]/ ) { |up| " #{up[-1, 1].upcase}" }.
|
364
|
+
strip
|
365
|
+
end
|
366
|
+
entry = aorta( entry )
|
367
|
+
return if entry.nil?
|
368
|
+
|
369
|
+
begin
|
370
|
+
weblog.storage.save_entry( entry_id, entry )
|
371
|
+
rescue Errno::ENOENT
|
372
|
+
puts
|
373
|
+
puts "The category for #{entry_id} doesn't exist."
|
374
|
+
print "Create it [Yn]? "
|
375
|
+
response = gets.strip
|
376
|
+
|
377
|
+
if response.empty? or response =~ /^[Yy]/
|
378
|
+
weblog.storage.save_entry( entry_id, entry, true )
|
379
|
+
else
|
380
|
+
puts
|
381
|
+
print "Supply a different shortName [<Enter> to discard post]: "
|
382
|
+
response = gets.strip
|
383
|
+
|
384
|
+
if response.empty?
|
385
|
+
return nil
|
386
|
+
else
|
387
|
+
entry_id = response
|
388
|
+
retry
|
389
|
+
end
|
390
|
+
end
|
391
|
+
end
|
392
|
+
weblog.regenerate( :update ) if @config['post upgen']
|
393
|
+
end
|
394
|
+
|
395
|
+
##
|
396
|
+
## Setup user's RC
|
397
|
+
##
|
398
|
+
def setup
|
399
|
+
@config = {}
|
400
|
+
puts "Welcome to hobix (a simple weblog tool). Looks like your"
|
401
|
+
puts "first time running hobix, eh? Time to get a bit of information"
|
402
|
+
puts "from you before you start using hobix. (All of this will be stored"
|
403
|
+
puts "in the file #{ Hobix::CommandLine::RC } if you need to edit.)"
|
404
|
+
puts
|
405
|
+
|
406
|
+
username = ''
|
407
|
+
default_user = ''
|
408
|
+
user_prompt = 'Your hobix username'
|
409
|
+
if ENV['USER']
|
410
|
+
default_user = ENV['USER']
|
411
|
+
user_prompt << " [<Enter> for #{ ENV['USER'] }]"
|
412
|
+
end
|
413
|
+
while username.empty?
|
414
|
+
puts
|
415
|
+
print "#{ user_prompt }: "
|
416
|
+
username = gets.strip
|
417
|
+
if username.empty?
|
418
|
+
username = default_user
|
419
|
+
end
|
420
|
+
end
|
421
|
+
@config['username'] = username
|
422
|
+
|
423
|
+
puts
|
424
|
+
puts "Your EDITOR environment variable is set to '#{ ENV['EDITOR'] }'."
|
425
|
+
puts "You can edit entries with your EDITOR or you can just use hobix."
|
426
|
+
puts "** NOTE: If you don't use your own editor, then you will be using"
|
427
|
+
puts " the Hobix built-in object editor, which is highly experimental"
|
428
|
+
puts " and may not work on your platform.)"
|
429
|
+
print "Use your EDITOR to edit entries? [Y/n]: "
|
430
|
+
editor = gets.strip.upcase
|
431
|
+
|
432
|
+
if editor == 'N'
|
433
|
+
@config['use editor'] = false
|
434
|
+
else
|
435
|
+
@config['use editor'] = true
|
436
|
+
end
|
437
|
+
|
438
|
+
puts
|
439
|
+
puts "After posting a new entry, would you like Hobix to automatically"
|
440
|
+
print "update the site? [Y/n]: "
|
441
|
+
post_upgen = gets.strip.upcase
|
442
|
+
|
443
|
+
if post_upgen == 'N'
|
444
|
+
@config['post upgen'] = false
|
445
|
+
else
|
446
|
+
@config['post upgen'] = true
|
447
|
+
end
|
448
|
+
|
449
|
+
|
450
|
+
save_config
|
451
|
+
end
|
452
|
+
|
453
|
+
##
|
454
|
+
## Setup personal information
|
455
|
+
##
|
456
|
+
def setup_personal
|
457
|
+
@config['personal'] ||= {}
|
458
|
+
puts
|
459
|
+
puts "Your personal information has not been setup yet."
|
460
|
+
[['name', 'Your real name', true],
|
461
|
+
['url', 'URL to your home page', false],
|
462
|
+
['email', 'Your e-mail address', false]].each do |k, txt, req|
|
463
|
+
print "#{ txt }: "
|
464
|
+
val = gets.strip
|
465
|
+
retry if req and val.empty?
|
466
|
+
@config['personal'][k] = val
|
467
|
+
end
|
468
|
+
save_config
|
469
|
+
end
|
470
|
+
|
471
|
+
##
|
472
|
+
## Extra setup, triggered upon installation
|
473
|
+
##
|
474
|
+
def setup_blogs
|
475
|
+
puts
|
476
|
+
puts " === Joining an existing weblog? ==="
|
477
|
+
puts "If you want to join an existing hobix weblog, we can do that now."
|
478
|
+
puts "Each weblog needs a name and a path. Use <ENTER> at any prompt"
|
479
|
+
puts "to simply move on."
|
480
|
+
puts
|
481
|
+
loop do
|
482
|
+
puts "Short name for weblog, used on the command line (i.e. hobix upgen blogName)."
|
483
|
+
print ": "
|
484
|
+
blogname = gets.strip
|
485
|
+
break if blogname.empty?
|
486
|
+
|
487
|
+
print "Path to weblog's hobix.yaml `#{ blogname }': "
|
488
|
+
blogpath = gets.strip
|
489
|
+
if blogpath.empty?
|
490
|
+
puts "*** Aborting setup of weblog `#{ blogname }'."
|
491
|
+
break
|
492
|
+
end
|
493
|
+
add_weblog( blogname, blogpath )
|
494
|
+
puts
|
495
|
+
puts "** Add another weblog?"
|
496
|
+
end
|
497
|
+
|
498
|
+
puts "To setup more weblogs later, use: hobix add #{ add_weblog_args.join( ' ' ) }"
|
499
|
+
puts
|
500
|
+
puts " === Create a new weblog? ==="
|
501
|
+
puts "If you want to create a new hobix weblog, we can do that now."
|
502
|
+
puts "Each weblog needs a name and a path. Use <ENTER> at any prompt"
|
503
|
+
puts "to simply move on."
|
504
|
+
loop do
|
505
|
+
puts
|
506
|
+
puts "Short name for weblog, used on the command line (i.e. hobix upgen blogName)."
|
507
|
+
print ": "
|
508
|
+
blogname = gets.strip
|
509
|
+
break if blogname.empty?
|
510
|
+
|
511
|
+
print "Path to create weblog `#{ blogname }': "
|
512
|
+
blogpath = gets.strip
|
513
|
+
if blogpath.empty?
|
514
|
+
puts "*** Aborting creation of weblog `#{ blogname }'."
|
515
|
+
break
|
516
|
+
end
|
517
|
+
create_weblog( blogname, blogpath )
|
518
|
+
end
|
519
|
+
puts "To create more weblogs later, use: hobix create #{ create_weblog_args.join( ' ' ) }"
|
520
|
+
puts
|
521
|
+
end
|
522
|
+
|
523
|
+
def aorta( obj )
|
524
|
+
if @config['use editor']
|
525
|
+
# I am quite displeased that Tempfile.open eats its blocks result,
|
526
|
+
# thereby necessitating this blecherous construct...
|
527
|
+
tempfile = nil
|
528
|
+
Tempfile.open("hobix.post") { |tempfile| tempfile << obj.to_yaml }
|
529
|
+
|
530
|
+
begin
|
531
|
+
created = File.mtime( tempfile.path )
|
532
|
+
system( "#{ ENV['EDITOR'] || 'vi' } #{ tempfile.path }" )
|
533
|
+
return nil unless File.exists?( tempfile.path )
|
534
|
+
|
535
|
+
if created < File.mtime( tempfile.path )
|
536
|
+
obj = YAML::load( tempfile.open )
|
537
|
+
else
|
538
|
+
puts "** Edit aborted"
|
539
|
+
obj = nil
|
540
|
+
end
|
541
|
+
rescue StandardError => e
|
542
|
+
puts "There was an error saving the entry: #{ e.class }: #{ e.message }"
|
543
|
+
print "Re-edit [Yn]? "
|
544
|
+
response = gets.strip
|
545
|
+
if response.empty? or response =~ /^[Yy]/
|
546
|
+
retry
|
547
|
+
else
|
548
|
+
puts "** Edit aborted"
|
549
|
+
obj = nil
|
550
|
+
end
|
551
|
+
ensure
|
552
|
+
# tempfile will get closed/unlinked when it's collected anyway;
|
553
|
+
# may as well do it here to provide some determinism for the user
|
554
|
+
begin
|
555
|
+
tempfile.close true
|
556
|
+
rescue
|
557
|
+
end
|
558
|
+
end
|
559
|
+
else
|
560
|
+
require 'hobix/util/objedit'
|
561
|
+
obj = Hobix::Util::ObjEdit( obj )
|
562
|
+
end
|
563
|
+
obj
|
564
|
+
end
|
565
|
+
|
566
|
+
def tabular( table, fields, desc = nil )
|
567
|
+
field_widths = fields.collect do |width, id, title|
|
568
|
+
([width.abs, title.length].max + 1) * ( width / width.abs )
|
569
|
+
end
|
570
|
+
client_format = field_widths.collect { |width| "%#{ width}s"}.join( ': ')
|
571
|
+
puts client_format % fields.collect { |width, id, title| title }
|
572
|
+
puts field_widths.collect { |width| "-" * width.abs }.join( ':-' )
|
573
|
+
table.each do |row|
|
574
|
+
puts client_format % fields.collect { |width, id, title| row[ id ] }
|
575
|
+
if desc
|
576
|
+
puts row[ desc ]
|
577
|
+
puts
|
578
|
+
end
|
579
|
+
end
|
580
|
+
end
|
581
|
+
|
582
|
+
def tabular_entries( entries )
|
583
|
+
entries.sort { |e1, e2| e1.id <=> e2.id }
|
584
|
+
name_width = entries.collect { |e| e.id.length }.max
|
585
|
+
rows = entries.inject([]) { |rows, entry| rows << [entry.id, entry.created] }
|
586
|
+
tabular( rows, [[-name_width, 0, 'shortName'], [-34, 1, 'created']] )
|
587
|
+
end
|
588
|
+
|
589
|
+
def puts( str = '' )
|
590
|
+
Kernel::puts str.gsub( /^\s+\|/, '' )
|
591
|
+
end
|
592
|
+
|
593
|
+
##
|
594
|
+
## Hobix over the wire
|
595
|
+
##
|
596
|
+
def http( *args )
|
597
|
+
p http_get( *args )
|
598
|
+
end
|
599
|
+
|
600
|
+
def http_get( weblog, *args )
|
601
|
+
require 'net/http'
|
602
|
+
response =
|
603
|
+
Net::HTTP.new( weblog.host, weblog.port ).start do |http|
|
604
|
+
http.get( File.expand_path( "remote/#{ args.join '/' }", weblog.path ) )
|
605
|
+
end
|
606
|
+
case response
|
607
|
+
when Net::HTTPSuccess then YAML::load( response.body )
|
608
|
+
else
|
609
|
+
response.error!
|
610
|
+
end
|
611
|
+
end
|
612
|
+
|
613
|
+
def http_post( weblog, url, obj )
|
614
|
+
require 'net/http'
|
615
|
+
response =
|
616
|
+
Net::HTTP.new( weblog.host, weblog.port ).start do |http|
|
617
|
+
http.post( File.expand_path( "remote/#{ url }", weblog.path ), obj.to_yaml, "Content-Type" => "text/yaml" )
|
618
|
+
end
|
619
|
+
case response
|
620
|
+
when Net::HTTPSuccess then YAML::load( response.body )
|
621
|
+
else
|
622
|
+
response.error!
|
623
|
+
end
|
624
|
+
end
|
625
|
+
|
626
|
+
def http_post_remote( weblog, entry_id )
|
627
|
+
entry = http_get( weblog, "post", entry_id )
|
628
|
+
if entry.class == Errno::ENOENT
|
629
|
+
entry = http_get( weblog, 'new' )
|
630
|
+
entry.author = @config['username']
|
631
|
+
entry.title = entry_id.split( '/' ).
|
632
|
+
last.
|
633
|
+
gsub( /^\w|_\w|[A-Z]/ ) { |up| " #{up[-1, 1].upcase}" }.
|
634
|
+
strip
|
635
|
+
end
|
636
|
+
entry = aorta( entry )
|
637
|
+
return if entry.nil?
|
638
|
+
|
639
|
+
rsp = http_post( weblog, "post/#{ entry_id }", entry )
|
640
|
+
http_get( weblog, "upgen" ) if @config['post upgen']
|
641
|
+
p rsp
|
642
|
+
end
|
643
|
+
|
644
|
+
def http_edit_remote( weblog )
|
645
|
+
config = http_get( weblog, "edit" )
|
646
|
+
config = aorta( config )
|
647
|
+
return if config.nil?
|
648
|
+
p http_post( weblog, "edit", config )
|
649
|
+
end
|
650
|
+
|
651
|
+
def http_list_remote( weblog, inpath = '' )
|
652
|
+
require 'hobix/storage/filesys'
|
653
|
+
entries = http_get( weblog, 'list', inpath )
|
654
|
+
if entries.empty?
|
655
|
+
puts "** No posts found in the weblog for path '#{inpath}'."
|
656
|
+
else
|
657
|
+
tabular_entries( entries )
|
658
|
+
end
|
659
|
+
end
|
660
|
+
|
661
|
+
def http_search_remote( weblog, words, inpath = '' )
|
662
|
+
require 'hobix/storage/filesys'
|
663
|
+
entries = http_get( weblog, 'search', words, inpath )
|
664
|
+
if entries.empty?
|
665
|
+
puts "** No posts found in the weblog for path '#{inpath}'."
|
666
|
+
else
|
667
|
+
tabular_entries( entries )
|
668
|
+
end
|
669
|
+
end
|
670
|
+
|
671
|
+
def http_patch_remote( *args )
|
672
|
+
puts "** Weblogs cannot be patched over the wire yet."
|
673
|
+
exit
|
674
|
+
end
|
675
|
+
end
|
676
|
+
end
|
677
|
+
|