blog.notmyidea.org/working-directly-on-your-server-how-to-backup-and-sync-your-dev-environment-with-unison.html
2019-11-07 17:39:15 +01:00

304 lines
No EOL
18 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
<title>Working directly on your server? How to backup and sync your dev environment with unison - Alexis - Carnets en ligne</title>
<meta charset="utf-8" />
<link href="https://blog.notmyidea.org/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="Alexis - Carnets en ligne Full Atom Feed" />
<link rel="stylesheet" href="https://blog.notmyidea.org/theme/css/poole.css"/>
<link rel="stylesheet" href="https://blog.notmyidea.org/theme/css/syntax.css"/>
<link rel="stylesheet" href="https://blog.notmyidea.org/theme/css/lanyon.css"/>
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=PT+Serif:400,400italic,700%7CPT+Sans:400">
<link rel="stylesheet" href="https://blog.notmyidea.org/theme/css/styles.css"/>
<style>
h1 {
font-family: "Avant Garde", Avantgarde, "Century Gothic", CenturyGothic, "AppleGothic", sans-serif;
padding: 80px 50px;
text-align: center;
text-transform: uppercase;
text-rendering: optimizeLegibility;
color: #202020;
letter-spacing: .1em;
text-shadow:
-1px -1px 1px #111,
2px 2px 1px #eaeaea;
}
#main {
text-align: justify;
text-justify: inter-word;
}
#main h1 {
padding: 10px;
}
.post-headline {
padding: 15px;
}
</style>
</head>
<body>
<!-- Target for toggling the sidebar `.sidebar-checkbox` is for regular
styles, `#sidebar-checkbox` for behavior. -->
<input type="checkbox" class="sidebar-checkbox" id="sidebar-checkbox">
<!-- Toggleable sidebar -->
<div class="sidebar" id="sidebar">
<div class="sidebar-item">
<div class="profile">
<img src="https://blog.notmyidea.org/theme/img/profile.png"/>
</div>
</div>
<nav class="sidebar-nav">
<a class="sidebar-nav-item" href="/">Articles</a>
<a class="sidebar-nav-item" href="https://www.vieuxsinge.com">Brasserie du Vieux Singe</a>
<a class="sidebar-nav-item" href="http://blog.notmyidea.org/pages/about.html">A propos</a>
<a class="sidebar-nav-item" href="https://twitter.com/ametaireau">Messages courts</a>
<a class="sidebar-nav-item" href="https://github.com/almet">Code</a>
</nav>
</div> <div class="wrap">
<div class="masthead">
<div class="container">
<h3 class="masthead-title">
<a href="https://blog.notmyidea.org/" title="Home">Alexis - Carnets en ligne</a>
</h3>
</div>
</div>
<div class="container content">
<div id="main" class="posts">
<h1 class="post-title">Working directly on your server? How to backup and sync your dev environment with unison</h1>
<span class="post-date">16 mars 2011, dans <a class="no-color" href="category/technologie.html">Technologie</a></span>
<img id="illustration" src="" />
<div class="post article">
<h1>🌟</h1>
<p>I have a server running freebsd since some time now, and was wondering
about the possibility to directly have a development environment ready
to use when I get a internet connexion, even if I'm not on my computer.</p>
<p>Since I use vim to code, and spend most of my time in a console while
developing, it's possible to work via ssh, from everywhere.</p>
<p>The only problem is the synchronisation of the source code, config files
etc. from my machine to the server.</p>
<p>Unison provides an interesting way to synchronise two folders, even over
a network. So let's do it !</p>
<h2 id="creating-the-jail">Creating the jail</h2>
<p>In case you don't use FreeBSD, you can skip this section.</p>
<div class="highlight"><pre><span></span><span class="o">#</span> <span class="n">I</span> <span class="n">have</span> <span class="n">a</span> <span class="n">flavour</span> <span class="n">jail</span> <span class="n">named</span> <span class="k">default</span>
<span class="err">$</span> <span class="n">ezjail</span><span class="o">-</span><span class="k">admin</span> <span class="o">-</span><span class="n">f</span> <span class="k">default</span> <span class="n">workspace</span><span class="p">.</span><span class="n">notmyidea</span><span class="p">.</span><span class="n">org</span> <span class="mi">172</span><span class="p">.</span><span class="mi">19</span><span class="p">.</span><span class="mi">1</span><span class="p">.</span><span class="mi">6</span>
<span class="err">$</span> <span class="n">ezjail</span><span class="o">-</span><span class="k">admin</span> <span class="k">start</span> <span class="n">workspace</span><span class="p">.</span><span class="n">notmyidea</span><span class="p">.</span><span class="n">org</span>
</pre></div>
<p>In my case, because the "default" flavour contains already a lot of
interesting things, my jail come already setup with ssh, bash and vim
for instance, but maybe you'll need it in your case.</p>
<p>I want to be redirected to the ssh of the jail when I connect to the
host with the 20006 port. Add lines in <code>/etc/pf.conf</code>:</p>
<div class="highlight"><pre><span></span> <span class="nv">workspace_jail</span><span class="o">=</span><span class="s2">&quot;172.19.1.6&quot;</span>
rdr on <span class="nv">$ext_if</span> proto tcp from any to <span class="nv">$ext_ip</span> port <span class="m">20006</span> -&gt; <span class="nv">$workspace_jail</span> port <span class="m">22</span>
</pre></div>
<p>Reload packet filter rules</p>
<div class="highlight"><pre><span></span>$ /etc/rc.d/pf reload
</pre></div>
<h2 id="working-with-unison">Working with unison</h2>
<p>Now that we've set up the jail. Set up unison on the server and on your
client. Unison is available on the freebsd ports so just install it</p>
<div class="highlight"><pre><span></span>$ ssh notmyidea.org -p <span class="m">20006</span>
$ make -C /usr/ports/net/unison-nox11 config-recursive
$ make -C /usr/ports/net/unison-nox11 package-recursive
</pre></div>
<p>Install as well unison on your local machine. Double check to install
the same version on the client and on the server. Ubuntu contains the
2.27.57 as well as the 2.32.52.</p>
<p>Check that unison is installed and reachable via ssh from your machine</p>
<div class="highlight"><pre><span></span>$ ssh notmyidea.org -p <span class="m">20006</span> unison -version
unison version <span class="m">2</span>.27.157
$ unison -version
unison version <span class="m">2</span>.27.57
</pre></div>
<h2 id="let-sync-our-folders">Let sync our folders</h2>
<p>The first thing I want to sync is my vim configuration. Well, it's
already <a href="http://github.com/ametaireau/dotfiles/">in a git repository</a>
but let's try to use unison for it right now.</p>
<p>I have two machines then: workspace, the jail, and ecureuil my laptop.</p>
<div class="highlight"><pre><span></span>unison .vim ssh://notmyidea.org:20006/.vim
unison .vimrc ssh://notmyidea.org:20006/.vimrc
</pre></div>
<p>It is also possible to put all the informations in a config file, and
then to only run unison. (fire up vim \~/.unison/default.prf.</p>
<p>Here is my config:</p>
<div class="highlight"><pre><span></span> <span class="na">root</span> <span class="o">=</span> <span class="s">/home/alexis</span>
<span class="s"> root = ssh://notmyidea.org:20006</span>
<span class="na">path</span> <span class="o">=</span> <span class="s">.vimrc</span>
<span class="s"> path = dotfiles</span>
<span class="s"> path = dev</span>
<span class="na">follow</span> <span class="o">=</span> <span class="s">Name *</span>
</pre></div>
<p>My vimrc is in fact a symbolic link on my laptop, but I don't want to
specify each of the links to unison. That's why the follow = Name * is
for.</p>
<p>The folders you want to synchronize are maybe a bit large. If so,
considering others options such as rsync for the first import may be a
good idea (I enjoyed my university huge upload bandwith to upload 2GB in
20mn ;)</p>
<h2 id="run-the-script-frequently">Run the script frequently</h2>
<p>Once that done, you just need to run the unison command line some times
when you want to sync your two machines. I've wrote a tiny script to get
some feedback from the sync:</p>
<div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
<span class="n">DEFAULT_LOGFILE</span> <span class="o">=</span> <span class="s2">&quot;~/unison.log&quot;</span>
<span class="n">PROGRAM_NAME</span> <span class="o">=</span> <span class="s2">&quot;Unison syncer&quot;</span>
<span class="k">def</span> <span class="nf">sync</span><span class="p">(</span><span class="n">logfile</span><span class="o">=</span><span class="n">DEFAULT_LOGFILE</span><span class="p">,</span> <span class="n">program_name</span><span class="o">=</span><span class="n">PROGRAM_NAME</span><span class="p">):</span>
<span class="c1"># init</span>
<span class="n">display_message</span> <span class="o">=</span> <span class="bp">True</span>
<span class="n">error</span> <span class="o">=</span> <span class="bp">False</span>
<span class="n">before</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span>
<span class="c1"># call unison to make the sync</span>
<span class="n">os</span><span class="o">.</span><span class="n">system</span><span class="p">(</span><span class="s1">&#39;unison -batch &gt; {0}&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">logfile</span><span class="p">))</span>
<span class="c1"># get the duration of the operation</span>
<span class="n">td</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">-</span> <span class="n">before</span>
<span class="n">delta</span> <span class="o">=</span> <span class="p">(</span><span class="n">td</span><span class="o">.</span><span class="n">microseconds</span> <span class="o">+</span> <span class="p">(</span><span class="n">td</span><span class="o">.</span><span class="n">seconds</span> <span class="o">+</span> <span class="n">td</span><span class="o">.</span><span class="n">days</span> <span class="o">*</span> <span class="mi">24</span> <span class="o">*</span> <span class="mi">3600</span><span class="p">)</span> <span class="o">*</span> <span class="mi">10</span><span class="o">**</span><span class="mi">6</span><span class="p">)</span> <span class="o">/</span> <span class="mi">10</span><span class="o">**</span><span class="mi">6</span>
<span class="c1"># check what was the last entry in the log</span>
<span class="n">log</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">expanduser</span><span class="p">(</span><span class="n">logfile</span><span class="p">))</span>
<span class="n">lines</span> <span class="o">=</span> <span class="n">log</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
<span class="k">if</span> <span class="s1">&#39;No updates to propagate&#39;</span> <span class="ow">in</span> <span class="n">lines</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span>
<span class="n">display_message</span> <span class="o">=</span> <span class="bp">False</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">output</span> <span class="o">=</span> <span class="p">[</span><span class="n">l</span> <span class="k">for</span> <span class="n">l</span> <span class="ow">in</span> <span class="n">lines</span> <span class="k">if</span> <span class="s2">&quot;Synchronization&quot;</span> <span class="ow">in</span> <span class="n">l</span><span class="p">]</span>
<span class="n">message</span> <span class="o">=</span> <span class="n">output</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="n">message</span> <span class="o">+=</span> <span class="s2">&quot; It took {0}s.&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">delta</span><span class="p">)</span>
<span class="k">if</span> <span class="n">display_message</span><span class="p">:</span>
<span class="n">os</span><span class="o">.</span><span class="n">system</span><span class="p">(</span><span class="s1">&#39;notify-send -i {2} &quot;{0}&quot; &quot;{1}&quot;&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">program_name</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span>
<span class="s1">&#39;error&#39;</span> <span class="k">if</span> <span class="n">error</span> <span class="k">else</span> <span class="s1">&#39;info&#39;</span><span class="p">))</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&quot;__main__&quot;</span><span class="p">:</span>
<span class="n">sync</span><span class="p">()</span>
</pre></div>
<p>This is probably perfectible, but that does the job.</p>
<p>Last step is to tell you machine to run that frequently. That's what
crontab is made for, so let's <code>crontab -e</code>:</p>
<div class="highlight"><pre><span></span> <span class="err">$</span> <span class="o">*</span> <span class="o">*/</span><span class="mi">3</span> <span class="o">*</span> <span class="o">*</span> <span class="o">*</span> <span class="p">.</span> <span class="o">~/</span><span class="p">.</span><span class="n">Xdbus</span><span class="p">;</span> <span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">bin</span><span class="o">/</span><span class="n">python</span> <span class="o">/</span><span class="n">home</span><span class="o">/</span><span class="n">alexis</span><span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">python</span><span class="o">/</span><span class="n">unison</span><span class="o">-</span><span class="n">syncer</span><span class="o">/</span><span class="n">sync</span><span class="p">.</span><span class="n">py</span>
</pre></div>
<p>The \~/.Xdbus allows cron to communicate with your X11 session. Here is
its content.</p>
<div class="highlight"><pre><span></span><span class="ch">#!/bin/bash</span>
<span class="c1"># Get the pid of nautilus</span>
<span class="nv">nautilus_pid</span><span class="o">=</span><span class="k">$(</span>pgrep -u <span class="nv">$LOGNAME</span> -n nautilus<span class="k">)</span>
<span class="c1"># If nautilus isn&#39;t running, just exit silently</span>
<span class="k">if</span> <span class="o">[</span> -z <span class="s2">&quot;</span><span class="nv">$nautilus_pid</span><span class="s2">&quot;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
<span class="nb">exit</span> <span class="m">0</span>
<span class="k">fi</span>
<span class="c1"># Grab the DBUS_SESSION_BUS_ADDRESS variable from nautilus&#39;s environment</span>
<span class="nb">eval</span> <span class="k">$(</span>tr <span class="s1">&#39;\0&#39;</span> <span class="s1">&#39;\n&#39;</span> &lt; /proc/<span class="nv">$nautilus_pid</span>/environ <span class="p">|</span> grep <span class="s1">&#39;^DBUS_SESSION_BUS_ADDRESS=&#39;</span><span class="k">)</span>
<span class="c1"># Check that we actually found it</span>
<span class="k">if</span> <span class="o">[</span> -z <span class="s2">&quot;</span><span class="nv">$DBUS_SESSION_BUS_ADDRESS</span><span class="s2">&quot;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
<span class="nb">echo</span> <span class="s2">&quot;Failed to find bus address&quot;</span> &gt;<span class="p">&amp;</span><span class="m">2</span>
<span class="nb">exit</span> <span class="m">1</span>
<span class="k">fi</span>
<span class="c1"># export it so that child processes will inherit it</span>
<span class="nb">export</span> DBUS_SESSION_BUS_ADDRESS
</pre></div>
<p>And it comes from
<a href="http://ubuntuforums.org/showthread.php?p=10148738#post10148738">here</a>.</p>
<p>A sync takes about 20s + the upload time on my machine, which stay
acceptable for all of my developments.</p>
</div>
</div>
</div>
<label for="sidebar-checkbox" class="sidebar-toggle"></label>
<script>
(function(document) {
var i = 0;
// snip empty header rows since markdown can't
var rows = document.querySelectorAll('tr');
for(i=0; i<rows.length; i++) {
var ths = rows[i].querySelectorAll('th');
var rowlen = rows[i].children.length;
if (ths.length > 0 && ths.length === rowlen) {
rows[i].remove();
}
}
})(document);
</script>
<script>
/* Lanyon & Poole are Copyright (c) 2014 Mark Otto. Adapted to Pelican 20141223 and extended a bit by @thomaswilley */
(function(document) {
var toggle = document.querySelector('.sidebar-toggle');
var sidebar = document.querySelector('#sidebar');
var checkbox = document.querySelector('#sidebar-checkbox');
document.addEventListener('click', function(e) {
var target = e.target;
if(!checkbox.checked ||
sidebar.contains(target) ||
(target === checkbox || target === toggle)) return;
checkbox.checked = false;
}, false);
})(document);
</script>
<!-- Piwik -->
<script type="text/javascript">
var _paq = _paq || [];
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//tracker.notmyidea.org/";
_paq.push(['setTrackerUrl', u+'piwik.php']);
_paq.push(['setSiteId', 3]);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<noscript><p><img src="//tracker.notmyidea.org/piwik.php?idsite=3" style="border:0;" alt="" /></p></noscript>
<!-- End Piwik Code -->
</div>
</body>
</html>