software_smithy 1.1 → 1.6

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.
@@ -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