gem_on_demand 1.0.0 → 1.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 517e2aeefdc0e9f09c3432de6c218d87f6f67587
4
- data.tar.gz: 2d79c118bec199a2af27b74a90096ce852bc0840
3
+ metadata.gz: 6b6bcd00804e18316740f3994fedc5e6023610c5
4
+ data.tar.gz: c8ea84b03172bbe87a8e51365870e229e5a3a973
5
5
  SHA512:
6
- metadata.gz: e8f8848702f5eacf1480cc2468337c4fc1cc9516f1b944a88cbc513fd8dae8558d01f6e7b49fda3eb66b5f99ea26964e81eebf248a5a626498780e5f9cc7d8c3
7
- data.tar.gz: 78b4e5368d71432e328e1c1547dc8d48a2ac1146cea2b95c9d99eebd8fa32126e8bf9940d7d9173c8682dd7d44a6896b50d04f125764654337a153e23d41837f
6
+ metadata.gz: fe4905d4fd9018f8028bddf38c61ef28d0346b7e4e91c0af4f007e36c770669e1f36acd28641d7eb055f41555d230de15bf80b9139cf15101971082364158b76
7
+ data.tar.gz: 802126017f0d2d5b05a88d18514246e7c76469ca65c8cf7df5381d71b61bcd0641fd762886a5e7e8cd87bdb0e3142db4be1c2ac6b695fc3fd124d7375aa1b5e2
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -1,173 +1,43 @@
1
1
  require 'tmpdir'
2
+ require 'gem_on_demand/checkout'
3
+ require 'gem_on_demand/project'
4
+ require 'gem_on_demand/utils'
5
+ require 'gem_on_demand/file_cache'
2
6
 
3
7
  module GemOnDemand
4
- PROJECT_CACHE = File.expand_path("~/.gem-on-demand/cache")
5
- DATA_CACHE = "cache"
6
- CACHE_DURATION = 15 * 60 # for project tags
7
- ProjectNotFound = Class.new(Exception)
8
- VERSION_REX = /^v?\d+\.\d+\.\d+(\.\w+)?$/ # with or without v and pre-release (cannot do others or we get: 'Malformed version number string 1.0.0-rails3' from bundler)
9
8
  HEAVY_FORKED = ["rails", "mysql", "mysql2"]
10
- MAX_VERSIONS = 50 # some projects just have a million versions ...
11
- DEPENDENCIES = "dependencies"
12
- NOT_FOUND = "not-found"
13
- UPDATED_AT = "updated_at"
14
9
 
15
10
  class << self
16
11
  def build_gem(user, project, version)
17
- inside_of_project(user, project) do
18
- cache("gem-#{version}") do
19
- checkout_version("v#{version}")
20
- gemspec = "#{project}.gemspec"
21
- remove_signing(gemspec)
22
- sh("gem build #{gemspec}")
23
- File.read("#{project}-#{version}.gem")
24
- end
12
+ checkout = Checkout.new(user, project)
13
+ checkout.chdir do
14
+ Project.new(user, project, checkout.cache).build_gem(version)
25
15
  end
26
16
  end
27
17
 
28
18
  def dependencies(user, gems)
29
19
  (gems - HEAVY_FORKED).map do |project|
30
- project_dependencies(user, project)
20
+ checkout = Checkout.new(user, project)
21
+ begin
22
+ checkout.chdir do
23
+ Project.new(user, project, checkout.cache).dependencies
24
+ end
25
+ rescue Checkout::NotFound
26
+ []
27
+ end
31
28
  end.flatten
32
29
  end
33
30
 
31
+ # expire update related caches so next run gets fresh tags + versions
34
32
  def expire(user, project)
