ponyhost 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.
Files changed (4) hide show
  1. data/README.md +8 -0
  2. data/bin/ponyhost +60 -0
  3. data/lib/ponyhost.rb +138 -0
  4. metadata +69 -0
data/README.md ADDED
@@ -0,0 +1,8 @@
1
+ ponyHost is a super simple way to use the Amazon AWS S3 Website feature.
2
+
3
+ $ cd your-website
4
+ $ gem install ponyhost
5
+ $ ponyhost create foobar
6
+ $ ponyhost push foobar
7
+ $ open http://foobar.ponyho.st
8
+
data/bin/ponyhost ADDED
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ponyhost'
4
+
5
+ command = ARGV.shift
6
+ bucketname = ARGV.shift
7
+ bucketname = PonyHost.normalize_bucketname(bucketname) if bucketname
8
+
9
+ if command == "server"
10
+ server()
11
+ elsif command == "list" || (["create", "push", "destroy", "show", "version"].include?(command) && bucketname != nil)
12
+ credentials = PonyHost.obtain_credentials
13
+
14
+ AWS::S3::Base.establish_connection!({
15
+ :access_key_id => credentials[:access_key_id],
16
+ :secret_access_key => credentials[:access_key_secret]
17
+ })
18
+
19
+ if(command == "create")
20
+ PonyHost.create(bucketname)
21
+ elsif(command == "push")
22
+ PonyHost.push(bucketname, ".")
23
+ elsif(command == "autopush")
24
+ # TODO
25
+ # monitor cwd and push automatically?
26
+ elsif(command == "destroy")
27
+ print "Do you really wanna destroy '#{bucketname}' (type 'YES'):"
28
+ PonyHost.destroy(bucketname) if STDIN.gets.chop == "YES"
29
+ elsif(command == "list")
30
+ puts "Your sites:"
31
+ PonyHost.list.each do |name|
32
+ puts "http://#{name}"
33
+ end
34
+ elsif(command == "show")
35
+ # deprecated?
36
+ PonyHost.show(bucketname)
37
+ elsif(command == "version")
38
+ puts "ponyhost version #{PonyHost::VERSION}"
39
+ puts "created by Johannes Wagener http://johannes.wagener.cc"
40
+ end
41
+ else
42
+ puts "usage: ponyhost <command> [<sitename>]"
43
+ puts " "
44
+ puts "available commands:"
45
+ puts " list Lists all sites/buckets from your S3 account"
46
+ puts " create [sitename] Creates a new bucket for your site"
47
+ puts " push [sitename] Pushes the current directory to the specified bucket/site"
48
+ puts " destroy [sitename] Removes all files and destroys the bucket"
49
+ puts " server Runs a local HTTP server for the current directory"
50
+ # puts " version Print version information"
51
+ puts " "
52
+ puts "Notes: if the sitename contains no '.' it will be suffixed with the default domain #{PonyHost::DEFAULT_DOMAIN}"
53
+ puts "To use your own domainname you have to set up the DNS correctly:"
54
+ puts "For a site under a subdomain like www.foobar.com you have to create a CNAME record for www.foobar.com to s3-website-us-east-1.amazonaws.com"
55
+ puts "For a site under a domain like foobar.com you have to create an A record pointing to 72.21.214.197"
56
+ puts "Once thats done you just have to create the site with the correct name:"
57
+ puts "$ ponyhost create www.foobar.com"
58
+ puts " "
59
+
60
+ end
data/lib/ponyhost.rb ADDED
@@ -0,0 +1,138 @@
1
+ require 'yaml'
2
+ require 'aws/s3'
3
+ require 'socket'
4
+ require 'digest/md5'
5
+
6
+ # monkey patch to add website to extract significant parameter
7
+ class AWS::S3::Authentication::CanonicalString
8
+ def extract_significant_parameter
9
+ request.path[/[&?](acl|torrent|logging|website)(?:&|=|$)/, 1]
10
+ end
11
+ end
12
+
13
+
14
+ class PonyHost
15
+ S3_CREDENTIAL_FILES = ["~/.ponyhost.yml"]
16
+ DEFAULT_DOMAIN = "lolcat.biz"
17
+ VERSION = "0.1"
18
+ class << self
19
+
20
+
21
+ def obtain_credentials
22
+ credential_file = File.expand_path(S3_CREDENTIAL_FILES.first)
23
+ if File.exists?(credential_file)
24
+ return YAML.load_file(credential_file)
25
+ else
26
+ puts "AWS Credentials file '#{credential_file}' missing. We'll create one."
27
+ puts "You'll find your Amazon AWS credentials here:"
28
+ puts "https://aws-portal.amazon.com/gp/aws/developer/account/index.html?ie=UTF8&action=access-key"
29
+ #http://aws.amazon.com/account/
30
+ credentials = {}
31
+ print "Your AWS Access Key ID: "
32
+ credentials[:access_key_id] = STDIN.gets.chop
33
+ print "Your AWS Access Key Secret: "
34
+ credentials[:access_key_secret] = STDIN.gets.chop
35
+ File.open(credential_file, "w") {|file| file.puts(credentials.to_yaml) }
36
+ return credentials
37
+ end
38
+ end
39
+
40
+ def create(bucketname)
41
+ bucket = AWS::S3::Bucket.create(bucketname, :access => :public_read)
42
+
43
+ body = '<?xml version="1.0" encoding="UTF-8"?>
44
+ <WebsiteConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
45
+ <IndexDocument><Suffix>index.html</Suffix></IndexDocument>
46
+ <ErrorDocument><Key>404.html</Key></ErrorDocument>
47
+ </WebsiteConfiguration>'
48
+
49
+ res = AWS::S3::Base.request(:put, "/#{bucketname}?website", {}, body)
50
+
51
+ puts "Site created: http://#{bucketname}"
52
+ puts "Push your files with: ponyhost push #{bucketname}"
53
+ end
54
+
55
+ def push(bucketname, directory = ".")
56
+ bucket = AWS::S3::Bucket.find(bucketname)
57
+ file_names = flat_list_directory(Dir.new(directory))
58
+
59
+ file_names.each do |file_name|
60
+ local_md5 = md5sum(file_name).chomp
61
+ remote_md5 = bucket[file_name] && bucket[file_name].about["etag"].gsub('"', '').chomp
62
+ if local_md5.to_s == remote_md5.to_s
63
+ puts "Skipping \t#{file_name}"
64
+ else
65
+ puts "Pushing \t#{file_name}"
66
+ AWS::S3::S3Object.store(file_name, open(file_name), bucketname, :access => :public_read)
67
+ end
68
+ end
69
+ end
70
+
71
+ def list
72
+ AWS::S3::Service.buckets.map(&:name)
73
+ end
74
+
75
+ def destroy(bucketname)
76
+ AWS::S3::Bucket.delete(bucketname, :force => true)
77
+ puts "'#{bucketname} is destroyed"
78
+ end
79
+
80
+ def show(bucketname)
81
+ res = AWS::S3::Base.request(:get, "/#{bucketname}?website") rescue res = $!
82
+ puts res
83
+ end
84
+
85
+ def server(port=9090)
86
+ s=TCPServer.new(port);
87
+ puts "Server running on http://localhost:#{port}"
88
+ loop do
89
+ _ = s.accept
90
+ requested_filename = _.gets.split[1]
91
+ requested_filename = "/index.html" if requested_filename == "/"
92
+ begin
93
+ data = File.read(".#{requested_filename}")
94
+ status = 200
95
+ rescue
96
+ status = 404
97
+ if File.exists?("404.html")
98
+ data = File.read("404.html")
99
+ else
100
+ data = "#{requested_filename} not found and no 404.html error page either."
101
+ end
102
+ end
103
+ status_msg = status == 200 ? "OK" : "NOT FOUND"
104
+ _ << "HTTP/1.0 #{status} #{status_msg}\r\n\r\n#{data}";
105
+
106
+ puts %Q{[#{Time.now}] "GET #{requested_filename}" #{status}}
107
+ _.close
108
+ end
109
+ end
110
+
111
+ def md5sum(file_name)
112
+ Digest::MD5.hexdigest(File.read(file_name))
113
+ end
114
+
115
+ def flat_list_directory(dir, path = "")
116
+ list = []
117
+ dir.each do |entry|
118
+ unless [".", ".."].include?(entry)
119
+ full_entry_path = path == "" ? entry : [path, entry].join("/")
120
+ if File.directory?(full_entry_path)
121
+ list += flat_list_directory(Dir.new(full_entry_path), full_entry_path)
122
+ else
123
+ list << full_entry_path
124
+ end
125
+ end
126
+ end
127
+ list
128
+ end
129
+
130
+ def normalize_bucketname(bucketname)
131
+ if bucketname.include?(".")
132
+ bucketname
133
+ else
134
+ "#{bucketname}.#{DEFAULT_DOMAIN}"
135
+ end
136
+ end
137
+ end
138
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ponyhost
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: "0.1"
6
+ platform: ruby
7
+ authors:
8
+ - Johannes Wagener
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-06-13 00:00:00 +02:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: aws-s3
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: "0"
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ description: ponyHost allows you to easily create S3 website buckets with a nice hostname and push files to it
28
+ email:
29
+ - johannes@wagener.cc
30
+ executables:
31
+ - ponyhost
32
+ extensions: []
33
+
34
+ extra_rdoc_files: []
35
+
36
+ files:
37
+ - lib/ponyhost.rb
38
+ - README.md
39
+ - bin/ponyhost
40
+ has_rdoc: true
41
+ homepage: http://ponyho.st
42
+ licenses: []
43
+
44
+ post_install_message:
45
+ rdoc_options: []
46
+
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 1.3.6
61
+ requirements: []
62
+
63
+ rubyforge_project: ponyhost
64
+ rubygems_version: 1.6.2
65
+ signing_key:
66
+ specification_version: 3
67
+ summary: Create super simple S3 powered websites
68
+ test_files: []
69
+