ecogem 0.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 60fc0a280bf16df9aa4c75207a8ab7932f30fc82
4
+ data.tar.gz: 4bd3bd7d9bbc67fd304fab346b9a673250e3029d
5
+ SHA512:
6
+ metadata.gz: b48b9f03002c2e445cce5f3130548a49f3253b532597f93437d05b3549fd4e77d16db8b17d68b050249aca1ff6b4875c9f1ac94f126ff4ae2efd83976a1971b5
7
+ data.tar.gz: b8da5d7c670404b81c4bf107ff78a8ee9be4b7a1051eab7003b6be90dac01e6e79e03a794a43b549a75ddfa5b75a222824b682259a4a94019ef452bfb782e8f3
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ /.ruby-version
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rbmary.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 mosop
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,143 @@
1
+ # Ecogem
2
+
3
+ Supplements Bundler for installing private gems.
4
+
5
+ ## Preface
6
+
7
+ When the gem A depends on my private gem B whose source is served from GitHub, I can write Gemfile with _:git_ option.
8
+
9
+ A's Gemfile:
10
+
11
+ ```ruby
12
+ source 'https://rubygems.org'
13
+ gem 'gem-b', git: 'git@github.com:me/gem-b.git'
14
+ gemspec
15
+ ```
16
+
17
+ It's cool. So, I also want to privately put A's source onto GitHub and use A in my application.
18
+
19
+ My application's Gemfile:
20
+
21
+ ```ruby
22
+ source 'https://rubygems.org'
23
+ gem 'gem-a', git: 'git@github.com:me/gem-a.git'
24
+ ```
25
+
26
+ Then `bundle install` prints:
27
+
28
+ Could not find gem 'gem-b (>= 0) ruby', which is required by gem 'gem-a (>= 0) ruby', in any of the sources.
29
+
30
+ Oh, my! Bundler does not resolve such deep dependencies.
31
+
32
+ To solve this, I need to:
33
+
34
+ * add the dependency again like:
35
+
36
+ ```ruby
37
+ gem 'gem-a', git: 'git@github.com:me/gem-a.git'
38
+ gem 'gem-b', git: 'git@github.com:me/gem-b.git'
39
+ ```
40
+
41
+ It's terrible. Where is DRY?
42
+
43
+ * host my private Gem server
44
+
45
+ The regular Gem server protocol is not suitable to exchange private resources because it has no sophisticated authentication method such as SSH.
46
+
47
+ * subscribe to Gemfury
48
+
49
+ Better than self hosting, however, there is still the problem about authentication.
50
+
51
+ * make Rubygems accept Git sources
52
+
53
+ * make Bundler resolve nested Git dependencies
54
+
55
+ These two seem to take forever.
56
+
57
+ Okay. The last option is Ecogem.
58
+
59
+ ## Dependencies
60
+
61
+ * fork(2) and UNIX domain socket
62
+ * Windows and several other platforms are not supported.
63
+
64
+ * Ruby >= 2.1 and ~> 2.2
65
+ * Tested on 2.1.5 (MRI)
66
+
67
+ * Bundler >= 1.7.9
68
+ * Tested on 1.7.9
69
+
70
+ ## Installation
71
+
72
+ Install the gem:
73
+
74
+ $ gem install ecogem
75
+
76
+ Also install Bundler if not installed:
77
+
78
+ $ gem install bundler
79
+
80
+ ## Usage
81
+
82
+ Rename your Gemfile to Ecogemfile and execute:
83
+
84
+ $ ecogem install
85
+
86
+ ## Example
87
+
88
+ When
89
+
90
+ * My application depends on gem-a whose source is served from GitHub
91
+ * gem-a depends on gem-b whose source is served from GitHub
92
+
93
+ Then `ecogem install` will:
94
+
95
+ 1. parse Ecogemfile
96
+
97
+ Ecogemfile:
98
+
99
+ ```ruby
100
+ source 'https://rubygems.org'
101
+ gem 'gem-a', git: 'git@github.com:me/gem-a.git'
102
+ gem 'rake' # from rubygems.org
103
+ ```
104
+
105
+ 1. fetch gem-a's Gemfile
106
+
107
+ gem-a's Gemfile:
108
+
109
+ ```ruby
110
+ source 'https://rubygems.org'
111
+ gem 'gem-b', git: 'git@github.com:me/gem-b.git'
112
+ gemspec
113
+ ```
114
+
115
+ 1. fetch gem-b's Gemfile
116
+
117
+ gem-b's Gemfile:
118
+
119
+ ```ruby
120
+ source 'https://rubygems.org'
121
+ gemspec
122
+ ```
123
+
124
+ 1. create a new Gemfile file
125
+
126
+ Gemfile:
127
+
128
+ ```ruby
129
+ source 'https://rubygems.org'
130
+ gem 'gem-b', '>= 0', git: 'git@github.com:me/gem-b.git', branch: 'master'
131
+ gem 'gem-a', '>= 0', git: 'git@github.com:me/gem-a.git', branch: 'master'
132
+ gem 'rake', '>= 0'
133
+ ```
134
+
135
+ 1. and finally execute `bundle install` with the new Gemfile
136
+
137
+ ## Contributing
138
+
139
+ 1. Fork it ( https://github.com/[my-github-username]/ecogem/fork )
140
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
141
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
142
+ 4. Push to the branch (`git push origin my-new-feature`)
143
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/bin/ecogem ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'ecogem'
4
+
5
+ Ecogem::Cli.start(ARGV)
6
+
data/ecogem.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ecogem/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ecogem"
8
+ spec.version = Ecogem::VERSION
9
+ spec.authors = ["mosop"]
10
+ spec.email = [""]
11
+ spec.summary = %q{Supplements Bundler for installing private gems.}
12
+ spec.description = %q{}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ end
data/lib/ecogem.rb ADDED
@@ -0,0 +1,36 @@
1
+ require_relative 'ecogem/version'
2
+
3
+ Object.autoload :Bundler, 'bundler' unless Object.const_defined?(:Bundler, false)
4
+
5
+ module Ecogem
6
+ %w[cli config env gemfile git gitsfile util workspace].each do |name|
7
+ pascal = name.split(/_/).map{|i| i[0].upcase + i[1..-1]}.join('')
8
+ autoload pascal, ::File.expand_path("../ecogem/#{name}", __FILE__)
9
+ end
10
+
11
+ def self.workspaces
12
+ ::Thread.current[:ecogem_workspaces] ||= []
13
+ end
14
+
15
+ def self.workspace
16
+ workspaces.last
17
+ end
18
+
19
+ def self.new_workspace(args, options = {}, &block)
20
+ Workspace.new(args, options) do |ws|
21
+ begin
22
+ ::Thread.current[:ecogem_workspaces] ||= []
23
+ workspaces << ws
24
+ break block.call(ws)
25
+ ensure
26
+ workspaces.pop
27
+ end
28
+ end
29
+ end
30
+
31
+ def self.git_path(key)
32
+ new_workspace(nil, readonly: true) do |ws|
33
+ break ws.gitsfile.dir_of(key)
34
+ end
35
+ end
36
+ end
data/lib/ecogem/cli.rb ADDED
@@ -0,0 +1,21 @@
1
+ require_relative 'cli/args'
2
+
3
+ module Ecogem
4
+ class Cli
5
+ def self.start(argv)
6
+ self.new(argv).execute
7
+ end
8
+
9
+ def initialize(argv)
10
+ @args = ::Ecogem::Cli::Args.new(argv)
11
+ end
12
+
13
+ def execute
14
+ raise "Unknown command: #{@args.command}" unless %w[install update].include?(@args.command)
15
+ require_relative "cli/commands/#{@args.command}"
16
+ klass_name = @args.command.split(/_/).map{|i| i[0].upcase + i[1..-1]}.join('')
17
+ klass = ::Ecogem::Cli::Commands.const_get(klass_name, false)
18
+ klass.new(@args).execute
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,35 @@
1
+ module Ecogem
2
+ class Cli
3
+ class Args
4
+ attr_reader :command
5
+
6
+ def initialize(argv)
7
+ @argv = argv.dup
8
+ parse
9
+ end
10
+
11
+ def options
12
+ @options ||= {}
13
+ end
14
+
15
+ def bundler_args
16
+ @argv
17
+ end
18
+
19
+ private def parse
20
+ @command = @argv.shift
21
+ extract_options
22
+ @argv.freeze
23
+ end
24
+
25
+ private def extract_options
26
+ %i[file port].each do |key|
27
+ if found = @argv.find_index("--ecogem-#{key}")
28
+ name, value = @argv.slice(found, 2)
29
+ options[key] = value
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,22 @@
1
+ require 'bundler'
2
+
3
+ module Ecogem
4
+ class Cli
5
+ module Commands
6
+ class Install
7
+ def initialize(args)
8
+ @args = args
9
+ end
10
+
11
+ def execute
12
+ ::Ecogem.new_workspace(@args) do |ws|
13
+ gemfile = "--gemfile=#{ws.gemfile.write.inspect}"
14
+ args = [*@args.bundler_args, gemfile].join(' ')
15
+ command = "bundle install #{args}"
16
+ system command
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ require 'bundler'
2
+
3
+ module Ecogem
4
+ class Cli
5
+ module Commands
6
+ class Update
7
+ def initialize(args)
8
+ @args = args
9
+ end
10
+
11
+ def execute
12
+ ::Ecogem.new_workspace(@args) do |ws|
13
+ gemfile = "--gemfile=#{ws.gemfile.write.inspect}"
14
+ args = [*@args.bundler_args, gemfile].join(' ')
15
+ command = "bundle update #{args}"
16
+ system command
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ module Ecogem
2
+ class Config < ::Ecogem::Util::Config
3
+ %w[entries git_source].each do |name|
4
+ pascal = name.split(/_/).map{|i| i[0].upcase + i[1..-1]}.join('')
5
+ autoload pascal, ::File.expand_path("../config/#{name}", __FILE__)
6
+ end
7
+
8
+ entry_namespace Entries
9
+ entry :git_sources
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ module Ecogem
2
+ class Config
3
+ module Entries
4
+ %w[git_sources].each do |name|
5
+ pascal = name.split(/_/).map{|i| i[0].upcase + i[1..-1]}.join('')
6
+ autoload pascal, ::File.expand_path("../entries/#{name}", __FILE__)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ module Ecogem
2
+ class Config
3
+ module Entries
4
+ class GitSources < ::Ecogem::Util::Config::Entry
5
+ def parse(data)
6
+ (data || []).map{|i| ::Ecogem::Config::GitSource.new(i)}
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ module Ecogem
2
+ class Config
3
+ class GitSource
4
+ def initialize(data)
5
+ @data = data
6
+ end
7
+
8
+ def uri
9
+ @data['uri']
10
+ end
11
+
12
+ def uri_alias
13
+ @data['uri_alias']
14
+ end
15
+ end
16
+ end
17
+ end
data/lib/ecogem/env.rb ADDED
@@ -0,0 +1,34 @@
1
+ require 'yaml'
2
+
3
+ module Ecogem
4
+ class Env
5
+ %w[git_source].each do |name|
6
+ pascal = name.split(/_/).map{|i| i[0].upcase + i[1..-1]}.join('')
7
+ autoload pascal, ::File.expand_path("../env/#{name}", __FILE__)
8
+ end
9
+
10
+ attr_reader :dir
11
+
12
+ def initialize(base, dir)
13
+ @base = base
14
+ @dir = ::File.expand_path(dir)
15
+ end
16
+
17
+ private def config_path
18
+ @config_path ||= "#{dir}/config"
19
+ end
20
+
21
+ def config
22
+ @config ||= ::Ecogem::Config.new(@base && @base.config, config_path)
23
+ end
24
+
25
+ def git_sources
26
+ @git_sources ||= ::Hash[config.values.git_sources.map{|i| [i.uri, i]}]
27
+ end
28
+
29
+ def git_source_uri_to_alias(uri)
30
+ source = git_sources[uri]
31
+ (source && source.uri_alias) || uri
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,95 @@
1
+ module Ecogem
2
+ class Gemfile
3
+ %w[dependency marshal source].each do |name|
4
+ pascal = name.split(/_/).map{|i| i[0].upcase + i[1..-1]}.join('')
5
+ autoload pascal, ::File.expand_path("../gemfile/#{name}", __FILE__)
6
+ end
7
+
8
+ def initialize(path)
9
+ @path = path
10
+ end
11
+
12
+ def dir
13
+ @dir ||= ::File.dirname(@pah)
14
+ end
15
+
16
+ private def dependencies
17
+ @dependencies ||= data.dependencies.map{|i| ::Ecogem::Gemfile::Dependency.new(self, i)}
18
+ end
19
+
20
+ private def extracted_dependencies
21
+ @extracted_dependencies ||= extract_dependencies([], [], false)
22
+ end
23
+
24
+ protected def extract_dependencies(into, gits, git_only)
25
+ dependencies.each do |d|
26
+ if d.source.git?
27
+ unless gits.include?(d.source.git.key)
28
+ gits << d.source.git.key
29
+ d.source.git.gemfile.extract_dependencies into, gits, true if d.source.git.gemfile
30
+ end
31
+ into << d
32
+ else
33
+ into << d unless git_only
34
+ end
35
+ end
36
+ into
37
+ end
38
+
39
+ private def sources
40
+ @sources ||= data.sources.instance_variable_get(:@rubygems_aggregate).remotes.map{|i| i.to_s}
41
+ end
42
+
43
+ def code
44
+ @code ||= begin
45
+ a = []
46
+ a << 'require "ecogem"'
47
+ a << sources.reverse.map{|i| "source #{i.inspect}"}.join("\n")
48
+ a << extracted_dependencies.map{|i| i.code}.uniq.join("\n")
49
+ a.join("\n\n")
50
+ end
51
+ end
52
+
53
+ def write(dir = nil, name = nil)
54
+ dir ||= ::File.dirname(@path)
55
+ name ||= 'Gemfile'
56
+ path = "#{dir}/#{name}"
57
+ ::File.write "#{dir}/#{name}", code
58
+ path
59
+ end
60
+
61
+ private def data
62
+ @data ||= load
63
+ end
64
+
65
+ private def load
66
+ in_r, in_w, out_r, out_w = []
67
+
68
+ begin
69
+ in_r, in_w = ::IO.pipe
70
+ out_r, out_w = ::IO.pipe
71
+
72
+ params = {
73
+ path: @path
74
+ }
75
+ ::Marshal.dump({path: @path}, in_w)
76
+
77
+ pid = ::Process.fork do
78
+ params = ::Marshal.load(in_r)
79
+
80
+ dsl = ::Bundler::Dsl.new
81
+ dsl.eval_gemfile(params[:path])
82
+ result = ::Ecogem::Gemfile::Marshal.new(dsl).to_data
83
+
84
+ ::Marshal.dump(result, out_w)
85
+ ::Process.exit!
86
+ end
87
+ ::Process.waitpid(pid)
88
+
89
+ ::Marshal.load(out_r)
90
+ ensure
91
+ [in_r, in_w, out_r, out_w].each{|i| i.close if i}
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,64 @@
1
+ module Ecogem
2
+ class Gemfile
3
+ class Dependency
4
+ def initialize(gemfile, data)
5
+ @gemfile = gemfile
6
+ @data = data
7
+ end
8
+
9
+ def name
10
+ @data.name
11
+ end
12
+
13
+ def source
14
+ @source ||= ::Ecogem::Gemfile::Source.new(self, @data.instance_variable_get(:@source))
15
+ end
16
+
17
+ def versions
18
+ @versions ||= @data.requirement.requirements.map{|i| "#{i[0]} #{i[1]}"}
19
+ end
20
+
21
+ def platforms
22
+ @platforms ||= @data.instance_variable_get(:@platforms).dup
23
+ end
24
+
25
+ def groups
26
+ @groups ||= @data.instance_variable_get(:@groups).dup
27
+ end
28
+
29
+ def code
30
+ @code ||= begin
31
+ a = ["gem \"#{name}\""]
32
+
33
+ if !(versions.size == 1 && versions[0] == '>= 0')
34
+ a << versions.map{|i| "\"#{i}\""}.join(', ')
35
+ end
36
+
37
+ if platforms.size > 0
38
+ s = if platforms.size == 1
39
+ ":#{platforms[0]}"
40
+ else
41
+ '[' + platforms.map{|i| ":#{i}"}.join(', ') + ']'
42
+ end
43
+ a << "platform: #{s}"
44
+ end
45
+
46
+ if groups.size > 0 && !(groups.size == 1 && groups[0] == :default)
47
+ s = if groups.size == 1
48
+ ":#{groups[0]}"
49
+ else
50
+ '[' + groups.map{|i| ":#{i}"}.join(', ') + ']'
51
+ end
52
+ a << "group: #{s}"
53
+ end
54
+
55
+ if s = source.code
56
+ a << s
57
+ end
58
+
59
+ a.join(', ')
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,35 @@
1
+ module Ecogem
2
+ class Gemfile
3
+ class Marshal
4
+ def initialize(dsl)
5
+ @dsl = dsl
6
+ end
7
+
8
+ def to_data
9
+ h = {
10
+ dependencies: @dsl.dependencies,
11
+ sources: @dsl.instance_variable_get(:@sources)
12
+ }
13
+ Data.new(h)
14
+ end
15
+
16
+ class Data
17
+ def initialize(hash)
18
+ @hash = hash
19
+ end
20
+
21
+ def dependencies
22
+ @hash[:dependencies]
23
+ end
24
+
25
+ def groups
26
+ @hash[:groups]
27
+ end
28
+
29
+ def sources
30
+ @hash[:sources]
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,58 @@
1
+ require 'fileutils'
2
+
3
+ module Ecogem
4
+ class Gemfile
5
+ class Source
6
+ attr_reader :git
7
+
8
+ def initialize(dependency, data)
9
+ @dependency = dependency
10
+ @data = data
11
+ end
12
+
13
+ def git?
14
+ @data && @data.options.key?('git')
15
+ end
16
+
17
+ def path?
18
+ @data && @data.options.key?('path')
19
+ end
20
+
21
+ def source?
22
+ @data && @data.options.key?('remotes')
23
+ end
24
+
25
+ def git_uri
26
+ @data.options['git']
27
+ end
28
+
29
+ def path
30
+ @data.options['path']
31
+ end
32
+
33
+ def source
34
+ @data.options['remotes'][0]
35
+ end
36
+
37
+ def ref
38
+ @data.ref
39
+ end
40
+
41
+ def git
42
+ @git ||= ::Ecogem::Git.new(git_uri, ref)
43
+ end
44
+
45
+ def code
46
+ @code ||= begin
47
+ if git?
48
+ "path: Ecogem.git_path(#{git.key.inspect})"
49
+ elsif path?
50
+ "path: #{path.to_s.inspect}"
51
+ elsif source?
52
+ "source: #{source.inspect}"
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
data/lib/ecogem/git.rb ADDED
@@ -0,0 +1,56 @@
1
+ require 'fileutils'
2
+
3
+ module Ecogem
4
+ class Git
5
+ def initialize(uri, ref)
6
+ @uri = uri
7
+ @ref = ref || 'master'
8
+ end
9
+
10
+ def key
11
+ @key ||= "#{@uri} #{@ref}"
12
+ end
13
+
14
+ def dir
15
+ @dir ||= ::Ecogem.workspace.gitsfile.dir_of(key)
16
+ end
17
+
18
+ def uri_alias
19
+ @uri_alias ||= ::Ecogem.workspace.env.git_source_uri_to_alias(@uri)
20
+ end
21
+
22
+ def exec(cmd)
23
+ puts "git: #{cmd}"
24
+ cmd = "git #{cmd}"
25
+ system("cd \"#{dir}\"; #{cmd}")
26
+ end
27
+
28
+ private def load
29
+ unless @loaded
30
+ ::FileUtils.rm_rf dir
31
+ ::FileUtils.mkdir_p dir
32
+ self.exec "init -q"
33
+ self.exec "remote add origin \"#{uri_alias}\""
34
+ self.exec "fetch -q origin #{@ref}"
35
+ raise CommandError unless $?.success?
36
+ self.exec "checkout -q FETCH_HEAD"
37
+ raise CommandError unless $?.success?
38
+ @loaded = true
39
+ end
40
+ end
41
+
42
+ private def gemfile_path
43
+ @gemfile_path ||= ::File.expand_path("#{dir}/Ecogemfile")
44
+ end
45
+
46
+ def gemfile
47
+ @gemfile ||= begin
48
+ load
49
+ ::Ecogem::Gemfile.new(gemfile_path) if ::File.file?(gemfile_path)
50
+ end
51
+ end
52
+
53
+ class CommandError < ::StandardError
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,19 @@
1
+ module Ecogem
2
+ class Gitsfile < ::Ecogem::Util::Config
3
+ %w[entries].each do |name|
4
+ pascal = name.split(/_/).map{|i| i[0].upcase + i[1..-1]}.join('')
5
+ autoload pascal, ::File.expand_path("../gitsfile/#{name}", __FILE__)
6
+ end
7
+
8
+ entry_namespace Entries
9
+ entry :keys
10
+
11
+ def dir_of(key)
12
+ i = values.keys.find_index(key) || begin
13
+ values.keys << key
14
+ values.keys.size - 1
15
+ end
16
+ "#{dir}/#{i+1}"
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,10 @@
1
+ module Ecogem
2
+ class Gitsfile
3
+ module Entries
4
+ %w[keys].each do |name|
5
+ pascal = name.split(/_/).map{|i| i[0].upcase + i[1..-1]}.join('')
6
+ autoload pascal, ::File.expand_path("../entries/#{name}", __FILE__)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,15 @@
1
+ module Ecogem
2
+ class Gitsfile
3
+ module Entries
4
+ class Keys < ::Ecogem::Util::Config::Entry
5
+ def parse(data)
6
+ (data || []).dup
7
+ end
8
+
9
+ def unparse(value)
10
+ value.dup
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,8 @@
1
+ module Ecogem
2
+ module Util
3
+ %w[config].each do |name|
4
+ pascal = name.split(/_/).map{|i| i[0].upcase + i[1..-1]}.join('')
5
+ autoload pascal, ::File.expand_path("../util/#{name}", __FILE__)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,62 @@
1
+ require 'yaml'
2
+
3
+ module Ecogem
4
+ module Util
5
+ class Config
6
+ %w[entry value value_container].each do |name|
7
+ pascal = name.split(/_/).map{|i| i[0].upcase + i[1..-1]}.join('')
8
+ autoload pascal, ::File.expand_path("../config/#{name}", __FILE__)
9
+ end
10
+
11
+ def self.entry_namespaces
12
+ @entry_namespaces ||= []
13
+ end
14
+
15
+ def self.entry_namespace(ns)
16
+ entry_namespaces << ns
17
+ end
18
+
19
+ def self.entry(key)
20
+ e = ::Ecogem::Util::Config::Entry.create(self, key)
21
+ entries[key] = e
22
+ end
23
+
24
+ def self.find_entry_class(key)
25
+ pascal = key.to_s.split(/_/).map{|i| i[0].upcase + i[1..-1]}.join('')
26
+ entry_namespaces.reverse.each do |ns|
27
+ return ns.const_get(pascal, false) if ns.const_defined?(pascal, false)
28
+ end
29
+ nil
30
+ end
31
+
32
+ def self.entries
33
+ @entries ||= {}
34
+ end
35
+
36
+ def initialize(base, path)
37
+ @base = base
38
+ @path = ::File.expand_path(path)
39
+ end
40
+
41
+ def dir
42
+ @dir ||= ::File.dirname(@path)
43
+ end
44
+
45
+ protected def value_container
46
+ @value_conatiner ||= ::Ecogem::Util::Config::ValueContainer.new(@base && @base.value_container, self, load || {})
47
+ end
48
+
49
+ def values
50
+ @values ||= value_container.proxy
51
+ end
52
+
53
+ private def load
54
+ ::YAML.load(::File.read(@path)) if ::File.file?(@path)
55
+ end
56
+
57
+ def save
58
+ ::File.write @path, value_container.values_to_h.to_yaml
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,19 @@
1
+ module Ecogem
2
+ module Util
3
+ class Config
4
+ class Entry
5
+ attr_reader :key
6
+
7
+ def initialize(config, key)
8
+ @config = config
9
+ @key = key
10
+ end
11
+
12
+ def self.create(config, key, options = {})
13
+ klass = options[:class] || config.find_entry_class(key)
14
+ klass.new(config, key)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,8 @@
1
+ module Ecogem
2
+ module Util
3
+ class Config
4
+ class Value
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,86 @@
1
+ module Ecogem
2
+ module Util
3
+ class Config
4
+ class ValueContainer
5
+ def initialize(base, config, default_data)
6
+ @base = base
7
+ @config = config
8
+ @default_data = default_data
9
+ end
10
+
11
+ def proxy
12
+ @proxy ||= Proxy.new(self)
13
+ end
14
+
15
+ def values
16
+ @values ||= h_to_values(@default_data || {})
17
+ end
18
+
19
+ def h_to_values(h)
20
+ values = {}
21
+ h.each do |k, v|
22
+ k = k.to_sym
23
+ entry = @config.class.entries[k]
24
+ values[k] = entry.parse(v) if entry
25
+ end
26
+ values
27
+ end
28
+
29
+ def values_to_h
30
+ h = {}
31
+ values.each do |k, v|
32
+ entry = @config.class.entries[k]
33
+ h[k.to_s] = entry.unparse(v)
34
+ end
35
+ h
36
+ end
37
+
38
+ def resolve_method(name, *args, &block)
39
+ key = name.to_s.sub(/(=)$/, '').to_sym
40
+ assign = $1
41
+ entry = @config.class.entries[key]
42
+ if entry
43
+ if assign
44
+ return values[key] = args.first
45
+ else
46
+ begin
47
+ return find_value(key)
48
+ rescue NotFoundError
49
+ value = entry.parse(nil)
50
+ values[key] = value
51
+ return value
52
+ end
53
+ end
54
+ end
55
+ raise UnresolvedError
56
+ end
57
+
58
+ def find_value(key)
59
+ return values[key] if values.key?(key)
60
+ return @base.find_value(key) if @base
61
+ raise NotFoundError
62
+ end
63
+
64
+ class NotFoundError < ::StandardError
65
+ end
66
+
67
+ class UnresolvedError < ::StandardError
68
+ end
69
+
70
+ class Proxy
71
+ def initialize(container)
72
+ @container = container
73
+ end
74
+
75
+ def method_missing(name, *args, &block)
76
+ begin
77
+ return @container.resolve_method(name, *args, &block)
78
+ rescue ::Ecogem::Util::Config::ValueContainer::UnresolvedError
79
+ end
80
+ super
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,3 @@
1
+ module Ecogem
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,65 @@
1
+ require 'fileutils'
2
+ require 'tmpdir'
3
+ require 'yaml'
4
+
5
+ module Ecogem
6
+ class Workspace
7
+ def initialize(args, options = {}, &block)
8
+ @args = args || ::Ecogem::Cli::Args.new([])
9
+ options = {}.merge(options)
10
+ new_tmpdir do |dir|
11
+ begin
12
+ @workdir = dir
13
+ block.call self
14
+ unless options[:readonly]
15
+ gitsfile.save
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ def global_env
22
+ @global_env ||= ::Ecogem::Env.new(nil, ::File.expand_path(::Dir.home + '/.ecogem'))
23
+ end
24
+
25
+ def env
26
+ @env ||= ::Ecogem::Env.new(global_env, env_path)
27
+ end
28
+
29
+ def gitsfile
30
+ @gitsfile ||= ::Ecogem::Gitsfile.new(nil, global_env.dir + '/gits/keys')
31
+ end
32
+
33
+ private def env_path
34
+ @env_path ||= begin
35
+ path = ::File.expand_path(@args.options[:env] || ::File.dirname(gemfile_path) + '/.ecogem')
36
+ raise "file exists: #{path}" if ::File.file?(path)
37
+ ::FileUtils.mkdir_p path unless ::File.exist?(path)
38
+ path
39
+ end
40
+ end
41
+
42
+ private def gemfile_path
43
+ @gemfile_path ||= ::File.expand_path(@args.options[:gemfile] || ::Dir.pwd + '/Ecogemfile')
44
+ end
45
+
46
+ def gemfile
47
+ @gemfile ||= ::Ecogem::Gemfile.new(gemfile_path)
48
+ end
49
+
50
+ private def tmp_path
51
+ @tmp_path ||= begin
52
+ path = File.expand_path(@args.options[:tmpdir] || "#{env_path}/tmp")
53
+ raise "file exists: #{path}" if ::File.file?(path)
54
+ path
55
+ end
56
+ end
57
+
58
+ def new_tmpdir(&block)
59
+ ::FileUtils.mkdir_p tmp_path unless ::File.exist?(tmp_path)
60
+ ::Dir.mktmpdir(nil, tmp_path) do |dir|
61
+ return block.call(dir)
62
+ end
63
+ end
64
+ end
65
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ecogem
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - mosop
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: ''
42
+ email:
43
+ - ''
44
+ executables:
45
+ - ecogem
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".gitignore"
50
+ - Gemfile
51
+ - LICENSE.txt
52
+ - README.md
53
+ - Rakefile
54
+ - bin/ecogem
55
+ - ecogem.gemspec
56
+ - lib/ecogem.rb
57
+ - lib/ecogem/cli.rb
58
+ - lib/ecogem/cli/args.rb
59
+ - lib/ecogem/cli/commands/install.rb
60
+ - lib/ecogem/cli/commands/update.rb
61
+ - lib/ecogem/config.rb
62
+ - lib/ecogem/config/entries.rb
63
+ - lib/ecogem/config/entries/git_sources.rb
64
+ - lib/ecogem/config/git_source.rb
65
+ - lib/ecogem/env.rb
66
+ - lib/ecogem/gemfile.rb
67
+ - lib/ecogem/gemfile/dependency.rb
68
+ - lib/ecogem/gemfile/marshal.rb
69
+ - lib/ecogem/gemfile/source.rb
70
+ - lib/ecogem/git.rb
71
+ - lib/ecogem/gitsfile.rb
72
+ - lib/ecogem/gitsfile/entries.rb
73
+ - lib/ecogem/gitsfile/entries/keys.rb
74
+ - lib/ecogem/util.rb
75
+ - lib/ecogem/util/config.rb
76
+ - lib/ecogem/util/config/entry.rb
77
+ - lib/ecogem/util/config/value.rb
78
+ - lib/ecogem/util/config/value_container.rb
79
+ - lib/ecogem/version.rb
80
+ - lib/ecogem/workspace.rb
81
+ homepage: ''
82
+ licenses:
83
+ - MIT
84
+ metadata: {}
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubyforge_project:
101
+ rubygems_version: 2.2.2
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: Supplements Bundler for installing private gems.
105
+ test_files: []