nimbu 0.4 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,13 +4,31 @@ require "nimbu/command/base"
4
4
  #
5
5
  class Nimbu::Command::Auth < Nimbu::Command::Base
6
6
 
7
+ # auth
8
+ #
9
+ # Authenticate, display token and current user
10
+ def index
11
+ Nimbu::Command::Help.new.send(:help_for_command, current_command)
12
+ end
13
+
7
14
  # auth:login
8
15
  #
9
16
  # log in with your nimbu credentials
10
17
  #
18
+ #Example:
19
+ #
20
+ # $ nimbu auth:login
21
+ #
22
+ # Please enter your Nimbu credentials:
23
+ #
24
+ # Login: email@example.com (or your Nimbu username)
25
+ # Password (typing will be hidden)
26
+ #
27
+ # Authentication successful.
28
+ #
11
29
  def login
12
30
  Nimbu::Auth.login
13
- display "Authentication successful."
31
+ display " => Authentication successful."
14
32
  end
15
33
 
16
34
  alias_command "login", "auth:login"
@@ -21,7 +39,7 @@ class Nimbu::Command::Auth < Nimbu::Command::Base
21
39
  #
22
40
  def logout
23
41
  Nimbu::Auth.logout
24
- display "Local credentials cleared."
42
+ display "=> Local credentials cleared."
25
43
  end
26
44
 
27
45
  alias_command "logout", "auth:logout"
@@ -31,7 +49,7 @@ class Nimbu::Command::Auth < Nimbu::Command::Base
31
49
  # display your api token
32
50
  #
33
51
  def token
34
- display Nimbu::Auth.api_key
52
+ display "=> Your personal API token is: #{Nimbu::Auth.token}"
35
53
  end
36
54
 
37
55
  end
@@ -1,6 +1,5 @@
1
1
  require "fileutils"
2
2
  require "nimbu/auth"
3
- require "nimbu/client/rendezvous"
4
3
  require "nimbu/command"
5
4
 
6
5
  class Nimbu::Command::Base
@@ -16,28 +15,8 @@ class Nimbu::Command::Base
16
15
  def initialize(args=[], options={})
17
16
  @args = args
18
17
  @options = options
19
-
20
- Nimbu.debug = args.include?("--debug")
21
- Nimbu.development = args.include?("--development") || args.include?("--dev")
22
- Nimbu.v2 = args.include?("--v2")
23
- end
24
-
25
- def app
26
- @app ||= if options[:app].is_a?(String)
27
- if confirm_mismatch?
28
- raise Nimbu::Command::CommandFailed, "Mismatch between --app and --confirm"
29
- end
30
- options[:app]
31
- elsif options[:confirm].is_a?(String)
32
- options[:confirm]
33
- elsif app_from_dir = extract_app_in_dir(Dir.pwd)
34
- app_from_dir
35
- else
36
- raise Nimbu::Command::CommandFailed, "No app specified.\nRun this command from an app folder or specify which app to use with --app <app name>"
37
- end
38
18
  end
39
19
 
40
-
41
20
  def nimbu
42
21
  Nimbu::Auth.client
43
22
  end
@@ -45,14 +24,14 @@ class Nimbu::Command::Base
45
24
  protected
46
25
 
47
26
  def self.inherited(klass)
48
- return if klass == Nimbu::Command::Base
27
+ unless klass == Nimbu::Command::Base
28
+ help = extract_help_from_caller(caller.first)
49
29
 
50
- help = extract_help_from_caller(caller.first)
51
-
52
- Nimbu::Command.register_namespace(
53
- :name => klass.namespace,
54
- :description => help.split("\n").first
55
- )
30
+ Nimbu::Command.register_namespace(
31
+ :name => klass.namespace,
32
+ :description => help.first
33
+ )
34
+ end
56
35
  end
57
36
 
58
37
  def self.method_added(method)
@@ -64,20 +43,17 @@ protected
64
43
  resolved_method = (method.to_s == "index") ? nil : method.to_s
65
44
  command = [ self.namespace, resolved_method ].compact.join(":")
