<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Justin Cummings</title>
    <description>The latest articles on DEV Community by Justin Cummings (@jlcummings).</description>
    <link>https://dev.to/jlcummings</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F473684%2F4de39bf1-3569-4556-8fd2-dcb3b60c3f05.jpeg</url>
      <title>DEV Community: Justin Cummings</title>
      <link>https://dev.to/jlcummings</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jlcummings"/>
    <language>en</language>
    <item>
      <title>🧟‍♂️ adventures in software development: automatic, scheduled wsl2 backups</title>
      <dc:creator>Justin Cummings</dc:creator>
      <pubDate>Sun, 15 Aug 2021 15:18:16 +0000</pubDate>
      <link>https://dev.to/jlcummings/adventures-in-software-development-automatic-scheduled-wsl2-backups-h12</link>
      <guid>https://dev.to/jlcummings/adventures-in-software-development-automatic-scheduled-wsl2-backups-h12</guid>
      <description>&lt;p&gt;As we rejoin our brave adventurer, we find that he has hurdled another piece of the backup puzzle, to be faced by yet even more hurdles when automatically scheduling Windows Subsystem for Linux (WSL2) backups.  He has scoured and squirmed his way to timely exports of the distribution of concern and beat back weird interactions with the foul, yet, beloved beast, Docker.&lt;/p&gt;

&lt;p&gt;The first step was creating an archive of the instance.  That is made possible by the ‘wsl’ command using the ‘export’ sub-command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Get a list of WSL `distributions` and their status&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wsl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-v&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="nx"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nx"&gt;VERSION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ubuntu&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="nx"&gt;Running&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;docker-desktop&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="nx"&gt;Running&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;docker-desktop-data&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Running&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Note the current directory/drive and change to a location to save the exported distribution to; I recommend not saving this to a location that is cloud synchronized, because it will be large and extremely time consuming to upload (and then sync to all connected devices).&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pwd&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nx"&gt;Path&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;----&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;C:\Users\justi\Documents&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Export a distribution for backup&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;# Note that this takes it offline and for several minutes, but ensures absolute consistency&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wsl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Ubuntu&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wsl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-v&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="nx"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nx"&gt;VERSION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ubuntu&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="nx"&gt;Converting&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;docker-desktop&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="nx"&gt;Running&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;docker-desktop-data&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Running&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="c"&gt;# Verify it completed once the 'State' shows as 'Stopped' for the given distribution.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ls&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="n"&gt;Directory:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\Users\justi\Documents&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;Mode&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="nx"&gt;LastWriteTime&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="nx"&gt;Length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;----&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="o"&gt;-------------&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;------&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;----&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;-a&lt;/span&gt;&lt;span class="o"&gt;---&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;/12/2021&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;2:52&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;PM&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;12001935360&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Ubuntu.tar&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we are confident that we can archive the distribution, the next step is to do it under automatic execution.  &lt;/p&gt;

&lt;p&gt;After fiddling around from near zero powershell or programatic task-scheduler knowledge, I currently can run the backup under the task scheduler for reoccurring, time-of-day and day-of-week based execution.  Personally, I set it to the late evening-to-very-early morning hours, like 2:30AM locally, but only weekly, because that is my risk vs cost threshold and don't feel more frequent backups would be helpful; however, you might. I could register the task through the 'Task Scheduler' GUI, but what fun is that?  Lets look a little more 😎.  &lt;/p&gt;

&lt;p&gt;Initial registration of the task is roughly prepared using power shell script.  The archives are date-tagged in the filename scheme to easily identify when they were created and to make sorting and visualizing other aspects like growth easy to see.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# .\Register-ScheduledBackup-WSL2.ps1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;# this is the meat; a lot of sides surround the main course, but this is how you add a scheduled task&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Register-ScheduledTask&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Trigger&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$trigger&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-TaskPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$TaskPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-TaskName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$taskName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$taskDescription&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Principal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$principle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Settings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$settingsSet&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;# using a subscription to the task scheduler log&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$subscription&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sh"&gt;@"
&amp;lt;QueryList&amp;gt;
    &amp;lt;Query Id="0" Path="Microsoft-Windows-TaskScheduler/Operational"&amp;gt;
        &amp;lt;Select Path="Microsoft-Windows-TaskScheduler/Operational"&amp;gt;
            *[EventData[@Name="ActionSuccess"][Data[@Name="TaskName"]="\&lt;/span&gt;&lt;span class="nv"&gt;$TaskPath&lt;/span&gt;&lt;span class="sh"&gt;\&lt;/span&gt;&lt;span class="nv"&gt;$taskName&lt;/span&gt;&lt;span class="sh"&gt;"][Data[@Name="ResultCode"]="0"]]
        &amp;lt;/Select&amp;gt;
    &amp;lt;/Query&amp;gt;
