harbor 0.16.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.
Files changed (84) hide show
  1. data/Rakefile +76 -0
  2. data/bin/harbor +7 -0
  3. data/lib/harbor.rb +17 -0
  4. data/lib/harbor/accessor_injector.rb +30 -0
  5. data/lib/harbor/application.rb +172 -0
  6. data/lib/harbor/auth/basic.rb +51 -0
  7. data/lib/harbor/block_io.rb +63 -0
  8. data/lib/harbor/cache.rb +90 -0
  9. data/lib/harbor/cache/disk.rb +99 -0
  10. data/lib/harbor/cache/item.rb +48 -0
  11. data/lib/harbor/cache/memory.rb +35 -0
  12. data/lib/harbor/cascade.rb +75 -0
  13. data/lib/harbor/console.rb +34 -0
  14. data/lib/harbor/container.rb +134 -0
  15. data/lib/harbor/contrib/debug.rb +236 -0
  16. data/lib/harbor/contrib/session/data_mapper.rb +74 -0
  17. data/lib/harbor/daemon.rb +105 -0
  18. data/lib/harbor/errors.rb +49 -0
  19. data/lib/harbor/events.rb +45 -0
  20. data/lib/harbor/exception_notifier.rb +59 -0
  21. data/lib/harbor/file.rb +66 -0
  22. data/lib/harbor/file_store.rb +69 -0
  23. data/lib/harbor/file_store/file.rb +100 -0
  24. data/lib/harbor/file_store/local.rb +71 -0
  25. data/lib/harbor/file_store/mosso.rb +154 -0
  26. data/lib/harbor/file_store/mosso/private.rb +8 -0
  27. data/lib/harbor/generator.rb +56 -0
  28. data/lib/harbor/generator/help.rb +34 -0
  29. data/lib/harbor/generator/setup.rb +82 -0
  30. data/lib/harbor/generator/skeletons/basic/config.ru.skel +21 -0
  31. data/lib/harbor/generator/skeletons/basic/lib/appname.rb.skel +49 -0
  32. data/lib/harbor/generator/skeletons/basic/lib/appname/controllers/home.rb +9 -0
  33. data/lib/harbor/generator/skeletons/basic/lib/appname/views/home/index.html.erb.skel +23 -0
  34. data/lib/harbor/generator/skeletons/basic/lib/appname/views/layouts/application.html.erb.skel +48 -0
  35. data/lib/harbor/generator/skeletons/basic/lib/appname/views/layouts/exception.html.erb.skel +13 -0
  36. data/lib/harbor/generator/skeletons/basic/lib/appname/views/layouts/login.html.erb.skel +11 -0
  37. data/lib/harbor/generator/skeletons/basic/log/development.log +0 -0
  38. data/lib/harbor/hooks.rb +105 -0
  39. data/lib/harbor/json_cookies.rb +37 -0
  40. data/lib/harbor/layouts.rb +61 -0
  41. data/lib/harbor/locale.rb +50 -0
  42. data/lib/harbor/locales.txt +22 -0
  43. data/lib/harbor/logging.rb +39 -0
  44. data/lib/harbor/logging/appenders/email.rb +84 -0
  45. data/lib/harbor/logging/request_logger.rb +34 -0
  46. data/lib/harbor/mail_servers/abstract.rb +12 -0
  47. data/lib/harbor/mail_servers/sendmail.rb +19 -0
  48. data/lib/harbor/mail_servers/smtp.rb +25 -0
  49. data/lib/harbor/mail_servers/test.rb +17 -0
  50. data/lib/harbor/mailer.rb +96 -0
  51. data/lib/harbor/messages.rb +17 -0
  52. data/lib/harbor/mime.rb +206 -0
  53. data/lib/harbor/plugin.rb +52 -0
  54. data/lib/harbor/plugin_list.rb +38 -0
  55. data/lib/harbor/request.rb +138 -0
  56. data/lib/harbor/response.rb +281 -0
  57. data/lib/harbor/router.rb +112 -0
  58. data/lib/harbor/script.rb +155 -0
  59. data/lib/harbor/session.rb +75 -0
  60. data/lib/harbor/session/abstract.rb +27 -0
  61. data/lib/harbor/session/cookie.rb +17 -0
  62. data/lib/harbor/shellwords.rb +26 -0
  63. data/lib/harbor/test/mailer.rb +10 -0
  64. data/lib/harbor/test/request.rb +28 -0
  65. data/lib/harbor/test/response.rb +17 -0
  66. data/lib/harbor/test/session.rb +11 -0
  67. data/lib/harbor/test/test.rb +22 -0
  68. data/lib/harbor/version.rb +3 -0
  69. data/lib/harbor/view.rb +89 -0
  70. data/lib/harbor/view_context.rb +134 -0
  71. data/lib/harbor/view_context/helpers.rb +7 -0
  72. data/lib/harbor/view_context/helpers/cache.rb +77 -0
  73. data/lib/harbor/view_context/helpers/form.rb +34 -0
  74. data/lib/harbor/view_context/helpers/html.rb +26 -0
  75. data/lib/harbor/view_context/helpers/text.rb +120 -0
  76. data/lib/harbor/view_context/helpers/url.rb +11 -0
  77. data/lib/harbor/xml_view.rb +57 -0
  78. data/lib/harbor/zipped_io.rb +203 -0
  79. data/lib/vendor/cloudfiles-1.3.0/cloudfiles.rb +77 -0
  80. data/lib/vendor/cloudfiles-1.3.0/cloudfiles/authentication.rb +46 -0
  81. data/lib/vendor/cloudfiles-1.3.0/cloudfiles/connection.rb +280 -0
  82. data/lib/vendor/cloudfiles-1.3.0/cloudfiles/container.rb +260 -0
  83. data/lib/vendor/cloudfiles-1.3.0/cloudfiles/storage_object.rb +253 -0
  84. metadata +155 -0
