csd 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/.gitignore +1 -1
  2. data/README.rdoc +19 -6
  3. data/VERSION +1 -1
  4. data/lib/csd.rb +40 -18
  5. data/lib/csd/application.rb +1 -2
  6. data/lib/csd/application/decklink/about.yml +1 -1
  7. data/lib/csd/application/decklink/base.rb +1 -0
  8. data/lib/csd/application/decklink/options/{install.rb → common.rb} +0 -2
  9. data/lib/csd/application/decklink/options/common_defaults.rb +2 -0
  10. data/lib/csd/application/default.rb +62 -6
  11. data/lib/csd/application/graphics.rb +30 -0
  12. data/lib/csd/application/graphics/about.yml +8 -0
  13. data/lib/csd/application/graphics/base.rb +157 -0
  14. data/lib/csd/application/graphics/error.rb +16 -0
  15. data/lib/csd/application/graphics/options/common.rb +11 -0
  16. data/lib/csd/application/graphics/options/common_defaults.rb +2 -0
  17. data/lib/csd/application/graphics/options/install.rb +11 -0
  18. data/lib/csd/application/graphics/options/install_defaults.rb +2 -0
  19. data/lib/csd/application/i2conf.rb +2 -1
  20. data/lib/csd/application/i2conf/about.yml +1 -1
  21. data/lib/csd/application/minisip/about.yml +1 -1
  22. data/lib/csd/application/minisip/base.rb +1 -0
  23. data/lib/csd/application/minisip/component/core.rb +20 -9
  24. data/lib/csd/application/minisip/unix.rb +0 -1
  25. data/lib/csd/application/mslog.rb +29 -0
  26. data/lib/csd/application/mslog/about.yml +8 -0
  27. data/lib/csd/application/mslog/base.rb +123 -0
  28. data/lib/csd/application/mslog/options/common.rb +7 -0
  29. data/lib/csd/application/mslog/options/common_defaults.rb +2 -0
  30. data/lib/csd/applications.rb +2 -0
  31. data/lib/csd/commands.rb +28 -28
  32. data/lib/csd/container.rb +20 -16
  33. data/lib/csd/options_parser.rb +19 -2
  34. data/lib/csd/user_interface/base.rb +4 -0
  35. metadata +19 -7
  36. data/csd.gemspec +0 -161
  37. data/lib/csd/application/opensips/about.yml +0 -2
data/.gitignore CHANGED
@@ -24,4 +24,4 @@ pkg
24
24
 
25
25
  ## PROJECT::SPECIFIC
26
26
  drop
27
- edge
27
+ edge
@@ -2,12 +2,24 @@
2
2
 
3
3
  CSD stands for Communication Systems Design and is a project of the Telecommunication Systems Laboratory (TSLab) of the Royal Institute of Technology in Stockholm, Sweden. Within CSD many software tools are used to build up various networks and services. This gem is supposed to automate processes to handle the compilation and installation of these software tools. Technology Transfer Alliance (TTA) is the project team, which maintains this code.
4
4
 