&amp;lt;/QueryList&amp;gt;
"@&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;# add a task that fires based on that subscription&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Register-ScheduledTask&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$dockerRestartAction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Trigger&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$dockerRestartTrigger&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-TaskPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$TaskPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-TaskName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Restart Docker'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Restart Docker on completion of '&lt;/span&gt;&lt;span class="nv"&gt;$taskName&lt;/span&gt;&lt;span class="s2"&gt;'"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Principal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$dockerRestartPrinciple&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Settings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$dockerRestartSettings&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: the above example only creates the scheduled task.  To update the scheduled task requires a different script.  That is not shown.  It is not implemented.  Instead, I just unregister, and register anew.  The actual backup script that is run via the above registration process is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# .\Backup-WSL2.ps1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;# parameter handling and logging omitted; here is the crux&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="nv"&gt;$command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-Command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;wsl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Definition&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$dateExecuted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-Date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Format&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;FileDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$commandArgs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--export &lt;/span&gt;&lt;span class="nv"&gt;$Distribution&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$DestinationPath&lt;/span&gt;&lt;span class="s2"&gt;\&lt;/span&gt;&lt;span class="nv"&gt;$Distribution&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;$dateExecuted&lt;/span&gt;&lt;span class="s2"&gt;.tar"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;# execute the backup&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Invoke-Expression&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;amp; &lt;/span&gt;&lt;span class="nv"&gt;$command&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$commandArgs&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is a problem with this.  For some reason when the export/archive of the WSL distribution finishes, the connection to the docker socket of the host is lost or corrupted or something, so Docker needs to be restarted before your distribution can interact with the host docker system: We 😵  &lt;/p&gt;

&lt;p&gt;I could reboot the entire machine, but just restarting docker seems to be sufficient.  I could use the Docker Desktop GUI/menus, but automatic restart would be nice while the underlying challenge remains.  TLDR; Be 😎.  &lt;/p&gt;

&lt;p&gt;Note: restarting all of docker has it's own consequences, so proceed cautiously as any other running containers on the same host, your machine, will also be stopped.&lt;/p&gt;

&lt;p&gt;The process to accomplish a docker restart via powershell is something that I am less comfortable showing, as it is based on a general instruction demonstrated in the following link: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/a/57560043/549306"&gt;Stackoverflow: Restart docker Windows 10 command line&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The reason I am less comfortable showing how I do it because: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Licensing attached to Stackoverflow user-contributed code may impede personal or professional efforts.&lt;/li&gt;
&lt;li&gt;The example solution does not work cleanly &lt;code&gt;as is&lt;/code&gt;.  So modification is required, and then I refer back to '#1' 😧.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But I will highlight the relevant commands here (with parameter handling, logging, and sleep or await commands omitted):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
# kill the underlying Windows services used by docker, as gracefully as possible
Stop-Service -InputObject $_ -ErrorAction Continue -Confirm:$false -Force
...
# kill the user facing docker desktop app without delay (the app has little consequence on the underlying docker system, and is mostly just a dashboard; not a criticism) 
Stop-Process -InputObject $_
...
# start the desktop app because it generally takes the longest to completely start and won't complain terribly if the underlying docker system isn't ready or available
$_.Start()
...
# start the underlying Windows services for docker
Start-Process -FilePath $clientAppPath -PassThru |
...
# execute a `docker info` command and parse the results for indicators of readiness
$healthCheckResult = $($ServiceHealthCommand)
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The complete script used to restart docker is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.\Restart-Suite.ps1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In any case, once Docker is restarted, I am able to rejoin/restart my now safely archived distribution.  &lt;/p&gt;

&lt;p&gt;The complete effort to-date is found here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jlcummings/backup-wsl2"&gt;backup-wsl2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Repeating the disclaimer in the repository README: this is very rookie stuff you will find here, and more importantly, it may be a terrible approach to managing wsl2 backups at the end of the day; but it is an option and maybe inspirational to someone with more foresight, talent, and time.&lt;/p&gt;