@@ -0,0 +1,100 @@
1
+ module Harbor
2
+ class FileStore
3
+ class File
4
+
5
+ attr_accessor :store, :path
6
+
7
+ def initialize(store, path)
8
+ @store = store
9
+ @path = path
10
+
11
+ @pending_writes = []
12
+ end
13
+
14
+ def copy_on_write
15
+ return @copy_on_write if @copy_on_write
16
+
17
+ @copy_on_write = []
18
+ if store.options[:copy_on_write]
19
+ store.options[:copy_on_write].each do |name|
20
+ @copy_on_write << Harbor::FileStore[name].get(@path)
21
+ end
22
+ end
23
+
24
+ @copy_on_write
25
+ end
26
+
27
+ def copy_on_read
28
+ return @copy_on_read if @copy_on_read
29
+
30
+ @copy_on_read = []
31
+ if store.options[:copy_on_read]
32
+ store.options[:copy_on_read].each do |name|
33
+ @copy_on_read << Harbor::FileStore[name].get(@path)
34
+ end
35
+ end
36
+
37
+ @copy_on_read
38
+ end
39
+
40
+ def write(data)
41
+ open("wb")
42
+
43
+ copy_on_write.each do |file|
44
+ if store.options[:async_copy]
45
+ @pending_writes << lambda { file.write(data) }
46
+ else
47
+ file.write(data)
48
+ end
49
+ end
50
+
51
+ if data
52
+ @stream.write(data)
53
+ else
54
+ @stream.close
55
+ @stream = nil
56
+
57
+ Thread.new {
58
+ @pending_writes.each { |write| write.call }
59
+ @pending_writes = []
60
+ } if store.options[:async_copy]
61
+ end
62
+ end
63
+
64
+ def read(bytes = nil)
65
+ open("r")
66
+
67
+ data = @stream.read(bytes)
68
+
69
+ copy_on_read.each { |file| file.write(data) }
70
+
71
+ unless bytes && data
72
+ @stream.close
73
+ @stream = nil
74
+ end
75
+
76
+ data
77
+ end
78
+
79
+ def size
80
+ store.size(path)
81
+ end
82
+
83
+ def open(mode = "r")
84
+ @stream ||= store.open(path, mode)
85
+ end
86
+
87
+ ##
88
+ # Returns the full path to this file
89
+ ##
90
+ def absolute_path
91
+ (@store.root + @path).to_s
92
+ end
93
+
94
+ def exists?
95
+ store.exists?(path)
96
+ end
97
+
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,71 @@
1
+ module Harbor
2
+ class FileStore
3
+ class Local < Harbor::FileStore
4
+
5
+ attr_accessor :root, :options
6
+
7
+ def initialize(path, options = {})
8
+ path = "#{path}/" unless path =~ /.*\/$/
9
+ @root = Pathname(path)
10
+
11
+ @options = options
12
+
13
+ ::FileUtils.mkdir_p(path.to_s)
14
+ end
15
+
16
+ def get(path)
17
+ path = strip_leading_slash(path)
18
+ Harbor::FileStore::File.new(self, path)
19
+ end
20
+
21
+ def put(path, absolute_path)
22
+ raise ArgumentError.new("Harbor::FileStore::Local#put[absolute_path] should be a path but was an IO") if absolute_path.is_a?(IO)
23
+ path = strip_leading_slash(path)
24
+ file = Harbor::FileStore::File.new(self, path)
25
+
26
+ ::FileUtils.mkdir_p((@root + path).parent.to_s) unless (@root + path).parent.exist?
27
+
28
+ ::FileUtils::cp(absolute_path, file.absolute_path)
29
+ file
30
+ end
31
+
32
+ def delete(path)
33
+ path = strip_leading_slash(path)
34
+ ::FileUtils.rm(@root + path)
35
+ Harbor::File.rmdir_p((@root + path).parent.to_s)
36
+ end
37
+
38
+ def exists?(path)
39
+ path = strip_leading_slash(path)
40
+ (@root + path).exist?
41
+ end
42
+
43
+ def open(path, mode = "r", &block)
44
+ path = strip_leading_slash(path)
45
+ ::FileUtils.mkdir_p((@root + path).parent.to_s) unless (@root + path).parent.exist?
46
+ ::File.open(@root + path, mode, &block)
47
+ end
48
+
49
+ def size(path)
50
+ path = strip_leading_slash(path)
51
+ ::File.size(@root + path)
52
+ end
53
+
54
+ def local?
55
+ true
56
+ end
57
+
58
+ private
59
+
60
+ def __size__
61
+ `du -sk #{Shellwords.escape(@root.to_s)} | awk '{ print $1; }'`.chomp.to_i * 1024
62
+ end
63
+
64
+ def strip_leading_slash(path)
65
+ path = path[1..path.size - 1] if path =~ /^\//
66
+ path
67
+ end
68
+
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,154 @@
1
+ require "vendor/cloudfiles-1.3.0/cloudfiles"
2
+
3
+ module Harbor
4
+ class FileStore
5
+ class Mosso < Harbor::FileStore
6
+
7
+ attr_accessor :container, :options
8
+
9
+ def initialize(username, api_key, container_name, options = {})
10
+ @username = username
11
+ @api_key = api_key
12
+ @container_name = container_name
13
+ @options = options
14
+ end
15
+
16
+ def get(path)
17
+ path = strip_leading_slash(path)
18
+ Harbor::FileStore::File.new(self, path)
19
+ end
20
+
21
+ def put(filename, file)
22
+ filename = strip_leading_slash(filename)
23
+ url = container.connection.storagehost + container.connection.storagepath + "/#{container.name}/#{filename}"
24
+ token = container.connection.authtoken
25
+
26
+ path = nil
27
+
28
+ if file.is_a?(::File)
29
+ path = file.path
30
+ elsif file.is_a?(Harbor::FileStore::File) && file.store.local?
31
+ path = file.store.path + file.path
32
+ end
33
+
34
+ make_path(::File.dirname(path))
35
+
36
+ command = <<-CMD
37
+ curl -X "PUT" \\
38
+ -T #{path ? Shellwords.escape(path.to_s) : "-"} \\
39
+ -H "X-Auth-Token: #{token}" \\
40
+ -H "Content-Type: text/plain" \\
41
+ https://#{url}
42
+ CMD
43
+
44
+ if path
45
+ system(command)
46
+ else
47
+ IO::popen(command, "w") do |session|
48
+ case file
49
+ when ::File
50
+ while data = file.read(500_000)
51
+ session.write(data)
52
+ end
53
+ when Harbor::FileStore::File
54
+ file.read do |block|
55
+ session.write(block)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ def delete(filename)
63
+ filename = strip_leading_slash(filename)
64
+ container.delete_object(filename)
65
+ end
66
+
67
+ def exists?(filename)
68
+ filename = strip_leading_slash(filename)
69
+ container.object_exists?(filename)
70
+ end
71
+
72
+ def open(filename, mode = "r", &block)
73
+ filename = strip_leading_slash(filename)
74
+ url = container.connection.storagehost + container.connection.storagepath + "/#{container.name}/#{filename}"
75
+ token = container.connection.authtoken
76
+
77
+ if mode == "r"
78
+ command = <<-CMD
79
+ curl -s -X "GET" \\
80
+ -D - \\
81
+ -H "X-Auth-Token: #{token}" \\
82
+ https://#{url}
83
+ CMD
84
+
85
+ stream = IO::popen(command, "r")
86
+
87
+ headers = []
88
+
89
+ while line = stream.gets
90
+ break if line == "\r\n"
91
+ headers << line
92
+ end
93
+ elsif mode =~ /w/
94
+ make_path(::File.dirname(filename))
95
+
96
+ command = <<-CMD
97
+ curl -X "PUT" \\
98
+ -T #{"-"} \\
99
+ -H "X-Auth-Token: #{token}" \\
100
+ -H "Content-Type: text/plain" \\
101
+ https://#{url}
102
+ CMD
103
+
104
+ stream = IO::popen(command, "w")
105
+ end
106
+
107
+ if block_given?
108
+ yield stream
109
+ stream.close
110
+ else
111
+ stream
112
+ end
113
+ end
114
+
115
+ def size(filename)
116
+ filename = strip_leading_slash(filename)
117
+ container.object(filename).bytes.to_i
118
+ end
119
+
120
+ def container
121
+ @container ||= connect!
122
+ end
123
+
124
+ private
125
+
126
+ def connect!
127
+ @connection = CloudFiles::Connection.new(@username, @api_key, true)
128
+ @container = @connection.container(@container_name)
129
+ end
130
+
131
+ def connected?
132
+ @connection && @connection.authok?
133
+ end
134
+
135
+ def make_path(path)
136
+ if path == "." || path == "/"
137
+ return
138
+ else
139
+ unless @container.object_exists?(path)
140
+ object = @container.create_object(path)
141
+ object.write(nil, { 'Content-Type' => 'application/directory'} )
142
+ end
143
+ make_path(::File.dirname(path))
144
+ end
145
+ end
146
+
147
+ def strip_leading_slash(path)
148
+ path = path[1..path.size - 1] if path =~ /^\//
149
+ path
150
+ end
151
+
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,8 @@
1
+ module Harbor
2
+ class FileStore
3
+ class Mosso
4
+ class Private < Harbor::FileStore::Mosso
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,56 @@
1
+ require 'pathname'
2
+ require 'erubis'
3
+
4
+ module Harbor
5
+
6
+ class Generator
7
+
8
+ class GeneratorError < StandardError; end
9
+ class UnknownCommandError < GeneratorError; end
10
+ class GeneratorArgumentError < GeneratorError; end
11
+
12
+ attr_accessor :app, :command, :klass, :description, :help
13
+
14
+ def initialize(app, command, klass, description, help)
15
+ @app, @command, @klass, @description, @help = app, command, klass, description, help
16
+ end
17
+
18
+ def self.run(app, command, options = [])
19
+ executor = if generator = @@generators["#{app}:#{command}"]
20
+ generator.klass.new(options)
21
+ else
22
+ puts usage(app)
23
+
24
+ exit(1)
25
+ end
26
+
27
+ executor.run
28
+ end
29
+
30
+ def self.usage(app)
31
+ usage = []
32
+ usage << "Usage #{app} command [options]"
33
+ usage << ""
34
+ usage << "Available commands:"
35
+
36
+ @@generators.select { |key,| key =~ /^#{app}/ }.sort.each do |key, generator|
37
+ usage << "%12s %s" % [generator.command, generator.description]
38
+ end
39
+
40
+ usage
41
+ end
42
+
43
+ @@generators = {}
44
+ def self.register(app, command, klass, description = "", help = "")
45
+ @@generators["#{app}:#{command}"] = new(app, command, klass, description, help)
46
+ end
47
+
48
+ def self.generators
49
+ @@generators
50
+ end
51
+
52
+ require Pathname(__FILE__).dirname + "generator/help"
53
+ require Pathname(__FILE__).dirname + "generator/setup"
54
+ end
55
+
56
+ end
@@ -0,0 +1,34 @@
1
+ module Harbor
2
+ class Generator
3
+
4
+ class HelpCommand
5
+ Harbor::Generator.register('harbor', 'help', self)
6
+
7
+ def initialize(options)
8
+ @command = options.first
9
+ end
10
+
11
+ def run
12
+ if @command
13
+ generator = Harbor::Generator.generators["harbor:#{@command}"]
14
+
15
+ if !generator
16
+ puts "Command '#{@command}' does not exist."
17
+ else
18
+ if generator.help.empty?
19
+ puts "No help available for '#{@command}'."
20
+ else
21
+ puts generator.help
22
+ end
23
+ end
24
+
25
+ exit(1)
26
+ else
27
+ puts Harbor::Generator.usage('harbor')
28
+ exit(1)
29
+ end
30
+ end
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,82 @@
1
+ require "fileutils"
2
+
3
+ module Harbor
4
+ class Generator
5
+ class SetupCommand
6
+ HELP = <<-HELP
7
+ Usage: harbor setup app_name
8
+
9
+ Sets up a new Harbor port using the conventional directory
10
+ structure. The application can be booted using your server
11
+ of choice:
12
+
13
+ > rackup # http://localhost:9292/
14
+ > unicorn # http://localhost:8080/
15
+ > thin -R config.ru start # http://localhost:3000/
16
+
17
+ HELP
18
+
19
+ Harbor::Generator.register('harbor', 'setup', self, "Sets up a new harbor project.", HELP)
20
+
21
+ attr_reader :app_name
22
+
23
+ def initialize(options)
24
+ @app_name = options.first
25
+
26
+ unless @app_name
27
+ puts HELP
28
+ exit(1)
29
+ end
30
+ end
31
+
32
+ def log(action, message)
33
+ puts "%12s %s" % [action, message]
34
+ end
35
+
36
+ def run
37
+ unless File.exists?(@app_name)
38
+ log("create", @app_name)
39
+ `mkdir #{@app_name}`
40
+ end
41
+
42
+ skeleton_path = Pathname(__FILE__).dirname + 'skeletons/basic'
43
+ Dir[skeleton_path + "**/*"].each do |item|
44
+ item = Pathname(item)
45
+ relative_path = "#{@app_name}/#{item.relative_path_from(skeleton_path)}"
46
+ relative_path.sub!("appname", @app_name)
47
+
48
+ if File.exists?(relative_path.sub(/\.skel$/, ""))
49
+ log("exists", relative_path.sub(/\.skel$/, ""))
50
+ next
51
+ end
52
+
53
+ if item.directory?
54
+ log("create", relative_path)
55
+
56
+ `mkdir #{relative_path}`
57
+ elsif relative_path.sub!(/\.skel$/, "")
58
+ log("create", relative_path)
59
+
60
+ ::File.open(relative_path, 'w') do |file|
61
+ file.puts Erubis::FastEruby.new(::File.read(item), :pattern => '##> <##').evaluate(self)
62
+ end
63
+ else
64
+ log("create", relative_path)
65
+
66
+ FileUtils.cp(item, relative_path)
67
+ end
68
+
69
+ end
70
+
71
+ `chmod +x #{@app_name}/config.ru`
72
+ end
73
+
74
+ def app_class
75
+ # 'sample' => 'Sample'
76
+ # 'cool_app' => 'CoolApp'
77
+ @app_name.gsub(/(^|-|_)[a-z0-9]{1}/) { |m| m.sub(/-|_/, '').upcase }
78
+ end
79
+
80
+ end
81
+ end
82
+ end