<?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: Nakul Kurane</title>
    <description>The latest articles on DEV Community by Nakul Kurane (@nakulkurane).</description>
    <link>https://dev.to/nakulkurane</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%2F336628%2F1511f757-0df0-4d17-879b-0b0100cc4668.jpeg</url>
      <title>DEV Community: Nakul Kurane</title>
      <link>https://dev.to/nakulkurane</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nakulkurane"/>
    <language>en</language>
    <item>
      <title>Backing Up My Logic Pro Projects to AWS S3 (Part 1)</title>
      <dc:creator>Nakul Kurane</dc:creator>
      <pubDate>Sun, 23 Feb 2020 16:08:15 +0000</pubDate>
      <link>https://dev.to/nakulkurane/backing-up-my-logic-pro-projects-to-aws-s3-part-1-2051</link>
      <guid>https://dev.to/nakulkurane/backing-up-my-logic-pro-projects-to-aws-s3-part-1-2051</guid>
      <description>&lt;p&gt;On a whim, just to play with Python and AWS, I thought of building a script to backup my Logic Pro projects to AWS S3. The premise of the script is that it will check a directory on my Macbook and upload any files that have been modified since the last time the file was uploaded to S3. This will run via a cron job (which, yes, only runs if my Macbook is awake). Anyway, let’s get started.&lt;/p&gt;

&lt;p&gt;As for how I built it, some prerequisites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PyCharm or any IDE&lt;/li&gt;
&lt;li&gt;Python 3.0+&lt;/li&gt;
&lt;li&gt;AWS account (&lt;a href="https://aws.amazon.com/free/"&gt;free tier&lt;/a&gt; should suffice for testing)&lt;/li&gt;
&lt;li&gt;Basic understanding of Python/programming&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This post won’t go into every code snippet as you can find it on my GitHub (coming soon), but will walk through the steps I took to assemble the components needed.&lt;/p&gt;

&lt;h2&gt;Objective&lt;/h2&gt;

&lt;p&gt;Compare files in a local folder with the respective files in S3 and zip and upload the local file if the local file is later than the one on S3 (last modified date time)&lt;/p&gt;

&lt;h1&gt;Part 1&lt;/h1&gt;

&lt;p&gt;In Part 1 of implementing this, we will simply go over how to connect to S3 via Python and how to get the last modified date time for a later comparison.&lt;/p&gt;

&lt;p&gt;So, we’ll go through the snippets for these steps and/or you can skip all of this and just check out the code on GitHub (coming soon).&lt;/p&gt;

&lt;h2&gt;Connecting to S3&lt;/h2&gt;

&lt;p&gt;How to connect to AWS S3? Fortunately, AWS offers a SDK for Python called boto3, so you simply need to install this module and then import it into your script.&lt;/p&gt;

&lt;p&gt;I am using Python 3.7 and pip3 so my command was &lt;code&gt;pip3 install boto3&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Import the following:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;
&lt;h1&gt;
  
  
  import AWS modules
&lt;/h1&gt;

&lt;p&gt;import boto3&lt;br&gt;
import logging&lt;br&gt;
from botocore.exceptions import ClientError&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You also need to install the aws cli module (AWS command line interface) so go ahead and do that with a &lt;code&gt;pip3 install aws cli&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Now, you will need to configure this aws cli tool to connect to your AWS account, so you should have an IAM user and group for the cli. Go to the IAM service in your AWS console to create that. &lt;/p&gt;

&lt;h3&gt;Creating IAM User and Group for AWS CLI&lt;/h3&gt;

&lt;p&gt;First, create a Group and attach the AdministratorAccess policy. Then, create a User and assign the User to the Group you just created. Continue to the end of the wizard and eventually, you will see a button to download a CSV which will contain your credentials. These will be the credentials you use to configure your aws cli.&lt;/p&gt;

&lt;p&gt;Have the Access Key ID and Secret Access Key ready and in your Terminal, type &lt;code&gt;aws configure&lt;/code&gt;. You will then be asked for the Key ID and Access Key so simply paste the values from the CSV. You will also be asked for region name (input the region where your S3 buckets are). The last input field asks for output format (you can just press Enter).&lt;/p&gt;