5
+ == Where is it?
6
+
7
+ * {Installation instructions}[http://ttai.notlong.com/]
8
+ * {Source Code}[http://github.com/csd/csd]
9
+ * {RDoc API}[http://rdoc.info/github/csd/csd/master]
10
+ * {Developer Forks}[http://github.com/csd/csd/network]
11
+ * {Bug Tracker}[http://github.com/csd/csd/issues]
12
+ * {Wiki}[http://wiki.github.com/csd/csd]
13
+
5
14
  == Requirements
6
15
 
7
- * Ruby >= 1.8.7
16
+ * {Ruby}[http://ruby-lang.org] (>= 1.8.7)
17
+ * {RubyGems}[http://rubygems.org] (>= 1.3.7)
8
18
 
9
19
  == Installation
10
20
 
21
+ After having installed RubyGems, in a console, type
22
+
11
23
  (sudo) gem install csd
12
24
 
13
25
  == Usage
@@ -16,13 +28,14 @@ In a console, type
16
28
 
17
29
  ai
18
30
 
31
+ For more details we refer to the {Wiki}[http://wiki.github.com/csd/csd].
32
+
19
33
  == Note on Patches/Pull Requests
20
34
 
21
- * Fork the project.
22
- * Make your feature addition or bug fix.
23
- * Add tests for it. This is important so we don't break it in a future version unintentionally.
24
- * Commit, do not mess with Rakefile, version, or history.
25
- (if you want to have your own version, that is fine but bump version in a commit by itself we can ignore when I pull)
35
+ * Fork the project
36
+ * Make your feature addition or bug fix
37
+ * Add tests for it. This is important so we don't break it in a future version unintentionally
38
+ * Commit, without the Rakefile and the VERSION file
26
39
  * Send us a pull request.
27
40
 
28
41
  == Copyright
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.2
1
+ 0.3.0
data/lib/csd.rb CHANGED
@@ -10,61 +10,83 @@ Dir[File.join(File.dirname(__FILE__), 'csd', '*.rb')].sort.each { |path| require
10
10
  module CSD
11
11
  class << self
12
12
 
13
- # This String holds the name of the executable the user used to bootstrap this gem
13
+ # This String holds the name of the executable the user used to execute/bootstrap this gem.
14
+ # It is useful for showing example commands to the end-user, such as "Please type: ai install minisip".
15
+ # Because the name of the executable might change after some time. Currently, +ai+ and +ttai+ are
16
+ # supported executables.
14
17
  attr_reader :executable
15
18
 
16
19
  # This method "runs" the whole CSD gem, so to speak.
17
20
  #
21
+ # ==== Options
22
+ #
23
+ # The following options can be passed as a hash.
24
+ #
25
+ # [+:executable+] A String which holds the name of the exectuable that was used to call this method (default: <tt>[EXECUTABLE]</tt>).
26
+ #
18
27
  def bootstrap(options={})
19
- @executable = options[:executable]
28
+ # Storing the important options into instance variables
29
+ @executable = options[:executable] || '[EXECUTABLE]'
30
+ # Reading the command-line arguments
20
31
  Options.parse!
32
+ # Intercepting and processing AI-internal commands such as "ai update" and "ai edge"
21
33
  respond_to_internal_ai_options
34
+ # Ensure that the chosen action, application (and optionally the scope) are valid
22
35
  respond_to_incomplete_arguments
23
36
  UI.debug "#{self}.bootstrap initializes the task #{Options.action.to_s.enquote if Options.action} of the application #{Applications.current.name.to_s.enquote if Applications.current} now"
37
+ # Passing on the desired action to the instance of the chosen application module (e.g. passing on "install" to the "MiniSIP" module)
24
38
  Applications.current.instance.send("#{Options.action}".to_sym) if Applications.current
25
39
  end
26
40
 
27
41
  private
28
42
 
43
+ # This method is the first in the chain of processing the command-line arguments. It will react to
44
+ # AI-internal commands such as "update" or "edge".
45
+ #
29
46
  def respond_to_internal_ai_options
30
- if !Applications.current and ARGV.include?('update')
47
+ # If an application was chosen, this is clearly not an internal AI functionality which the user requested
48
+ return if Applications.current
49
+ # Other than that, react to some predefined commands
50
+ if ARGV.include?('update')
31
51
  update_ai_using_rubygems
32
- elsif !Applications.current and ARGV.include?('edge')
52
+ elsif ARGV.include?('edge')
33
53
  update_ai_to_cutting_edge
34
54
  end
35
55
  end
36
56
 
37
- # Updating the AI
57
+ # Updating the AI via the internal RubyGems mechanism (i.e. <tt>gem update</tt>).
58
+ # The AI will quit with status code 0 after the operation was successful.
38
59
  #
39
60
  def update_ai_using_rubygems
40
61
  UI.info "Updating the AI to the newest version".green.bold
41
62
  Cmd.run "sudo gem update csd --no-ri --no-rdoc", :announce_pwd => false, :verbose => true
42
- exit!
63
+ exit! # with status code 0
43
64
  end
44
65
 
45
66
  # This method is used to conveniently update the AI without officially publishing it on RubyGems.
46
- # This can be handy when testing many things on many machines at the same time :)
67
+ # This can be handy when testing many things on many machines in a very short amount of time :)
68
+ # Basically this function will download a list of predefined locations on where the cutting-edge
69
+ # gem of the AI can be obtained from. Then it will go through each location in order to download
70
+ # and install the edge version. The AI quits after the first successful download+installation attempt.
47
71
  #
48
72
  def update_ai_to_cutting_edge
49
73
  UI.info "Updating the AI to the cutting-edge experimental version".green.bold
50
74
  # Create a temporary working directory
51
75
  Path.edge_tmp = Dir.mktmpdir
52
76
  Path.edge_file = File.join(Path.edge_tmp, 'edge.gem')
53
- # Retrieve list of possible locations for edge versions
54
- # Note that you can just modify that list to add your own locations
55
- # You can modify the list at http://github.com/csd/csd/downloads
56
- # Note that the Amazon G3 cache used by Github takes about 12 hours to refresh the file, though!
77
+ # Retrieve list of possible locations for edge versions. Note that you can just modify that list to add your own locations
78
+ # You can modify the list at http://github.com/csd/csd/downloads but note that the Amazon G3 cache (used by Github) takes about 12 hours to refresh the file, though!
57
79
  for location in Net::HTTP.get_response(URI.parse('http://cloud.github.com/downloads/csd/csd/edge.txt')).body.split.each do
58
80
  # See if there is a downloadable edge version at this location. If not, move on to the next location
59
81
  next unless Cmd.download(location, Path.edge_file).success?
60
- # If the download was successful here, let's update the AI from that downloaded gem-file and exit
82
+ # If the download was successful here, let's update the AI from that downloaded gem-file and quit the loop
61
83
  updated = Cmd.run("sudo gem install #{Path.edge_file} --no-ri --no-rdoc", :announce_pwd => false, :verbose => true).success?
62
84
  break
63
85
  end
64
86
  UI.info "Currently there is no edge version published.".green.bold unless updated
65
87
  # Cleaning up the temporary directory
66
88
  FileUtils.rm_r Path.edge_tmp
67
- exit!
89
+ exit! # with status code 0
68
90
  end
69
91
 
70
92
  # This method check the arguments the user has provided and terminates the AI with
@@ -72,11 +94,11 @@ module CSD
72
94
  #
73
95
  def respond_to_incomplete_arguments
74
96
  choose_application unless Applications.current
75
- choose_action unless Options.valid_action?
76
- choose_scope if Options.scope and not Options.valid_scope?
97
+ choose_action unless Options.valid_action?
98
+ choose_scope if Options.scope and not Options.valid_scope?
77
99
  end
78
100
 
79
- # This methods lists all available applications
101
+ # This methods lists all applications that the AI currently supports.
80
102
  #
81
103
  def choose_application
82
104
  UI.separator
@@ -95,7 +117,7 @@ module CSD
95
117
  raise Error::Argument::NoApplication
96
118
  end
97
119
 
98
- # This methods lists all available actions for a specific application
120
+ # This methods lists all available actions for the currently selected application.
99
121
  #
100
122
  def choose_action
101
123
  UI.separator
@@ -118,7 +140,7 @@ module CSD
118
140
  raise Error::Argument::NoAction
119
141
  end
120
142
 
121
- # This methods lists all available scopes for a specific application and action
143
+ # This methods lists all available scopes for the currently selected application and action.
122
144
  #
123
145
  def choose_scope
124
146
  UI.separator
@@ -1,3 +1,2 @@
1
1
  # -*- encoding: UTF-8 -*-
2
- require "csd/application/default"
3
-
2
+ require "csd/application/default"
@@ -1,5 +1,5 @@
1
1
  human: DeckLink
2
- description: Capture card drivers for the Blackmagic Design DeckLink device used by MiniSIP.
2
+ description: Blackmagic Design DeckLink capture card drivers.
3
3
  actions:
4
4
  public:
5
5
  - install: Download and install the DeckLink drivers.
@@ -26,6 +26,7 @@ module CSD
26
26
  apply
27
27
  add_boot_loader
28
28
  send_notification
29
+ cleanup_working_directory
29
30
  end
30
31
 
31
32
  def introduction
@@ -2,12 +2,10 @@
2
2
 
3
3
  opts.headline 'WORKING DIRECTORY OPTIONS'.green.bold
4
4
 
5
- self.temp = true
6
5
  opts.on("--no-temp", "Use a subdirectory in the current directory as working directory and not /tmp.") do |value|
7
6
  self.temp = value
8
7
  end
9
8
 
10
- self.work_dir = nil
11
9
  opts.on("--work-dir [PATH]", "Defines and/or creates the working directory. This will override the --no-temp option.") do |value|
12
10
  self.work_dir = value
13
11
  end
@@ -0,0 +1,2 @@
1
+ self.temp = true
2
+ self.work_dir = nil
@@ -3,11 +3,16 @@ require 'csd/application/default/base'
3
3
  require 'yaml'
4
4
 
5
5
  module CSD
6
- # This namespace holds all individual application Modules
6
+ # This namespace holds all individual application Modules.
7
7
  #
8
8
  module Application
9
9
 
10
- # This is the root class of all Applications
10
+ # This is a module which contains all methods that each Application must implement. It provides
11
+ # the basic functionality so that it can be simply included by a real Application module to get
12
+ # started. The only thing that (in that case) really needs to be implemented is the +instance+
13
+ # method which chooses and holds the actual Application Module instance which will perform the
14
+ # task. All other functions in this module just require an +about.yml+ file to be placed in the
15
+ # specific application sub-directory.
11
16
  #
12
17
  module Default
13
18
 
@@ -18,22 +23,73 @@ module CSD
18
23
  raise Error::Application::NoInstanceMethod, "The application module must define an method called `instance´."
19
24
  end
20
25
 
26
+ # This method returns the Name of the application formatted as a command-line argument. By default
27
+ # it returns the name of the own class without capital letters. E.g. the class +MyClass+ would turn
28
+ # into +my_class+. It can be overwritten by the implementation of the actual application if another
29
+ # name is desired, or if the name needs to change in the future for some reason.
30
+ #
21
31
  def name
22
32
  self.to_s.demodulize.underscorize
23
33
  end
24
-
34
+
35
+ # This method returns a short description of the application. By default it just reads the description
36
+ # provided in the +about.yml+ file. It can be overwritten if the +about.yml+ file is not used for some reason.
37
+ #
25
38
  def description
26
39
  about.description
27
40
  end
28
-
41
+
42
+ # In order to present the name of this application to humans, neither the class name, nor the name
43
+ # as it appears in a command-line argument should be used. In other words, it should not be +Minisip+
44
+ # or +minisip+, but +MiniSIP+. This method returns that string and it is manually defined in the
45
+ # +about.yml+ file.
46
+ #
29
47
  def human
30
48
  about.human
31
49
  end
32
-
50
+
51
+ # This method returns a hash containing all valid actions (i.e. tasks) for this application. Note that
52
+ # the structure of this hash must be in a particular way. In the first level of the hash, a differentiation
53
+ # is made between actions intended for public use, such as "install" and for AI-developer use, such as
54
+ # "compile" or "package". For example:
55
+ #
56
+ # {'public' => [...], 'developer' => [...]}
57
+ #
58
+ # Each of these two keys holds an +Array+ with the actions. Each action is defined as a hash with the key
59
+ # as the action name and the value as the action description. One action looks like this for example:
60
+ #
61
+ # [{'install' => 'Downloads and installs the cooles application of all'}]
62
+ #
63
+ # Several actions look like this, respectively:
64
+ #
65
+ # [ {'install' => 'Downloads and installs the cooles application of all'},
66
+ # {'update' => 'Updates this cool application fully automatically'} ]
67
+ #
68
+ # The reason for choosing an Array and not a Hash to hold the actions is, because when they are presented
69
+ # to the end-user, the order of listing them up should be definable. It is not alphabetically, but sorted
70
+ # manually. A fully valid return value might look like this:
71
+ #
72
+ # { 'public' => [ {'install' => 'Downloads and installs this application' }
73
+ # {'remove' => 'Removes this cool application immediately'} ],
74
+ # 'developer' => [ {'package' => 'Creates a debian-package for this application'} ]
75
+ # }
76
+ #
33
77
  def actions
34
78
  about.actions
35
79
  end
36
-
80
+
81
+ # Some applications might react not only to tasks (such as +install+ or +compile+), but also to a more
82
+ # fine-grained scope. Typically this is a sub-component of an application. For example, MiniSIP has the
83
+ # sub-components "FFmpeg", "HDVIPER", "Plugins", etc. If an AI-developer wants to test only a particular
84
+ # part of the whole installation routine, he can instruct the AI to only perform the tasks needed to
85
+ # install that sub-component. This will save a lot of time in testing the functionality. In general,
86
+ # scopes are optional, but they may be defined here.
87
+ #
88
+ # The scopes are specific for each action. It might be that the "install" action of minisip, has scopes
89
+ # a, b, and c, whereas the "compile" action has maybe no scope at all. Similarly to the +actions+ method,
90
+ # this method defines scopes in a hash, where each key represents one action and the value holds an +Array+
91
+ # of all available scopes.
92
+ #
37
93
  def scopes(action)
38
94
  (about.scopes.is_a?(Hash) and about.scopes.key?(action)) ? about.scopes[action] : []
39
95
  end
@@ -0,0 +1,30 @@
1
+ # -*- encoding: UTF-8 -*-
2
+ require 'csd/application/default'
3
+ require 'csd/application/graphics/error'
4
+ require 'csd/application/graphics/base'
5
+
6
+ module CSD
7
+ module Application
8
+ # This is the Application Module to update the graphics card drivers.
9
+ #
10
+ module Graphics
11
+ class << self
12
+
13
+ include CSD::Application::Default
14
+
15
+ # This method will check which system we're on and initialize the correct sub-module.
16
+ # Currently we only support Ubuntu.
17
+ #
18
+ def instance
19
+ if Gem::Platform.local.ubuntu?
20
+ UI.debug "#{self}.instance finishes the system check"
21
+ Base.new
22
+ else
23
+ raise 'Sorry, currently only Ubuntu is supported.'
24
+ end
25
+ end
26
+
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,8 @@
1
+ # -*- encoding: UTF-8 -*-
2
+ human: Graphics
3
+ description: Graphic card drivers to improve video quality.
4
+ actions:
5
+ public:
6
+ - install: Downloads and installs the latest graphic card driver.
7
+ scopes:
8
+ --- {}
@@ -0,0 +1,157 @@
1
+ # -*- encoding: UTF-8 -*-
2
+ require 'csd/application/default/base'
3
+
4
+ module CSD
5
+ module Application
6
+ module Graphics
7
+ class Base < CSD::Application::Base
8
+
9
+ # This method will notify users about following operations and initiate installation process.
10
+ # The reason of creating another method to carry out actual installation process is to keep the
11
+ # source code clean and easy to read.
12
+ #
13
+ def install
14
+ UI.separator
15
+ UI.info "This operation will download and install the latest graphics card drivers.".green.bold
16
+ UI.separator
17
+ introduction
18
+ install!
19
+ end
20
+
21
+ # This method is to create a working directory to preserve graphical card installation scripts,
22
+ # initiate graphics card installation GUI and
23
+ # clean up the working directory when the graphical card driver has been successfully installed.
24
+ #
25
+ def install!
26
+ define_relative_paths
27
+ create_working_directory
28
+ process_graphics_card
29
+ cleanup_working_directory
30
+ end
31
+
32
+ def introduction
33
+ UI.info " Working directory: ".green.bold + Path.work.to_s.yellow
34
+ if Options.debug
35
+ UI.info " Your Platform: ".green + Gem::Platform.local.humanize.to_s.yellow
36
+ UI.info(" Application module: ".green + self.class.name.to_s.yellow)
37
+ end
38
+ UI.separator
39
+ if Options.help
40
+ UI.info Options.helptext
41
+ # Cleanup in case the working directory was temporary and is empty
42
+ Path.work.rmdir if Options.temp and Path.work.directory? and Path.work.children.empty?
43
+ raise CSD::Error::Argument::HelpWasRequested
44
+ else
45
+ raise Interrupt unless Options.yes or Options.reveal or UI.continue?
46
+ end
47
+ end
48
+
49
+ # This method will determine the model of graphics card and initiate corresponding installation process
50
+ # Currently, only Radeon and GeForce graphics cards are supported.
51
+ #
52
+ def process_graphics_card
53
+ case determine_graphic_card
54
+ when /Radeon/
55
+ install_radeon
56
+ when /GeForce/
57
+ install_geforce
58
+ else
59
+ raise Error::Graphics::CardNotSupported, "Sorry, currently only ATI Radeon and nVIDIA GeForce are supported"
60
+ end
61
+ end
62
+
63
+ # The method is to detect graphics card model
64
+ #
65
+ # ====Returns
66
+ # * It will return 'Radeon',when options of force_radeon is set.
67
+ # * It will return 'Radeon',when options of force_radeon is set.
68
+ # * Otherwise, it will return the result of graphics card checking command.
69
+ # ====Purpose
70
+ # This methold is supposed to detect the current graphics card models and initiate corresponding
71
+ # installation process. However, whenever a user want to force its system to install another graphics
72
+ # card driver, it will fake the detection result and comply with users' request.
73
+ #
74
+ def determine_graphic_card
75
+ return 'Radeon' if Options.force_radeon
76
+ return 'GeForce' if Options.force_geforce
77
+ Cmd.run('lspci | grep VGA', :internal => true).output
78
+ end
79
+
80
+ def install_radeon
81
+ Cmd.git_clone 'drivers for ATI radeon', 'git://github.com/csd/ati.git', Path.radeon
82
+ Cmd.run "chmod +x #{Path.radeon_run}", :announce_pwd => false
83
+ proprietary_continue
84
+ Cmd.run "sh #{Path.radeon_run}", :announce_pwd => false
85
+ end
86
+
87
+ def install_geforce
88
+ if xserver_running? or Options.reveal
89
+ UI.separator
90
+ UI.info 'This operation cannot be performed in the GNOME environment.'.red.bold
91
+ UI.info 'The AI can stop GNOME for you now. Once this happens, you need'.green.bold
92
+ UI.info 'to provide your Linux credentials and start the AI again from there.'.green.bold
93
+ UI.separator
94
+ if Options.yes or Options.reveal or UI.continue?
95
+ Cmd.run "sudo /etc/init.d/gdm stop", :announce_pwd => false
96
+ raise Error::Graphics::XServerStillRunning
97
+ else
98
+ raise Interrupt
99
+ end
100
+ else
101
+ Cmd.run "sudo /etc/init.d/gdm start" unless install_geforce!
102
+ cleanup_working_directory
103
+ end
104
+ end
105
+
106
+ def xserver_running?
107
+ result = Cmd.run('ps -ef', :internal => true)
108
+ result.success? and (result.output =~ /bin\/X.+gdm/ or result.output =~ /xinit/)
109
+ end
110
+
111
+ def install_geforce!
112
+ raise Error::Graphics::Amd64NotSupported, "Sorry, nVIDIA GeForce is currently only supported on x86" unless Gem::Platform.local.cpu == 'x86'
113
+ Cmd.git_clone 'drivers for nVIDIA GeForce', 'git://github.com/csd/nvidia.git', Path.geforce
114
+ Cmd.run "chmod +x #{Path.geforce_run}", :announce_pwd => false
115
+ proprietary_continue_for_geforce
116
+ # Note that we cannot use Cmd.run here, because the User input is not forwared to
117
+ # the executed application correctly. We will use Ruby's native command execution
118
+ # Cmd.run "sudo #{Path.geforce_run}", :announce_pwd => false, :verbose => true, :die_on_failure => false
119
+ system "sudo #{Path.geforce_run}"
120
+ end
121
+
122
+ def proprietary_continue
123
+ UI.separator
124
+ UI.info 'The proprietary installer for your graphic card will now be executed.'.green.bold
125
+ UI.info 'Please follow the instructions manually.'.green.bold
126
+ UI.separator
127
+ wait_for_confirmation
128
+ end
129
+
130
+ def proprietary_continue_for_geforce
131
+ UI.separator
132
+ UI.info 'The proprietary installer for your graphic card will now be executed.'.green.bold
133
+ UI.info 'Be sure to select "Yes" when asked if nvidia-xconfig should update your X configuration.'.green.bold
134
+ UI.info 'Please restart your computer after exiting the wizard.'.green.bold
135
+ UI.separator
136
+ wait_for_confirmation
137
+ end
138
+
139
+ def wait_for_confirmation
140
+ unless UI.continue? or Options.reveal
141
+ cleanup_working_directory
142
+ raise Interrupt
143
+ end
144
+ end
145
+
146
+ def define_relative_paths
147
+ UI.debug "#{self.class}#define_relative_paths defines relative graphics paths now"
148
+ Path.radeon = Pathname.new(File.join(Path.work, 'radeon'))
149
+ Path.radeon_run = Pathname.new(File.join(Path.radeon, 'ati-driver-installer-10-7-x86.x86_64.run'))
150
+ Path.geforce = Pathname.new(File.join(Path.work, 'geforce'))
151
+ Path.geforce_run = Pathname.new(File.join(Path.geforce, 'NVIDIA-Linux-x86-256.44.run.sh'))
152
+ end
153
+
154
+ end
155
+ end
156
+ end
157
+ end