pluto 0.7.0 → 0.8.0
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/{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
|