Class: Origen::ImportManager

Inherits:
Object
  • Object
show all
Defined in:
lib/origen/import_manager.rb

Overview

Responsible for ensuring that all dependencies defined in config.imports are available.

Workspaces will automatically be created and updated to the correct version as required.

An instance of this class is hooked up to:

Origen.import_manager

Constant Summary collapse

SHARED_CONTENTS_TYPES =
[:pattern, :templates, :command_launcher, :program]

Instance Method Summary collapse

Constructor Details

#initializeImportManager

Returns a new instance of ImportManager.



13
14
15
16
17
18
19
20
21
22
23
# File 'lib/origen/import_manager.rb', line 13

def initialize
  @required = false
  # These will be updated as plugins are imported.
  # Min and required are treated the same here, basically we don't allow plugins
  # to dictate a specific version and this will be taken as a minimum requirement.
  # Plugins can however block execution by specifying a max required version
  # that must not be exceeded.
  @required_origen_version = Origen.config.required_origen_version ||
                             Origen.config.min_required_origen_version
  @max_required_origen_version = Origen.config.max_required_origen_version
end

Instance Method Details

Returns all symlinks created by adding plugins Usage right now is to mask these links in unmanaged files.



225
226
227
228
229
230
231
# File 'lib/origen/import_manager.rb', line 225

def all_symlinks
  links = []
  SHARED_CONTENTS_TYPES.each do |type|
    links << symlinks_in_dir("#{type}") unless type == :command_launcher
  end
  links.flatten.uniq.compact
end

#command_launcherObject



246
247
248
# File 'lib/origen/import_manager.rb', line 246

def command_launcher
  @command_launcher ||= []
end

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Handles all symlink creation since Ruby/Windows is ropey. On windows it will create an additional flag file to easily tell us a symlink is active later.



147
148
149
150
151
152
153
154
# File 'lib/origen/import_manager.rb', line 147

def create_symlink(from, to)
  if Origen.running_on_windows?
    system("call mklink /D #{to.to_s.gsub('/', '\\')} #{from.to_s.gsub('/', '\\')}")
    File.new("#{to}_is_a_symlink", 'w') {}
  else
    FileUtils.symlink from, to
  end
end

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Manually handle symlink deletion to support windows



158
159
160
161
162
163
164
165
166
# File 'lib/origen/import_manager.rb', line 158

def delete_symlink(path)
  if Origen.running_on_windows?
    # Don't use regular rm on windows symlink, will delete into the remote dir!
    system("call cmd /c rmdir #{path.to_s.gsub('/', '\\')}")
    FileUtils.rm_f("#{path}_is_a_symlink")
  else
    FileUtils.rm_f(path)
  end
end

Deletes any symlink pointing to the shared content of the specified plugin



235
236
237
238
239
240
241
242
243
244
# File 'lib/origen/import_manager.rb', line 235

def delete_symlinks_of_plugin(plugin)
  SHARED_CONTENTS_TYPES.each do |type|
    unless type == :command_launcher
      link = "#{Origen.root}/#{type}/#{plugin.name}"
      if File.exist?(link)
        delete_symlink(link) if symlink?(link)
      end
    end
  end
end

#named_importsObject

Returns a hash containing all imports



135
136
137
# File 'lib/origen/import_manager.rb', line 135

def named_imports
  imports
end

#namesObject

Returns an array of symbols that represent the names of all imports



126
127
128
129
130
131
132
# File 'lib/origen/import_manager.rb', line 126

def names
  return @names if @names
  names = Origen.plugins.map(&:name)
  # Had a bug where this was caching too early, don't cache until all plugins are loaded
  @names = names if Origen.app_loaded?
  names
end

#origen_root(name) ⇒ Object

Returns the path to origen root for the given import name



140
141
142
# File 'lib/origen/import_manager.rb', line 140

def origen_root(name)
  origen_root_for(named_imports[name])
end

#path_within_a_plugin(path) ⇒ Object

Return the plugin name if the path specified is from that plugin



198
199
200
201
202
203
204
205
206
207
208
# File 'lib/origen/import_manager.rb', line 198

