nimbu 0.4 → 0.5.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.
@@ -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