space 0.0.3 → 0.0.4

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