66
45
  banner = extract_banner(help) || command
67
- permute = !banner.index("*")
68
- banner.gsub!("*", "")
69
46
 
70
47
  Nimbu::Command.register_command(
71
48
  :klass => self,
72
49
  :method => method,
73
50
  :namespace => self.namespace,
74
51
  :command => command,
75
- :banner => banner,
76
- :help => help,
52
+ :banner => banner.strip,
53
+ :help => help.join("\n"),
77
54
  :summary => extract_summary(help),
78
55
  :description => extract_description(help),
79
- :options => extract_options(help),
80
- :permute => permute
56
+ :options => extract_options(help)
81
57
  )
82
58
  end
83
59
 
@@ -91,19 +67,6 @@ protected
91
67
  app
92
68
  end
93
69
 
94
- #
95
- # Parse the caller format and identify the file and line number as identified
96
- # in : http://www.ruby-doc.org/core/classes/Kernel.html#M001397. This will
97
- # look for a colon followed by a digit as the delimiter. The biggest
98
- # complication is windows paths, which have a color after the drive letter.
99
- # This regex will match paths as anything from the beginning to a colon
100
- # directly followed by a number (the line number).
101
- #
102
- # Examples of the caller format :
103
- # * c:/Ruby192/lib/.../lib/nimbu/command/addons.rb:8:in `<module:Command>'
104
- # * c:/Ruby192/lib/.../nimbu-2.0.1/lib/nimbu/command/pg.rb:96:in `<class:Pg>'
105
- # * /Users/ph7/...../xray-1.1/lib/xray/thread_dump_signal_handler.rb:9
106
- #
107
70
  def self.extract_help_from_caller(line)
108
71
  # pull out of the caller the information for the file path and line number
109
72
  if line =~ /^(.+?):(\d+)/
@@ -112,50 +75,46 @@ protected
112
75
  raise "unable to extract help from caller: #{line}"
113
76
  end
114
77
 
115
- def self.extract_help(file, line)
78
+ def self.extract_help(file, line_number)
116
79
  buffer = []
117
- lines = File.read(file).split("\n")
118
-
119
- catch(:done) do
120
- (line.to_i-2).downto(0) do |i|
121
- case lines[i].strip[0..0]
122
- when "", "#" then buffer << lines[i]
123
- else throw(:done)
124
- end
80
+ lines = Nimbu::Command.files[file]
81
+
82
+ (line_number.to_i-2).downto(0) do |i|
83
+ line = lines[i]
84
+ case line[0..0]
85
+ when ""
86
+ when "#"
87
+ buffer.unshift(line[1..-1])
88
+ else
89
+ break
125
90
  end
126
91
  end
127
92
 
