masq
Version:
A simple local dns server extracted from Pow
430 lines (296 loc) • 17 kB
HTML
<html>
<head>
<title>installer.coffee</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
<link rel="stylesheet" media="all" href="docco.css" />
</head>
<body>
<div id="container">
<div id="background"></div>
<ul id="jump_to">
<li>
<a class="large" href="javascript:void(0);">Jump To …</a>
<a class="small" href="javascript:void(0);">+</a>
<div id="jump_wrapper">
<div id="jump_page_wrapper">
<div id="jump_page">
<a class="source" href="command.html">
command.coffee
</a>
<a class="source" href="configuration.html">
configuration.coffee
</a>
<a class="source" href="daemon.html">
daemon.coffee
</a>
<a class="source" href="dns_server.html">
dns_server.coffee
</a>
<a class="source" href="index.html">
index.coffee
</a>
<a class="source" href="installer.html">
installer.coffee
</a>
<a class="source" href="logger.html">
logger.coffee
</a>
<a class="source" href="utils.html">
utils.coffee
</a>
</div>
</div>
</li>
</ul>
<ul class="sections">
<li id="title">
<div class="annotation">
<h1>installer.coffee</h1>
</div>
</li>
<li id="section-1">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-1">¶</a>
</div>
<p>The <code>Installer</code> class, in conjunction with the private
<code>InstallerFile</code> class, creates and installs local and system
configuration files if they’re missing or out of date. It’s used by
the Pow install script to set up the system for local development.</p>
</div>
<div class="content"><div class='highlight'><pre>
async = <span class="hljs-built_in">require</span> <span class="hljs-string">"async"</span>
fs = <span class="hljs-built_in">require</span> <span class="hljs-string">"fs"</span>
path = <span class="hljs-built_in">require</span> <span class="hljs-string">"path"</span>
{mkdirp} = <span class="hljs-built_in">require</span> <span class="hljs-string">"./utils"</span>
{chown} = <span class="hljs-built_in">require</span> <span class="hljs-string">"./utils"</span>
util = <span class="hljs-built_in">require</span> <span class="hljs-string">"util"</span></pre></div></div>
</li>
<li id="section-2">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-2">¶</a>
</div>
<p>Import the Eco templates for the <code>/etc/resolver</code> and <code>launchd</code>
configuration files.</p>
</div>
<div class="content"><div class='highlight'><pre>resolverSource = <span class="hljs-built_in">require</span> <span class="hljs-string">"./templates/resolver"</span></pre></div></div>
</li>
<li id="section-3">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-3">¶</a>
</div>
<p>firewallSource = require “./templates/cx.masq.firewall.plist”</p>
</div>
<div class="content"><div class='highlight'><pre>daemonSource = <span class="hljs-built_in">require</span> <span class="hljs-string">"./templates/cx.masq.masqd.plist"</span></pre></div></div>
</li>
<li id="section-4">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-4">¶</a>
</div>
<p><code>InstallerFile</code> represents a single file candidate for installation:
a pathname, a string of the file’s source, and optional flags
indicating whether the file needs to be installed as root and what
permission bits it should have.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">InstallerFile</span></span>
constructor: <span class="hljs-function"><span class="hljs-params">(@path, source, @root = <span class="hljs-literal">false</span>, @mode = <span class="hljs-number">0</span>o644)</span> -></span>
@source = source.trim()</pre></div></div>
</li>
<li id="section-5">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-5">¶</a>
</div>
<p>Check to see whether the file actually needs to be installed. If
the file exists on the filesystem with the specified path and
contents, <code>callback</code> is invoked with false. Otherwise, <code>callback</code>
is invoked with true.</p>
</div>
<div class="content"><div class='highlight'><pre> isStale: <span class="hljs-function"><span class="hljs-params">(callback)</span> -></span>
fs.exists @path, <span class="hljs-function"><span class="hljs-params">(exists)</span> =></span>
<span class="hljs-keyword">if</span> exists
fs.readFile @path, <span class="hljs-string">"utf8"</span>, <span class="hljs-function"><span class="hljs-params">(err, contents)</span> =></span>
<span class="hljs-keyword">if</span> err
callback <span class="hljs-literal">true</span>
<span class="hljs-keyword">else</span>
callback @source <span class="hljs-keyword">isnt</span> contents.trim()
<span class="hljs-keyword">else</span>
callback <span class="hljs-literal">true</span></pre></div></div>
</li>
<li id="section-6">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-6">¶</a>
</div>
<p>Create all the parent directories of the file’s path, if
necessary, and then invoke <code>callback</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> vivifyPath: <span class="hljs-function"><span class="hljs-params">(callback)</span> -></span>
mkdirp path.dirname(@path), callback</pre></div></div>
</li>
<li id="section-7">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-7">¶</a>
</div>
<p>Write the file’s source to disk and invoke <code>callback</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> writeFile: <span class="hljs-function"><span class="hljs-params">(callback)</span> -></span>
fs.writeFile @path, @source, <span class="hljs-string">"utf8"</span>, callback</pre></div></div>
</li>
<li id="section-8">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-8">¶</a>
</div>
<p>If the root flag is set for this file, change its ownership to the
<code>root</code> user and <code>wheel</code> group. Then invoke <code>callback</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> setOwnership: <span class="hljs-function"><span class="hljs-params">(callback)</span> -></span>
<span class="hljs-keyword">if</span> @root
chown @path, <span class="hljs-string">"root:wheel"</span>, callback
<span class="hljs-keyword">else</span>
callback <span class="hljs-literal">false</span></pre></div></div>
</li>
<li id="section-9">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-9">¶</a>
</div>
<p>Set permissions on the installed file with <code>chmod</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> setPermissions: <span class="hljs-function"><span class="hljs-params">(callback)</span> -></span>
fs.chmod @path, @mode, callback</pre></div></div>
</li>
<li id="section-10">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-10">¶</a>
</div>
<p>Install a file asynchronously, first by making its parent
directory, then writing it to disk, and finally setting its
ownership and permission bits.</p>
</div>
<div class="content"><div class='highlight'><pre> install: <span class="hljs-function"><span class="hljs-params">(callback)</span> -></span>
async.series [
@vivifyPath.bind(@),
@writeFile.bind(@),
@setOwnership.bind(@),
@setPermissions.bind(@)
], callback</pre></div></div>
</li>
<li id="section-11">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-11">¶</a>
</div>
<p>The <code>Installer</code> class operates on a set of <code>InstallerFile</code> instances.
It can check to see if any files are stale and whether or not root
access is necessary for installation. It can also install any stale
files asynchronously.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">module</span>.exports = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Installer</span></span></pre></div></div>
</li>
<li id="section-12">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-12">¶</a>
</div>
<p>Factory method that takes a <code>Configuration</code> instance and returns
an <code>Installer</code> for system firewall and DNS configuration files.</p>
</div>
<div class="content"><div class='highlight'><pre> @getSystemInstaller: <span class="hljs-function"><span class="hljs-params">(configuration)</span> -></span>
files = [</pre></div></div>
</li>
<li id="section-13">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-13">¶</a>
</div>
<p>new InstallerFile “/Library/LaunchDaemons/cx.masq.firewall.plist”,
firewallSource(configuration),
true</p>
</div>
<div class="content"><div class='highlight'><pre> ]
<span class="hljs-keyword">for</span> domain <span class="hljs-keyword">in</span> configuration.domains
files.push <span class="hljs-keyword">new</span> InstallerFile <span class="hljs-string">"/etc/resolver/<span class="hljs-subst">#{domain}</span>"</span>,
resolverSource(configuration),
<span class="hljs-literal">true</span>
<span class="hljs-keyword">new</span> Installer files</pre></div></div>
</li>
<li id="section-14">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-14">¶</a>
</div>
<p>Factory method that takes a <code>Configuration</code> instance and returns
an <code>Installer</code> for the Pow <code>launchctl</code> daemon configuration file.</p>
</div>
<div class="content"><div class='highlight'><pre> @getLocalInstaller: <span class="hljs-function"><span class="hljs-params">(configuration)</span> -></span>
<span class="hljs-keyword">new</span> Installer [
<span class="hljs-keyword">new</span> InstallerFile <span class="hljs-string">"<span class="hljs-subst">#{process.env.HOME}</span>/Library/LaunchAgents/cx.masq.masqd.plist"</span>,
daemonSource(configuration)
]</pre></div></div>
</li>
<li id="section-15">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-15">¶</a>
</div>
<p>Create an installer for a set of files.</p>
</div>
<div class="content"><div class='highlight'><pre> constructor: <span class="hljs-function"><span class="hljs-params">(@files = [])</span> -></span></pre></div></div>
</li>
<li id="section-16">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-16">¶</a>
</div>
<p>Invoke <code>callback</code> with an array of any files that need to be
installed.</p>
</div>
<div class="content"><div class='highlight'><pre> getStaleFiles: <span class="hljs-function"><span class="hljs-params">(callback)</span> -></span>
async.select @files, <span class="hljs-function"><span class="hljs-params">(file, proceed)</span> -></span>
file.isStale proceed
, callback @files</pre></div></div>
</li>
<li id="section-17">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-17">¶</a>
</div>
<p>Invoke <code>callback</code> with a boolean argument indicating whether or
not any files need to be installed as root.</p>
</div>
<div class="content"><div class='highlight'><pre> needsRootPrivileges: <span class="hljs-function"><span class="hljs-params">(callback)</span> -></span>
@getStaleFiles (files) ->
async.detect files, <span class="hljs-function"><span class="hljs-params">(file, proceed)</span> -></span>
proceed file.root
, <span class="hljs-function"><span class="hljs-params">(result)</span> -></span>
callback result?</pre></div></div>
</li>
<li id="section-18">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-18">¶</a>
</div>
<p>Installs any stale files asynchronously and then invokes
<code>callback</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> install: <span class="hljs-function"><span class="hljs-params">(callback)</span> -></span>
@getStaleFiles (files) ->
async.forEach files, <span class="hljs-function"><span class="hljs-params">(file, proceed)</span> -></span>
file.install (err) ->
util.puts file.path <span class="hljs-keyword">unless</span> err
proceed err
, callback</pre></div></div>
</li>
</ul>
</div>
</body>
</html>