pluto 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/{History.markdown → History.md} +0 -0
- data/Manifest.txt +7 -18
- data/README.md +172 -0
- data/Rakefile +11 -6
- data/config/pluto.index.yml +19 -0
- data/lib/pluto.rb +14 -12
- data/lib/pluto/cli/main.rb +213 -0
- data/lib/pluto/cli/opts.rb +38 -2
- data/lib/pluto/formatter.rb +17 -39
- data/lib/pluto/installer.rb +58 -0
- data/lib/pluto/lister.rb +42 -0
- data/lib/pluto/manifest_helpers.rb +50 -0
- data/lib/pluto/models.rb +60 -5
- data/lib/pluto/schema.rb +38 -6
- data/lib/pluto/updater.rb +90 -114
- data/lib/pluto/version.rb +1 -1
- metadata +65 -33
- data/README.markdown +0 -107
- data/lib/pluto/cli/runner.rb +0 -96
- data/lib/pluto/server.rb +0 -108
- data/lib/pluto/server/public/feed-icon-10x10.png +0 -0
- data/lib/pluto/server/public/style.css +0 -79
- data/lib/pluto/server/views/_debug.erb +0 -16
- data/lib/pluto/server/views/_version.erb +0 -5
- data/lib/pluto/server/views/debug.erb +0 -14
- data/lib/pluto/server/views/feeds.erb +0 -13
- data/lib/pluto/server/views/index.erb +0 -3
- data/lib/pluto/server/views/items.erb +0 -12
- data/lib/pluto/server/views/layout.erb +0 -22
- data/lib/pluto/server/views/sites.erb +0 -21
- data/templates/blank.html.erb +0 -133
- data/templates/blank.top.html.erb +0 -10
- data/templates/blank.txt +0 -5
- data/templates/feed-icon-10x10.png +0 -0
data/lib/pluto/cli/opts.rb
CHANGED
@@ -2,12 +2,27 @@ module Pluto
|
|
2
2
|
|
3
3
|
class Opts
|
4
4
|
|
5
|
+
def initialize
|
6
|
+
load_shortcuts
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
def merge_gli_options!( options={} )
|
11
|
+
@verbose = true if options[:verbose] == true
|
12
|
+
|
13
|
+
@config_path = options[:config] if options[:config].present?
|
14
|
+
@output_path = options[:output] if options[:output].present?
|
15
|
+
|
16
|
+
@manifest = options[:template] if options[:template].present?
|
17
|
+
end
|
18
|
+
|
19
|
+
|
5
20
|
def manifest=(value)
|
6
21
|
@manifest = value
|
7
22
|
end
|
8
23
|
|
9
24
|
def manifest
|
10
|
-
@manifest || 'blank
|
25
|
+
@manifest || 'blank'
|
11
26
|
end
|
12
27
|
|
13
28
|
def verbose=(value)
|
@@ -23,7 +38,8 @@ class Opts
|
|
23
38
|
end
|
24
39
|
|
25
40
|
def config_path
|
26
|
-
@config_path || '~/.pluto'
|
41
|
+
## @config_path || '~/.pluto' --- old code
|
42
|
+
@config_path || File.join( Env.home, '.pluto' )
|
27
43
|
end
|
28
44
|
|
29
45
|
|
@@ -35,6 +51,26 @@ class Opts
|
|
35
51
|
@output_path || '.'
|
36
52
|
end
|
37
53
|
|
54
|
+
def load_shortcuts
|
55
|
+
@shortcuts = YAML.load_file( "#{Pluto.root}/config/pluto.index.yml" )
|
56
|
+
end
|
57
|
+
|
58
|
+
def map_fetch_shortcut( key )
|
59
|
+
# NB: always returns an array!!! 0,1 or more entries
|
60
|
+
# - no value - return empty ary
|
61
|
+
|
62
|
+
## todo: normalize key???
|
63
|
+
value = @shortcuts.fetch( key, nil )
|
64
|
+
|
65
|
+
if value.nil?
|
66
|
+
[]
|
67
|
+
elsif value.kind_of?( String )
|
68
|
+
[value]
|
69
|
+
else # assume it's an array already; ## todo: check if it's an array
|
70
|
+
value
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
38
74
|
|
39
75
|
end # class Opts
|
40
76
|
|
data/lib/pluto/formatter.rb
CHANGED
@@ -5,7 +5,7 @@ class Formatter
|
|
5
5
|
include LogUtils::Logging
|
6
6
|
|
7
7
|
include Models
|
8
|
-
|
8
|
+
include ManifestHelper
|
9
9
|
|
10
10
|
def initialize( opts, config )
|
11
11
|
@opts = opts
|
@@ -28,10 +28,23 @@ class Formatter
|
|
28
28
|
manifests = installed_template_manifests.select { |m| m[0] == manifest_name+'.txt' }
|
29
29
|
|
30
30
|
if manifests.empty?
|
31
|
-
|
32
|
-
|
31
|
+
|
32
|
+
### try - autodownload
|
33
|
+
puts "*** template pack '#{manifest_name}' not found; trying auto-install..."
|
34
|
+
|
35
|
+
Installer.new( opts ).install( manifest_name )
|
36
|
+
|
37
|
+
### try again
|
38
|
+
|
39
|
+
# check for matching manifests
|
40
|
+
manifests = installed_template_manifests.select { |m| m[0] == manifest_name+'.txt' }
|
41
|
+
|
42
|
+
if manifests.empty?
|
43
|
+
puts "*** error: unknown template pack '#{manifest_name}'; use pluto ls to list installed template packs"
|
44
|
+
exit 2
|
45
|
+
end
|
33
46
|
end
|
34
|
-
|
47
|
+
|
35
48
|
manifestsrc = manifests[0][1]
|
36
49
|
pakpath = opts.output_path
|
37
50
|
|
@@ -40,41 +53,6 @@ class Formatter
|
|
40
53
|
Pakman::Templater.new.merge_pak( manifestsrc, pakpath, binding, name )
|
41
54
|
end
|
42
55
|
|
43
|
-
private
|
44
|
-
|
45
|
-
def installed_template_manifest_patterns
|
46
|
-
|
47
|
-
# 1) search . # that is, working/current dir
|
48
|
-
# 2) search <config_dir>
|
49
|
-
# 3) search <gem>/templates
|
50
|
-
|
51
|
-
builtin_patterns = [
|
52
|
-
"#{Pluto.root}/templates/*.txt"
|
53
|
-
]
|
54
|
-
config_patterns = [
|
55
|
-
"#{File.expand_path(opts.config_path)}/*.txt",
|
56
|
-
"#{File.expand_path(opts.config_path)}/*/*.txt"
|
57
|
-
]
|
58
|
-
current_patterns = [
|
59
|
-
"*.txt",
|
60
|
-
"*/*.txt"
|
61
|
-
]
|
62
|
-
|
63
|
-
patterns = []
|
64
|
-
patterns += current_patterns
|
65
|
-
patterns += config_patterns
|
66
|
-
patterns += builtin_patterns
|
67
|
-
end
|
68
|
-
|
69
|
-
def installed_template_manifests
|
70
|
-
excludes = [
|
71
|
-
"Manifest.txt",
|
72
|
-
"*/Manifest.txt"
|
73
|
-
]
|
74
|
-
|
75
|
-
Pakman::Finder.new.find_manifests( installed_template_manifest_patterns, excludes )
|
76
|
-
end
|
77
|
-
|
78
56
|
end # class Formatter
|
79
57
|
|
80
58
|
end # module Pluto
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Pluto
|
2
|
+
|
3
|
+
class Installer
|
4
|
+
|
5
|
+
### fix: remove opts, use config (wrapped!!)
|
6
|
+
|
7
|
+
include LogUtils::Logging
|
8
|
+
|
9
|
+
def initialize( opts )
|
10
|
+
@opts = opts
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :opts
|
14
|
+
|
15
|
+
|
16
|
+
def install( shortcut_or_source )
|
17
|
+
|
18
|
+
logger.debug "fetch >#{shortcut_or_source}<"
|
19
|
+
|
20
|
+
## check for builtin shortcut (assume no / or \)
|
21
|
+
if shortcut_or_source.index( '/' ).nil? && shortcut_or_source.index( '\\' ).nil?
|
22
|
+
shortcut = shortcut_or_source
|
23
|
+
sources = opts.map_fetch_shortcut( shortcut )
|
24
|
+
|
25
|
+
if sources.empty?
|
26
|
+
puts "** Error: No mapping found for shortcut '#{shortcut}'."
|
27
|
+
return
|
28
|
+
end
|
29
|
+
puts " Mapping fetch shortcut '#{shortcut}' to: #{sources.join(',')}"
|
30
|
+
else
|
31
|
+
sources = [shortcut_or_source] # pass arg through unmapped
|
32
|
+
end
|
33
|
+
|
34
|
+
sources.each do |source|
|
35
|
+
install_template( source )
|
36
|
+
end
|
37
|
+
|
38
|
+
end # method run
|
39
|
+
|
40
|
+
|
41
|
+
def install_template( src )
|
42
|
+
# src = 'http://github.com/geraldb/slideshow/raw/d98e5b02b87ee66485431b1bee8fb6378297bfe4/code/templates/fullerscreen.txt'
|
43
|
+
# src = 'http://github.com/geraldb/sandbox/raw/13d4fec0908fbfcc456b74dfe2f88621614b5244/s5blank/s5blank.txt'
|
44
|
+
uri = URI.parse( src )
|
45
|
+
logger.debug "scheme: #{uri.scheme}, host: #{uri.host}, port: #{uri.port}, path: #{uri.path}"
|
46
|
+
|
47
|
+
pakname = File.basename( uri.path ).downcase.gsub('.txt','')
|
48
|
+
pakpath = File.expand_path( "#{opts.config_path}/#{pakname}" )
|
49
|
+
|
50
|
+
logger.debug "packname >#{pakname}<"
|
51
|
+
logger.debug "pakpath >#{pakpath}<"
|
52
|
+
|
53
|
+
Pakman::Fetcher.new.fetch_pak( src, pakpath )
|
54
|
+
end
|
55
|
+
|
56
|
+
end # class Installer
|
57
|
+
|
58
|
+
end # module Pluto
|
data/lib/pluto/lister.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
module Pluto
|
2
|
+
|
3
|
+
class Lister
|
4
|
+
|
5
|
+
include LogUtils::Logging
|
6
|
+
|
7
|
+
include ManifestHelper
|
8
|
+
|
9
|
+
def initialize( opts )
|
10
|
+
@opts = opts
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :opts
|
14
|
+
|
15
|
+
def list
|
16
|
+
home = Env.home
|
17
|
+
## replace home w/ ~ (to make out more readable (shorter))
|
18
|
+
## e.g. use gsub( home, '~' )
|
19
|
+
|
20
|
+
puts ''
|
21
|
+
puts 'Installed template packs in search path'
|
22
|
+
|
23
|
+
installed_template_manifest_patterns.each_with_index do |pattern,i|
|
24
|
+
puts " [#{i+1}] #{pattern.gsub(home,'~')}"
|
25
|
+
end
|
26
|
+
puts ' include:'
|
27
|
+
|
28
|
+
manifests = installed_template_manifests
|
29
|
+
if manifests.empty?
|
30
|
+
puts " -- none --"
|
31
|
+
else
|
32
|
+
manifests.each do |manifest|
|
33
|
+
pakname = manifest[0].gsub('.txt','')
|
34
|
+
manifestpath = manifest[1].gsub(home,'~')
|
35
|
+
puts "%16s (%s)" % [pakname,manifestpath]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end # method list
|
39
|
+
|
40
|
+
end # class Lister
|
41
|
+
|
42
|
+
end # module Pluto
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Pluto
|
2
|
+
|
3
|
+
module ManifestHelper
|
4
|
+
|
5
|
+
## shared methods for handling manifest lookups
|
6
|
+
##
|
7
|
+
# note: required attribs (in host class) include:
|
8
|
+
# - opts.config_path
|
9
|
+
|
10
|
+
def installed_template_manifest_patterns
|
11
|
+
|
12
|
+
# 1) search . # that is, working/current dir
|
13
|
+
# 2) search <config_dir>
|
14
|
+
# 3) search <gem>/templates
|
15
|
+
|
16
|
+
###
|
17
|
+
# Note
|
18
|
+
# -- for now - no longer ship w/ builtin template packs
|
19
|
+
# - download on demand if needed
|
20
|
+
|
21
|
+
builtin_patterns = [
|
22
|
+
## "#{Pluto.root}/templates/*.txt"
|
23
|
+
]
|
24
|
+
config_patterns = [
|
25
|
+
## "#{File.expand_path(opts.config_path)}/*.txt",
|
26
|
+
"#{File.expand_path(opts.config_path)}/*/*.txt"
|
27
|
+
]
|
28
|
+
current_patterns = [
|
29
|
+
## "*.txt",
|
30
|
+
"*/*.txt"
|
31
|
+
]
|
32
|
+
|
33
|
+
patterns = []
|
34
|
+
patterns += current_patterns
|
35
|
+
patterns += config_patterns
|
36
|
+
patterns += builtin_patterns
|
37
|
+
end
|
38
|
+
|
39
|
+
def installed_template_manifests
|
40
|
+
excludes = [
|
41
|
+
"Manifest.txt",
|
42
|
+
"*/Manifest.txt"
|
43
|
+
]
|
44
|
+
|
45
|
+
Pakman::Finder.new.find_manifests( installed_template_manifest_patterns, excludes )
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
end # module Manifest
|
50
|
+
end # module Slideshow
|
data/lib/pluto/models.rb
CHANGED
@@ -1,13 +1,42 @@
|
|
1
1
|
module Pluto
|
2
2
|
module Models
|
3
|
-
|
3
|
+
|
4
4
|
class Feed < ActiveRecord::Base
|
5
5
|
self.table_name = 'feeds'
|
6
|
-
|
6
|
+
|
7
7
|
has_many :items
|
8
8
|
has_many :subscriptions
|
9
9
|
has_many :sites, :through => :subscriptions
|
10
|
-
|
10
|
+
|
11
|
+
|
12
|
+
def self.latest
|
13
|
+
# note: order by first non-null datetime field
|
14
|
+
# coalesce - supported by sqlite (yes), postgres (yes)
|
15
|
+
|
16
|
+
# note: if not published_at,touched_at or built_at use hardcoded 1999-01-01 for now
|
17
|
+
order( "coalesce(published_at,touched_at,built_at,'1999-01-01') desc" )
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def published_at?
|
22
|
+
read_attribute(:published_at).present?
|
23
|
+
end
|
24
|
+
|
25
|
+
def published_at
|
26
|
+
## todo/fix: use a new name - do NOT squeeze convenience lookup into existing
|
27
|
+
# db backed attribute
|
28
|
+
|
29
|
+
if read_attribute(:published_at).present?
|
30
|
+
read_attribute(:published_at)
|
31
|
+
elsif read_attribute(:touched_at).present?
|
32
|
+
## try touched_at (aka updated (ATOM))
|
33
|
+
read_attribute(:touched_at)
|
34
|
+
else ## try build_at (aka lastBuildDate (RSS))
|
35
|
+
read_attribute(:built_at)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end # class Feed
|
11
40
|
|
12
41
|
class Item < ActiveRecord::Base
|
13
42
|
self.table_name = 'items'
|
@@ -15,9 +44,30 @@ class Item < ActiveRecord::Base
|
|
15
44
|
belongs_to :feed
|
16
45
|
|
17
46
|
def self.latest
|
18
|
-
order
|
47
|
+
# note: order by first non-null datetime field
|
48
|
+
# coalesce - supported by sqlite (yes), postgres (yes)
|
49
|
+
|
50
|
+
# note: if not published_at,touched_at or built_at use hardcoded 1999-01-01 for now
|
51
|
+
order( "coalesce(published_at,touched_at,'1999-01-01') desc" )
|
19
52
|
end
|
20
|
-
|
53
|
+
|
54
|
+
def published_at?
|
55
|
+
read_attribute(:published_at).present?
|
56
|
+
end
|
57
|
+
|
58
|
+
def published_at
|
59
|
+
## todo/fix: use a new name - do NOT squeeze convenience lookup into existing
|
60
|
+
# db backed attribute
|
61
|
+
|
62
|
+
if read_attribute(:published_at).present?
|
63
|
+
read_attribute(:published_at)
|
64
|
+
else ## try touched_at (aka updated)
|
65
|
+
read_attribute(:touched_at)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end # class Item
|
70
|
+
|
21
71
|
|
22
72
|
class Site < ActiveRecord::Base
|
23
73
|
self.table_name = 'sites'
|
@@ -33,6 +83,11 @@ class Subscription < ActiveRecord::Base
|
|
33
83
|
belongs_to :feed
|
34
84
|
end
|
35
85
|
|
86
|
+
class Action < ActiveRecord::Base
|
87
|
+
self.table_name = 'actions'
|
88
|
+
|
89
|
+
end
|
90
|
+
|
36
91
|
|
37
92
|
end # module Models
|
38
93
|
end # module Pluto
|
data/lib/pluto/schema.rb
CHANGED
@@ -5,9 +5,11 @@ class CreateDb < ActiveRecord::Migration
|
|
5
5
|
|
6
6
|
def up
|
7
7
|
create_table :sites do |t|
|
8
|
-
t.string
|
9
|
-
t.string
|
10
|
-
t.
|
8
|
+
t.string :title, :null => false # e.g Planet Ruby, Planet JavaScript, etc.
|
9
|
+
t.string :key, :null => false # e.g. ruby, js, etc.
|
10
|
+
t.datetime :fetched_at # last fetched/checked date -- make not null ??
|
11
|
+
|
12
|
+
t.timestamps # created_at, updated_at
|
11
13
|
end
|
12
14
|
|
13
15
|
create_table :subscriptions do |t| # has_many join table (sites/feeds)
|
@@ -18,21 +20,51 @@ class CreateDb < ActiveRecord::Migration
|
|
18
20
|
|
19
21
|
create_table :feeds do |t|
|
20
22
|
t.string :title, :null => false
|
23
|
+
t.string :title2 # e.g. subtitle (atom)
|
24
|
+
t.text :summary # e.g. description (rss)
|
21
25
|
t.string :url, :null => false
|
22
26
|
t.string :feed_url, :null => false
|
27
|
+
t.string :generator # feed generator (e.g. wordpress, etc.) from feed
|
28
|
+
|
29
|
+
t.datetime :published_at # from feed published(atom)+ pubDate(rss)
|
30
|
+
t.datetime :built_at # from feed lastBuiltDate(rss)
|
31
|
+
t.datetime :touched_at # from feed updated(atom)
|
32
|
+
|
33
|
+
# -- our own (meta) fields
|
23
34
|
t.string :key, :null => false
|
24
|
-
t.
|
35
|
+
t.string :format # e.g. atom (1.0), rss 2.0, rss 0.7 etc.
|
36
|
+
t.string :etag # last etag
|
37
|
+
t.datetime :fetched_at # last fetched/checked date
|
38
|
+
t.timestamps # created_at, updated_at
|
25
39
|
end
|
26
40
|
|
27
41
|
create_table :items do |t|
|
28
42
|
t.string :title # todo: add some :null => false ??
|
29
|
-
t.string :url
|
30
43
|
t.string :guid
|
44
|
+
t.string :url
|
45
|
+
t.text :summary # e.g. description (rss), summary (atom)
|
31
46
|
t.text :content
|
32
|
-
|
47
|
+
|
48
|
+
t.datetime :published_at # from feed (published) + pubDate(rss)
|
49
|
+
t.datetime :touched_at # from feed updated (atom)
|
50
|
+
|
51
|
+
## todo: add :last_updated_at ?? (NOTE: updated_at already take by auto-timestamps)
|
33
52
|
t.references :feed, :null => false
|
53
|
+
|
54
|
+
t.datetime :fetched_at # last fetched/check date
|
55
|
+
t.timestamps # created_at, updated_at
|
56
|
+
|
57
|
+
## t.string :author
|
58
|
+
## todo: add author/authors, category/categories
|
59
|
+
end
|
60
|
+
|
61
|
+
create_table :actions do |t|
|
62
|
+
t.string :title # e.g. new site, new subscription, update feeds, etc.
|
63
|
+
t.string :object # todo: find better names for action attribs ??
|
64
|
+
t.string :object_type
|
34
65
|
t.timestamps
|
35
66
|
end
|
67
|
+
|
36
68
|
end
|
37
69
|
|
38
70
|
def down
|