&lt;p&gt;Great! Now, your aws cli should be configured to connect to your AWS S3 bucket(s).&lt;/p&gt;

&lt;h3&gt;Create S3 Client and Resource&lt;/h3&gt;

&lt;p&gt;So, next we need to create a client and a resource for accessing S3 methods (the client and resource offer different methods based on usage, you can read more &lt;a href="https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#s3"&gt;here&lt;/a&gt;).&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;
&lt;h1&gt;
  
  
  CREATE CLIENT AND RESOURCE FOR S3
&lt;/h1&gt;

&lt;p&gt;s3Client = boto3.client('s3')&lt;br&gt;
s3Resource = boto3.resource('s3')&lt;/p&gt;
&lt;h1&gt;
  
  
  object for all s3 buckets
&lt;/h1&gt;

&lt;p&gt;bucket_name = '' # NAME OF BUCKET GOES HERE, HARD CODED FOR NOW&lt;/p&gt;
&lt;h1&gt;
  
  
  CREATE BUCKET OBJECT FOR THE BUCKET OF CHOICE
&lt;/h1&gt;

&lt;p&gt;bucket = s3Resource.Bucket(bucket_name)&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;h2&gt;Retrieve object's last modified date time (upload time)&lt;/h2&gt;

&lt;p&gt;Ok, so what needs to be done to retrieve an object’s last modified date time?&lt;/p&gt;

