space 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/Gemfile +2 -0
  2. data/Gemfile.lock +17 -2
  3. data/Guardfile +5 -0
  4. data/README.md +4 -0
  5. data/Rakefile +1 -1
  6. data/bin/space +2 -1
  7. data/lib/core_ext/{enumerable.rb → enumerable/map_slice.rb} +2 -7
  8. data/lib/core_ext/{string.rb → string/wrap.rb} +1 -2
  9. data/lib/space.rb +6 -16
  10. data/lib/space/app.rb +36 -48
  11. data/lib/space/app/command.rb +45 -0
  12. data/lib/space/app/command/builtin.rb +43 -0
  13. data/lib/space/app/command/development.rb +60 -0
  14. data/lib/space/app/handler.rb +47 -0
  15. data/lib/space/app/logger.rb +21 -0
  16. data/lib/space/{action → app}/parser.rb +3 -2
  17. data/lib/space/config.rb +14 -6
  18. data/lib/space/events.rb +34 -0
  19. data/lib/space/events/buffer.rb +18 -0
  20. data/lib/space/events/event.rb +14 -0
  21. data/lib/space/helpers.rb +30 -15
  22. data/lib/space/models.rb +7 -0
  23. data/lib/space/models/project.rb +48 -0
  24. data/lib/space/models/project/bundler.rb +30 -0
  25. data/lib/space/models/repo.rb +46 -29
  26. data/lib/space/models/repo/bundle.rb +39 -0
  27. data/lib/space/models/repo/dependency.rb +22 -0
  28. data/lib/space/models/repo/git.rb +52 -0
  29. data/lib/space/models/repos.rb +31 -26
  30. data/lib/space/models/repos/collection.rb +26 -0
  31. data/lib/space/models/repos/scope.rb +18 -0
  32. data/lib/space/screen.rb +19 -15
  33. data/lib/space/screen/dashboard.rb +28 -0
  34. data/lib/space/screen/progress.rb +15 -0
  35. data/lib/space/screen/view.rb +43 -0
  36. data/lib/space/shell.rb +56 -0
  37. data/lib/space/shell/command.rb +63 -0
  38. data/lib/space/shell/watch.rb +50 -0
  39. data/lib/space/shell/watcher.rb +40 -0
  40. data/lib/space/templates/{project.erb → header.erb} +0 -1
  41. data/lib/space/templates/{repository.erb → repo.erb} +1 -1
  42. data/lib/space/tmux.rb +11 -0
  43. data/lib/space/version.rb +1 -1
  44. metadata +33 -15
  45. data/lib/space/action.rb +0 -84
  46. data/lib/space/models/bundle.rb +0 -44
  47. data/lib/space/models/command.rb +0 -28
  48. data/lib/space/models/commands.rb +0 -23
  49. data/lib/space/models/dependency.rb +0 -18
  50. data/lib/space/models/git.rb +0 -23
  51. data/lib/space/view.rb +0 -25
@@ -0,0 +1,21 @@
1
+ require 'logger'
2
+ require 'fileutils'
3
+
4
+ module Space
5
+ class App
6
+ class Logger < ::Logger
7
+ def initialize
8
+ truncate
9
+ super('/tmp/space.log')
10
+ end
11
+
12
+ def truncate
13
+ File.open(filename, 'w+') { |f| f.write('-' * 80 + "\n") }
14
+ end
15
+
16
+ def filename
17
+ '/tmp/space.log'
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,5 +1,5 @@
1
1
  module Space
2
- class Action
2
+ class App
3
3
  class Parser
4
4
  attr_reader :names, :line
5
5
 
@@ -11,7 +11,7 @@ module Space
11
11
  @line = line
12
12
  scope = parse_scope
13
13
  command = parse_command
14
- [scope, command]
14
+ [scope || names, command]
15
15
  end
16
16
 
17
17
  private
@@ -35,3 +35,4 @@ module Space
35
35
  end
36
36
  end
37
37
  end
