rypple 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in ripple.gemspec
4
+ gemspec
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
@@ -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
@@ -0,0 +1,3 @@
1
+ module Ripple
2
+ VERSION = "0.0.1"
3
+ 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
@@ -0,0 +1,5 @@
1
+ ---
2
+ :destinationDir: ./test
3
+ :dropbox:
4
+ :sync:
5
+ - "**"
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
+