Module: JSS::Composer
- Defined in:
- lib/jss.rb,
lib/jss/composer.rb
Overview
This module provides two methods for building very simple Casper-happy .pkg and .dmg packages for deployment.
Unlike Composer.app from JAMF, this module currently doesn’t offer a way to do a before/after disk scan and use the differences to build the root folder from which the package is built. Nor does the module support editing the pre/post install scripts in .pkgs.
The ‘root folder’, a folder representing the root filesystem of the target machine where the package will be installed, must already exist and be fully populated and with correct permissions.
Constant Summary collapse
- PKG_UTIL =
the apple pkgutil tool
Pathname.new "/usr/sbin/pkgutil"
- PKGBUILD =
The location of the cli tool for making .pkgs
Pathname.new "/usr/bin/pkgbuild"
- PKG_BUNDLE_ID_PFX =
the default bundle identifier prefix for pkgs
'jss_gem_composer'- HDI_UTIL =
Apple’s hdiutil for making dmgs
'/usr/bin/hdiutil'- DEFAULT_OUT_DIR =
Where to save the output ?
Pathname.new "/Users/Shared"
Class Method Summary collapse
-
.mk_dmg(name, root, out_dir = DEFAULT_OUT_DIR) ⇒ Pathname
Make a casper-happy .dmg out of a root folder, permissions are assumed to be correct.
-
.mk_pkg(name, version, root, opts = {}) ⇒ Pathname
Make a casper-happy .pkg out of a root folder, permissions are assumed to be correct.
Class Method Details
.mk_dmg(name, root, out_dir = DEFAULT_OUT_DIR) ⇒ Pathname
Make a casper-happy .dmg out of a root folder, permissions are assumed to be correct.
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/jss/composer.rb', line 193 def self.mk_dmg(name, root, out_dir = DEFAULT_OUT_DIR) dmg_filename = "#{name}.dmg" dmg_vol = name dmg_out = Pathname.new "#{out_dir}/#{dmg_filename}" if dmg_out.exist? mv_to = dmg_out.dirname + "#{dmg_out.basename}.#{Time.now.strftime('%Y%m%d%H%M%S')}" dmg_out.rename mv_to end # if dmg out exist ### TODO - this may need to be sudo'd to handle proper internal permissions. system "#{HDI_UTIL} create -volname '#{dmg_vol}' -scrub -srcfolder '#{root}' '#{dmg_out}'" raise RuntimeError, "There was an error building the .dmg" unless $?.exitstatus == 0 return Pathname.new dmg_out end |
.mk_pkg(name, version, root, opts = {}) ⇒ Pathname
Make a casper-happy .pkg out of a root folder, permissions are assumed to be correct.
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 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/jss/composer.rb', line 107 def self.mk_pkg(name, version, root, opts = {}) raise NoSuchItemError, "Missing pkgbuild tool. Please make sure you're running 10.8 or later." unless PKGBUILD.executable? opts[:out_dir] ||= DEFAULT_OUT_DIR opts[:bundle_id_prefix] ||= PKG_BUNDLE_ID_PFX pkg_filename = name.end_with?(".pkg") ? name : name+".pkg" pkg_id = opts[:pkg_id] pkg_id ||= opts[:bundle_id_prefix] + "." + name pkg_out = "#{opts[:out_dir]}/#{pkg_filename}" pkg_ownership = opts[:preserve_ownership] ? "preserve" : "recommended" if opts[:signing_identity] signing = "--sign #{Shellwords.escape opts[:signing_identity]}" signing << " --keychain #{Shellwords.escape opts[:keychain].to_s}" if opts[:keychain] signing << ' --timestamp' if opts[:include_timestamp] signing << ' --timestamp=none' if opts[:include_timestamp] == false case opts[:certs] when Array opts[:certs].each { |c| signing << " --cert #{Shellwords.escape c}" } when String signing << " --cert #{Shellwords.escape opts[:certs]}" end # case else signing = '' end # if opts[:signing_identity] ### first, run 'analyze' to get a 'component plist' in which we can change some settings ### for any bundles in the root (bundles like .apps, frameworks, plugins, etc..) ### ### we edit the settings thus: ### BundleOverwriteAction = upgrade, totally replace any version current on disk ### BundleIsVersionChecked = false, allow us to install regardless of what version is currently installed ### BundleIsRelocatable = false, if there's a version of this in some other location, Do Not move this one there after installation ### BundleHasStrictIdentifier = false, don't care if there's something at the install path with a different bundle id. ### ### In other words, just install the thing! ### (see 'man pkgbuild' for more info) ### ### comp_plist_out = Pathname.new "/tmp/#{PKG_BUNDLE_ID_PFX}-#{pkg_filename}.plist" system "#{PKGBUILD} --analyze --root '#{root}' '#{comp_plist_out}'" comp_plist = Plist.parse_xml comp_plist_out.read ### if the plist is empty, there are no bundles in the pkg if comp_plist[0].nil? comp_plist_arg = '' else ### otherwise, edit the bundle dictionaries comp_plist.each do |bndl| bndl.delete "ChildBundles" if bndl["ChildBundles"] bndl["BundleOverwriteAction"] = "upgrade" bndl["BundleIsVersionChecked"] = false bndl["BundleIsRelocatable"] = false bndl["BundleHasStrictIdentifier"] = false end ### write out the edits comp_plist_out.open('w'){|f| f.write comp_plist.to_plist} comp_plist_arg = "--component-plist '#{comp_plist_out}'" end ### now build the pkg begin it_built = system "#{PKGBUILD} --identifier '#{pkg_id}' --version '#{version}' --ownership #{pkg_ownership} --install-location / --root '#{root}' #{signing} #{comp_plist_arg} '#{pkg_out}' " raise RuntimeError, "There was an error building the .pkg" unless it_built ensure comp_plist_out.delete if comp_plist_out.exist? end return Pathname.new pkg_out end |