38
+
data/lib/space/config.rb CHANGED
@@ -2,15 +2,23 @@ module Space
2
2
  class Config < Hashr
3
3
  class << self
4
4
  def load(name)
5
- paths = %W(~/.space/#{name}.yml ./.#{name}.yml).map { |path| File.expand_path(path) }
6
- unless path = paths.detect { |path| File.exists?(path) }
7
- puts("Could not find #{name}.yml at either of ~/.space/#{name}.yml and ./.#{name}.yml")
8
- exit
9
- end
10
- new(YAML.load(File.read(path)))
5
+ new(YAML.load(File.read(path(name))))
11
6
  end
7
+
8
+ private
9
+
10
+ def path(name)
11
+ path = paths(name).detect { |path| File.exists?(path) }
12
+ path || raise("Could not find #{name}.yml at either of ~/.space/#{name}.yml and ./.space/#{name}.yml")
13
+ end
14
+
15
+ def paths(name)
16
+ %w(. ~).map { |path| File.expand_path("#{path}/.space/#{name}.yml") }
17
+ end
12
18
  end
13
19
 
20
+ define :template_dir => File.expand_path('../templates', __FILE__)
21
+
14
22
  def paths
15
23
  @paths ||= repositories.map { |path| base_dir ? "#{base_dir}/#{path}" : path }
16
24
  end
@@ -0,0 +1,34 @@
1
+ module Space
2
+ module Events
3
+ autoload :Buffer, 'space/events/buffer'
4
+ autoload :Event, 'space/events/event'
5
+
6
+ attr_reader :buffer
7
+
8
+ def buffering
9
+ @buffer = Buffer.new
10
+ yield.tap do
11
+ buffer, @buffer = @buffer, nil
12
+ buffer.flush
13
+ end
14
+ end
15
+
16
+ def buffering?
17
+ !!@buffer
18
+ end
19
+
20
+ def observers
21
+ @observers ||= []
22
+ end
23
+
24
+ def subscribe(observer)
25
+ observers << observer
26
+ end
27
+
28
+ def notify(*args)
29
+ event = args.first.is_a?(Event) ? args.first : Event.new(self, *args)
30
+ App.logger.debug "Event on #{self.class.name.split('::').last}: #{event.source.class.name.split('::').last} #{event.event.inspect}"
31
+ buffering? ? buffer.push(event) : observers.each { |observer| observer.notify(event) }
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,18 @@
1
+ module Space
2
+ module Events
3
+ class Buffer < Array
4
+ def push(event)
5
+ # if any? { |e| e.source == event.source }
6
+ # App.logger.debug("REJECT event #{event.event.inspect} on #{event.source.class.name.split("\\n").last}")
7
+ # else
8
+ super
9
+ # end
10
+ end
11
+
12
+ def flush
13
+ each { |event| event.source.notify(*event) }
14
+ clear
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ module Space
2
+ module Events
3
+ class Event
4
+ attr_reader :source, :event, :data
5
+
6
+ def initialize(source, event, data = {})
7
+ @source = source
8
+ @event = event
9
+ @data = data
10
+ end
11
+ end
12
+ end
13
+ end
14
+
data/lib/space/helpers.rb CHANGED
@@ -1,25 +1,44 @@
1
1
  # encoding: UTF-8
2
2
  require 'ansi/core'
3
- require 'core_ext/string'
3
+ require 'core_ext/string/wrap'
4
4
 
5
5
  module Space
6
6
  module Helpers
7
7
  def project_title
8
- "Project: #{app.name}".ansi(:bold)
8
+ "Project: #{name}".ansi(:bold)
9
9
  end
10
10
 
11
- def repo_title
12
- title = "#{repo.name.ansi(:bold)} [#{git.branch}, #{git.commit}] [#{repo.number}]"
13
- title += " *" if repo_selected?
14
- title
11
+ def tableize(string)
12
+ string.split(' ')
13
+ project.local_repos.join(', ')
14
+ end
15
+
16
+ def repo_name
17
+ repo.name.ansi(:bold)
18
+ end
19
+
20
+ def repo_status
21
+ [git.branch, git.commit, repo_local].compact.join(', ')
22
+ end
23
+
24
+ def repo_local
25
+ 'L'.ansi(:bold, :red) if repo_local?
26
+ end
27
+
28
+ def repo_local?
29
+ project.local_repos.include?(repo.name)
15
30
  end
16
31
 
17
32
  def repo_selected?
18
- app.repos.scoped? && app.repos.include?(repo)
33
+ repos.scoped? && repos.scope.include?(repo)
19
34
  end
20
35
 
21
36
  def git_status
22
- "Git: #{format_boolean(git.clean?)}"
37
+ "Git: #{format_boolean(git.clean?)}#{git_ahead if git.ahead?}"
38
+ end
39
+
40
+ def git_ahead
41
+ " #{git.ahead} commit#{'s' if git.ahead > 1} ahead".ansi(:yellow)
23
42
  end
24
43
 
25
44
  def bundle_status
@@ -34,20 +53,16 @@ module Space
34
53
  bundle.deps.map { |dep| "• #{dep.ref} #{format_boolean(dep.fresh?)} #{dep.name}" }.join("\n")
35
54
  end
36
55
 
37
- def bundle_local
38
- repos = bundle.local_repos
39
- "\nLocal: #{repos.join(', ')}\n" unless repos.empty?
40
- end
41
-
42
56
  def format_boolean(value)
43
57
  value ? '✔'.ansi(:green, :bold) : '⚡'.ansi(:red, :bold)
44
58
  end
45
59
 
46
- def i(string)
60
+ def i(string, width = 2)
47
61
  lines = string.split("\n")
48
62
  lines = lines.map { |line| line.wrap(80).split("\n") }.flatten
49
- lines = lines.map { |line| " #{line}" }
63
+ lines = lines.map { |line| [' ' * width, line].join }
50
64
  lines.join("\n")
51
65
  end
52
66
  end
53
67
  end
68
+
@@ -0,0 +1,7 @@
1
+ module Space
2
+ module Models
3
+ autoload :Project, 'space/models/project'
4
+ autoload :Repos, 'space/models/repos'
5
+ autoload :Repo, 'space/models/repo'
6
+ end
7
+ end
@@ -0,0 +1,48 @@
1
+ module Space
2
+ module Models
3
+ class Project
4
+ include Events
5
+
6
+ autoload :Bundler, 'space/models/project/bundler'
7
+
8
+ attr_reader :name, :repos, :bundler, :config
9
+
10
+ def initialize(name)
11
+ @name = name
12
+ @config = Config.load(name)
13
+ @repos = Repos.new(self, config.paths)
14
+ @bundler = Bundler.new(self)
15
+ end
16
+
17
+ def local_repos
18
+ bundler.config.keys.map do |key|
19
+ key =~ /^local\.(.+)$/
20
+ $1 if repos.names.include?($1)
21
+ end.compact
22
+ end
23
+
24
+ def names
25
+ @names ||= Tmux.windows || repos.names
26
+ end
27
+
28
+ def number(name)
29
+ if number = names.index(name)
30
+ number + 1
31
+ else
32
+ names << name
33
+ number(name)
34
+ end
35
+ end
36
+
37
+ def refresh
38
+ bundler.refresh
39
+ repos.all.each(&:refresh)
40
+ end
41
+
42
+ def subscribe(*args)
43
+ super
44
+ [bundler, repos].each { |object| object.subscribe(self) }
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,30 @@
1
+ require 'core_ext/enumerable/map_slice'
2
+
3
+ module Space
4
+ module Models
5
+ class Project
6
+ class Bundler
7
+ include Events, Shell
8
+
9
+ commands config: 'bundle config'
10
+
11
+ watch '~/.bundle/config'
12
+
13
+ attr_reader :project
14
+
15
+ def initialize(project)
16
+ @project = project
17
+ super()
18
+ end
19
+
20
+ def config
21
+ lines = result(:config).split("\n")[2..-1] || []
22
+ values = lines.map_slice(3) do |name, value, _|
23
+ [name, value =~ /: "(.*)"/ && $1]
24
+ end
25
+ Hash[*values.compact.flatten]
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,40 +1,57 @@
1
1
  module Space
2
- class Repo
3
- attr_reader :number, :path, :git, :bundle
4
-
5
- def initialize(number, path)
6
- @number = number
7
- @path = File.expand_path(path)
8
- @git = Git.new(path)
9
- @bundle = Bundle.new(path)
10
- end
2
+ module Models
3
+ class Repo
4
+ autoload :Bundle, 'space/models/repo/bundle'
5
+ autoload :Dependency, 'space/models/repo/dependency'
6
+ autoload :Git, 'space/models/repo/git'
11
7
 
12
- def name
13
- @name ||= File.basename(path)
14
- end
8
+ include Events
15
9
 
16
- def ref
17
- git.commit
18
- end
10
+ attr_reader :project, :path, :git, :bundle
19
11
 
20
- def dependencies
21
- Repos.select(bundle.deps.map(&:name))
22
- end
12
+ def initialize(project, path)
13
+ @project = project
14
+ @path = File.expand_path(path)
15
+ @git = Git.new(self)
16
+ @bundle = Bundle.new(self, project.repos)
17
+ end
23
18
 
24
- def reset
25
- git.reset
26
- bundle.reset
27
- end
19
+ def name
20
+ @name ||= File.basename(path)
21
+ end
28
22
 
29
- def execute(cmd)
30
- chdir do
31
- puts "in #{path}".ansi(:bold, :yellow)
32
- system(cmd)
23
+ def number
24
+ @number ||= project.number(name)
25
+ end
26
+
27
+ def ref
28
+ git.commit
33
29
  end
34
- end
35
30
 
36
- def chdir(&block)
37
- Dir.chdir(path, &block)
31
+ def deps
32
+ bundle.deps
33
+ end
34
+
35
+ def refresh
36
+ git.refresh
37
+ bundle.refresh
38
+ end
39
+
40
+ def execute(cmd)
41
+ chdir do
42
+ puts "in #{path}".ansi(:bold, :yellow)
43
+ system(cmd)
44
+ end
45
+ end
46
+
47
+ def chdir(&block)
48
+ Dir.chdir(path, &block)
49
+ end
50
+
51
+ def subscribe(*args)
52
+ super
53
+ [git, bundle].each { |object| object.subscribe(self) }
54
+ end
38
55
  end
39
56
  end
40
57
  end
@@ -0,0 +1,39 @@
1
+ require 'observer'
2
+
3
+ module Space
4
+ module Models
5
+ class Repo
6
+ class Bundle
7
+ include Events, Shell
8
+
9
+ commands check: 'bundle check',
10
+ list: 'bundle list'
11
+
12
+ watch 'Gemfile',
13
+ 'Gemfile.lock'
14
+
15
+ attr_reader :repo, :repos
16
+
17
+ def initialize(repo, repos)
18
+ @repo = repo
19
+ @repos = repos
20
+ super(repo.path)
21
+ end
22
+
23
+ def clean?
24
+ info =~ /dependencies are satisfied/
25
+ end
26
+
27
+ def info
28
+ result(:check).split("\n").first
29
+ end
30
+
31
+ def deps
32
+ result(:list).scan(/\* ([\w-]+) \(.* ([\d|\w]+)\)/).map do |name, ref|
33
+ Dependency.new(repos.find_by_name(name), ref) if repos.names.include?(name)
34
+ end.compact
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,22 @@
1
+ module Space
2
+ module Models
3
+ class Repo
4
+ class Dependency
5
+ attr_reader :repo, :ref
6
+
7
+ def initialize(repo, ref)
8
+ @repo = repo
9
+ @ref = ref
10
+ end
11
+
12
+ def name
13
+ repo.name
14
+ end
15
+
16
+ def fresh?
17
+ repo.ref == ref
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end