stastic 0.1.0 → 0.2.0

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/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