rypple 0.0.1
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/Gemfile +4 -0
- data/README +1 -0
- data/Rakefile +1 -0
- data/bin/rippleInstall.rb +169 -0
- data/lib/ripple/base.rb +181 -0
- data/lib/ripple/version.rb +3 -0
- data/lib/ripple.rb +1 -0
- data/pkg/ripple-0.0.1.gem +0 -0
- data/ripple.gemspec +22 -0
- data/ripple.yaml +5 -0
- metadata +102 -0
data/Gemfile
ADDED
data/README
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
A tool for integrating some remote file store (e.g. Dropbox) with a static site generator (e.g. jekyll) with some tools to ease remote updating of the site.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,169 @@
|
|
1
|
+
#!/bin/ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'ripple'
|
4
|
+
|
5
|
+
baseCGI = <<'eos'
|
6
|
+
#!/usr/bin/ruby
|
7
|
+
gemPath = "%%GEM_PATH"
|
8
|
+
configPath = "%%CONFIG_PATH"
|
9
|
+
inDir = "%%IN_DIR"
|
10
|
+
outDir = "%%OUT_DIR"
|
11
|
+
|
12
|
+
if !gemPath.empty?
|
13
|
+
$:.push(gemPath)
|
14
|
+
ENV['GEM_PATH'] = gemPath
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'cgi'
|
18
|
+
require 'rubygems'
|
19
|
+
require 'ripple'
|
20
|
+
require 'jekyll'
|
21
|
+
|
22
|
+
cgi = CGI.new
|
23
|
+
|
24
|
+
puts cgi.header
|
25
|
+
|
26
|
+
puts "<h1>Rippling . . .</h1>"
|
27
|
+
if Ripple.sync(configPath)
|
28
|
+
puts "<h1>Generating Static Site</h1>"
|
29
|
+
puts `%%COMMAND #{inDir} #{outDir}`
|
30
|
+
end
|
31
|
+
eos
|
32
|
+
|
33
|
+
updateHTML = <<'eos'
|
34
|
+
<html>
|
35
|
+
<head>
|
36
|
+
<title>Update Site with Ripple!</title>
|
37
|
+
</head>
|
38
|
+
<body>
|
39
|
+
<h1> Throw a stone into the pond..</h1>
|
40
|
+
<form action="update.cgi" method="POST">
|
41
|
+
<input type="submit" value="Ripple">
|
42
|
+
</form>
|
43
|
+
</body>
|
44
|
+
</html>
|
45
|
+
eos
|
46
|
+
|
47
|
+
htaccess = <<'eos'
|
48
|
+
AuthName "Ripple Updater"
|
49
|
+
AuthType Basic
|
50
|
+
AuthUserFile %%AUTH_FILE
|
51
|
+
Require valid-user
|
52
|
+
eos
|
53
|
+
|
54
|
+
configBase = File.join(ENV["HOME"], '.ripple')
|
55
|
+
puts "Configuring the Ripple update script for web use."
|
56
|
+
puts "Please enter directory for Ripple Configuration. Default:", configBase
|
57
|
+
directory = gets.chomp!
|
58
|
+
|
59
|
+
if !directory.empty?
|
60
|
+
configBase = directory
|
61
|
+
end
|
62
|
+
|
63
|
+
conf = Ripple.loadConfiguration(configBase)
|
64
|
+
session, client, keys = Ripple.connectToDropbox(configBase)
|
65
|
+
|
66
|
+
if !conf.nil? and !keys.nil?
|
67
|
+
Ripple.cleanup(conf, keys, configBase)
|
68
|
+
end
|
69
|
+
|
70
|
+
baseCGI.gsub!(/%%CONFIG_PATH/, configBase)
|
71
|
+
|
72
|
+
choice = false
|
73
|
+
insert = true
|
74
|
+
while !choice do
|
75
|
+
puts "Is your web host set up to use ruby gems? (y/N)"
|
76
|
+
answer = gets.chomp!.downcase!
|
77
|
+
if answer.nil? or answer.empty?
|
78
|
+
choice = true
|
79
|
+
elsif answer == "n" or answer == "y"
|
80
|
+
insert = (answer == "n")
|
81
|
+
choice = true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
if insert
|
86
|
+
gemPath = ''
|
87
|
+
if ENV.has_key?('GEM_HOME')
|
88
|
+
gemPath = ENV['GEM_HOME']
|
89
|
+
else
|
90
|
+
puts "Please enter search path for the ruby gems."
|
91
|
+
gemPath = gets.chomp!
|
92
|
+
end
|
93
|
+
|
94
|
+
baseCGI.gsub!(/%%GEM_PATH/, gemPath)
|
95
|
+
end
|
96
|
+
|
97
|
+
puts "Where should static site files be store?"
|
98
|
+
inDir = File.expand_path(gets.chomp!)
|
99
|
+
|
100
|
+
if !File.exists?(inDir)
|
101
|
+
begin
|
102
|
+
Dir.mkdir(inDir)
|
103
|
+
rescue SystemCallError
|
104
|
+
puts "Cannot create", inDir, ", create this directory and run this script again."
|
105
|
+
exit
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
baseCGI.gsub!(/%%IN_DIR/, inDir)
|
110
|
+
|
111
|
+
puts "Where should the static site generator output files?"
|
112
|
+
outDir = File.expand_path(gets.chomp!)
|
113
|
+
|
114
|
+
if !File.exists?(inDir)
|
115
|
+
begin
|
116
|
+
Dir.mkdir(outDir)
|
117
|
+
rescue SystemCallError
|
118
|
+
puts "Cannot create output directory", outDir, ", fix this and run this script again."
|
119
|
+
exit
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
baseCGI.gsub!(/%%OUT_DIR/, outDir)
|
124
|
+
|
125
|
+
command = File.join("#{ENV["GEM_HOME"]}", 'bin', 'jekyll')
|
126
|
+
if File.exists?(command)
|
127
|
+
puts "Please enter any arguments to pass to jekyll"
|
128
|
+
args = gets.chomp!
|
129
|
+
baseCGI.gsub!(/%%COMMAND/, command + ' ' + args)
|
130
|
+
end
|
131
|
+
|
132
|
+
rippleDir = File.join(inDir, 'ripple')
|
133
|
+
|
134
|
+
if !File.exists?(rippleDir)
|
135
|
+
begin
|
136
|
+
Dir.mkdir(rippleDir)
|
137
|
+
rescue SystemCallError
|
138
|
+
"Cannot create ripple directory."
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
File.open(File.join(rippleDir, 'update.html'), 'w', 0644) { |f| f.puts updateHTML }
|
143
|
+
|
144
|
+
out = File.join(rippleDir, 'update.cgi')
|
145
|
+
File.open(out, 'w', 0755) { |f| f.puts baseCGI }
|
146
|
+
|
147
|
+
puts "Should I enable basic user authentication for the update script? (Y/n):"
|
148
|
+
|
149
|
+
answer = gets.chomp!
|
150
|
+
if answer.nil? or answer.empty? or answer.downcase! == 'y'
|
151
|
+
print "Enter user name for authentication:"
|
152
|
+
user = gets.chomp!
|
153
|
+
print "Enter password for authentication:"
|
154
|
+
chars = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a
|
155
|
+
salt = chars[rand(chars.size - 1)] + chars[rand(chars.size - 1)]
|
156
|
+
pass = gets.chomp!.crypt(salt)
|
157
|
+
authFile = File.join(configBase, '.htpasswd')
|
158
|
+
File.open(authFile, 'w') { |f| f.puts "#{user}:#{pass}" }
|
159
|
+
htaccess.gsub!(/%%AUTH_FILE/, authFile)
|
160
|
+
File.open(File.join(rippleDir, '.htaccess'), 'w') { |f| f.puts htaccess }
|
161
|
+
end
|
162
|
+
|
163
|
+
puts "Attempting first update"
|
164
|
+
|
165
|
+
if Ripple.sync(configBase)
|
166
|
+
puts `jekyll #{inDir} #{outDir}`
|
167
|
+
else
|
168
|
+
puts "Ripple sync failed."
|
169
|
+
end
|
data/lib/ripple/base.rb
ADDED
@@ -0,0 +1,181 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
module Ripple
|
3
|
+
require 'fileutils'
|
4
|
+
require 'yaml'
|
5
|
+
require "rubygems"
|
6
|
+
require 'dropbox_sdk'
|
7
|
+
require 'pathname'
|
8
|
+
|
9
|
+
ACCESS_TYPE = :app_folder
|
10
|
+
DefaultConfiguration = {
|
11
|
+
:destinationDir => './test',
|
12
|
+
:dropbox => {
|
13
|
+
:sync => ['**'],
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
DropboxKeyFile = "dropbox_session.yaml"
|
18
|
+
RippleConfigFile = "ripple.yaml"
|
19
|
+
|
20
|
+
def Ripple.connectToDropbox(path)
|
21
|
+
dropConf = File.join(path, DropboxKeyFile)
|
22
|
+
#Load Dropbox API dropboxKeys from file, if applicable.
|
23
|
+
if File.exists?(dropConf)
|
24
|
+
dropboxKeys = YAML::load(File.read(dropConf))
|
25
|
+
else
|
26
|
+
puts "A Dropbox API key/secret is required for accessing your sync files."
|
27
|
+
puts "You can visit https://www.dropbox.com/developers/apps to generate these."
|
28
|
+
puts "Please enter your Dropbox API key"
|
29
|
+
dropboxKeys['key'] = gets.chomp!
|
30
|
+
puts "Please enter your Dropbox API secret"
|
31
|
+
dropboxKeys['secret'] = gets.chomp!
|
32
|
+
end
|
33
|
+
|
34
|
+
session = nil
|
35
|
+
|
36
|
+
if dropboxKeys.has_key?(:session)
|
37
|
+
session = DropboxSession.deserialize(dropboxKeys[:session])
|
38
|
+
else
|
39
|
+
session = DropboxSession.new(dropboxKeys[:key], dropboxKeys[:secret])
|
40
|
+
session.get_request_token
|
41
|
+
authorize_url = session.get_authorize_url
|
42
|
+
puts "Visit #{authorize_url} to log in to Dropbox. Hit enter when you have done this."
|
43
|
+
gets
|
44
|
+
session.get_access_token
|
45
|
+
end
|
46
|
+
|
47
|
+
if session.nil?
|
48
|
+
return nil, nil, nil
|
49
|
+
end
|
50
|
+
|
51
|
+
if !dropboxKeys.has_key?(:session)
|
52
|
+
dropboxKeys[:session] = session.serialize()
|
53
|
+
end
|
54
|
+
|
55
|
+
client = DropboxClient.new(session, ACCESS_TYPE)
|
56
|
+
|
57
|
+
if client.nil?
|
58
|
+
return nil, nil, nil
|
59
|
+
else
|
60
|
+
return session, client, dropboxKeys
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def Ripple.loadConfiguration(path)
|
65
|
+
conf = Ripple::DefaultConfiguration.dup
|
66
|
+
|
67
|
+
ripConf = File.join(path, RippleConfigFile)
|
68
|
+
# Load configuration and override any values that differ from the default.
|
69
|
+
if File.exists?(ripConf)
|
70
|
+
loadedConf = YAML::load(File.read(ripConf))
|
71
|
+
conf.merge!(loadedConf)
|
72
|
+
end
|
73
|
+
|
74
|
+
conf[:destinationDir] = File.expand_path(conf[:destinationDir])
|
75
|
+
if !File.directory?(conf[:destinationDir])
|
76
|
+
begin
|
77
|
+
Dir.mkdir(conf[:destinationDir])
|
78
|
+
rescue SystemCallError
|
79
|
+
raise RuntimeError, "Destination doesn't exist and cannot be created."
|
80
|
+
end
|
81
|
+
end
|
82
|
+
return conf
|
83
|
+
end
|
84
|
+
|
85
|
+
def Ripple.cleanup(conf, keys, path)
|
86
|
+
dropConfig = File.join(path, DropboxKeyFile)
|
87
|
+
File.open(dropConfig, 'w') do|file|
|
88
|
+
file.puts keys.to_yaml
|
89
|
+
end
|
90
|
+
|
91
|
+
rippleConf = File.join(path, RippleConfigFile)
|
92
|
+
File.open(rippleConf, 'w') do |file|
|
93
|
+
file.puts conf.to_yaml
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Iterates over dropbox directory, returing paths and state hash for each file
|
98
|
+
# oldFileState should be a hash of paths to state hashes, same as return values
|
99
|
+
def Ripple.walkDropbox(client, path, fileState, oldFileState)
|
100
|
+
#Here we need to actually sync newest files.
|
101
|
+
begin
|
102
|
+
useState = (!oldFileState.nil? and oldFileState.has_key?(path) and oldFileState[path]["path"] == path)
|
103
|
+
oldState = useState ? oldFileState[path]["hash"] : nil
|
104
|
+
states = client.metadata(path, 10000, true, oldState)
|
105
|
+
rescue DropboxNotModified
|
106
|
+
puts "Files have not changed."
|
107
|
+
return nil
|
108
|
+
end
|
109
|
+
|
110
|
+
files = { states["path"] => states }
|
111
|
+
#State represents a folder
|
112
|
+
if states["is_dir"] and states.has_key?("contents")
|
113
|
+
states["contents"].each{ |xx|
|
114
|
+
if !xx.nil?
|
115
|
+
files[xx["path"]] = xx
|
116
|
+
end
|
117
|
+
useState = (!oldFileState.nil? and oldFileState.has_key?(xx["path"]))
|
118
|
+
old = (useState ? oldFileState[xx["path"]]["hash"] : nil)
|
119
|
+
subs = Ripple.walkDropbox(client, xx["path"], fileState, old)
|
120
|
+
if !subs.nil?
|
121
|
+
files.merge!(subs)
|
122
|
+
end
|
123
|
+
}
|
124
|
+
end
|
125
|
+
|
126
|
+
return files
|
127
|
+
end
|
128
|
+
|
129
|
+
def Ripple.sync(path = "")
|
130
|
+
conf = Ripple.loadConfiguration(path)
|
131
|
+
begin
|
132
|
+
session, client, dropboxKeys = Ripple.connectToDropbox(path)
|
133
|
+
rescue DropboxAuthError
|
134
|
+
puts "Dropbox authorization failed."
|
135
|
+
Ripple.cleanup(conf, dropboxKeys, path)
|
136
|
+
return
|
137
|
+
rescue NameError
|
138
|
+
puts "Destination does not exist."
|
139
|
+
Ripple.cleanup(conf, dropboxKeys, path)
|
140
|
+
return
|
141
|
+
end
|
142
|
+
|
143
|
+
if session.nil?
|
144
|
+
puts "Could not connect to Dropbox."
|
145
|
+
Ripple.cleanup(conf, dropboxKeys, path)
|
146
|
+
return
|
147
|
+
end
|
148
|
+
|
149
|
+
destDir = conf[:destinationDir]
|
150
|
+
|
151
|
+
fileState = {}
|
152
|
+
oldFileState = dropboxKeys[:files]
|
153
|
+
files = Ripple.walkDropbox(client, '/', fileState, oldFileState)
|
154
|
+
|
155
|
+
if !files.nil?
|
156
|
+
files.keys.each { |x|
|
157
|
+
file = client.get_file(x)
|
158
|
+
File.open(File.join(destDir, x), 'w') {|f| f.puts file}
|
159
|
+
}
|
160
|
+
end
|
161
|
+
|
162
|
+
conf[:dropbox][:sync].each { |ii|
|
163
|
+
Dir.glob(File.join(destDir, ii)).each { |oo|
|
164
|
+
if !File.directory?(oo)
|
165
|
+
upName = Pathname.new(oo).relative_path_from(Pathname.new(destDir)).to_s
|
166
|
+
upName = File.join("", upName)
|
167
|
+
if files.nil? or !files.has_key?(upName)
|
168
|
+
up = File.open(oo)
|
169
|
+
client.put_file(upName, up, true)
|
170
|
+
up.close()
|
171
|
+
end
|
172
|
+
end
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
dropboxKeys[:files] = Ripple.walkDropbox(client, '/', fileState, {})
|
177
|
+
Ripple.cleanup(conf, dropboxKeys, path)
|
178
|
+
|
179
|
+
return true
|
180
|
+
end
|
181
|
+
end
|
data/lib/ripple.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'ripple/base'
|
Binary file
|
data/ripple.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "lib/ripple/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "rypple"
|
7
|
+
s.version = Ripple::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Jason Ziglar"]
|
10
|
+
s.email = ["jasedit@catexia.com"]
|
11
|
+
s.homepage = "https://github.com/jasedit/ripple"
|
12
|
+
s.summary = %q{Dropbox interface for jekyll.}
|
13
|
+
s.description = %q{A gem providing a Dropbox syncing interface for jekyll, along with a cgi file to update jekyll.}
|
14
|
+
|
15
|
+
s.add_runtime_dependency "jekyll"
|
16
|
+
s.add_runtime_dependency "dropbox-sdk"
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
end
|
data/ripple.yaml
ADDED
metadata
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rypple
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Jason Ziglar
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-02-27 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: jekyll
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: dropbox-sdk
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 3
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id002
|
48
|
+
description: A gem providing a Dropbox syncing interface for jekyll, along with a cgi file to update jekyll.
|
49
|
+
email:
|
50
|
+
- jasedit@catexia.com
|
51
|
+
executables:
|
52
|
+
- rippleInstall.rb
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
extra_rdoc_files: []
|
56
|
+
|
57
|
+
files:
|
58
|
+
- Gemfile
|
59
|
+
- README
|
60
|
+
- Rakefile
|
61
|
+
- bin/rippleInstall.rb
|
62
|
+
- lib/ripple.rb
|
63
|
+
- lib/ripple/base.rb
|
64
|
+
- lib/ripple/version.rb
|
65
|
+
- pkg/ripple-0.0.1.gem
|
66
|
+
- ripple.gemspec
|
67
|
+
- ripple.yaml
|
68
|
+
homepage: https://github.com/jasedit/ripple
|
69
|
+
licenses: []
|
70
|
+
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
hash: 3
|
82
|
+
segments:
|
83
|
+
- 0
|
84
|
+
version: "0"
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
hash: 3
|
91
|
+
segments:
|
92
|
+
- 0
|
93
|
+
version: "0"
|
94
|
+
requirements: []
|
95
|
+
|
96
|
+
rubyforge_project:
|
97
|
+
rubygems_version: 1.8.17
|
98
|
+
signing_key:
|
99
|
+
specification_version: 3
|
100
|
+
summary: Dropbox interface for jekyll.
|
101
|
+
test_files: []
|
102
|
+
|