35
- remove_directory "#{PROJECT_CACHE}/#{user}/#{project}/#{DATA_CACHE}"
36
- end
37
-
38
- private
39
-
40
- def project_dependencies(user, project)
41
- inside_of_project(user, project) do
42
- cache DEPENDENCIES do
43
- versions_for_project.last(MAX_VERSIONS).map do |version|
44
- next unless dependencies = dependencies_for_version(project, version)
45
- {
46
- :name => project,
47
- :number => version.sub(/^v/, ""),
48
- :platform => "ruby",
49
- :dependencies => Marshal.load(dependencies)
50
- }
51
- end.compact
52
- end
53
- end
54
- rescue ProjectNotFound
55
- []
56
- end
57
-
58
- def versions_for_project
59
- sh("git tag").split($/).grep(VERSION_REX)
60
- end
61
-
62
- def dependencies_for_version(project, version)
63
- cache "dependencies-#{version}" do
64
- checkout_version(version)
65
- sh(%{ruby -e 'print Marshal.dump(eval(File.read("#{project}.gemspec")).runtime_dependencies.map{|d| [d.name, d.requirement.to_s]})'}, :fail => :allow)
33
+ checkout = Checkout.new(user, project)
34
+ [
35
+ Checkout::UPDATED_AT,
36
+ Checkout::NOT_FOUND,
37
+ Project::DEPENDENCIES
38
+ ].each do |key|
39
+ checkout.cache.delete key
66
40
  end
67
41
  end
68
-
69
- def cache(file, value = nil, &block)
70
- ensure_directory(DATA_CACHE)
71
- file = "#{DATA_CACHE}/#{file}"
72
- if block
73
- if File.exist?(file)
74
- Marshal.load(File.read(file))
75
- else
76
- result = yield
77
- File.write(file, Marshal.dump(result))
78
- result
79
- end
80
- else
81
- if value.nil?
82
- Marshal.load(File.read(file)) if File.exist?(file)
83
- else
84
- File.write(file, Marshal.dump(value))
85
- end
86
- end
87
- end
88
-
89
- def expire_key(key)
90
- key = "#{DATA_CACHE}/#{key}"
91
- File.unlink(key) if File.exist?(key)
92
- end
93
-
94
- def sh(command, options = { })
95
- puts command
96
- result = `#{command}`
97
- if $?.success?
98
- result
99
- elsif options[:fail] == :allow
100
- false
101
- else
102
- raise "Command failed: #{result}"
103
- end
104
- end
105
-
106
- def inside_of_project(user, project, &block)
107
- dir = "#{PROJECT_CACHE}/#{user}"
108
- ensure_directory(dir)
109
- Dir.chdir(dir) do
110
- clone_or_refresh_project(user, project)
111
- Dir.chdir(project, &block)
112
- end
113
- end
114
-
115
- def ensure_directory(dir)
116
- FileUtils.mkdir_p(dir) unless File.directory?(dir)
117
- end
118
-
119
- def clone_or_refresh_project(user, project)
120
- if File.directory?("#{project}/.git")
121
- if refresh?(project)
122
- Dir.chdir(project) do
123
- sh "git fetch origin"
124
- expire_key DEPENDENCIES
125
- end
126
- refreshed!(project)
127
- end
128
- elsif not_found?(project)
129
- raise ProjectNotFound
130
- else
131
- remove_directory(project)
132
- found = sh "git clone git@github.com:#{user}/#{project}.git", :fail => :allow
133
- if found
134
- refreshed!(project)
135
- else
136
- not_found!(project)
137
- raise ProjectNotFound
138
- end
139
- end
140
- end
141
-
142
- def remove_directory(project)
143
- FileUtils.rm_rf(project) if File.exist?(project)
144
- end
145
-
146
- def not_found?(project)
147
- File.directory?(project) && Dir.chdir(project) { cache(NOT_FOUND) }
148
- end
149
-
150
- def not_found!(project)
151
- ensure_directory(project)
152
- Dir.chdir(project) { cache(NOT_FOUND, true) }
153
- end
154
-
155
- def refreshed!(project)
156
- Dir.chdir(project) { cache(UPDATED_AT, Time.now.to_i) }
157
- end
158
-
159
- def refresh?(project)
160
- Dir.chdir(project) { cache(UPDATED_AT).to_i } < Time.now.to_i - CACHE_DURATION
161
- end
162
-
163
- def checkout_version(version)
164
- sh("git checkout #{version} --force")
165
- end
166
-
167
- # ERROR: While executing gem ... (Gem::Security::Exception)
168
- # certificate /CN=michael/DC=grosser/DC=it not valid after 2014-02-03 18:13:11 UTC
169
- def remove_signing(gemspec)
170
- File.write(gemspec, File.read(gemspec).gsub(/.*\.(signing_key|cert_chain).*/, ""))
171
- end
172
42
  end
