familyjewels 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ stage
2
+ test_repos
3
+ gems
4
+ *.sublime*
5
+ *.gem
6
+ .bundle
7
+ Gemfile.lock
8
+ pkg/*
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.8.7@fj-new --create
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in family_jewels.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ Project To Do List
2
+ ==========
3
+
4
+ Next Up
5
+ ----------
6
+
7
+ * Write automated tests to confirm functionality
8
+ * Add tasks for cleanly re-generating indexes
9
+ * Test installation build with real-world configuration
10
+ * Refactor Project#build into Builder class
11
+ * Refactor Project#register into Config class
12
+
13
+ Big List
14
+ ----------
15
+
16
+ * Improve handling of error cases
17
+ * Use whenever to set up cron scheduling
18
+ * Helper scripts for setting up apache static index hosting
19
+ * Sinatra (or similar) to serve static indexes
20
+ * Build binary commands
21
+ * Fill in gemspec
22
+ * Define rubygems dependencies
23
+ * Handle missing support gems (bundler, rake, builder)
24
+ * Sep. gem to provide web interface for management (add/remove/edit/schedule project builds)
25
+
26
+ Done
27
+ ----------
28
+
29
+ * Use Bundler to isolate gem sets from the system gems
30
+
31
+ Probably Not
32
+ ----------
33
+
34
+ * Consider whether to use rvm to manage gemsets (too much installation overhead?)
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/test ADDED
@@ -0,0 +1,18 @@
1
+ #! /usr/bin/env ruby
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'family_jewels'
5
+
6
+ FamilyJewels::Project.register(
7
+ :verbose => true,
8
+ :clone_url => 'git@github.com:subakva/familyjewels-test.git'
9
+ )
10
+ FamilyJewels::Project.register(
11
+ :verbose => true,
12
+ :clone_url => 'git@github.com:subakva/familyjewels-test.git',
13
+ :branch_name => 'experiment'
14
+ )
15
+
16
+ FamilyJewels::Project.all.each do |project|
17
+ project.build
18
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "family_jewels/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "familyjewels"
7
+ s.version = FamilyJewels::VERSION
8
+ s.authors = ["Jason Wadsworth"]
9
+ s.email = ["jdwadsworth@gmail.com"]
10
+ s.homepage = "http://github.com/subakva/familyjewels"
11
+ s.summary = %q{Build Private Gems}
12
+ s.description = %q{Tools for building and publishing private and customized Ruby gems}
13
+
14
+ s.rubyforge_project = "familyjewels"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ s.add_development_dependency "rspec"
23
+ s.add_runtime_dependency "bundler", "~> 1.0.0"
24
+ end
@@ -0,0 +1,3 @@
1
+ require 'family_jewels/version'
2
+ require 'family_jewels/config'
3
+ require 'family_jewels/project'
@@ -0,0 +1,17 @@
1
+ module FamilyJewels
2
+ class Config
3
+ class << self
4
+ def gems_dir(create_if_missing = true)
5
+ dir = File.join(ENV['PWD'], 'gems')
6
+ FileUtils.mkdir(dir) if create_if_missing && !File.exists?(dir)
7
+ dir
8
+ end
9
+
10
+ def stage_dir(create_if_missing = true)
11
+ dir = File.join(ENV['PWD'], 'stage')
12
+ FileUtils.mkdir(dir) if create_if_missing && !File.exists?(dir)
13
+ dir
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,239 @@
1
+ require 'fileutils'
2
+
3
+ # Test Notes
4
+ # builder_name is not a valid directory name
5
+ # builder_name contains a directory separator
6
+
7
+ module FamilyJewels
8
+ class Project
9
+
10
+ DEFAULTS = {
11
+ :remote_name => 'origin',
12
+ :branch_name => 'master',
13
+ :install_task => 'install'
14
+ }
15
+
16
+ attr_accessor :clone_url, :branch_name, :project_name, :builder_name, :verbose, :remote_name, :install_task
17
+
18
+ # Create a new Project.
19
+ #
20
+ # * :clone_url - The URL to use to clone the git repository
21
+ # :remote_name - The name of the git remote origin [default: origin]
22
+ # :branch_name - The name of the git branch to build [default: master]
23
+ # :project_name - The name of the project ( eg. srbase )
24
+ # :builder_name - The name for this build of the project ( eg. srbase-master )
25
+ # :install_task - The name of the rake task used to install the project as a gem
26
+ # :verbose - Enable verbose output
27
+ #
28
+ def initialize(attributes = nil)
29
+ attributes ||= {}
30
+ attributes = DEFAULTS.merge(attributes)
31
+
32
+ raise ArgumentError.new(":clone_url is a required attribute.") unless attributes.has_key?(:clone_url)
33
+ raise ArgumentError.new(":branch_name is a required attribute.") unless attributes.has_key?(:branch_name)
34
+
35
+ self.verbose = attributes[:verbose]
36
+ self.clone_url = attributes[:clone_url]
37
+ self.remote_name = attributes[:remote_name]
38
+ self.branch_name = attributes[:branch_name]
39
+ self.install_task = attributes[:install_task]
40
+ self.project_name = attributes[:project_name] || parse_project_name(clone_url)
41
+ self.builder_name = attributes[:builder_name] || "#{self.project_name}-#{self.branch_name}"
42
+ end
43
+
44
+ def clone_dir
45
+ File.join(Config.stage_dir, self.builder_name)
46
+ end
47
+
48
+ # Returns true if the project has already been cloned
49
+ def cloned?
50
+ File.exists?(self.clone_dir)
51
+ end
52
+
53
+ # Clones the project into the staging area
54
+ def clone!
55
+ puts "=> Cloning into #{self.clone_dir}" if self.verbose
56
+
57
+ run_command("git clone #{self.clone_url} #{self.clone_dir}")
58
+ FileUtils.cd(self.clone_dir) do
59
+ run_command("git checkout #{self.branch_name}")
60
+ end
61
+ end
62
+
63
+ # Fetches the latest changes from the remote repository.
64
+ # Returns true if the project has changed
65
+ def fetch!
66
+ puts "=> Fetching remote changes: #{self.remote_name}" if self.verbose
67
+
68
+ project_changed = false
69
+ FileUtils.cd(self.clone_dir) do
70
+ run_command("git fetch #{self.remote_name}")
71
+ run_command("git status") do |output|
72
+ project_changed = (output =~ /Your branch is behind/)
73
+ end
74
+ end
75
+ project_changed
76
+ end
77
+
78
+ # Resets the local branch to match the remote version.
79
+ def merge_branch!
80
+ puts "=> Resetting branch: #{self.branch_name}" if self.verbose
81
+
82
+ FileUtils.cd(self.clone_dir) do
83
+ run_command("git merge #{self.remote_name}/#{self.branch_name}")
84
+ end
85
+ false
86
+ end
87
+
88
+ # Returns true if the project has a file with the specified name
89
+ def has_file?(filename)
90
+ File.exists?(File.join(self.clone_dir, filename))
91
+ end
92
+
93
+ # Returns true if the project has a Gemfile
94
+ def has_gemfile?
95
+ has_file?('Gemfile')
96
+ end
97
+
98
+ # Returns true if the project has a Rakefile
99
+ def has_rakefile?
100
+ has_file?('Rakefile')
101
+ end
102
+
103
+ def has_install_task?
104
+ return false unless self.install_task && has_rakefile?
105
+ has_task = false
106
+ FileUtils.cd(self.clone_dir) do
107
+ run_command("rake -T #{self.install_task}") do |output|
108
+ has_task = (output =~ Regexp.new("rake #{self.install_task}"))
109
+ end
110
+ end
111
+ has_task
112
+ end
113
+
114
+ # Processes the project, installing gems to be indexed as required.
115
+ def build(options = nil)
116
+ # TODO: Extract into Builder
117
+
118
+ puts "\n======================================================================"
119
+ puts "=> Building: #{self.builder_name}"
120
+ self.print_attributes if self.verbose
121
+ puts "======================================================================\n\n"
122
+
123
+ options ||= {}
124
+ options = {
125
+ :install_dependencies => true,
126
+ :install_as_gem => true
127
+ }.merge(options)
128
+
129
+ if self.cloned?
130
+ if self.fetch!
131
+ self.merge_branch!
132
+ else
133
+ puts "\n======================================================================"
134
+ puts "=> No remote changes."
135
+ puts "======================================================================"
136
+ return false
137
+ end
138
+ else
139
+ self.clone!
140
+ end
141
+
142
+ if self.has_gemfile? && options[:install_dependencies]
143
+ puts "\n======================================================================"
144
+ puts "=> Installing Dependencies"
145
+ puts "======================================================================"
146
+
147
+ FileUtils.cd(self.clone_dir) do
148
+ # TODO: Figure out why the output from the bundle command isn't showing
149
+ # "bundle install --path #{Config.gems_dir} 2>&1" ?
150
+ run_command("bundle install --path #{Config.gems_dir}")
151
+ end
152
+ end
153
+
154
+ if self.has_install_task? && options[:install_as_gem]
155
+ puts "\n======================================================================"
156
+ puts "=> Installing Gem"
157
+ puts "======================================================================"
158
+
159
+ FileUtils.cd(self.clone_dir) do
160
+ # TODO: Make this work with other versions of Ruby
161
+ gem_home = "#{Config.gems_dir}/ruby/1.8"
162
+ gem_path = gem_home
163
+ rake_path = "#{gem_home}/bin/rake"
164
+
165
+ unless File.exists?(File.join(gem_home, 'bin', 'bundle'))
166
+ run_command("GEM_HOME=#{gem_home} GEM_PATH=#{gem_path} gem install bundler")
167
+ end
168
+ run_command("GEM_HOME=#{gem_home} GEM_PATH=#{gem_path} #{rake_path} install")
169
+ end
170
+ end
171
+
172
+ return true
173
+ end
174
+
175
+ protected
176
+
177
+ def print_attributes
178
+ puts "=> - verbose : #{self.verbose}"
179
+ puts "=> - clone_url : #{self.clone_url}"
180
+ puts "=> - remote_name : #{self.remote_name}"
181
+ puts "=> - branch_name : #{self.branch_name}"
182
+ puts "=> - project_name : #{self.project_name}"
183
+ puts "=> - builder_name : #{self.builder_name}"
184
+ puts "=> - install_task : #{self.install_task}"
185
+ end
186
+
187
+ def parse_project_name(git_url)
188
+ git_url.match(/^.*\/(.*)\.git$/)[1]
189
+ end
190
+
191
+ def run_command(command, &block)
192
+ if self.verbose
193
+ puts "=> Running: #{command}"
194
+ puts
195
+ end
196
+
197
+ output = `#{command} 2>&1`
198
+ # output = `#{command}`
199
+ successful = ($?.exitstatus == 0)
200
+
201
+ if self.verbose
202
+ puts output
203
+ puts
204
+ puts "=> Success?: #{successful}"
205
+ end
206
+
207
+ yield(output) if block_given? && successful
208
+
209
+ # TODO: What is the best way to handle errors? Skip the failed project and move on to the next?
210
+ unless successful
211
+ puts "=> Cammand Failed: #{command}"
212
+ puts "=> #{$?.inspect}"
213
+ unless self.verbose
214
+ puts "=> Output:"
215
+ puts
216
+ puts output
217
+ puts
218
+ end
219
+ raise "Command Failed: #{command}"
220
+ end
221
+ return successful
222
+ end
223
+
224
+ class << self
225
+ # TODO: Move to Config
226
+ def register(*args)
227
+ @projects ||= []
228
+ project = FamilyJewels::Project.new(*args)
229
+ @projects << project
230
+ puts " => Registered #{project.builder_name}" if project.verbose
231
+ project
232
+ end
233
+
234
+ def all
235
+ (@projects || []).dup
236
+ end
237
+ end
238
+ end
239
+ end
@@ -0,0 +1,3 @@
1
+ module FamilyJewels
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: familyjewels
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Jason Wadsworth
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-09-18 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rspec
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :development
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: bundler
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ hash: 23
44
+ segments:
45
+ - 1
46
+ - 0
47
+ - 0
48
+ version: 1.0.0
49
+ type: :runtime
50
+ version_requirements: *id002
51
+ description: Tools for building and publishing private and customized Ruby gems
52
+ email:
53
+ - jdwadsworth@gmail.com
54
+ executables:
55
+ - test
56
+ extensions: []
57
+
58
+ extra_rdoc_files: []
59
+
60
+ files:
61
+ - .gitignore
62
+ - .rvmrc
63
+ - Gemfile
64
+ - README.md
65
+ - Rakefile
66
+ - bin/test
67
+ - familyjewels.gemspec
68
+ - lib/family_jewels.rb
69
+ - lib/family_jewels/config.rb
70
+ - lib/family_jewels/project.rb
71
+ - lib/family_jewels/version.rb
72
+ has_rdoc: true
73
+ homepage: http://github.com/subakva/familyjewels
74
+ licenses: []
75
+
76
+ post_install_message:
77
+ rdoc_options: []
78
+
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ hash: 3
87
+ segments:
88
+ - 0
89
+ version: "0"
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ hash: 3
96
+ segments:
97
+ - 0
98
+ version: "0"
99
+ requirements: []
100
+
101
+ rubyforge_project: familyjewels
102
+ rubygems_version: 1.4.2
103
+ signing_key:
104
+ specification_version: 3
105
+ summary: Build Private Gems
106
+ test_files: []
107
+