&lt;p&gt;I’ve written a method to loop through the objects in a bucket and call an AWS method to get the last modified time, shown below (yes, this can be written other ways as well).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;bucket.objects.all()&lt;/code&gt; returns a Collection which you can iterate through (read more on Collections &lt;a href="https://boto3.amazonaws.com/v1/documentation/api/latest/guide/collections.html"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;So you can see I began looping through that and only calling the &lt;b&gt;last_modified&lt;/b&gt; method if the S3 object contained Logic_Projects and .zip in the key name. &lt;/p&gt;

&lt;p&gt;If you’re not familiar, the key is simply how S3 identifies an Object. I am looking for Logic_Projects because I made a folder with that name and am also checking for .zip just in case I upload something else in the folder by accident (but this script will only upload zips to that folder, so it’s just a safety check).&lt;/p&gt;

&lt;p&gt;If it passes those checks, then I proceed to the date time conversions. &lt;/p&gt;

&lt;p&gt;You’ll notice I am calling two other methods in this loop, called &lt;b&gt;utc_to_est&lt;/b&gt; and stamp_to_epoch before I finally return a value. That is to make datetime comparisons easier later on. The &lt;b&gt;last_modified&lt;/b&gt; method returns a date in UTC format so it could look like this: 2019-12-07 19:47:36+00:00. &lt;/p&gt;

&lt;p&gt;When I am comparing modification times, I’d rather just compare numbers. The date AWS returns is in UTC, also referred to as GMT (Greenwich Mean Time).&lt;/p&gt;

&lt;p&gt;So I added a function to convert this datetime to Eastern Standard Time, shown below:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now that we’re in the right timezone, I want to convert it to a number, so I converted it to an Epoch time, which is the number of seconds that have elapsed since 00:00:00 UTC on January 1, 1970 (Why Epoch time is this date is not in the scope of this post).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;OK, that's all for Part 1! In this post, we've &lt;b&gt;connected to AWS via Python (boto3)&lt;/b&gt; and we've created a method to &lt;b&gt;get the last modified time (in seconds since Epoch and in EST) of an object in S3.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;In Part 2, we will go over comparing the last modified time of a file in S3 with the last modified time of that file locally.&lt;/p&gt;

&lt;p&gt;This post also appears on Medium (link below).&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="https://medium.com/@nakulkurane/backing-up-my-logic-pro-projects-to-aws-s3-part-1-671d408dd39c?source=friends_link&amp;amp;amp;sk=a1330cb7d10d45f48226960f4a955b99" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NlbnTVhi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/fit/c/96/96/1%2AbXnbaQHEN3AzKSycH_-mHw%402x.jpeg" alt="Nakul Kurane"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://medium.com/@nakulkurane/backing-up-my-logic-pro-projects-to-aws-s3-part-1-671d408dd39c?source=friends_link&amp;amp;amp;sk=a1330cb7d10d45f48226960f4a955b99" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Backing Up My Logic Pro Projects to AWS S3 (Part 1) | by Nakul Kurane | Analytics Vidhya | Medium&lt;/h2&gt;
      &lt;h3&gt;Nakul Kurane ・ &lt;time&gt;Mar 2, 2020&lt;/time&gt; ・ 
      &lt;div class="ltag__link__servicename"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hnDHPsJs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/medium-f709f79cf29704f9f4c2a83f950b2964e95007a3e311b77f686915c71574fef2.svg" alt="Medium Logo"&gt;
        Medium
      &lt;/div&gt;
    &lt;/h3&gt;
&lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>python</category>
      <category>aws</category>
      <category>s3</category>
    </item>
    <item>
      <title>How to Execute a Cron Job on Mac with Crontab</title>
      <dc:creator>Nakul Kurane</dc:creator>
      <pubDate>Mon, 17 Feb 2020 17:17:13 +0000</pubDate>
      <link>https://dev.to/nakulkurane/how-to-execute-a-cron-job-on-mac-with-crontab-1mc6</link>
      <guid>https://dev.to/nakulkurane/how-to-execute-a-cron-job-on-mac-with-crontab-1mc6</guid>
      <description>&lt;h1&gt;Prologue&lt;/h1&gt;

&lt;p&gt;Before I write the steps below, I would recommend installing the latest version of Python with homebrew. &lt;a href="https://brew.sh/"&gt;Homebrew&lt;/a&gt; is a package manager just like pip and anaconda and frankly, I’m just using that in this example because I tried for hours to run a simple cron job to no avail. I frequently got errors about not being able to open the file I wanted to execute or not finding the installed python version. I won’t get into my errors in this post but you’re free to use any other Python installation if you like.&lt;/p&gt;

&lt;p&gt;I uninstalled my Python 3.x versions I had installed (via pip and conda) and started from scratch — uninstalling was also a hassle. So let’s say you’re on your Mac and have the default Python distribution which I believe should be 2.7.10. Few to no developers are updating modules in this version so when you’re building projects, it’s best to have the latest version of Python installed.&lt;/p&gt;

&lt;p&gt;I followed &lt;a href="https://realpython.com/installing-python/#step-2-install-homebrew-part-2"&gt;Real Python’s guide&lt;/a&gt; to install Python 3 via Homebrew (a quick few steps really) so I will assume you have done the same going forward in this post.&lt;/p&gt;

&lt;h1&gt;Steps&lt;/h1&gt;

&lt;p&gt;Open up your Terminal command prompt on your Mac and navigate to the home directory by running &lt;code&gt;cd ~/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For me, it is &lt;code&gt;Users/Nakul&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We will be using Mac OS’s in-built crontab feature to write our cron jobs.&lt;/p&gt;

&lt;p&gt;Type &lt;code&gt;crontab -e&lt;/code&gt; and press Enter.&lt;/p&gt;

&lt;p&gt;This should open up an empty file, this is where you will write your cron jobs. You can write the job to run a shell script or a Python script in this case.&lt;/p&gt;

&lt;p&gt;Type &lt;code&gt;:q!&lt;/code&gt; to exit the editor.&lt;/p&gt;

&lt;p&gt;Assuming you followed the Homebrew guide above, double check your Python installation path. You can do so by typing &lt;code&gt;which python3&lt;/code&gt; in your Terminal. It should display &lt;code&gt;/usr/local/bin/python3&lt;/code&gt; (which is an alias for the actual homebrew installation location but that’s fine, we won’t go into that right now). You will include this path in your cron job syntax, which we’ll get into.&lt;/p&gt;

&lt;p&gt;Before we write our cron job, we should have a script which we want to run.&lt;/p&gt;

&lt;p&gt;I’ve already created a directory &lt;code&gt;/Documents/Python/cron&lt;/code&gt; in my home directory and created a simple script called &lt;code&gt;cron_test.py&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: this Python script needs to be executable so change the permissions on it to allow for that, I just ran a chmod 777 cron_test.py&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;cron_test.py&lt;/code&gt; script simply creates a directory with the current date and time as the name.&lt;/p&gt;

&lt;p&gt;The script text is as follows if you want to use the same script:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;
&lt;h1&gt;
  
  
  !/usr/bin/python3
&lt;/h1&gt;

&lt;p&gt;from datetime import datetime&lt;br&gt;
import os&lt;br&gt;
sysDate = datetime.now()&lt;/p&gt;
&lt;h1&gt;
  
  
  convert system date to string
&lt;/h1&gt;

&lt;p&gt;curSysDate = (str(sysDate))&lt;/p&gt;
&lt;h1&gt;
  
  
  parse the date only from the string
&lt;/h1&gt;

&lt;p&gt;curDate = curSysDate[0:10]&lt;/p&gt;
&lt;h1&gt;
  
  
  parse the hour only from the string
&lt;/h1&gt;

&lt;p&gt;curHour = curSysDate[11:13]&lt;/p&gt;
&lt;h1&gt;
  
  
  parse the minutes only from the string
&lt;/h1&gt;

&lt;p&gt;curMin = curSysDate[14:16]&lt;/p&gt;
&lt;h1&gt;
  
  
  concatenate hour and minute with underscore
&lt;/h1&gt;

&lt;p&gt;curTime = curHour + ‘_’ + curMin&lt;/p&gt;
&lt;h1&gt;
  
  
  val for the folder name
&lt;/h1&gt;

&lt;p&gt;folderName = curDate + ‘_’ + curTime&lt;/p&gt;
&lt;h1&gt;
  
  
  make a directory
&lt;/h1&gt;

&lt;p&gt;os.mkdir(folderName)&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;You might wonder what that first line &lt;code&gt;#!/usr/bin/python3&lt;/code&gt; is. That line is referred to as a shebang and how the cron job will interpret the script so in this case it will run the cron_test.py with Python (as if you executed python &lt;code&gt;cron_test.py&lt;/code&gt; in your Terminal).&lt;/p&gt;

&lt;p&gt;Ok, so we have Python 3.x installed, we have a Python script, now let’s write the cron job to run this!&lt;/p&gt;

&lt;p&gt;Let’s say we want to run this script every minute (mostly for the purpose of testing on your end so you can see the results without waiting too long).&lt;/p&gt;

&lt;p&gt;The cron job syntax is as follows:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;*/1 * * * * cd ~/Documents/Python/cron &amp;amp;&amp;amp; /usr/local/bin/python3 cron_test.py &amp;gt;&amp;gt; ~/Documents/Python/cron/cron.txt 2&amp;gt;&amp;amp;1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;What does the above mean? Let’s analyze it quickly.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;*/1 * * * *&lt;/code&gt; simply means that the job will run every minute.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cd ~/Documents/Python/cron &amp;amp;&amp;amp; /usr/local/bin/python3&lt;/code&gt; navigates to the directory where the script you want to execute is located and specifies to use Python instead of Bash to execute (since it is a Python script, also remember that we added the shebang within the script, I found that it needed to be in both places to work).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cron_test.py&lt;/code&gt; is the script filename.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;gt;&amp;gt; ~/Documents/Python/cron/cron.txt&lt;/code&gt; specifies where to output the logs in case the execution of the job has any issues.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;2&amp;gt;&amp;amp;1&lt;/code&gt; simply disables email because by default, the cron job will try to send an email but we don’t have an address specified.&lt;/p&gt;

&lt;p&gt;Anyway, that should be enough to get you writing and testing your scripts, so go on!&lt;/p&gt;

&lt;p&gt;Feel free to browse the web to learn more about cron jobs and crontab. I decided to write this for those who have a fundamental understanding of programming and wanted to write a cron job as soon as possible.&lt;/p&gt;

&lt;p&gt;Hope this helped; go write some jobs!&lt;br&gt;
Find me on the web:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/nakulkurane/"&gt;Follow on LinkedIn&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>cron</category>
      <category>mac</category>
      <category>crontab</category>
    </item>
  </channel>
</rss>