def path_within_a_plugin(path)
  ret_value = nil
  names.each do |plugin|
    subpath = path.slice(/.*\/#{plugin.to_s}/)
    if subpath && symlink?(subpath)
      ret_value = (plugin.to_sym if plugin.class != Symbol) || plugin
      break
    end
  end
  ret_value
end

#plugin_instance(name) ⇒ Object

Returns the app instance of the given plugin name



121
122
123
# File 'lib/origen/import_manager.rb', line 121

def plugin_instance(name)
  Origen.application_instance(origen_root_for(imports[name]))
end

#plugin_version(plugin_name) ⇒ Object

Returns the version of the given plugin that is installed



115
116
117
118
# File 'lib/origen/import_manager.rb', line 115

def plugin_version(plugin_name)
  load File.join(origen_root_for(imports[plugin_name]), 'config', 'version.rb')
  Origen::VersionString.new(Origen.import_manager.plugin_instance(plugin_name).class::VERSION)
end

#require!Object

This will fetch all imports (if required), add the libs to the load path, and require the environments.



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/origen/import_manager.rb', line 27

def require!
  unless required?
    while updates_required?
      puts 'The following imports need to be updated, this will now happen automatically:'
      puts ''
      dirty_imports.each do |name, import|
        if import[:path]
          puts "  #{name} - #{import[:path]}"
        else
          puts "  #{name} - #{import[:version]}"
        end
      end
      puts ''
      update!
    end
    if @required_origen_version
      if @max_required_origen_version
        if Origen::VersionString.new(@required_origen_version).greater_than?(@max_required_origen_version)
          puts ''
          puts "Your application needs to run Origen version #{@required_origen_version}, however"
          puts "the version of the #{@max_lib} plugin required by your import tree is not"
          puts "permitted to run above Origen version #{@max_required_origen_version}."
          puts 'You may need to consult with the plugin owner to see if this restriction can be'
          puts 'removed or if a newer version of the plugin without this restriction already'
          puts 'exists.'
          puts ''
          exit 0
        end
      end
      if Origen.version.less_than?(@required_origen_version)
        if Origen.config.required_origen_version
          puts ''
          puts "A dependent plugin requires at least Origen version #{@required_origen_version}, however"
          puts "your main application currently specifies #{Origen.config.required_origen_version}."
          puts 'To proceed you must update the required_origen_version in config/application.rb'
          puts "to be: #{@required_origen_version}"
          puts ''
          exit 0
        else
          Origen.version_checker.update_origen(@required_origen_version)
        end
      end
    end
    add_libs_to_load_path!
    require_environments!
    add_shared_contents!
    remove_unwanted_symlinks!
    @required = true
  end
end

#required=(value) ⇒ Object



84
85
86
# File 'lib/origen/import_manager.rb', line 84

def required=(value)
  @required = value
end

#required?Boolean

Returns true if the imports have already been required and added to the load path of the current thread

Returns:

  • (Boolean)


80
81
82
# File 'lib/origen/import_manager.rb', line 80

def required?
  @required
end

#symlink?(path) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns true if the given path is a symlink. Since Ruby’s handling of symlinks is ropey we will manually maintain a flag (an empty file that means true when present) to indicate when an import is currently setup as a symlink to a path.

Returns:

  • (Boolean)


172
173
174
175
176
177
178
# File 'lib/origen/import_manager.rb', line 172

def symlink?(path)
  if Origen.running_on_windows?
    File.exist?("#{path}_is_a_symlink")
  else
    File.symlink?(path)
  end
end

Returns true if the given file is a symlink and a link to a file within the application’s imports directory, generally this can be used to identify symlinks which have been added by the imports/plugin manager to expose the pattern/program/templates directories of plugins

Returns:

  • (Boolean)


184
185
186
187
188
189
190
191
192
193
194
# File 'lib/origen/import_manager.rb', line 184

def symlink_to_imports_dir?(path)
  if Origen.running_on_windows?
    # Not sure how to do this yet on windows, for now just defaulting
    # to the original behavior of testing if it is a symlink
    symlink?(path)
  else
    if File.symlink?(path)
      !!(File.readlink(path) =~ /^#{ws.imports_directory}/)
    end
  end
end

Returns a list of paths which are symlinks within the supplied dir



211
212
213
214
215
216
217
218
219
220
221
# File 'lib/origen/import_manager.rb', line 211

def symlinks_in_dir(dir)
  list = []
  if File.exist?(dir)
    Dir.entries(dir).each do |file|
      if symlink_to_imports_dir?("#{dir}/#{file}")
        list << "#{dir}/#{file}"
      end
    end
  end
  list
end

#validate_production_status(force = false) ⇒ Object



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
# File 'lib/origen/import_manager.rb', line 88

def validate_production_status(force = false)
  if Origen.mode.production? || force
    imports.each do |_name, import|
      if import[:path]
        fail "The following import is defined as a path, but that is not allowed in production: #{import}"
      end
      version = Origen::VersionString.new(import[:version])
      unless version.valid?
        fail "The following import version is not in a valid format: #{import}"
      end
      if version.latest?
        fail "Latest is not allowed as an import version in production: #{import}"
      end
    end

    if File.exist?("#{Origen.root}/Gemfile")
      File.readlines("#{Origen.root}/Gemfile").each do |line|
        # http://rubular.com/r/yNGDGB6M2r
        if line =~ /^\s*gem\s+(("|')\w+("|')),.*(:path\s*=>|path:)/
          fail "The following gem is defined as a path in your Gemfile, but that is not allowed in production: #{Regexp.last_match[1]}"
        end
      end
    end
  end
end