hobix 0.4
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.
- checksums.yaml +7 -0
- data/bin/hobix +90 -0
- data/lib/hobix/api.rb +91 -0
- data/lib/hobix/article.rb +22 -0
- data/lib/hobix/base.rb +477 -0
- data/lib/hobix/bixwik.rb +200 -0
- data/lib/hobix/commandline.rb +661 -0
- data/lib/hobix/comments.rb +99 -0
- data/lib/hobix/config.rb +39 -0
- data/lib/hobix/datamarsh.rb +110 -0
- data/lib/hobix/entry.rb +83 -0
- data/lib/hobix/facets/comments.rb +74 -0
- data/lib/hobix/facets/publisher.rb +314 -0
- data/lib/hobix/facets/trackbacks.rb +80 -0
- data/lib/hobix/linklist.rb +76 -0
- data/lib/hobix/out/atom.rb +92 -0
- data/lib/hobix/out/erb.rb +64 -0
- data/lib/hobix/out/okaynews.rb +55 -0
- data/lib/hobix/out/quick.rb +312 -0
- data/lib/hobix/out/rdf.rb +97 -0
- data/lib/hobix/out/redrum.rb +26 -0
- data/lib/hobix/out/rss.rb +115 -0
- data/lib/hobix/plugin/bloglines.rb +73 -0
- data/lib/hobix/plugin/calendar.rb +220 -0
- data/lib/hobix/plugin/flickr.rb +110 -0
- data/lib/hobix/plugin/recent_comments.rb +82 -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 +398 -0
- data/lib/hobix/trackbacks.rb +94 -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 +860 -0
- data/lib/hobix.rb +223 -0
- metadata +87 -0
@@ -0,0 +1,661 @@
|
|
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
|
+
end
|
113
|
+
|
114
|
+
# List all your weblogs
|
115
|
+
def blogs_weblog_explain; "List your weblogs."; end
|
116
|
+
def blogs_weblog_args; []; end
|
117
|
+
def blogs_weblog
|
118
|
+
if @config['weblogs'].respond_to? :sort
|
119
|
+
blogs = @config['weblogs'].sort
|
120
|
+
name_width = blogs.collect { |b| b[0].length }.max
|
121
|
+
tabular( blogs, [[-name_width, 0, 'weblog-name'], [-40, 1, 'path']] )
|
122
|
+
else
|
123
|
+
puts "** You have no blogs set up. Use `hobix setup_blogs' to get started."
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def load_patchsets
|
128
|
+
File.open( "#{ Hobix::SHARE_PATH }/default-blog-modes.yaml" ) { |f| YAML::load( f ) }
|
129
|
+
end
|
130
|
+
|
131
|
+
# Create a new skeleton for a weblog
|
132
|
+
def create_weblog_explain; "Create a brand new weblog."; end
|
133
|
+
def create_weblog_args; ['weblog-name', '/path/to/']; end
|
134
|
+
def create_weblog( name, path )
|
135
|
+
@config['weblogs'] ||= {}
|
136
|
+
if @config['weblogs'][name]
|
137
|
+
print "*** Blog '#{ name }' exists already! Overwrite?? [y/N]: "
|
138
|
+
if gets.strip.upcase != 'Y'
|
139
|
+
puts "*** Creation of weblog `#{ name }' aborted."
|
140
|
+
return
|
141
|
+
end
|
142
|
+
end
|
143
|
+
path = File.expand_path( path )
|
144
|
+
puts <<-NOTE
|
145
|
+
|*** Creation of weblog `#{ name }' will add the following directory"
|
146
|
+
| structure to directory #{ path }"
|
147
|
+
|
|
148
|
+
| #{ path }
|
149
|
+
| hobix.yaml <- configuration
|
150
|
+
|
|
151
|
+
| entries/ <- edit and organize
|
152
|
+
| your news items,
|
153
|
+
| articles and so on.
|
154
|
+
|
|
155
|
+
| skel/ <- contains your
|
156
|
+
| templates
|
157
|
+
|
|
158
|
+
| htdocs/ <- html is created here,
|
159
|
+
| store all your images here,
|
160
|
+
| this is your viewable
|
161
|
+
| websyht
|
162
|
+
|
|
163
|
+
| lib/ <- extra hobix libraries
|
164
|
+
| (plugins) go here
|
165
|
+
|
|
166
|
+
NOTE
|
167
|
+
print "Create this structure? [y/N]: "
|
168
|
+
if gets.strip.upcase != 'Y'
|
169
|
+
puts "*** Creation of weblog `#{ name }' aborted."
|
170
|
+
return
|
171
|
+
end
|
172
|
+
|
173
|
+
modes = load_patchsets
|
174
|
+
|
175
|
+
puts "The default blog is available in the following modes:"
|
176
|
+
puts " #{ modes.keys.join( ', ' ) }"
|
177
|
+
puts
|
178
|
+
mode = nil
|
179
|
+
loop do
|
180
|
+
print "Modes: [Comma between each mode or Enter for none] "
|
181
|
+
mode = gets.strip.downcase
|
182
|
+
m = mode
|
183
|
+
break if mode.empty? or not mode.split( /,/ ).detect { |m| m.strip!; not modes.has_key?( m ) }
|
184
|
+
puts "*** No `#{ m }' mode available."
|
185
|
+
end
|
186
|
+
|
187
|
+
require 'fileutils'
|
188
|
+
FileUtils.makedirs path
|
189
|
+
FileUtils.cp_r Dir.glob( "#{ Hobix::SHARE_PATH }/default-blog/*" ), path
|
190
|
+
|
191
|
+
# apply any patches
|
192
|
+
patchlist = mode.split( /,/ ).map { |m| modes[m.strip] }.flatten.uniq
|
193
|
+
require 'hobix/util/patcher'
|
194
|
+
patchlist.collect! { |p| "#{ Hobix::SHARE_PATH }/default-blog.#{ p }.patch" }
|
195
|
+
patcher = Hobix::Util::Patcher[ *patchlist ]
|
196
|
+
patcher.apply( path )
|
197
|
+
|
198
|
+
hobix_yaml = File.join( path, "hobix.yaml" )
|
199
|
+
join_as_author( name, hobix_yaml )
|
200
|
+
weblog = Hobix::Weblog.load( hobix_yaml )
|
201
|
+
weblog.setup
|
202
|
+
edit_action( weblog )
|
203
|
+
end
|
204
|
+
|
205
|
+
# Add a weblog to local config
|
206
|
+
def add_weblog_explain; "Adds a pre-existing hobix weblog to your list."; end
|
207
|
+
def add_weblog_args; ['weblog-name', '/path/to/hobix.yaml']; end
|
208
|
+
def add_weblog( name, path )
|
209
|
+
@config['weblogs'] ||= {}
|
210
|
+
path = File.expand_path( path )
|
211
|
+
puts "*** Checking for existence of blog."
|
212
|
+
require 'hobix/weblog'
|
213
|
+
if File.directory? path
|
214
|
+
path = File.join( path, 'hobix.yaml' )
|
215
|
+
puts "*** Path is a directory, using `#{ path }'."
|
216
|
+
end
|
217
|
+
unless File.exists? path
|
218
|
+
puts "*** No file `#{ path }' found! Aborting."
|
219
|
+
return
|
220
|
+
end
|
221
|
+
join_as_author( name, path )
|
222
|
+
end
|
223
|
+
|
224
|
+
def join_as_author( name, path )
|
225
|
+
weblog = Hobix::Weblog.load( path )
|
226
|
+
puts "*** Joining blog `#{ weblog.title }', adding you as author."
|
227
|
+
weblog.authors[@config['username']] = @config['personal']
|
228
|
+
weblog.save( path )
|
229
|
+
@config['weblogs'][name] = path
|
230
|
+
save_config
|
231
|
+
end
|
232
|
+
|
233
|
+
# Update the site
|
234
|
+
def upgen_action_explain; "Update site with only the latest changes."; end
|
235
|
+
def upgen_action_args; ['weblog-name']; end
|
236
|
+
def upgen_action( weblog )
|
237
|
+
weblog.regenerate( :update )
|
238
|
+
end
|
239
|
+
|
240
|
+
# Regenerate the site
|
241
|
+
def regen_action_explain; "Regenerate the all the pages throughout the site."; end
|
242
|
+
def regen_action_args; ['weblog-name']; end
|
243
|
+
def regen_action( weblog )
|
244
|
+
weblog.regenerate
|
245
|
+
end
|
246
|
+
|
247
|
+
# Edit a weblog from local config
|
248
|
+
def edit_action_explain; "Edit weblog's configuration"; end
|
249
|
+
def edit_action_args; ['weblog-name']; end
|
250
|
+
def edit_action( weblog )
|
251
|
+
path = weblog.hobix_yaml
|
252
|
+
weblog = aorta( weblog )
|
253
|
+
return if weblog.nil?
|
254
|
+
weblog.save( path )
|
255
|
+
end
|
256
|
+
|
257
|
+
# Delete a weblog from local config
|
258
|
+
def del_weblog_explain; "Remove weblog from your list."; end
|
259
|
+
def del_weblog_args; ['weblog-name']; end
|
260
|
+
def del_weblog( name )
|
261
|
+
@config['weblogs'] ||= {}
|
262
|
+
@config['weblogs'].delete( name )
|
263
|
+
save_config
|
264
|
+
end
|
265
|
+
|
266
|
+
# Run a DRuby daemon for blogs in your configuration
|
267
|
+
def druby_weblog_explain; "Start the DRuby daemon for weblogs in your config."; end
|
268
|
+
def druby_weblog_args; []; end
|
269
|
+
def druby_weblog
|
270
|
+
if @config['weblogs']
|
271
|
+
unless @config['druby']
|
272
|
+
@config['druby'] = 'druby://:4081'
|
273
|
+
puts "** No drb url found, using #{ @config['druby'] }"
|
274
|
+
end
|
275
|
+
require 'drb'
|
276
|
+
blogs = {}
|
277
|
+
@config['weblogs'].each do |name, path|
|
278
|
+
blogs[name] = Hobix::Weblog.load path
|
279
|
+
end
|
280
|
+
require 'hobix/api'
|
281
|
+
api = Hobix::API.new blogs
|
282
|
+
DRb.start_service @config['druby'], api
|
283
|
+
DRb.thread.join
|
284
|
+
else
|
285
|
+
puts "** No blogs found in the configuration."
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
# Patch a weblog
|
290
|
+
def patch_action_explain; "Applies a patch to a weblog."; end
|
291
|
+
def patch_action_args; ['weblog-name', 'patch-name']; end
|
292
|
+
def patch_action( weblog, patch )
|
293
|
+
require 'hobix/util/patcher'
|
294
|
+
modes = load_patchsets
|
295
|
+
patchlist = modes[patch.strip].map { |p| "#{ Hobix::SHARE_PATH }/default-blog.#{ p }.patch" }
|
296
|
+
patcher = Hobix::Util::Patcher[ *patchlist ]
|
297
|
+
patcher.apply( weblog.path )
|
298
|
+
end
|
299
|
+
|
300
|
+
# List entries
|
301
|
+
def list_action_explain; "List all posts within a given path."; end
|
302
|
+
def list_action_args; ['weblog-name', 'search/path']; end
|
303
|
+
def list_action( weblog, inpath = '' )
|
304
|
+
entries = weblog.storage.find( :all => true, :inpath => inpath )
|
305
|
+
if entries.empty?
|
306
|
+
puts "** No posts found in the weblog for path '#{inpath}'."
|
307
|
+
else
|
308
|
+
tabular_entries( entries )
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
# Search (disabled in 0.4)
|
313
|
+
# def search_action_explain; "Search for words within posts of a given path."; end
|
314
|
+
# def search_action_args; ['weblog-name', 'word1,word2', 'search/path']; end
|
315
|
+
# def search_action( weblog, words, inpath = '' )
|
316
|
+
# entries = weblog.storage.find( :all => true, :inpath => inpath, :search => words.split( ',' ) )
|
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
|
+
# Post a new entry
|
325
|
+
def post_action_explain; "Add or edit a post with identifier 'shortName'.\n" +
|
326
|
+
"(You can use full paths. 'blog/weddings/anotherPatheticWedding')\n" +
|
327
|
+
"'type' specifies the type of entry to create if the entry does not\n" +
|
328
|
+
"already exist." ; end
|
329
|
+
def post_action_args; ['weblog-name', '[type]', 'shortName']; end
|
330
|
+
def post_action( weblog, *args )
|
331
|
+
if args.size == 1
|
332
|
+
entry_type = nil
|
333
|
+
entry_id = args[0]
|
334
|
+
elsif args.size == 2
|
335
|
+
( entry_type, entry_id ) = args
|
336
|
+
else
|
337
|
+
raise ArgumentError, "Wrong number of arguments"
|
338
|
+
end
|
339
|
+
|
340
|
+
entry_class = weblog.entry_class(entry_type)
|
341
|
+
begin
|
342
|
+
entry = weblog.storage.load_entry( entry_id )
|
343
|
+
if entry_type and not entry.instance_of? entry_class
|
344
|
+
raise TypeError, "#{entry_id} already exists with a different type (#{entry.class})"
|
345
|
+
end
|
346
|
+
rescue Errno::ENOENT
|
347
|
+
entry = entry_class.new
|
348
|
+
entry.author = @config['username']
|
349
|
+
entry.title = entry_id.split( '/' ).
|
350
|
+
last.
|
351
|
+
gsub( /^\w|\W\w|_\w|[A-Z]/ ) { |up| " #{up[-1, 1].upcase}" }.
|
352
|
+
strip
|
353
|
+
end
|
354
|
+
entry = aorta( entry )
|
355
|
+
return if entry.nil?
|
356
|
+
|
357
|
+
begin
|
358
|
+
weblog.storage.save_entry( entry_id, entry )
|
359
|
+
rescue Errno::ENOENT
|
360
|
+
puts
|
361
|
+
puts "The category for #{entry_id} doesn't exist."
|
362
|
+
print "Create it [Yn]? "
|
363
|
+
response = gets.strip
|
364
|
+
|
365
|
+
if response.empty? or response =~ /^[Yy]/
|
366
|
+
weblog.storage.save_entry( entry_id, entry, true )
|
367
|
+
else
|
368
|
+
puts
|
369
|
+
print "Supply a different shortName [<Enter> to discard post]: "
|
370
|
+
response = gets.strip
|
371
|
+
|
372
|
+
if response.empty?
|
373
|
+
return nil
|
374
|
+
else
|
375
|
+
entry_id = response
|
376
|
+
retry
|
377
|
+
end
|
378
|
+
end
|
379
|
+
end
|
380
|
+
weblog.regenerate( :update ) if @config['post upgen']
|
381
|
+
end
|
382
|
+
|
383
|
+
##
|
384
|
+
## Setup user's RC
|
385
|
+
##
|
386
|
+
def setup
|
387
|
+
@config = {}
|
388
|
+
puts "Welcome to hobix (a simple weblog tool). Looks like your"
|
389
|
+
puts "first time running hobix, eh? Time to get a bit of information"
|
390
|
+
puts "from you before you start using hobix. (All of this will be stored"
|
391
|
+
puts "in the file #{ Hobix::CommandLine::RC } if you need to edit.)"
|
392
|
+
puts
|
393
|
+
|
394
|
+
username = ''
|
395
|
+
default_user = ''
|
396
|
+
user_prompt = 'Your hobix username'
|
397
|
+
if ENV['USER']
|
398
|
+
default_user = ENV['USER']
|
399
|
+
user_prompt << " [<Enter> for #{ ENV['USER'] }]"
|
400
|
+
end
|
401
|
+
while username.empty?
|
402
|
+
puts
|
403
|
+
print "#{ user_prompt }: "
|
404
|
+
username = gets.strip
|
405
|
+
if username.empty?
|
406
|
+
username = default_user
|
407
|
+
end
|
408
|
+
end
|
409
|
+
@config['username'] = username
|
410
|
+
|
411
|
+
puts
|
412
|
+
puts "Your EDITOR environment variable is set to '#{ ENV['EDITOR'] }'."
|
413
|
+
puts "You can edit entries with your EDITOR or you can just use hobix."
|
414
|
+
puts "** NOTE: If you don't use your own editor, then you will be using"
|
415
|
+
puts " the Hobix built-in object editor, which is highly experimental"
|
416
|
+
puts " and may not work on your platform.)"
|
417
|
+
print "Use your EDITOR to edit entries? [Y/n]: "
|
418
|
+
editor = gets.strip.upcase
|
419
|
+
|
420
|
+
if editor == 'N'
|
421
|
+
@config['use editor'] = false
|
422
|
+
else
|
423
|
+
@config['use editor'] = true
|
424
|
+
end
|
425
|
+
|
426
|
+
puts
|
427
|
+
puts "After posting a new entry, would you like Hobix to automatically"
|
428
|
+
print "update the site? [Y/n]: "
|
429
|
+
post_upgen = gets.strip.upcase
|
430
|
+
|
431
|
+
if post_upgen == 'N'
|
432
|
+
@config['post upgen'] = false
|
433
|
+
else
|
434
|
+
@config['post upgen'] = true
|
435
|
+
end
|
436
|
+
save_config
|
437
|
+
end
|
438
|
+
|
439
|
+
##
|
440
|
+
## Setup personal information
|
441
|
+
##
|
442
|
+
def setup_personal
|
443
|
+
@config['personal'] ||= {}
|
444
|
+
puts
|
445
|
+
puts "Your personal information has not been setup yet."
|
446
|
+
[['name', 'Your real name', true],
|
447
|
+
['url', 'URL to your home page', false],
|
448
|
+
['email', 'Your e-mail address', false]].each do |k, txt, req|
|
449
|
+
print "#{ txt }: "
|
450
|
+
val = gets.strip
|
451
|
+
retry if req and val.empty?
|
452
|
+
@config['personal'][k] = val
|
453
|
+
end
|
454
|
+
save_config
|
455
|
+
end
|
456
|
+
|
457
|
+
##
|
458
|
+
## Extra setup, triggered upon installation
|
459
|
+
##
|
460
|
+
def setup_blogs
|
461
|
+
puts
|
462
|
+
puts " === Joining an existing weblog? ==="
|
463
|
+
puts "If you want to join an existing hobix weblog, we can do that now."
|
464
|
+
puts "Each weblog needs a name and a path. Use <ENTER> at any prompt"
|
465
|
+
puts "to simply move on."
|
466
|
+
loop do
|
467
|
+
puts
|
468
|
+
puts "Short name for weblog, used on the command line (i.e. hobix upgen blogName)."
|
469
|
+
print ": "
|
470
|
+
blogname = gets.strip
|
471
|
+
break if blogname.empty?
|
472
|
+
|
473
|
+
print "Path to weblog's hobix.yaml `#{ blogname }': "
|
474
|
+
blogpath = gets.strip
|
475
|
+
if blogpath.empty?
|
476
|
+
puts "*** Aborting setup of weblog `#{ blogname }'."
|
477
|
+
break
|
478
|
+
end
|
479
|
+
add_weblog( blogname, blogpath )
|
480
|
+
end
|
481
|
+
|
482
|
+
puts "To setup more weblogs later, use: hobix add #{ add_weblog_args.join( ' ' ) }"
|
483
|
+
puts
|
484
|
+
puts " === Create a new weblog? ==="
|
485
|
+
puts "If you want to create a new hobix weblog, we can do that now."
|
486
|
+
puts "Each weblog needs a name and a path. Use <ENTER> at any prompt"
|
487
|
+
puts "to simply move on."
|
488
|
+
loop do
|
489
|
+
puts
|
490
|
+
puts "Short name for weblog, used on the command line (i.e. hobix upgen blogName)."
|
491
|
+
print ": "
|
492
|
+
blogname = gets.strip
|
493
|
+
break if blogname.empty?
|
494
|
+
|
495
|
+
print "Path to create weblog `#{ blogname }': "
|
496
|
+
blogpath = gets.strip
|
497
|
+
if blogpath.empty?
|
498
|
+
puts "*** Aborting creation of weblog `#{ blogname }'."
|
499
|
+
break
|
500
|
+
end
|
501
|
+
create_weblog( blogname, blogpath )
|
502
|
+
end
|
503
|
+
puts "To create more weblogs later, use: hobix create #{ create_weblog_args.join( ' ' ) }"
|
504
|
+
puts
|
505
|
+
end
|
506
|
+
|
507
|
+
def aorta( obj )
|
508
|
+
if @config['use editor']
|
509
|
+
# I am quite displeased that Tempfile.open eats its blocks result,
|
510
|
+
# thereby necessitating this blecherous construct...
|
511
|
+
tempfile = nil
|
512
|
+
Tempfile.open("hobix.post") { |tempfile| tempfile << obj.to_yaml }
|
513
|
+
|
514
|
+
begin
|
515
|
+
created = File.mtime( tempfile.path )
|
516
|
+
system( "#{ ENV['EDITOR'] || 'vi' } #{ tempfile.path }" )
|
517
|
+
return nil unless File.exists?( tempfile.path )
|
518
|
+
|
519
|
+
if created < File.mtime( tempfile.path )
|
520
|
+
obj = YAML::load( tempfile.open )
|
521
|
+
else
|
522
|
+
puts "** Edit aborted"
|
523
|
+
obj = nil
|
524
|
+
end
|
525
|
+
rescue StandardError => e
|
526
|
+
puts "There was an error saving the entry: #{ e.class }: #{ e.message }"
|
527
|
+
print "Re-edit [Yn]? "
|
528
|
+
response = gets.strip
|
529
|
+
if response.empty? or response =~ /^[Yy]/
|
530
|
+
retry
|
531
|
+
else
|
532
|
+
puts "** Edit aborted"
|
533
|
+
obj = nil
|
534
|
+
end
|
535
|
+
ensure
|
536
|
+
# tempfile will get closed/unlinked when it's collected anyway;
|
537
|
+
# may as well do it here to provide some determinism for the user
|
538
|
+
begin
|
539
|
+
tempfile.close true
|
540
|
+
rescue
|
541
|
+
end
|
542
|
+
end
|
543
|
+
else
|
544
|
+
require 'hobix/util/objedit'
|
545
|
+
obj = Hobix::Util::ObjEdit( obj )
|
546
|
+
end
|
547
|
+
obj
|
548
|
+
end
|
549
|
+
|
550
|
+
def tabular( table, fields, desc = nil )
|
551
|
+
field_widths = fields.collect do |width, id, title|
|
552
|
+
([width.abs, title.length].max + 1) * ( width / width.abs )
|
553
|
+
end
|
554
|
+
client_format = field_widths.collect { |width| "%#{ width}s"}.join( ': ')
|
555
|
+
puts client_format % fields.collect { |width, id, title| title }
|
556
|
+
puts field_widths.collect { |width| "-" * width.abs }.join( ':-' )
|
557
|
+
table.each do |row|
|
558
|
+
puts client_format % fields.collect { |width, id, title| row[ id ] }
|
559
|
+
if desc
|
560
|
+
puts row[ desc ]
|
561
|
+
puts
|
562
|
+
end
|
563
|
+
end
|
564
|
+
end
|
565
|
+
|
566
|
+
def tabular_entries( entries )
|
567
|
+
entries.sort { |e1, e2| e1.id <=> e2.id }
|
568
|
+
name_width = entries.collect { |e| e.id.length }.max
|
569
|
+
rows = entries.inject([]) { |rows, entry| rows << [entry.id, entry.created] }
|
570
|
+
tabular( rows, [[-name_width, 0, 'shortName'], [-34, 1, 'created']] )
|
571
|
+
end
|
572
|
+
|
573
|
+
def puts( str = '' )
|
574
|
+
Kernel::puts str.gsub( /^\s+\|/, '' )
|
575
|
+
end
|
576
|
+
|
577
|
+
##
|
578
|
+
## Hobix over the wire
|
579
|
+
##
|
580
|
+
def http( *args )
|
581
|
+
p http_get( *args )
|
582
|
+
end
|
583
|
+
|
584
|
+
def http_get( weblog, *args )
|
585
|
+
require 'net/http'
|
586
|
+
response =
|
587
|
+
Net::HTTP.new( weblog.host, weblog.port ).start do |http|
|
588
|
+
http.get( File.expand_path( "remote/#{ args.join '/' }", weblog.path ) )
|
589
|
+
end
|
590
|
+
case response
|
591
|
+
when Net::HTTPSuccess then YAML::load( response.body )
|
592
|
+
else
|
593
|
+
response.error!
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
597
|
+
def http_post( weblog, url, obj )
|
598
|
+
require 'net/http'
|
599
|
+
response =
|
600
|
+
Net::HTTP.new( weblog.host, weblog.port ).start do |http|
|
601
|
+
http.post( File.expand_path( "remote/#{ url }", weblog.path ), obj.to_yaml, "Content-Type" => "text/yaml" )
|
602
|
+
end
|
603
|
+
case response
|
604
|
+
when Net::HTTPSuccess then YAML::load( response.body )
|
605
|
+
else
|
606
|
+
response.error!
|
607
|
+
end
|
608
|
+
end
|
609
|
+
|
610
|
+
def http_post_remote( weblog, entry_id )
|
611
|
+
entry = http_get( weblog, "post", entry_id )
|
612
|
+
if entry.class == Errno::ENOENT
|
613
|
+
entry = http_get( weblog, 'new' )
|
614
|
+
entry.author = @config['username']
|
615
|
+
entry.title = entry_id.split( '/' ).
|
616
|
+
last.
|
617
|
+
gsub( /^\w|_\w|[A-Z]/ ) { |up| " #{up[-1, 1].upcase}" }.
|
618
|
+
strip
|
619
|
+
end
|
620
|
+
entry = aorta( entry )
|
621
|
+
return if entry.nil?
|
622
|
+
|
623
|
+
rsp = http_post( weblog, "post/#{ entry_id }", entry )
|
624
|
+
http_get( weblog, "upgen" ) if @config['post upgen']
|
625
|
+
p rsp
|
626
|
+
end
|
627
|
+
|
628
|
+
def http_edit_remote( weblog )
|
629
|
+
config = http_get( weblog, "edit" )
|
630
|
+
config = aorta( config )
|
631
|
+
return if config.nil?
|
632
|
+
p http_post( weblog, "edit", config )
|
633
|
+
end
|
634
|
+
|
635
|
+
def http_list_remote( weblog, inpath = '' )
|
636
|
+
require 'hobix/storage/filesys'
|
637
|
+
entries = http_get( weblog, 'list', inpath )
|
638
|
+
if entries.empty?
|
639
|
+
puts "** No posts found in the weblog for path '#{inpath}'."
|
640
|
+
else
|
641
|
+
tabular_entries( entries )
|
642
|
+
end
|
643
|
+
end
|
644
|
+
|
645
|
+
def http_search_remote( weblog, words, inpath = '' )
|
646
|
+
require 'hobix/storage/filesys'
|
647
|
+
entries = http_get( weblog, 'search', words, inpath )
|
648
|
+
if entries.empty?
|
649
|
+
puts "** No posts found in the weblog for path '#{inpath}'."
|
650
|
+
else
|
651
|
+
tabular_entries( entries )
|
652
|
+
end
|
653
|
+
end
|
654
|
+
|
655
|
+
def http_patch_remote( *args )
|
656
|
+
puts "** Weblogs cannot be patched over the wire yet."
|
657
|
+
exit
|
658
|
+
end
|
659
|
+
end
|
660
|
+
end
|
661
|
+
|