software_smithy 1.1 → 1.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -43,6 +43,9 @@ module Smithy
43
43
  def notice_exist(file)
44
44
  puts "exists ".rjust(12).color(:blue).bright + file
45
45
  end
46
+ def notice_using(file)
47
+ puts "using ".rjust(12).color(:blue).bright + file
48
+ end
46
49
  def notice_link(file1, file2)
47
50
  puts "link ".rjust(12).bright + file1 + " -> " + file2
48
51
  end
@@ -83,7 +86,7 @@ module Smithy
83
86
  begin
84
87
  FileUtils.send method, nil, new_group, f, options
85
88
  rescue
86
- raise "Could not set group \"#{new_group}\" on \"#{f}\""
89
+ # raise "Could not set group \"#{new_group}\" on \"#{f}\""
87
90
  end
88
91
  end
89
92
 
@@ -96,7 +99,7 @@ module Smithy
96
99
  else
97
100
  command = "chmod g+w #{f}"
98
101
  unless options[:noop]
99
- # Check to see if it's already group writeable
102
+ # Check to see if it's already group writable
100
103
  # convert the integer to a string in base 8
101
104
  mode = File.stat(f).mode.to_s(8)
102
105
  # check the group bit, convert back to integer
@@ -134,7 +137,7 @@ module Smithy
134
137
  installed = false
135
138
 
136
139
  force = options.try(:[],:force)
137
- force = Smithy::Config.global.try(:[], :"force")
140
+ force = Smithy::Config.global.try(:[], :"force") unless force
138
141
  options.reject!{|k,v| k==:force}
139
142
 
140
143
  if File.exists?(dest) && !force
@@ -143,8 +146,8 @@ module Smithy
143
146
  installed = true
144
147
  else
145
148
  notice_conflict dest
146
- overwrite = nil
147
- while overwrite.nil? do
149
+ overwrite = "unknown"
150
+ while overwrite == "unknown" do
148
151
  prompt = Readline.readline(" "*FILE_NOTICE_COLUMNS+"Overwrite? (enter \"h\" for help) [ynsdh] ")
149
152
  case prompt.downcase
150
153
  when "y"
@@ -208,6 +211,7 @@ module Smithy
208
211
  end
209
212
 
210
213
  def render_erb(args = {})
214
+ args[:options] = {} unless args[:options]
211
215
  options = {:noop => false, :verbose => false}
212
216
  options.merge!(args[:options])
213
217
  erb_filename = args[:erb]
@@ -219,7 +223,10 @@ module Smithy
219
223
  rendered_file = "#{File.dirname(dest)}/.#{File.basename(dest)}_#{Time.now.to_i}"
220
224
  end
221
225
 
222
- erb = ERB.new(File.read(erb_filename), nil, "<>")
226
+ erb_string = args[:erb_string]
227
+ erb_string = File.read(erb_filename) if erb_string.blank?
228
+
229
+ erb = ERB.new(erb_string, nil, "<>")
223
230
  File.open(rendered_file, "w+") do |f|
224
231
  f.write erb.result(args[:binding])
225
232
  end
