Class: Jim::Installer

Inherits:
Object
  • Object
show all
Defined in:
lib/jim/installer.rb

Overview

Installer is the workhorse of Jim. It handles taking an install path (a url, a local path, anything that Downlow.get can handle), staging it into a temporary directory and extracting the file(s) into a path for the specific name and version of the lib. names and versions are determined automatically or can be passed in as options.

Constant Summary collapse

IGNORE_DIRS =
%w{
  vendor
  external
  test
  tests
  unit
  site
  examples
  demo
  min
  \_([^\/]+)
  \.([^\/]+)
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(fetch_path, install_path, options = {}) ⇒ Installer

Create an installer. fetch_path is anything that Downlow can understand. Install path is the final directory



37
38
39
40
41
# File 'lib/jim/installer.rb', line 37

def initialize(fetch_path, install_path, options = {})
  @fetch_path   = Pathname.new(fetch_path)
  @install_path = Pathname.new(install_path)
  @options      = options
end

Instance Attribute Details

#fetch_pathObject (readonly)

Returns the value of attribute fetch_path.



33
34
35
# File 'lib/jim/installer.rb', line 33

def fetch_path
  @fetch_path
end

#fetched_pathObject (readonly)

Returns the value of attribute fetched_path.



33
34
35
# File 'lib/jim/installer.rb', line 33

def fetched_path
  @fetched_path
end

#install_pathObject (readonly)

Returns the value of attribute install_path.



33
34
35
# File 'lib/jim/installer.rb', line 33

def install_path
  @install_path
end

#nameObject (readonly)

Returns the value of attribute name.



33
34
35
# File 'lib/jim/installer.rb', line 33

def name
  @name
end

#optionsObject (readonly)

Returns the value of attribute options.



33
34
35
# File 'lib/jim/installer.rb', line 33

def options
  @options
end

#package_jsonObject (readonly)

Returns the value of attribute package_json.



33
34
35
# File 'lib/jim/installer.rb', line 33

def package_json
  @package_json
end

#versionObject (readonly)

Returns the value of attribute version.



33
34
35
# File 'lib/jim/installer.rb', line 33

def version
  @version
end

Class Method Details

.tmp_rootObject

Get the tmp_root where files are staged



24
25
26
# File 'lib/jim/installer.rb', line 24

def self.tmp_root
  @tmp_root ||= Pathname.new('/tmp/jim')
end

.tmp_root=(new_tmp_root) ⇒ Object

Set the tmp_root where files are staged. Default: ‘/tmp/jim’



29
30
31
# File 'lib/jim/installer.rb', line 29

def self.tmp_root=(new_tmp_root)
  @tmp_root = Pathname.new(new_tmp_root)
end

Instance Method Details

#determine_name_and_versionObject

Determine the name and version of the @fetched_path. Tries a number of strategies in order until both name and version are found:

  • from options (options …)

  • from comments (// name: )

  • from a package.json ({“name”: })

  • from the filename (name-1.0.js)

If no version can be found, version is set as “0”



131
132
133
134
135
136
137
138
# File 'lib/jim/installer.rb', line 131

def determine_name_and_version
  (name && version) ||
  name_and_version_from_options ||
  name_and_version_from_comments ||
  name_and_version_from_package_json ||
  name_and_version_from_filename
  @version = (version == "0" && options[:parent_version]) ? options[:parent_version] : version
end

#fetchObject

Fetch the file at fetch_path with and stage into a tmp directory. Returns the staged directory of fetched file(s).



45
46
47
48
49
50
# File 'lib/jim/installer.rb', line 45

def fetch
  logger.debug "Fetching #{fetch_path}"
  @fetched_path = Downlow.get(fetch_path, tmp_path, :tmp_dir => tmp_root)
  logger.debug "Fetched #{@fetched_path}"
  @fetched_path
end

#installObject

Fetch and install the files determining their name and version if not provided. If the fetch_path contains a directory of files, it iterates over the directory installing each file that isn’t in IGNORE_DIRS and a name and version can be determined for. It also installs a package.json file along side the JS file that contains meta data including the name and version, also merging with the original package.json if found.

If options == true it will just copy the single file without any leading directories or a package.json. ‘shallow’ installation is used for Bundle#vendor



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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
# File 'lib/jim/installer.rb', line 61

def install
  fetch
  parse_package_json
  determine_name_and_version

  if !name || name.to_s =~ /^\s*$/ # blank
    raise(Jim::InstallError, "Could not determine name for #{@fetched_path}")
  end

  logger.info "Installing #{name} #{version}"
  logger.debug "fetched_path #{@fetched_path}"

  if options[:shallow]
    shallow_filename = [name, (version == "0" ? nil : version)].compact.join('-')
    final_path = install_path + "#{shallow_filename}#{fetched_path.extname}"
  else
    final_path = install_path + 'lib' + "#{name}-#{version}" + "#{name}.js"
  end

  if @fetched_path.directory?
    # install every js file
    installed_paths = []
    sub_options = options.merge({
      :name => nil,
      :version => nil,
      :parent_version => version,
      :package_json => package_json.merge("name" => nil)
    })
    Jim.each_path_in_directories([@fetched_path], '.js', IGNORE_DIRS) do |subfile|
      logger.debug "Found file #{subfile}"
      installed_paths << Jim::Installer.new(subfile, install_path, sub_options).install
    end
    logger.debug "Extracted to #{install_path}, #{installed_paths.length} file(s)"
    return installed_paths
  end

  logger.debug "Installing to #{final_path}"
  if final_path.exist?
    logger.debug "#{final_path} already exists"
    if options[:force]
      FileUtils.rm_rf(final_path)
    elsif Digest::MD5.hexdigest(File.read(final_path)) == Digest::MD5.hexdigest(File.read(@fetched_path))
      logger.warn "Duplicate file, skipping"
      return final_path
    else
      logger.error "Trying to install to #{final_path}, but file already exists and is different."
      return false
    end
  end

  Downlow.extract(@fetched_path, :destination => final_path, :tmp_dir => tmp_root)
  # install json
  install_package_json(final_path.dirname + 'package.json') if !options[:shallow]
  installed = final_path.directory? ? Dir.glob(final_path + '**/*').length : 1
  logger.debug "Extracted to #{final_path}, #{installed} file(s)"
  final_path
ensure
  FileUtils.rm_rf(@fetched_path) if @fetched_path && @fetched_path.exist?
  final_path
end