stastic 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "rubygems"
2
+ require "rake"
3
+ require "rspec/core/rake_task"
4
+
5
+
6
+ task :default => :spec
7
+
8
+ RSpec::Core::RakeTask.new(:spec) do |t|
9
+ t.pattern = "spec/**/*_spec.rb"
10
+ end
11
+
data/bin/stastic CHANGED
@@ -1,5 +1,15 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
3
6
  require 'stastic'
7
+ require 'stastic/command'
8
+ require 'stastic/generator'
9
+
10
+ args = ARGV.dup
11
+ ARGV.clear
12
+ command = args.shift.strip rescue 'help'
13
+
14
+ Stastic::Command.run(command, args)
4
15
 
5
- puts "stastic (http://stastic.com) - #{Stastic::VERSION}"
data/lib/server.rb ADDED
@@ -0,0 +1,43 @@
1
+ require 'webrick'
2
+
3
+ class Server < WEBrick::HTTPServer
4
+ class NonCachingFileHandler < WEBrick::HTTPServlet::FileHandler
5
+ def prevent_caching(res)
6
+ res['ETag'] = nil
7
+ res['Last-Modified'] = Time.now + 100**4
8
+ res['Cache-Control'] = 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0'
9
+ res['Pragma'] = 'no-cache'
10
+ res['Expires'] = Time.now - 100**4
11
+ end
12
+
13
+ def do_GET(req, res)
14
+ super
15
+ prevent_caching(res)
16
+ end
17
+ end
18
+
19
+ def initialize(path, port)
20
+ @port = port
21
+ @path = path
22
+ mime_types = WEBrick::HTTPUtils::DefaultMimeTypes
23
+ mime_types.store 'js', 'application/javascript'
24
+ super(
25
+ :Port => @port,
26
+ :MimeTypes => mime_types
27
+ )
28
+ end
29
+
30
+ def start
31
+ mount("/", NonCachingFileHandler, @path)
32
+ t = Thread.new {
33
+ super
34
+ }
35
+
36
+ trap("INT") { shutdown }
37
+ t.join()
38
+ end
39
+ end
40
+
41
+
42
+
43
+
@@ -0,0 +1,72 @@
1
+ require 'rest-client'
2
+ require 'json'
3
+
4
+ module Stastic
5
+ class InvalidCredentials < RestClient::Forbidden; end
6
+ class ValidationFailed < RestClient::UnprocessableEntity; end
7
+
8
+ class Client
9
+ attr_accessor :user, :token, :host
10
+
11
+ def self.authenticate(email, password)
12
+ client = new
13
+ client.request(:get, "/authenticate", {:email => email, :password => password})["token"]
14
+ end
15
+
16
+ def self.request(method, uri, payload = nil, headers = {})
17
+ client = new
18
+ client.request(method, uri, payload, headers)
19
+ end
20
+
21
+ def self.create(name = nil)
22
+ if name
23
+ request(:post, "/sites", {:site => {:name => name}})
24
+ else
25
+ request(:post, "/sites")
26
+ end
27
+ end
28
+
29
+ def self.list
30
+ request(:get, "/sites")
31
+ end
32
+
33
+ def self.publish(site_id, archive_path)
34
+ request(:put, "/sites/#{site_id}/publish", {:site => {:archive => File.new(archive_path)}})
35
+ end
36
+
37
+ def self.rename(site_id, name)
38
+ request(:put, "/sites/#{site_id}", {:site => {:name => name}})
39
+ end
40
+
41
+ def self.add_domain(site_id, domain_name)
42
+ request(:post, "/sites/#{site_id}/domains", {:domain => {:host => domain_name}})
43
+ end
44
+
45
+ def self.remove_domain(site_id, domain_name)
46
+ request(:delete, "/sites/#{site_id}/domains/#{domain_name}")
47
+ end
48
+
49
+ def initialize(host = "http://stastic.com")
50
+ if Stastic::Config.exists?
51
+ self.user = Stastic::Config.user
52
+ self.token = Stastic::Config.token
53
+ end
54
+ self.host = host
55
+ end
56
+
57
+ def request(method, uri, payload = nil, headers = {})
58
+ headers.merge!(:accept => 'json', "X-STASTIC" => Stastic::VERSION)
59
+
60
+ response = RestClient::Request.execute(
61
+ :method => method,
62
+ :url => host + uri,
63
+ :headers => headers,
64
+ :payload => payload,
65
+ :user => user,
66
+ :password => token)
67
+
68
+ return JSON::parse(response.body)
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,41 @@
1
+ require 'trollop'
2
+ require 'stastic/config'
3
+ require 'stastic/client'
4
+ require 'stastic/commands/base'
5
+ Dir["#{File.dirname(__FILE__)}/commands/*.rb"].each { |c| require c }
6
+
7
+ module Stastic
8
+ module Command
9
+ extend self
10
+
11
+ class UnknownCommand < RuntimeError; end
12
+ class InvalidOptions < RuntimeError; end
13
+
14
+
15
+ def run(cmd, args)
16
+ begin
17
+ klass, method = parse_command(cmd)
18
+ runner = klass.new(args)
19
+ raise UnknownCommand unless runner.respond_to?(method)
20
+ runner.send(method)
21
+ rescue UnknownCommand
22
+ puts "Invalid command `#{cmd}`. Run `stastic help` for available commands."
23
+ rescue InvalidOptions
24
+ puts "Invalid options for `#{cmd}`. Run `stastic help` for more information."
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def parse_command(cmd)
31
+ begin
32
+ klass, method = cmd.split(':')
33
+ return eval("Stastic::Command::#{klass.capitalize}"), method || :index
34
+ rescue NameError, NoMethodError
35
+ puts $!.inspect
36
+ raise UnknownCommand
37
+ end
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,8 @@
1
+ module Stastic::Command
2
+ class Auth < Base
3
+
4
+ def index
5
+ request_credentials
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,96 @@
1
+ module Stastic::Command
2
+ class Base
3
+
4
+ def initialize(args); end
5
+
6
+ private
7
+
8
+ def request_credentials
9
+ print "Enter your Stastic login credentials.\n\n"
10
+ attempts = 0
11
+
12
+ begin
13
+ attempts += 1
14
+ print " Email: "
15
+ email = ask
16
+ print " Password: "
17
+ password = ask_for_password
18
+ token = Stastic::Client.authenticate(email, password)
19
+ rescue Stastic::InvalidCredentials
20
+ if attempts < 3
21
+ print "\nInvalid credentials - try again.\n\n"
22
+ retry
23
+ else
24
+ print "\nInvalid credentials -- too many tries!\n"
25
+ exit
26
+ end
27
+ end
28
+
29
+ Stastic::Config.update({:user => email, :token => token}, :global)
30
+ print "\nYour credentials have been saved.\n"
31
+ end
32
+
33
+ def echo_off
34
+ system "stty -echo"
35
+ end
36
+
37
+ def echo_on
38
+ system "stty echo"
39
+ end
40
+
41
+ def ask
42
+ gets.strip
43
+ end
44
+
45
+ def ask_for_password
46
+ echo_off
47
+ password = ask
48
+ puts
49
+ echo_on
50
+ return password
51
+ end
52
+
53
+ def with_valid_user
54
+ request_credentials unless Stastic::Config.credentials?
55
+ begin
56
+ yield
57
+ rescue RestClient::Forbidden
58
+ request_credentials
59
+ retry
60
+ rescue RestClient::UnprocessableEntity => e
61
+ puts "There was an error with the request:"
62
+ puts
63
+ JSON.parse(e.response)['errors'].each do |msg|
64
+ printf(" * %s\n", msg)
65
+ end
66
+ puts
67
+ exit -1
68
+ end
69
+ end
70
+
71
+ def with_valid_site
72
+ request_credentials unless Stastic::Config.credentials?
73
+ missing_site_id unless Stastic::Config.site_defined?
74
+ begin
75
+ yield
76
+ rescue RestClient::Forbidden
77
+ request_credentials
78
+ retry
79
+ rescue RestClient::UnprocessableEntity => e
80
+ puts "Error:"
81
+ puts e.response.to_s
82
+ puts
83
+ exit
84
+ end
85
+ end
86
+
87
+ def missing_site_id
88
+ puts "No Stastic Site found. To create a site, run:"
89
+ puts
90
+ puts " stastic create"
91
+ puts
92
+ exit
93
+ end
94
+ end
95
+ end
96
+
@@ -0,0 +1,68 @@
1
+ module Stastic::Command
2
+ class Create < Base
3
+ attr_accessor :name
4
+ attr_accessor :template
5
+
6
+ def initialize(args = [])
7
+ case args.size
8
+ when 0
9
+ self.name = nil
10
+ when 1
11
+ if args.first == "--template"
12
+ self.template = "default"
13
+ else
14
+ self.name = args.first
15
+ end
16
+ when 2
17
+ raise(Stastic::InvalidOptions) unless args.first == "--template"
18
+ self.template = "default"
19
+ self.name = args.last
20
+ puts self.template
21
+ else
22
+ raise(Stastic::InvalidOptions)
23
+ end
24
+ end
25
+
26
+ def index
27
+ if template
28
+ copy_template("#{File.dirname(__FILE__)}/../../../templates/#{template}/")
29
+ end
30
+
31
+ response = with_valid_user do
32
+ Stastic::Client.create(name)
33
+ end
34
+
35
+ if response["id"]
36
+ Stastic::Config.add(:site_id => response["id"])
37
+ end
38
+
39
+ if response["name"]
40
+ Stastic::Config.add(:name => response["name"])
41
+ print "Your site has been created!\n\n"
42
+ print " Site Name: #{Stastic::Config.name}\n"
43
+ print " Site URL: #{Stastic::Config.name}.stastic.com\n\n"
44
+ print "Use `stastic publish` to publish your site whenever you're ready.\n"
45
+ end
46
+
47
+ end
48
+
49
+ private
50
+
51
+ def copy_template(src)
52
+ dest = Dir.pwd
53
+ Dir.foreach(src) do |file|
54
+ s = File.join(src, file)
55
+ d = File.join(dest, file)
56
+
57
+ if File.directory?(s)
58
+ FileUtils.cp_r(s, d, :preserve => true)
59
+ else
60
+ FileUtils.cp(s,d, :preserve => true)
61
+ end
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+ end
68
+
@@ -0,0 +1,41 @@
1
+ module Stastic::Command
2
+ class Domains < Base
3
+ attr_accessor :domain_name
4
+
5
+ def initialize(args = [])
6
+ case args.size
7
+ when 1
8
+ self.domain_name = args.first
9
+ raise(Stastic::Command::InvalidOptions) unless validate_domain(domain_name)
10
+ else
11
+ raise(Stastic::Command::InvalidOptions)
12
+ end
13
+
14
+ end
15
+
16
+ def index
17
+ end
18
+
19
+ def add
20
+ print "Adding domain #{domain_name}... "
21
+ with_valid_site do
22
+ Stastic::Client.add_domain(Stastic::Config.site_id, domain_name)
23
+ end
24
+ puts "Success\n"
25
+ end
26
+
27
+ def remove
28
+ print "Removing domain #{domain_name}... "
29
+ with_valid_site do
30
+ Stastic::Client.remove_domain(Stastic::Config.site_id, domain_name)
31
+ end
32
+ puts "Success\n"
33
+ end
34
+
35
+ private
36
+ def validate_domain(domain_name)
37
+ domain_name =~ /^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.){1,3}([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$/
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,33 @@
1
+ module Stastic::Command
2
+ class Help < Base
3
+
4
+ def index
5
+ print usage
6
+ end
7
+
8
+ private
9
+
10
+ def usage
11
+ <<-EOF
12
+ stastic (#{Stastic::VERSION}) - command-line tool for managing your Stastic sites
13
+
14
+ Available Commands
15
+ ------------------
16
+
17
+ stastic help # You're looking at it!
18
+ stastic create [name] # Create a site (using the current directory)
19
+ stastic publish # Publish the site
20
+ stastic info # Show info about the current site
21
+ stastic list # List sites associated with your account
22
+ stastic rename <name> # Rename the site (name.stastic.com)
23
+ stastic domains:add <domain> # Add a domain to the site (example.com)
24
+ stastic domains:remove <domain> # Remove a domain from the site
25
+ stastic preview # Start local HTTP server
26
+ stastic set site_root <path> # Set the local path to the static files
27
+
28
+ EOF
29
+ end
30
+
31
+ end
32
+ end
33
+
@@ -0,0 +1,26 @@
1
+ module Stastic::Command
2
+ class Info < Base
3
+ attr_accessor :name
4
+
5
+ def index
6
+ puts info
7
+ end
8
+
9
+ private
10
+
11
+ def info
12
+ generator = Stastic::Generator.detect
13
+ <<-EOF
14
+ stastic version : #{Stastic::VERSION}
15
+ user : #{Stastic::Config.user}
16
+ active site name : #{Stastic::Config.name}
17
+ active site id : #{Stastic::Config.site_id}
18
+ active site url : http://#{Stastic::Config.name}.stastic.com/
19
+
20
+ generator : #{generator.desc}
21
+ site_root : #{generator.site_root}
22
+
23
+ EOF
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,37 @@
1
+ module Stastic::Command
2
+ class List < Base
3
+
4
+ def index
5
+ list
6
+ end
7
+
8
+ private
9
+
10
+ def list
11
+ response = with_valid_user { Stastic::Client.list }
12
+
13
+ puts header
14
+ response['sites'].each do |site|
15
+ site_info(site, site['id'] == Stastic::Config.site_id ? "*" : " ")
16
+ end
17
+ puts
18
+ end
19
+
20
+ def header
21
+ <<-EOF
22
+
23
+ Your Stastic Sites
24
+ -----------------
25
+
26
+ name url
27
+ ---- ---
28
+ EOF
29
+ end
30
+
31
+ def site_info(site, marker = " ")
32
+ printf("%-2s%-30s http://%s.stastic.com\n", marker, site['name'], site['name'])
33
+ end
34
+
35
+ end
36
+ end
37
+
@@ -0,0 +1,9 @@
1
+ module Stastic::Command
2
+ class Preview < Base
3
+
4
+ def index
5
+ generator = Stastic::Generator.detect
6
+ generator.preview
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,34 @@
1
+ module Stastic::Command
2
+ class Publish < Base
3
+
4
+ def index
5
+ publish
6
+ end
7
+
8
+ private
9
+ def publish
10
+ puts "Detecting..."
11
+ generator = Stastic::Generator.detect
12
+ puts "Found: #{generator.desc}"
13
+
14
+ puts "Building..."
15
+ generator.build
16
+
17
+ puts "Packaging..."
18
+ archive_path = generator.package
19
+
20
+ print "Uploading..."
21
+ upload(archive_path)
22
+
23
+ end
24
+
25
+ def upload(archive_path)
26
+ print "Uploading your archive...\n"
27
+ reponse = with_valid_site do
28
+ Stastic::Client.publish(Stastic::Config.site_id, archive_path)
29
+ end
30
+ puts "Complete\n"
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,25 @@
1
+ module Stastic::Command
2
+ class Rename < Base
3
+ attr_accessor :new_name
4
+
5
+ def initialize(args = [])
6
+ case args.size
7
+ when 1
8
+ self.new_name = args.first
9
+ else
10
+ raise(Stastic::Command::InvalidOptions)
11
+ end
12
+ end
13
+
14
+ def index
15
+ print "Changing Site Name... "
16
+ response = with_valid_site do
17
+ Stastic::Client.rename(Stastic::Config.site_id, new_name)
18
+ end
19
+ Stastic::Config.update(:name => response["name"])
20
+ puts "Success\n"
21
+ end
22
+
23
+ end
24
+ end
25
+
@@ -0,0 +1,54 @@
1
+ module Stastic::Command
2
+ class Set < Base
3
+ attr_accessor :settings
4
+
5
+ VALID_SETTINGS = [:site_root, :site_id]
6
+
7
+ def initialize(args = [])
8
+ case args.size
9
+ when 0
10
+ raise(Stastic::Command::InvalidOptions)
11
+ else
12
+ self.settings = parse_args(args)
13
+ validate_settings(settings)
14
+ end
15
+ end
16
+
17
+ def index
18
+ update_settings(settings)
19
+ end
20
+
21
+ private
22
+ def parse_args(args)
23
+ args.inject(Hash.new) do |h,arg|
24
+ k,v = arg.split('=')
25
+ h[k.to_sym] = v
26
+ h
27
+ end
28
+ end
29
+
30
+ def validate_settings(settings)
31
+ raise(Stastic::Command::InvalidOptions) unless settings.keys.all? {|key| VALID_SETTINGS.include?(key)}
32
+ end
33
+
34
+ def set_name(name)
35
+ print "Changing Site Name... "
36
+ begin
37
+ response = Stastic::Client.request(:put, "/sites/#{Stastic::Config.site_id}", {:site => {:name => name}})
38
+ rescue Stastic::InvalidCredentials
39
+ request_credentials
40
+ retry
41
+ rescue Stastic::ValidationFailed
42
+ print "Could not change site name\n"
43
+ exit
44
+ end
45
+
46
+ puts "Success\n"
47
+ true
48
+ end
49
+
50
+ def update_settings(settings)
51
+ Stastic::Config.update(settings)
52
+ end
53
+ end
54
+ end