@@ -0,0 +1,203 @@
1
+ module Smithy
2
+ class Formula
3
+ attr_accessor :formula_file, :name, :build_name, :prefix, :package, :module_setup
4
+
5
+ def self.formula_name
6
+ self.to_s.underscore.split("/").last.gsub /_formula$/, ""
7
+ end
8
+ def formula_name
9
+ self.class.formula_name
10
+ end
11
+
12
+ def initialize(passed_package = nil)
13
+ @formula_file = __FILE__
14
+ raise "no install method implemented" unless self.respond_to?(:install)
15
+ raise "homepage must be specified" if homepage.blank?
16
+ raise "url must be specified" if url.blank?
17
+ if passed_package
18
+ set_package(passed_package)
19
+ else
20
+ # guess name and build_name
21
+ @name = self.formula_name
22
+ @build_name = operating_system
23
+ initialize_modules
24
+ end
25
+ end
26
+
27
+ # setup module environment by purging and loading only what's needed
28
+ def initialize_modules
29
+ @modules = nil # re-evaluate modules block
30
+ @module_commands = nil # re-evaluate module_commands block
31
+ @module_setup = ""
32
+ raise "please specify modules OR modules_command, not both" if modules.present? && module_commands.present?
33
+ if ENV["MODULESHOME"]
34
+ @modulecmd = "modulecmd sh"
35
+ @modulecmd = "#{ENV["MODULESHOME"]}/bin/modulecmd sh" if File.exists?("#{ENV["MODULESHOME"]}/bin/modulecmd")
36
+ if modules.present?
37
+ @module_setup << `#{@module_setup} #{@modulecmd} purge 2>/dev/null` << " "
38
+ raise "modules must return a list of strings" unless modules.is_a? Array
39
+ @module_setup << `#{@module_setup} #{@modulecmd} load #{modules.join(" ")}` << " "
40
+ elsif module_commands.present?
41
+ module_commands.each do |command|
42
+ @module_setup << `#{@module_setup} #{@modulecmd} #{command}` << " "
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ def set_package(p)
49
+ @package = p
50
+ @name = p.name
51
+ @version = p.version
52
+ @build_name = p.build_name
53
+ @prefix = p.prefix
54
+ initialize_modules
55
+ end
56
+
57
+ # DSL Methods
58
+ %w{ homepage url md5 sha1 sha2 sha256 modules module_commands depends_on modulefile }.each do |attr|
59
+ class_eval %Q{
60
+ def self.#{attr}(value = nil, &block)
61
+ @#{attr} = block_given? ? block : value unless @#{attr}
62
+ @#{attr}
63
+ end
64
+ def #{attr}
65
+ @#{attr} = self.class.#{attr}.is_a?(Proc) ? instance_eval(&self.class.#{attr}) : self.class.#{attr} unless @#{attr}
66
+ @#{attr}
67
+ end
68
+ }
69
+ end
70
+
71
+ # DLS Version Method, can set a version or guess based on the filename
72
+ def self.version(value = nil)
73
+ unless @version
74
+ if value
75
+ @version = value
76
+ else
77
+ @version = url_filename_version_number(url) if url.present?
78
+ end
79
+ end
80
+ @version
81
+ end
82
+
83
+ def version
84
+ @version = self.class.version unless @version
85
+ @version
86
+ end
87
+
88
+ # DLS Version Method, can set a version or guess based on the filename
89
+ def self.disable_group_writable(value = true)
90
+ @disable_group_writable = true
91
+ @disable_group_writable
92
+ end
93
+
94
+ def group_writable?
95
+ ! self.class.instance_variables.include?(:@disable_group_writable)
96
+ end
97
+
98
+ def run_install
99
+ check_dependencies if depends_on
100
+ install
101
+ notice_success "SUCCESS #{@prefix}"
102
+ return true
103
+ end
104
+
105
+ def create_modulefile
106
+ return false if modulefile.blank?
107
+ notice "Creating Modulefile for #{package.prefix}"
108
+ m = ModuleFile.new :package => package
109
+ FileUtils.mkdir_p(File.dirname(m.module_file))
110
+ FileOperations.render_erb(:erb_string => modulefile, :binding => m.get_binding, :destination => m.module_file)
111
+ FileOperations.make_group_writable(m.module_file)
112
+ FileOperations.set_group(m.module_file, package.group)
113
+ return true
114
+ end
115
+
116
+ def module_list
117
+ if ENV['MODULESHOME']
118
+ notice "module list"
119
+ Kernel.system @module_setup + "#{@modulecmd} list 2>&1"
120
+ end
121
+ end
122
+
123
+ def module_is_available?(mod)
124
+ return false unless @modulecmd
125
+
126
+ if `#{@modulecmd} avail #{mod} 2>&1` =~ /#{mod}/
127
+ true
128
+ else
129
+ false
130
+ end
131
+ end
132
+
133
+ def module_environment_variable(mod, var)
134
+ module_display = `#{@modulecmd} display #{mod} 2>&1`
135
+ if module_display =~ /(\S+)\s+#{var}\s+(.*)$/
136
+ return $2
137
+ else
138
+ return ""
139
+ end
140
+ end
141
+
142
+ def fail_command
143
+ $stdout.flush
144
+ $stderr.flush
145
+ raise <<-EOF.strip_heredoc
146
+ The last command exited with status: #{$?.exitstatus}
147
+ Formula: #{formula_file}
148
+ Build Directory: #{@package.source_directory}
149
+ EOF
150
+ end
151
+
152
+ def patch(content, *args)
153
+ patch_file_name = "patch.diff"
154
+ File.open(patch_file_name, "w+") do |f|
155
+ f.write(content)
156
+ end
157
+ args << "-p1" if args.empty?
158
+ patch_command = "patch #{args.join(' ')} <#{patch_file_name}"
159
+ notice patch_command
160
+ Kernel.system patch_command
161
+ fail_command if $?.exitstatus != 0
162
+ end
163
+
164
+ def system(*args)
165
+ notice args.join(' ')
166
+ if args.first == :nomodules
167
+ args.shift
168
+ Kernel.system args.join(' ')
169
+ else
170
+ Kernel.system @module_setup + args.join(' ')
171
+ end
172
+ fail_command if $?.exitstatus != 0
173
+ end
174
+
175
+ def check_dependencies
176
+ @depends_on = [depends_on] if depends_on.is_a? String
177
+ missing_packages = []
178
+ notice "Searching for dependencies"
179
+ depends_on.each do |package|
180
+ name, version, build = package.split('/')
181
+ path = Package.all(:name => name, :version => version, :build => build).first
182
+ if path
183
+ notice_using(path)
184
+ p = Package.new(:path => path)
185
+ new_name = p.name.underscore
186
+ class_eval %Q{
187
+ def #{new_name}
188
+ @#{new_name} = Package.new(:path => "#{path}") if @#{new_name}.nil?
189
+ @#{new_name}
190
+ end
191
+ }
192
+ else
193
+ missing_packages << package
194
+ #TODO build package instead?
195
+ end
196
+ end
197
+ unless missing_packages.empty?
198
+ raise "#{self.class} depends on: #{missing_packages.join(" ")}"
199
+ end
200
+ end
201
+
202
+ end #class Formula
203
+ end #module Smithy
@@ -0,0 +1,198 @@
1
+ module Smithy
2
+ # This class acts as a controller for formula subcommands
3
+ class FormulaCommand
4
+ # Return formula directories in order of precedence
5
+ # 1. formula directories specified on the command line
6
+ # 2. formulas located in ~/.smithy/formulas/
7
+ # 3. smithy's built in formulas
8
+ def self.formula_directories
9
+ unless @formula_directories
10
+ @formula_directories = [ File.join(ENV["HOME"], ".smithy/formulas") ]
11
+ if Smithy::Config.global[:"formula-directories"]
12
+ Smithy::Config.global[:"formula-directories"].reverse.each do |dir|
13
+ @formula_directories << dir
14
+ end
15
+ end
16
+ @formula_directories << File.join(@@smithy_bin_root, "formulas")
17
+ end
18
+ @formula_directories
19
+ end
20
+
21
+ # Prepend a directory to the formula file paths
22
+ def self.prepend_formula_directory(dir)
23
+ @formula_directories.unshift(dir)
24
+ @formula_directories
25
+ end
26
+
27
+ # Returns an array containing the full paths
28
+ # to each file name in order of precedence
29
+ def self.formula_files
30
+ unless @formula_files
31
+ @formula_files = []
32
+ formula_directories.each do |dir|
33
+ @formula_files += Dir.glob(File.join(File.expand_path(dir),"*.rb")).sort
34
+ end
35
+ end
36
+ @formula_files
37
+ end
38
+
39
+ # Format the full file paths to display only the name
40
+ def self.formula_names
41
+ @formula_names = formula_files.collect{|f| File.basename(f,"_formula.rb")}.uniq unless @formula_names
42
+ @formula_names
43
+ end
44
+
45
+ # Return the file path of a single formula file
46
+ def self.formula_file_path(name)
47
+ formula_files.select{|f| f =~ /\/#{name}_formula.rb/}.first
48
+ end
49
+
50
+ # Return the file contents of a formula
51
+ def self.formula_contents(name)
52
+ raise "unkown formula '#{name}'" unless formula_file_path(name).present? && File.exists?(formula_file_path(name))
53
+ File.read(formula_file_path(name))
54
+ end
55
+
56
+ def self.initialize_directories(options)
57
+ prepend_formula_directory(options[:d]) if options[:d]
58
+ end
59
+
60
+ def self.which_command(options,args)
61
+ initialize_directories(options)
62
+ formula_name = args.first.split("/").first
63
+ puts formula_file_path(formula_name)
64
+ end
65
+
66
+ def self.display_command(options,args)
67
+ initialize_directories(options)
68
+ formula_name = args.first.split("/").first
69
+ puts formula_contents(formula_name)
70
+ end
71
+
72
+ def self.list_command(options,args)
73
+ initialize_directories(options)
74
+ puts formula_names
75
+ end
76
+
77
+ # construct a new fomula object given a formula name or full name/version/build
78
+ def self.build_formula(package, formula_name = nil)
79
+ name, version, build = package.split("/")
80
+ formula_name = name if formula_name.blank?
81
+ raise "unknown formula #{formula_name}" unless formula_names.include?(formula_name)
82
+
83
+ require formula_file_path(formula_name)
84
+ f = "#{formula_name.underscore.camelize}Formula".constantize.new
85
+ # Set the actual formula file path, otherwise it's just formula.rb
86
+ f.formula_file = formula_file_path(formula_name)
87
+
88
+ version = f.version if version.blank?
89
+ build = operating_system if build.blank?
90
+ p = Package.new :path => [name, version, build].join("/"), :group_writable => f.group_writable?
91
+ f.set_package(p) if p.valid?
92
+
93
+ return f
94
+ end
95
+
96
+ def self.install_command(options,args)
97
+ initialize_directories(options)
98
+
99
+ packages = args.dup
100
+ raise "You must supply at least one package to install" if packages.empty?
101
+
102
+ packages.each do |package|
103
+ f = build_formula(package, options[:"formula-name"])
104
+ f.package.create(:formula => true)
105
+
106
+ formula_prefix_contents = Dir["#{f.prefix}/*"]
107
+ unless formula_prefix_contents.empty?
108
+ # overwrite = "unknown"
109
+ # while overwrite == "unknown" do
110
+ # notice_conflict f.package.prefix
111
+ # prompt = Readline.readline(" "*FILE_NOTICE_COLUMNS+"Is not empty, delete contents? (enter \"h\" for help) [ynhq] ")
112
+ # case prompt.downcase
113
+ # when "y"
114
+ # overwrite = true
115
+ # when "n"
116
+ # overwrite = false
117
+ # when "h"
118
+ # indent = " "*FILE_NOTICE_COLUMNS
119
+ # puts indent+"y - yes, delete existing install"
120
+ # puts indent+"n - no, do not overwrite"
121
+ # puts indent+"h - help, show this help"
122
+ # puts indent+"q - exit now"
123
+ # when "q"
124
+ # raise "Abort new formula install"
125
+ # end
126
+ # end
127
+ # if overwrite
128
+ if options[:clean]
129
+ notice "cleaning #{f.prefix}"
130
+ formula_prefix_contents.each do |f|
131
+ FileUtils.rm_rf(f)
132
+ end
133
+ end
134
+ # end
135
+ end
136
+
137
+ if f.url.eql?("none")
138
+ Dir.chdir File.join(f.package.prefix)
139
+ else
140
+ d = DownloadCache.new(f, options[:"formula-name"]).get
141
+ raise "Download failure" unless d
142
+ # f.package.extract(:archive => d, :overwrite => true)
143
+ f.package.extract(:archive => d)
144
+ Dir.chdir File.join(f.package.prefix, "source")
145
+ end
146
+
147
+ if f.run_install
148
+ f.package.create_valid_build_file
149
+ f.package.set_file_permissions_recursive
150
+
151
+ if f.modulefile.present?
152
+ f.create_modulefile
153
+ elsif options[:"modulefile"]
154
+ ModuleFile.new(:package => f.package).create
155
+ end
156
+ end
157
+ end #packages.each
158
+ end
159
+
160
+ def self.new_command(options,args)
161
+ @formula_name = options[:name]
162
+ @formula_name = url_filename_basename(args.first) unless options[:name]
163
+ @formula_name = @formula_name.camelize
164
+ @formula_url = args.first
165
+ @formula_homepage = options[:homepage]
166
+ @formula_homepage = "#{URI(@formula_url).scheme}://#{URI(@formula_url).host}/" unless options[:homepage]
167
+
168
+ destination = File.join(ENV["HOME"], ".smithy/formulas")
169
+ destination = Smithy::Config.global[:"formula-directories"].first if Smithy::Config.global[:"formula-directories"]
170
+ FileUtils::mkdir_p(destination)
171
+
172
+ destination = File.join(destination, "#{@formula_name.underscore}_formula.rb")
173
+ FileOperations.render_erb :binding => binding,
174
+ :erb => File.join(@@smithy_bin_root, "etc/templates/formula.rb.erb"),
175
+ :destination => destination
176
+ if Smithy::Config.global[:"file-group-name"]
177
+ FileOperations.set_group(destination, Smithy::Config.global[:"file-group-name"])
178
+ FileOperations.make_group_writable(destination)
179
+ end
180
+ end
181
+
182
+ def self.create_module_command(options,args)
183
+ packages = args.dup
184
+ raise "You must supply at least one package to install" if packages.empty?
185
+
186
+ packages.each do |package|
187
+ f = build_formula(package, options[:"formula-name"])
188
+ if f.modulefile.present?
189
+ f.create_modulefile
190
+ else
191
+ ModuleFile.new(:package => f.package).create
192
+ end
193
+ end
194
+ end
195
+
196
+ end #FormulaCommand
197
+
198
+ end