gem_on_demand 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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