128
- buffer.map! do |line|
129
- line.strip.gsub(/^#/, "")
130
- end
131
-
132
- buffer.reverse.join("\n").strip
93
+ buffer
133
94
  end
134
95
 
135
96
  def self.extract_banner(help)
136
- help.split("\n").first
97
+ help.first
137
98
  end
138
99
 
139
100
  def self.extract_summary(help)
140
- extract_description(help).split("\n").first
101
+ extract_description(help).split("\n")[2].to_s.split("\n").first
141
102
  end
142
103
 
143
104
  def self.extract_description(help)
144
- lines = help.split("\n").map { |l| l.strip }
145
- lines.shift
146
- lines.reject do |line|
147
- line =~ /^-(.+)#(.+)/
148
- end.join("\n").strip
105
+ help.reject do |line|
106
+ line =~ /^\s+-(.+)#(.+)/
107
+ end.join("\n")
149
108
  end
150
109
 
151
110
  def self.extract_options(help)
152
- help.split("\n").map { |l| l.strip }.select do |line|
153
- line =~ /^-(.+)#(.+)/
154
- end.inject({}) do |hash, line|
155
- description = line.split("#", 2).last.strip
156
- long = line.match(/--([A-Za-z\- ]+)/)[1].strip
157
- short = line.match(/-([A-Za-z ])/)[1].strip
158
- hash.update(long.split(" ").first => { :desc => description, :short => short, :long => long })
111
+ help.select do |line|
112
+ line =~ /^\s+-(.+)#(.+)/
113
+ end.inject([]) do |options, line|
114
+ args = line.split('#', 2).first
115
+ args = args.split(/,\s*/).map {|arg| arg.strip}.sort.reverse
116
+ name = args.last.split(' ', 2).first[2..-1]
117
+ options << { :name => name, :args => args }
159
118
  end
160
119
  end
161
120
 
@@ -170,6 +129,10 @@ protected
170
129
  options[:confirm] && (options[:confirm] != options[:app])
171
130
  end
172
131
 
132
+ def current_command
133
+ Nimbu::Command.current_command
134
+ end
135
+
173
136
  def extract_app_in_dir(dir)
174
137
  return unless remotes = git_remotes(dir)
175
138
 
@@ -0,0 +1,63 @@
1
+ require "nimbu/command/base"
2
+
3
+ # open the current site in your browser (simulator, admin)
4
+ #
5
+ class Nimbu::Command::Browse < Nimbu::Command::Base
6
+ # index
7
+ #
8
+ # open the current site in your browser
9
+ #
10
+ def index
11
+ cmd = browse_command(args) do
12
+ dest = args.shift
13
+ dest = nil if dest == '--'
14
+
15
+ if dest
16
+ #site = nimbu browser dest
17
+ else
18
+ # $ nimbu browse
19
+ site = Nimbu::Auth.site
20
+ end
21
+
22
+ abort "Usage: nimbu browse <SITE>" unless site
23
+ "https://#{site}.#{Nimbu::Auth.admin_host}"
24
+ end
25
+ exec(cmd)
26
+ end
27
+
28
+ # index
29
+ #
30
+ # open the simulator for your current site
31
+ #
32
+ def simulator
33
+ cmd = browse_command(args) do
34
+ "http://localhost:4567"
35
+ end
36
+ exec(cmd)
37
+ end
38
+
39
+ # index
40
+ #
41
+ # open the admin area for your current site
42
+ #
43
+ def admin
44
+ cmd = browse_command(args) do
45
+ "https://#{Nimbu::Auth.site}.#{Nimbu::Auth.admin_host}/admin"
46
+ end
47
+ exec(cmd)
48
+ end
49
+
50
+ protected
51
+
52
+ def browse_command(args)
53
+ url_only = args.delete('-u')
54
+ url = yield
55
+
56
+ exec_args = []
57
+ exec_args.push(url_only ? 'echo' : browser_launcher)
58
+ exec_args.push url
59
+ exec_args.join(" ")
60
+ end
61
+
62
+ end
63
+
@@ -4,7 +4,7 @@ require "nimbu/command/base"
4
4
  #
5
5
  class Nimbu::Command::Help < Nimbu::Command::Base
6
6
 
7
- PRIMARY_NAMESPACES = %w( auth server themes )
7
+ PRIMARY_NAMESPACES = %w( auth server themes sites init browse )
8
8
 
9
9
  # help [COMMAND]
10
10
  #
@@ -261,10 +261,12 @@ module Nimbu
261
261
  display(format_with_bang(message), new_line)
262
262
  end
263
263
 
264
- def error_with_failure(message)
265
- display "failed"
266
- output_with_bang(message)
267
- exit 1
264
+ def self.error_with_failure
265
+ @@error_with_failure ||= false
266
+ end
267
+
268
+ def self.error_with_failure=(new_error_with_failure)
269
+ @@error_with_failure = new_error_with_failure
268
270
  end
269
271
 
270
272
  def self.included_into
@@ -1,24 +1,23 @@
1
1
  require "nimbu/command/base"
2
2
  require 'term/ansicolor'
3
3
 
4
- # authentication (login, logout)
4
+ # working directory initialization
5
5
  #
6
6
  class Nimbu::Command::Init < Nimbu::Command::Base
7
7
  include Term::ANSIColor
8
8
 
9
9
  # index
10
10
  #
11
- # log in with your nimbu credentials
11
+ # initialize your working directory to code a selected theme
12
12
  #
13
13
  def index
14
14
  if Nimbu::Auth.read_configuration && Nimbu::Auth.read_credentials
15
15
  print green(bold("CONGRATULATIONS!")), ": this directory is already configured as a Nimbu theme."
16
16
  else
17
- display "Initialize the Nimbu configuration file."
18
- config = Nimbu::Auth.get_configuration
17
+ credentials = Nimbu::Auth.get_credentials
19
18
 
20
- display "Configuration ready: #{config}"
21
- config = Nimbu::Auth.get_credentials
19
+ display "Initializing the Nimbu configuration file."
20
+ config = Nimbu::Auth.get_configuration
22
21
 
23
22
  display "Initializing directories:"
24
23
  display " - layouts"
@@ -1,8 +1,6 @@
1
1
  require "nimbu/command/base"
2
2
  require "nimbu/server/base"
3
3
  require 'term/ansicolor'
4
- require 'compass'
5
- require 'compass/exec'
6
4
  require 'thin'
7
5
 
8
6
  # running a local server to speed up designing Nimbu themes
@@ -11,124 +9,190 @@ class Nimbu::Command::Server < Nimbu::Command::Base
11
9
  include Term::ANSIColor
12
10
  # server
13
11
  #
14
- # list available commands or display help for a specific command
12
+ # starts a local development server, using the data from the Nimbu cloud in real time.
13
+ #
14
+ # -p PORT, --port PORT # set the port on which to start the http server
15
+ # -h, --haml # start local HAML watcher
16
+ # -c, --compass # start local Compass watcher
17
+ # -d, --debug # enable debugging output
15
18
  #
16
19
  def index
17
20
  # Check if config file is present?
18
21
  if !Nimbu::Auth.read_configuration || !Nimbu::Auth.read_credentials
19
22
  print red(bold("ERROR")), ": this directory does not seem to contain any Nimbu theme or your credentials are not set. \n ==> Run \"", bold { "nimbu init"}, "\" to initialize this directory."
20
23
  else
21
- no_haml = args.include?("--no-haml")
22
- no_compass = args.include?("--no-compass")
24
+ no_compilation = true #! options[:'no-compile']
25
+ with_haml = options[:haml]
26
+ with_compass = options[:compass]
23
27
 
24
- if !(File.exists?(File.join(Dir.pwd,'haml')) && File.directory?(File.join(Dir.pwd,'haml')))
25
- no_haml = true
26
- puts red("\n !! WARNING: no ./haml directory detected => starting without HAML support !!")
28
+ if with_compass
29
+ require 'compass'
30
+ require 'compass/exec'
27
31
  end
28
32
 
29
- puts white("\nStarting up Nimbu Server" + (no_compass ? "" : " + Compass Watcher") + (no_haml ? "" : " + HAML Compiler") + "...")
30
- puts green(
31
- "\n _ ___ __ \n" +
32
- " / | / (_)____ ___ / /_ __ __\n" +
33
- " / |/ / // __ `__ \\/ __ \\/ / / /\n" +
34
- " / /| / // / / / / / /_/ / /_/ / \n" +
35
- " /_/ |_/_//_/ /_/ /_/_.___/\\__,_/ \n")
33
+ if with_haml
34
+ require 'haml'
35
+ end
36
36
 
37
- puts green("\nConnnected to '#{Nimbu::Auth.host}', using '#{Nimbu::Auth.theme}' theme.\n")
37
+ services = []
38
+ services << "HAML" if with_haml
39
+ services << "Compass" if with_compass
40
+ title = "Starting up Nimbu Server"
41
+ title << "(with local #{services.join(' and ')} watcher)" if with_compass || with_haml
42
+ title << "..."
43
+ puts white("\n#{title}")
44
+ puts green(nimbu_header)
45
+ puts green("\nConnnected to '#{Nimbu::Auth.site}.#{Nimbu::Auth.admin_host}', using '#{Nimbu::Auth.theme}' theme#{Nimbu.debug ? ' (in debug mode)'.red : nil}.\n")
38
46
 
39
- rd1, wr1 = IO::pipe
40
- rd2, wr2 = IO::pipe
41
- rd3, wr3 = IO::pipe
47
+ server_read, server_write = IO::pipe
48
+ haml_read, haml_write = IO::pipe
49
+ compass_read, compass_write = IO::pipe
50
+ compiler_read, compiler_write = IO::pipe
42
51
 
43
52
  server_pid = Process.fork do
44
- $stdout.reopen(wr1)
45
- rd1.close
46
- puts "Starting..."
47
- options = {
48
- :Port => 4567,
53
+ $stdout.reopen(server_write)
54
+ server_read.close
55
+ puts "Starting server..."
56
+ server_options = {
57
+ :Port => options[:port] || 4567,
49
58
  :DocumentRoot => Dir.pwd
50
59
  }
51
- Rack::Handler::Thin.run Nimbu::Server::Base, options do |server|
60
+ Rack::Handler::Thin.run Nimbu::Server::Base, server_options do |server|
52
61
  [:INT, :TERM].each { |sig| trap(sig) { server.respond_to?(:stop!) ? server.stop! : server.stop } }
53
62
  end
54
63
  end
55
64
 
65
+ # assets_pid = Process.fork do
66
+ # $stdout.reopen(compiler_write)
67
+ # compiler_read.close
68
+ # puts "Starting watcher..."
69
+ # HamlWatcher.watch
70
+ # end unless no_compilation
71
+
56
72
  haml_pid = Process.fork do
57
- $stdout.reopen(wr2)
58
- rd2.close
73
+ $stdout.reopen(haml_write)
74
+ haml_read.close
59
75
  puts "Starting..."
60
- HamlWatcher.watch
61
- end unless no_haml
76
+ haml_listener = HamlWatcher.watch
77
+ [:INT, :TERM].each do |sig|
78
+ Signal.trap(sig) do
79
+ puts green("== Stopping HAML watcher\n")
80
+ haml_listener.stop
81
+ puts haml_listener
82
+ end
83
+ end
84
+ Process.waitall
85
+ end if with_haml
62
86
 
63
87
  compass_pid = Process.fork do
64
- $stdout.reopen(wr3)
65
- rd3.close
88
+ $stdout.reopen(compass_write)
89
+ compass_read.close
66
90
  puts "Starting..."
67
91
  Compass::Exec::SubCommandUI.new(["watch","."]).run!
68
- end unless no_compass
69
-
92
+ end if with_compass
70
93
 
71
94
  watch_server_pid = Process.fork do
72
95
  trap('INT') { exit }
73
- wr1.close
74
- rd1.each do |line|
96
+ server_write.close
97
+ server_read.each do |line|
75
98
  print cyan("SERVER: ") + white(line) + ""
76
99
  end
77
100
  end
101
+
102
+ # watch_assets_pid = Process.fork do
103
+ # trap('INT') { exit }
104
+ # compiler_write.close
105
+ # compiler_read.each do |line|
106
+ # print magenta("ASSETS: ") + white(line) + ""
107
+ # end
108
+ # end unless no_compilation
109
+
78
110
  watch_haml_pid = Process.fork do
79
111
  trap('INT') { exit }
80
- wr2.close
81
- rd2.each do |line|
112
+ haml_write.close
113
+ haml_read.each do |line|
82
114
  print magenta("HAML: ") + white(line) + ""
83
115
  end
84
- end unless no_haml
116
+ end if with_haml
85
117
 
86
118
  watch_compass_pid = Process.fork do
87
119
  trap('INT') { exit }
88
- wr3.close
89
- rd3.each do |line|
120
+ compass_write.close
121
+ compass_read.each do |line|
90
122
  print yellow("COMPASS: ") + white(line) + ""
91
123
  end
92
- end unless no_compass
124
+ end if with_compass
93
125
 
94
- [:INT, :TERM].each do |sig|
126
+ [:INT, :TERM].each do |sig|
95
127
  trap(sig) do
96
128
  puts yellow("\n== Waiting for all processes to finish...")
129
+ Process.kill('INT', haml_pid) if haml_pid && running?(haml_pid)
97
130
  Process.waitall
98
131
  puts green("== Nimbu has ended its work " + bold("(crowd applauds!)\n"))
99
132
  end
100
133
  end
101
134
 
102
- Process.waitall
135
+ Process.waitall
136
+ end
137
+ end
138
+
139
+ protected
140
+
141
+ def nimbu_header
142
+ h = ""
143
+ h << "\n o8o .o8"
144
+ h << "\n `\"' \"888"
145
+ h << "\nooo. .oo. oooo ooo. .oo. .oo. 888oooo. oooo oooo"
146
+ h << "\n`888P\"Y88b `888 `888P\"Y88bP\"Y88b d88' `88b `888 `888"
147
+ h << "\n 888 888 888 888 888 888 888 888 888 888"
148
+ h << "\n 888 888 888 888 888 888 888 888 888 888"
149
+ h << "\no888o o888o o888o o888o o888o o888o `Y8bod8P' `V88V\"V8P'"
150
+ end
151
+
152
+ def running?(pid)
153
+ begin
154
+ Process.getpgid( pid )
155
+ true
156
+ rescue Errno::ESRCH
157
+ false
103
158
  end
104
159
  end
105
160
  end
106
161
 
107
162
  require 'rubygems'
108
- require 'fssm'
163
+ require 'listen'
109
164
  require 'haml'
110
165
 
111
166
  class HamlWatcher
112
167
  class << self
113
168
  include Term::ANSIColor
114
-
169
+
115
170
  def watch
116
171
  refresh
117
172
  puts ">>> Haml is polling for changes. Press Ctrl-C to Stop."
118
- FSSM.monitor('haml', '**/*.haml') do
119
- update do |base, relative|
173
+ listener = Listen.to('haml')
174
+ listener.relative_paths(true)
175
+ listener.filter(/\.haml$/)
176
+ modifier = lambda do |modified, added, removed|
177
+ puts modified.inspect
178
+ modified.each do |relative|
120
179
  puts ">>> Change detected to: #{relative}"
121
180
  HamlWatcher.compile(relative)
122
- end
123
- create do |base, relative|
181
+ end if modified
182
+
183
+ added.each do |relative|
124
184
  puts ">>> File created: #{relative}"
125
185
  HamlWatcher.compile(relative)
126
- end
127
- delete do |base, relative|
186
+ end if added
187
+
188
+ removed.each do |relative|
128
189
  puts ">>> File deleted: #{relative}"
129
190
  HamlWatcher.remove(relative)
130
- end
191
+ end if removed
131
192
  end
193
+ listener.change(&modifier)
194
+ listener.start(false)
195
+ listener
132
196
  end
133
197
 
134
198
  def output_file(filename)
@@ -153,7 +217,7 @@ class HamlWatcher
153
217
  puts "\033[0;#{color}m#{action}\033[0m #{output_file_name}"
154
218
  FileUtils.mkdir_p(File.dirname(output_file_name))
155
219
  File.open(output_file_name,'w') {|f| f.write(result)}
156
- rescue Exception => e
220
+ rescue Exception => e
157
221
  print red("#{plainError e, file}\n")
158
222
  output_file_name = output_file(file)
159
223
  result = goHere(e, file)
@@ -194,7 +258,7 @@ class HamlWatcher
194
258
  return (exception.message.scan(/:(\d+)/).first || ["??"]).first if exception.is_a?(::SyntaxError)
195
259
  (exception.backtrace[0].scan(/:(\d+)/).first || ["??"]).first
196
260
  end
197
-
261
+
198
262
  def plainError(message, nameoffile)
199
263
  @plainMessage = ""
200
264
  @plainMessage += "Error: #{message} \n"
@@ -202,7 +266,7 @@ class HamlWatcher
202
266
  @plainMessage += "File error detected: #{nameoffile}"
203
267
  return @plainMessage
204
268
  end
205
-
269
+
206
270
  def sassErrorLine message
207
271
  return message
208
272
  end