&lt;p&gt;Insert Tim Allen as Tim the Toolman Taylor trope.  I connected a service restart to the end of the backup script to automatically restart Docker after exporting the wsl instance at a regular time of day when I wasn't heavily using the machine.  I should add more steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;modify my process to also copy a complete, intact archive periodically to another location; one other option might be ‘rysnc’ the archive chunks to remote storage for isolation from the source (likely you want to stage it to &lt;code&gt;local&lt;/code&gt; network storage first and let that NAS/SAN sync to offsite  during off-peak periods)&lt;/li&gt;
&lt;li&gt;test the recovery process; if you can't recover from it, the backup is not worth making&lt;/li&gt;
&lt;li&gt;shrink the live distribution somehow, as the growth of the image has a negative affect on the archive process in terms of time and space (experience shows this is going to be fruitless in most cases)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>wsl2</category>
      <category>powershell</category>
      <category>backup</category>
    </item>
    <item>
      <title>🧟‍♂️ adventures in software development: first run of swiftlint analyze</title>
      <dc:creator>Justin Cummings</dc:creator>
      <pubDate>Sun, 15 Aug 2021 14:29:56 +0000</pubDate>
      <link>https://dev.to/jlcummings/adventures-in-software-development-first-run-of-swiftlint-analyze-41c0</link>
      <guid>https://dev.to/jlcummings/adventures-in-software-development-first-run-of-swiftlint-analyze-41c0</guid>
      <description>&lt;p&gt;Effective, efficient, safe, easy to reason about and maintain code is what professionals strive towards.  In essence, clean.  Using tools that can help us clean-up code should be common practice.  &lt;/p&gt;

&lt;p&gt;For Swift, the compiler finds many issues.  To go beyond a valid build based on legal swift and allowed Xcode configurations when building on Mac, adding linting and AST static analysis is not hard, and raises the bar towards more idiomatic code.  While Apple continues to refine and expand the basic built in tooling, the community has several tools to augment the build process in the meantime.  One of those tools is &lt;a href="https://realm.github.io/SwiftLint/"&gt;swiftlint&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The instructions on the website for installing and running the linter (both from the command line, and as a build step inside Xcode) are straightforward.  I won't go into installing or linting here.  How to run your first AST static analysis using &lt;code&gt;swiftlint&lt;/code&gt;, which is experimental, is what I will describe from hands-on-experience beyond the somewhat sparse instructions on the tool's site.&lt;/p&gt;

&lt;p&gt;To run the &lt;code&gt;swiftlint&lt;/code&gt; AST static analysis, you must provide a successful, full-build log (incremental builds will not work, supposedly).  Let me underline this point: Xcode build logs are required, so you won't be doing this outside of a Mac at this time.  Normally, the build log from running the build process from the IDE is not exposed or kept in the project directory, so you have to do things a bit differently.  &lt;/p&gt;

&lt;p&gt;Creating a project-local build log is possible, and configuring it to do as a default process is possible, but beyond the scope of this article.  There are reasons to and  not to include a build log by default locally.  At this time, Apple feels the convention should be to exclude them locally, so that is how we will roll.&lt;/p&gt;

&lt;p&gt;Using the Xcode command-line tools (v12.5) in the terminal from the project root directory, issue the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xcodebuild -list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Command line invocation:
    /Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -list

User defaults from command line:
    IDEPackageSupportUseBuiltinSCM = YES

Information about project "DifferenceOfSquares":
    Targets:
        DifferenceOfSquares
        DifferenceOfSquaresPackageDescription
        DifferenceOfSquaresPackageTests
        DifferenceOfSquaresTests

    Build Configurations:
        Debug
        Release

    If no build configuration is specified and -scheme is not passed then "Release" is used.

    Schemes:
        DifferenceOfSquares-Package

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The relevant parts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
    Schemes:
        DifferenceOfSquares-Package
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the information from that list of schemes, you can now create a build log that can be passed to the analyzer.&lt;/p&gt;

&lt;p&gt;Using the Xcode command-line tools (v12.5) in the terminal from the project root directory, issue the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xcodebuild -scheme DifferenceOfSquares-Package clean build &amp;gt; build.log
swiftlint analyze --compiler-log-path ./build.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Analyzing Swift files in current working directory
Analyzing 'DifferenceOfSquares.swift' (1/1)
Done analyzing! Found 0 violations, 0 serious in 1 file.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There you have it.  A static-analysis on my exercism project, 'DifferenceOfSquares' in the swift track.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>tooling</category>
      <category>codequality</category>
    </item>
  </channel>
</rss>