173
43
  end
@@ -0,0 +1,80 @@
1
+ module GemOnDemand
2
+ class Checkout
3
+ NotFound = Class.new(Exception)
4
+ NOT_FOUND = "not-found"
5
+ UPDATED_AT = "updated_at"
6
+ DIR = File.expand_path("~/.gem-on-demand/cache")
7
+ CACHE_DURATION = 15 * 60 # for project tags
8
+
9
+ attr_accessor :user, :project
10
+
11
+ def initialize(user, project)
12
+ self.user = user
13
+ self.project = project
14
+ Utils.ensure_directory(dir)
15
+ end
16
+
17
+ def chdir(&block)
18
+ clone_or_refresh
19
+ Dir.chdir(dir, &block)
20
+ end
21
+
22
+ def cache
23
+ @cache ||= FileCache.new("#{dir}/cache")
24
+ end
25
+
26
+ private
27
+
28
+ def dir
29
+ "#{DIR}/#{user}/#{project}"
30
+ end
31
+
32
+ def was_not_found?
33
+ cache.read(NOT_FOUND)
34
+ end
35
+
36
+ def not_found!
37
+ cache.write(NOT_FOUND, true)
38
+ raise NotFound
39
+ end
40
+
41
+ def need_refresh?
42
+ cache.read(UPDATED_AT).to_i < Time.now.to_i - CACHE_DURATION
43
+ end
44
+
45
+ def fresh!
46
+ cache.write(UPDATED_AT, Time.now.to_i)
47
+ end
48
+
49
+ def clone_or_refresh
50
+ if cloned?
51
+ refresh if need_refresh?
52
+ elsif was_not_found?
53
+ not_found!
54
+ else
55
+ clone
56
+ end
57
+ end
58
+
59
+ def refresh
60
+ Dir.chdir(dir) { Utils.sh "git fetch origin" }
61
+ cache.delete Project::DEPENDENCIES
62
+ fresh!
63
+ end
64
+
65
+ def clone
66
+ Utils.remove_directory(dir)
67
+ cloned = Utils.sh "git clone git@github.com:#{user}/#{project}.git #{dir}", :fail => :allow
68
+ Utils.ensure_directory(dir)
69
+ if cloned
70
+ fresh!
71
+ else
72
+ not_found!
73
+ end
74
+ end
75
+
76
+ def cloned?
77
+ File.directory?("#{dir}/.git")
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,28 @@
1
+ module GemOnDemand
2
+ class FileCache
3
+ def initialize(dir)
4
+ @dir = dir
5
+ end
6
+
7
+ def write(file, value)
8
+ Utils.ensure_directory(@dir)
9
+ file = "#{@dir}/#{file}"
10
+ File.write(file, Marshal.dump(value))
11
+ value
12
+ end
13
+
14
+ def read(file)
15
+ file = "#{@dir}/#{file}"
16
+ Marshal.load(File.read(file)) if File.exist?(file)
17
+ end
18
+
19
+ def delete(file)
20
+ file = "#{@dir}/#{file}"
21
+ File.unlink(file) if File.exist?(file)
22
+ end
23
+
24
+ def fetch(file, &block)
25
+ read(file) || write(file, yield)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,57 @@
1
+ module GemOnDemand
2
+ class Project
3
+ MAX_VERSIONS = 50 # some projects just have a million versions ...
4
+ DEPENDENCIES = "dependencies"
5
+ VERSION_REX = /^v?\d+\.\d+\.\d+(\.\w+)?$/ # with or without v and pre-release (cannot do others or we get: 'Malformed version number string 1.0.0-rails3' from bundler)
6
+
7
+ attr_accessor :user, :name, :cache
8
+
9
+ def initialize(user, name, cache)
10
+ self.user = user
11
+ self.name = name
12
+ self.cache = cache
13
+ end
14
+
15
+ def dependencies
16
+ cache.fetch DEPENDENCIES do
17
+ versions.last(MAX_VERSIONS).map do |version|
18
+ next unless dependencies = dependencies_for_version(version)
19
+ {
20
+ :name => name,
21
+ :number => version.sub(/^v/, ""),
22
+ :platform => "ruby",
23
+ :dependencies => dependencies
24
+ }
25
+ end.compact
26
+ end
27
+ end
28
+
29
+ def build_gem(version)
30
+ cache.fetch("gem-#{version}") do
31
+ checkout_version("v#{version}")
32
+ gemspec = "#{name}.gemspec"
33
+ Utils.remove_signing(gemspec)
34
+ Utils.sh("gem build #{gemspec}")
35
+ File.read("#{name}-#{version}.gem")
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def dependencies_for_version(version)
42
+ cache.fetch "dependencies-#{version}" do
43
+ checkout_version(version)
44
+ result = Utils.sh(%{ruby -e 'print Marshal.dump(eval(File.read("#{name}.gemspec")).runtime_dependencies.map{|d| [d.name, d.requirement.to_s]})'}, :fail => :allow)
45
+ Marshal.load(result) if result
46
+ end
47
+ end
48
+
49
+ def checkout_version(version)
50
+ Utils.sh("git checkout #{version} --force")
51
+ end
52
+
53
+ def versions
54
+ Utils.sh("git tag").split($/).grep(VERSION_REX)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,31 @@
1
+ module GemOnDemand
2
+ module Utils
3
+ class << self
4
+ def sh(command, options = { })
5
+ puts command
6
+ result = `#{command}`
7
+ if $?.success?
8
+ result
9
+ elsif options[:fail] == :allow
10
+ false
11
+ else
12
+ raise "Command failed: #{result}"
13
+ end
14
+ end
15
+
16
+ def ensure_directory(dir)
17
+ FileUtils.mkdir_p(dir) unless File.directory?(dir)
18
+ end
19
+
20
+ def remove_directory(dir)
21
+ FileUtils.rm_rf(dir) if File.exist?(dir)
22
+ end
23
+
24
+ # ERROR: While executing gem ... (Gem::Security::Exception)
25
+ # certificate /CN=michael/DC=grosser/DC=it not valid after 2014-02-03 18:13:11 UTC
26
+ def remove_signing(gemspec)
27
+ File.write(gemspec, File.read(gemspec).gsub(/.*\.(signing_key|cert_chain).*/, ""))
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,3 +1,3 @@
1
1
  module GemOnDemand
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gem_on_demand
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Grosser
@@ -30,7 +30,7 @@ cert_chain:
30
30
  F5etKHZg0j3eHO31/i2HnswY04lqGImUu6aM5EnijFTB7PPW2KwKKM4+kKDYFdlw
31
31
  /0WV1Ng2/Y6qsHwmqGg2VlYj2h4=
32
32
  -----END CERTIFICATE-----
33
- date: 2014-03-01 00:00:00.000000000 Z
33
+ date: 2014-03-02 00:00:00.000000000 Z
34
34
  dependencies:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: sinatra
@@ -54,8 +54,12 @@ extra_rdoc_files: []
54
54
  files:
55
55
  - MIT-LICENSE.txt
56
56
  - lib/gem_on_demand.rb
57
+ - lib/gem_on_demand/checkout.rb
57
58
  - lib/gem_on_demand/cli.rb
59
+ - lib/gem_on_demand/file_cache.rb
60
+ - lib/gem_on_demand/project.rb
58
61
  - lib/gem_on_demand/server.rb
62
+ - lib/gem_on_demand/utils.rb
59
63
  - lib/gem_on_demand/version.rb
60
64
  homepage: https://github.com/grosser/gem_on_demand
61
65
  licenses:
metadata.gz.sig CHANGED
Binary file