Jaharmi’s Irreality - renewable hyperlinks with 0% transfat since 1999http://www.jaharmi.com/frontpage
enMunki trials with a local repositoryhttp://www.jaharmi.com/2015/07/21/munki_trials_with_a_local_repository
<p>While I was working on how to <a href="/2015/06/07/compare_os_x_versions_using_only_strings">compare <span class="caps">OS</span> X versions using only strings</a> and <a href="http://www.jaharmi.com/2015/06/03/create_a_munki_alert_with_just_one_button">create a Munki alert with just one button</a>, I tested with a local Munki repository. It let me perform tests without affecting a &#8220;real&#8221; Munki&nbsp;repo.</p>
<p>To set this up, I first changed the Munki SoftwareRepoURL preference so that it used a &#8220;file&#8221;&nbsp;<span class="caps">URL</span>:</p>
<pre><code> defaults write SoftwareRepoURL "file:///Users/jeremy/Documents/munki_repo"
</code></pre>
<p>I then created that folder and its&nbsp;subfolders.</p>
<pre><code> mkdir -p ~/Documents/munki_repo/{catalogs,manifests,pkgsinfo}
</code></pre>
<p>I added the &#8220;nopkg&#8221; pkginfo for the alert testing by creating it from the command line. I piped the makepkginfo output the BBEdit, edited the pkginfo there, and saved the resulting file to the &#8220;pkgsinfo&#8221;&nbsp;folder.</p>
<pre><code> makepkginfo --nopkg --name="ok_cancel_alert" | bbedit
</code></pre>
<p>To test the conditional version string comparisons, I created and populated a property list in the &#8220;manifests&#8221; folder. I initially tried to use the &#8220;site_default&#8221; manifest name, since I thought that it would be the most generic — and thus useful —&nbsp;idea.</p>
<p>It wasn&#8217;t working, though. I had to specify the name of a manifest that matched the hostname of the computer. I was thinking that there was some reliance on <span class="caps">DNS</span>, but I eventually realized that I&#8217;d set the <a href="https://github.com/munki/munki/wiki/Preferences">ClientIdentifier preference</a>.</p>
<pre><code> sudo defaults delete /Library/Preferences/ManagedInstalls.plist ClientIdentifier
</code></pre>
<p>Once I had removed this preference, the client was able to fall through to the generic &#8220;site&#95;default&#8221; manifest. That was exactly what I wanted. The &#8220;managedsoftwareupdate&#8221; tool was able to try for various manifest names using the standard ordered list of identifiers before it finally settled on &#8220;site&#95;default&#8221;&nbsp;one.</p>
<pre><code> Request failed. Trying site_default...
Getting manifest site_default...
Using manifest: site_default
</code></pre>
<p>Once that was sorted out, I was able to create pkgsinfo and manifests to use in local testing. I could also remove any pkgsinfo that were no longer needed for testing. I still had to remember to &#8220;makecatalogs&#8221; for any pkginfo changes to take&nbsp;effect.</p>
<pre><code> makecatalogs ~/Documents/munki_repo
</code></pre>
<p>This technique was definitely useful to me for testing on a local system. It didn&#8217;t affect any other network-based Munki repository and required minimal setup, starting with a preference change on the client. I would also expect it to work locally within virtual machines that are used for testing. The Munki repository in a local folder also allows it to be used offline, should the need arise for&nbsp;that.</p>
LearningMac OS XOpen sourceSystem administrationWed, 22 Jul 2015 02:26:34 +0000Jaharmi486 at http://www.jaharmi.comThis is where we used to livehttp://www.jaharmi.com/2015/07/15/this_is_where_we_used_to_live
<p>I know I don’t live there anymore — and haven’t lived there for a long time — but I feel compelled to note that my parents finally sold their home on <a href="http://www.cubalake.org">Cuba Lake</a>.</p>
<p>We visited at the beginning of the month and had a great time with the family. We’ll have to make some new traditions to get together in some other&nbsp;place.</p>
<p>Cuba felt like the same <em>place</em>, in many ways, but very different in others — if for no other reason than I’m no longer who I was when I was growing up there, and many friends that I knew have moved&nbsp;elsewhere.</p>
<p>I’ll miss it, in the same wistful sense that I miss other things that have ended, or that I might never see again. It feels like we’ve built up quite a few of those cherished but fading memories in a short time, thanks in no small part to our own move to&nbsp;Pennsylvania.</p>
FamilyFriendsWorldWed, 15 Jul 2015 15:56:37 +0000Jaharmi485 at http://www.jaharmi.comVersion comparison by string with JAMF JSS Smart Groupshttp://www.jaharmi.com/2015/06/07/version_comparison_by_string_with_jamf_jss_smart_groups
<p><span class="caps">JAMF</span> <span class="caps">JSS</span> can create Smart Groups, which are similar to Smart Playlists in iTunes or Smart Folders in the Finder. When it comes to string comparisons, the following search operators are available: “is,” “is not,” “like,” and “not&nbsp;like.”</p>
<p><a href="http://www.jaharmi.com/2015/06/07/compare_os_x_versions_using_only_strings"><span class="caps">OS</span> X version comparison using strings</a> (the introduction to this series) works with <span class="caps">JAMF</span> <span class="caps">JSS</span>. Searches with the “like” and “not like” operators do not anchor on periods, in my experience. This switches to the second kind of comparison I <a href="http://www.jaharmi.com/2015/06/07/version_comparison_solution_pseudocode">described in the pseudocode</a>.</p>
<ol>
<li>Create the “<span class="caps">OS</span> X v10.8 and newer” smart&nbsp;group.</li>
<li>Add the following criteria to the group. The default &#8220;and&#8221; is used to join them.
<ul>
<li>“Operating system” “like”&nbsp;“10&#8221;</li>
<li>“Operating system” “not like”&nbsp;“10.3&#8221;</li>
<li>“Operating system” “not like”&nbsp;“10.4&#8221;</li>
<li>“Operating system” “not like”&nbsp;“10.5&#8221;</li>
<li>“Operating system” “not like”&nbsp;“10.6&#8221;</li>
<li>“Operating system” “not like”&nbsp;“10.7&#8221;</li>
</ul></li>
<li>Save the smart&nbsp;group.</li>
</ol>
<p>Create the first one, then use the <span class="caps">JSS</span>&#8217; &#8220;Clone&#8221; function, to make additional comparisons for other <span class="caps">OS</span> X versions. Edit the copies as&nbsp;needed.</p>
<p>No ongoing maintenance of older Smart Groups should be required. I had previously up with a scheme that used Smart Groups relying on other Smart Groups. It required one update to the prior “and greater” group for each new <span class="caps">OS</span> X release. The maintenance effort can be avoided with the technique above and both produce the same&nbsp;effect.</p>
Mac OS XSun, 07 Jun 2015 11:46:30 +0000Jaharmi484 at http://www.jaharmi.comVersion comparison by string with Munki conditionalshttp://www.jaharmi.com/2015/06/07/version_comparison_by_string_with_munki_conditionals
<p>Munki can use Python&#8217;s version comparison tools to perform mathematical version comparisons for the minimum and maximum <span class="caps">OS</span> versions and minimum Munki version specified in pkgsinfo&nbsp;files.</p>
<p>In manifest files&#8217; conditional items, though, only string comparisons are available. The <a href="http://www.jaharmi.com/2015/06/07/compare_os_x_versions_using_only_strings"><span class="caps">OS</span> X version comparison using strings</a> (the introduction to this series) technique can be useful with <a href="https://github.com/munki/munki/wiki/Conditional-Items#built-in-conditions">the &#8220;os_vers&#8221; attribute in manifests</a>.</p>
<p>Conditional items use NSPredicates support for regular expressions. These searches can anchor on&nbsp;periods.</p>
<p><div class="geshifilter"><div class="xml geshifilter-xml"><span class="sc3"><span class="re1">&lt;?xml</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span> <span class="re0">encoding</span>=<span class="st0">&quot;<span class="caps">UTF</span>-8&quot;</span><span class="re2">?&gt;</span></span><br />
<span class="sc0">&lt;!<span class="caps">DOCTYPE</span> plist <span class="caps">PUBLIC</span> &quot;-//Apple//<span class="caps">DTD</span> <span class="caps">PLIST</span> 1.0//<span class="caps">EN</span>&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;</span><br />
<span class="sc3"><span class="re1">&lt;plist</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span><span class="re2">&gt;</span></span><br />
<span class="sc3"><span class="re1">&lt;dict<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;key<span class="re2">&gt;</span></span></span>catalogs<span class="sc3"><span class="re1">&lt;/key<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;array<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;string<span class="re2">&gt;</span></span></span>production<span class="sc3"><span class="re1">&lt;/string<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/array<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;key<span class="re2">&gt;</span></span></span>conditional_items<span class="sc3"><span class="re1">&lt;/key<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;array<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;dict<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;key<span class="re2">&gt;</span></span></span>condition<span class="sc3"><span class="re1">&lt;/key<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;string<span class="re2">&gt;</span></span></span>os_vers <span class="caps">BEGINSWITH</span> &quot;10.&quot; <span class="caps">AND</span> <span class="caps">NOT</span> (os_vers <span class="caps">BEGINSWITH</span> &quot;10.0.&quot; <span class="caps">OR</span> os_vers <span class="caps">BEGINSWITH</span> &quot;10.1.&quot; <span class="caps">OR</span> os_vers <span class="caps">BEGINSWITH</span> &quot;10.2.&quot; <span class="caps">OR</span> os_vers <span class="caps">BEGINSWITH</span> &quot;10.3.&quot; <span class="caps">OR</span> os_vers <span class="caps">BEGINSWITH</span> &quot;10.4.&quot; <span class="caps">OR</span> os_vers <span class="caps">BEGINSWITH</span> &quot;10.5.&quot; <span class="caps">OR</span> os_vers <span class="caps">BEGINSWITH</span> &quot;10.6.&quot; <span class="caps">OR</span> os_vers <span class="caps">BEGINSWITH</span> &quot;10.7.&quot;)<span class="sc3"><span class="re1">&lt;/string<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;key<span class="re2">&gt;</span></span></span>managed_installs<span class="sc3"><span class="re1">&lt;/key<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;array</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;key<span class="re2">&gt;</span></span></span>managed_uninstalls<span class="sc3"><span class="re1">&lt;/key<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;array</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;key<span class="re2">&gt;</span></span></span>managed_updates<span class="sc3"><span class="re1">&lt;/key<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;array</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;key<span class="re2">&gt;</span></span></span>optional_installs<span class="sc3"><span class="re1">&lt;/key<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;array</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/dict<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/array<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/dict<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/plist<span class="re2">&gt;</span></span></span></div></div></p>
Mac OS XSun, 07 Jun 2015 11:42:53 +0000Jaharmi483 at http://www.jaharmi.comVersion comparison by string with UNIX shellhttp://www.jaharmi.com/2015/06/07/version_comparison_by_string_with_unix_shell
<p>The <a href="http://www.jaharmi.com/2015/06/07/compare_os_x_versions_using_only_strings"><span class="caps">OS</span> X version comparison using strings</a> (the introduction to this series) can be implemented with a <span class="caps">UNIX</span> shell script. I figured the most direct method was to use grep. I also like case&nbsp;statements.</p>
<p>These searches can anchor on&nbsp;periods.</p>
<p><div class="geshifilter"><div class="bash geshifilter-bash"><span class="co0">#!/bin/bash</span><br />
<br />
<span class="co0"># Get the current <span class="caps">OS</span> version to serve as an example</span><br />
<span class="re2">THIS_OS</span>=$<span class="br0">&#40;</span>sw_vers -productVersion<span class="br0">&#41;</span><br />
<br />
<span class="co0"># Determine if the <span class="caps">OS</span> version starts with &quot;10.&quot;</span><br />
<span class="kw3">echo</span> <span class="st0">&quot;<span class="es3">${THIS_OS}</span>&quot;</span> <span class="sy0">|</span> <span class="kw2">grep</span> <span class="re5">-q</span> <span class="re5">-e</span> <span class="st_h">&#8216;^10.&#8217;</span><br />
<br />
<span class="kw1">case</span> <span class="re4">$?</span> <span class="kw1">in</span><br />
&nbsp; &nbsp; <span class="co0"># If the <span class="caps">OS</span> version matches the initial basic criteria,</span><br />
&nbsp; &nbsp; <span class="co0"># then determine if it is greater than a specific <span class="caps">OS</span> X version</span><br />
&nbsp; &nbsp; <span class="co0"># by string comparison against lower major version numbers.</span><br />
&nbsp; &nbsp; <span class="nu0">0</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co0"># Eliminate each major <span class="caps">OS</span> X version, one by one, with string matching.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co0"># Stop with the version before the one of interest.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;<span class="es3">${THIS_OS}</span>&quot;</span> <span class="sy0">|</span> \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">grep</span> <span class="re5">-v</span> <span class="re5">-q</span> \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re5">-e</span> <span class="st_h">&#8216;^10.0.&#8217;</span> \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re5">-e</span> <span class="st_h">&#8216;^10.1.&#8217;</span> \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re5">-e</span> <span class="st_h">&#8216;^10.2.&#8217;</span> \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re5">-e</span> <span class="st_h">&#8216;^10.3.&#8217;</span> \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re5">-e</span> <span class="st_h">&#8216;^10.4.&#8217;</span> \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re5">-e</span> <span class="st_h">&#8216;^10.5.&#8217;</span> \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re5">-e</span> <span class="st_h">&#8216;^10.6.&#8217;</span> \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re5">-e</span> <span class="st_h">&#8216;^10.7.&#8217;</span> <span class="sy0">&amp;&amp;</span> \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;<span class="caps">OS</span> X <span class="es3">${THIS_OS}</span> is version <span class="caps">OS</span> X 10.9 or greater.&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">;;</span><br />
&nbsp; &nbsp; <span class="sy0">*</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;<span class="caps">OS</span> X version number not found.&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">;;</span><br />
<span class="kw1">esac</span></div></div></p>
Mac OS XSun, 07 Jun 2015 11:40:43 +0000Jaharmi482 at http://www.jaharmi.comVersion comparison solution pseudocodehttp://www.jaharmi.com/2015/06/07/version_comparison_solution_pseudocode
<p>This <a href="http://www.jaharmi.com/2015/06/07/compare_os_x_versions_using_only_strings"><span class="caps">OS</span> X version comparison solution</a> (the introduction to this series) takes some setup for each version&nbsp;comparison.</p>
<p>Once created, the comparison can be copied or cloned to form the basis for the next comparison. The duplicate copy can be edited to create new clauses for another comparison (adding &#8220;is this <span class="caps">OS</span> X 10.9 or later?&#8221; and &#8220;is this <span class="caps">OS</span> X 10.10 or later?&#8221; when needed). It also accommodates new <span class="caps">OS</span> X versions without any changes, assuming that the version numbering scheme continues with either 10.x (or increments above 10.x to 11.x and&nbsp;beyond).</p>
<p>The pseudocode to answer the &#8220;is this <span class="caps">OS</span> X 10.8 or later?&#8221; question could be expressed this&nbsp;way:</p>
<ul>
<li>Does the version start with <span class="caps">OS</span> X &#8220;10.&#8221;?
<ul>
<li>Does the version not start with <span class="caps">OS</span> X&nbsp;&#8220;10.0.&#8221;?</li>
<li>Does the version not start with <span class="caps">OS</span> X&nbsp;&#8220;10.1.&#8221;?</li>
<li>Does the version not start with <span class="caps">OS</span> X&nbsp;&#8220;10.2.&#8221;?</li>
<li>Does the version not start with <span class="caps">OS</span> X&nbsp;&#8220;10.3.&#8221;?</li>
<li>Does the version not start with <span class="caps">OS</span> X&nbsp;&#8220;10.4.&#8221;?</li>
<li>Does the version not start with <span class="caps">OS</span> X&nbsp;&#8220;10.5.&#8221;?</li>
<li>Does the version not start with <span class="caps">OS</span> X&nbsp;&#8220;10.6.&#8221;?</li>
<li>Does the version not start with <span class="caps">OS</span> X&nbsp;&#8220;10.7.&#8221;?</li>
</ul></li>
</ul>
<p>If the result of evaluating those statements is true, then the <span class="caps">OS</span> X version is 10.8 or&nbsp;greater.</p>
<p>Note the periods: This technique works as long as the periods can be evaluated, to serve as anchors between the&nbsp;numbers.</p>
<p>In some circumstances, the periods cannot be used as anchors. In cases like that, I have dropped off checking for <span class="caps">OS</span> X 10.0, 10.1, and 10.2. I expect that those are the three versions most likely to conflict with any further <span class="caps">OS</span> X releases in the 10.x&nbsp;series.</p>
<ul>
<li>Is the version like <span class="caps">OS</span> X &#8220;10&#8221;?
<ul>
<li>Is the version not like <span class="caps">OS</span> X&nbsp;&#8220;10.3&#8221;?</li>
<li>Is the version not like <span class="caps">OS</span> X&nbsp;&#8220;10.4&#8221;?</li>
<li>Is the version not like <span class="caps">OS</span> X&nbsp;&#8220;10.5&#8221;?</li>
<li>Is the version not like <span class="caps">OS</span> X&nbsp;&#8220;10.6&#8221;?</li>
<li>Is the version not like <span class="caps">OS</span> X&nbsp;&#8220;10.7&#8221;?</li>
</ul></li>
</ul>
<p>These techniques can be applied in a few different&nbsp;environments.</p>
Mac OS XSun, 07 Jun 2015 11:36:43 +0000Jaharmi481 at http://www.jaharmi.comCompare OS X versions using only stringshttp://www.jaharmi.com/2015/06/07/compare_os_x_versions_using_only_strings
<p>There are many system administration tasks in <span class="caps">OS</span> X that require version comparisons. Looking back over my time managing <span class="caps">OS</span> X, I&#8217;m surprised that this still presents some complexities in 2015. This article is the first in a short series on this topic and presents a solution to one of the common&nbsp;problems.</p>
<p>I have found that the most robust tools for these comparisons are available in the Python Standard Library, which makes them available <span title="This is, itself, a version comparison. Ahem.">up through at least <span class="caps">OS</span> X 10.10 Yosemite</span>. The modules in Python have the advantage of treating versions more like numbers — so greater than, less than, and equal comparisons are&nbsp;possible.</p>
<p>With Python, I believe we have at least two good choices of libraries that handle versions <em>as</em>&nbsp;versions.</p>
<ul>
<li><p>I wrote about &#8220;distutils.version&#8221; just over <a href="http://www.jaharmi.com/2007/05/21/using_python_distutils_version_to_compare_mac_os" title="Using Python distutils.version to compare Mac OS X version numbers">eight years ago</a>, after talking about the problem with my friend <a href="http://stevelosh.com" title="Steve Losh">Steve</a>. It offers two classes, StrictVersion and LooseVersion, that are each helpful in their own way. It is probably more popular on <span class="caps">OS</span> X, by the <a href="https://github.com/munki/munki/blob/master/code/client/munkilib/munkicommon.py#L44">shear volume of everyday usage</a>.</p></li>
<li><p>My friend <a href="https://twitter.com/natewalck" title="Nate Walck">Nate</a> and I included &#8220;pkg&#95;resources.parse&#95;version&#8221; in our <a href="http://www.jaharmi.com/psumacconf_2013_python_talk">Penn State Mac Admins Conference 2013 talk</a>, &#8220;Practical Python for Sysadmins&#8221; (slides 50 and 52). That module does the job and sounded good in <a href="https://www.python.org/dev/peps/pep-0386/"><span class="caps">PEP</span> 386</a>. It presents an alternative to &#8220;distutils.version&#8221; if you want&nbsp;one.</p></li>
</ul>
<p>Many system management tools resort to string comparison. Many scripts break down strings for numeric comparisons of components. These two techniques can accomplish what needs to be done, but have they have&nbsp;limits.</p>
<p>Especially when it is all that&#8217;s available, string comparison feels very limited. I have struggled trying to figure out how to handle &#8220;greater than&#8221; or &#8220;greater than or equal to&#8221; comparisons within those confines. In my own work, that particular comparison is a common, recurring need. There are many instances when I need to answer a basic question like &#8220;is this <span class="caps">OS</span> X 10.8 or later?&#8221; In number line&nbsp;terms:</p>
<p><img src="/files/NumberLineOSX108OrGreater.png" alt="NumberLineOSX108OrGreater.png" title="NumberLineOSX108OrGreater.png" width="439" height="39" class="inline" /></p>
<p>With some trial and error, I now have a way that appears to work reliably. I realized it could apply generally to different tools. I don&#8217;t know if it&#8217;s novel, since I haven&#8217;t found any references elsewhere to a similar technique. (If you know of one, I&#8217;d like to link to&nbsp;it.)</p>
<p>Find out <a href="http://www.jaharmi.com/2015/06/07/compare_os_x_versions_using_only_strings">more about this</a>.</p>
Mac OS XSun, 07 Jun 2015 11:34:29 +0000Jaharmi480 at http://www.jaharmi.comCreate a Munki alert with just one buttonhttp://www.jaharmi.com/2015/06/03/create_a_munki_alert_with_just_one_button
<p>I found that there is a way to get only one button in a Munki preinstall alert. By default, there are two, one for “<span class="caps">OK</span>” and the other for&nbsp;“Cancel.&#8221;</p>
<ol>
<li>Override the &#8220;ok label&#8221; with a blank&nbsp;string.</li>
<li>Set the &#8220;cancel label&#8221; to the &#8220;<span class="caps">OK</span>&#8221;&nbsp;string.</li>
</ol>
<p>The alert dictionary looks like&nbsp;this:</p>
<p><div class="geshifilter"><div class="bash geshifilter-bash">&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">&lt;</span>key<span class="sy0">&gt;</span>preinstall_alert<span class="sy0">&lt;/</span>key<span class="sy0">&gt;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">&lt;</span>dict<span class="sy0">&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">&lt;</span>key<span class="sy0">&gt;</span>alert_title<span class="sy0">&lt;/</span>key<span class="sy0">&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">&lt;</span>string<span class="sy0">&gt;</span>Alert<span class="sy0">&lt;/</span>string<span class="sy0">&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">&lt;</span>key<span class="sy0">&gt;</span>alert_detail<span class="sy0">&lt;/</span>key<span class="sy0">&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">&lt;</span>string<span class="sy0">&gt;</span>This is an alert that you should cancel, even <span class="kw1">if</span> the button label is <span class="st0">&quot;<span class="caps">OK</span>.&quot;</span><span class="sy0">&lt;/</span>string<span class="sy0">&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">&lt;</span>key<span class="sy0">&gt;</span>ok_label<span class="sy0">&lt;/</span>key<span class="sy0">&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">&lt;</span>string<span class="sy0">&gt;&lt;/</span>string<span class="sy0">&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">&lt;</span>key<span class="sy0">&gt;</span>cancel_label<span class="sy0">&lt;/</span>key<span class="sy0">&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">&lt;</span>string<span class="sy0">&gt;</span><span class="caps">OK</span><span class="sy0">&lt;/</span>string<span class="sy0">&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">&lt;/</span>dict<span class="sy0">&gt;</span></div></div></p>
<p>It results in a dialog with a single, default button labelled &#8220;<span class="caps">OK</span>,&#8221; instead of two buttons. It looks like&nbsp;this:</p>
<p><img src="/files/MunkiMSC_optional_alert_singlebutton_02.png" alt="MunkiMSC_optional_alert_singlebutton_02.png" title="MunkiMSC_optional_alert_singlebutton_02.png" width="427" height="210" class="inline" /></p>
<p>It wasn’t immediately obvious to me that setting a blank label for one of the alert buttons would make that button disappear, but I’m glad it&nbsp;did.</p>
<p><strong>Update:</strong> This could be used for an optional deployment with conditions. It provide an indication that an installation is available but conditions need to be&nbsp;met.</p>
<ol>
<li>Provide the real deployment when specific conditions are&nbsp;met.</li>
<li>When those conditions aren’t met, provide a simple alternate deployment — a different pkginfo with the same display name and icon — that will present the alert with a single button to describe how to meet the conditions. When the user clicks “<span class="caps">OK</span>,” the alternate deployment is cancelled. No harm, no foul. Using a simple install check script (“exit 0”), the alternate deployment will keep appearing until the conditions are met and the <em>real</em> deployment is in&nbsp;scope.</li>
</ol>
LearningAppleComputingExplorationMac OS XOpen sourceSystem administrationSuppliersTechnologyThu, 04 Jun 2015 02:43:22 +0000Jaharmi474 at http://www.jaharmi.comArchive OS X Installer application workflowhttp://www.jaharmi.com/2014/10/19/archive_os_x_installer_application_workflow
<p>I created an automated workflow to help me archive the OS X Installer application when I download updates from the Mac App Store. The release of OS X Yosemite and all these inadequately-labeled installer apps I have lying around at home spurred me on.</p>
<p>Each archived installer is saved as a disk image to /Users/Shared and named with its OS X version number and build.</p>
<p>I thought that it might be of general interest, so you can see more at <a href="https://bitbucket.org/jaharmi/archive-os-x-installer-application/overview">Bitbucket</a> or <a href="https://github.com/Jaharmi/archive_osx_installer_app">Github</a>. The workflow is automated courtesy of <a href="http://www.noodlesoft.com/hazel.php">Noodlesoft Hazel</a>.</p>
AppleMac OS XMacintoshOpen sourceScriptingShellSoftwareSystem administrationSuppliersTechnologySun, 19 Oct 2014 19:12:39 +0000Jaharmi473 at http://www.jaharmi.comIn a whole different Size Classhttp://www.jaharmi.com/2014/10/15/in_a_whole_different_size_class
<p>The march towards responsive design — now with <code class="freelink freelink-error freelink-Array freelink-error-Array">[Bad link]</code> — is a watershed moment for iOS. I can’t help but think that some of the moves Apple has made — and might make at its October 2014 announcement tomorrow — are centered around screens. This is all speculation on my part, but it’s been rolling around my head for a while now.</p>
<p>What if there’s no 5-inch iPhone 6 because Apple wants to move developers to update for Size Classes? No longer having the same iPhone screen as last year in the flagship phones is strong encouragement; both the iPhone 6 and 6 Plus demand that apps be updated. The big screens are a marquee feature of both new phones. Adding Notification Center interfaces is probably another part of this.</p>
<p>I could certainly see more encouragement coming from an expansion of the iPad line, adding a larger model alongside the existing 8 and 10 inch devices. Split screen display of multiple apps? More encouragement.</p>
<p>My conceit for some time has been that the establishment of the iPad Mini would eventually free Apple to increase the resolution and screen density of the iPad Air. There’s not necessarily a reason for the Mini and the Air to share the same resolution. Bumping up the resolution and density on the Air this year would give one more reason to throw out the pixel-perfect designs of the past. (I just hope the GPUs can handle such a move.)</p>
ExplorationThu, 16 Oct 2014 03:40:59 +0000Jaharmi472 at http://www.jaharmi.com