Class: SkippyLib::CExtensionManager
- Inherits:
-
Object
- Object
- SkippyLib::CExtensionManager
- Includes:
- ObjectUtils
- Defined in:
- modules/c_extension_manager.rb
Overview
Loads the appropriate C Extension loader after ensuring the appropriate version has been copied from the staging area.
Defined Under Namespace
Classes: IncompatibleVersion
Instance Method Summary collapse
-
#initialize(extension, library_path) ⇒ CExtensionManager
constructor
The
library_path
argument should point to the path where a 'stage' folder is located with the following folder structure:. - #inspect ⇒ String (also: #to_s)
-
#prepare_path ⇒ String
Copies the necessary C Extension libraries to a version dependent folder from where they can be loaded.
Constructor Details
#initialize(extension, library_path) ⇒ CExtensionManager
The library_path
argument should point to the path where a 'stage'
folder is located with the following folder structure:
+ <library_path>
+-+ stage
+-+ 1.8
| +-+ HelloWorld.so
| + HelloWorld.bundle
+-+ 2.0
+-+ HelloWorld.so
+ HelloWorld.bundle
The appropriate file will be copied on demand to a folder structure like:
<library_path>/<EXTENSION_VERSION>/<RUBY_VERSION>/HelloWorld.so
When a new version is deployed the files will be copied again from the staging area to a new folder named with the new extension version.
The old versions are cleaned up if possible. This attempt is done upon each time #prepare_path is called.
This way the C extensions can be updated because they are never loaded from the staging folder directly.
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'modules/c_extension_manager.rb', line 53 def initialize(extension, library_path) # ENV, __FILE__, $LOAD_PATH, $LOADED_FEATURE and more might return an # encoding different from UTF-8 under Windows. It's often ASCII-US or # ASCII-8BIT. If the developer has derived from these strings the encoding # sticks with it and will often lead to errors further down the road when # trying to load the files. To work around this the path is attempted to # be relabeled as UTF-8 if we can produce a valid UTF-8 string. # I'm forcing an encoding instead of converting because the encoding label # of the strings seem to be consistently mislabeled - the data is in # fact UTF-8. if library_path.respond_to?(:encoding) test_path = library_path.dup.force_encoding('UTF-8') library_path = test_path if test_path.valid_encoding? end unless version =~ VERSION_PATTERN raise ArgumentError, 'Version must be in "X.Y.Z" format' end unless File.directory?(library_path) raise IOError, "Stage path not found: #{library_path}" end @extension = extension @path = library_path @stage = File.join(library_path, 'stage') @target = File.join(library_path, extension.version) end |
Instance Method Details
#inspect ⇒ String Also known as: to_s
151 152 153 |
# File 'modules/c_extension_manager.rb', line 151 def inspect inspect_object end |
#prepare_path ⇒ String
Copies the necessary C Extension libraries to a version dependent folder from where they can be loaded. This will allow the SketchUp RBZ installer to update the extension without running into errors when trying to overwrite files from previous installation.
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'modules/c_extension_manager.rb', line 88 def prepare_path ruby_version = RUBY_VERSION.match(/(\d+\.\d+)\.\d/)[1] stage_path = File.join(@stage, ruby_version, Platform::ID) target_path = File.join(@target, ruby_version, Platform::ID) fallback = false begin # Copy files if target doesn't exist. unless File.directory?(stage_path) raise IncompatibleVersion, "Staging directory not found: #{stage_path}" end unless File.directory?(target_path) FileUtils.mkdir_p(target_path) end stage_content = Dir.entries(stage_path) target_content = Dir.entries(target_path) unless (stage_content - target_content).empty? FileUtils.copy_entry(stage_path, target_path) end # Clean up old versions. filter = File.join(@path, '*') Dir.glob(filter).each { |entry| next unless File.directory?(entry) next if [@stage, @target].include?(entry) next unless entry =~ VERSION_PATTERN begin FileUtils.rm_r(entry) rescue puts "#{@extension.name} - Unable to clean up: #{entry}" end } rescue Errno::EACCES if fallback UI.( "Failed to load #{@extension.name}. Missing permissions to " \ 'Plugins and temp folder.' ) raise else # Even though the temp folder contains the username, it appear to be # returned in DOS 8.3 format which Ruby 1.8 can open. Fall back to # using the temp folder for these kind of systems. puts "#{@extension.name} - Unable to access: #{target_path}" short_name = @extension.name.gsub(/[^A-Za-z0-9_-]/, '') temp_lib_path = File.join(Platform.temp_path, short_name) target_path = File.join(temp_lib_path, @extension.version, ruby_version, Platform::ID) puts "#{@extension.name} - Falling back to: #{target_path}" fallback = true retry end end target_path end |