Categories
Programming

Easily Dockerize Node Apps

Quick script to Dockerize and tag your Node app with the current version number without having to dig through files for values. For me, this is important as I use Docker with EC2 and ECS on AWS. Using the project version number and name, from the project.json file, allows me to automagically tag the Docker image… which, in turn, allows me to easily deploy specific versions of the app or service for various release methods (blue/green, etc.).

First, the script itself …

#! /bin/bash

main() {

  local SCRIPT_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$(basename "${BASH_SOURCE[0]}")"
  local BASE_DIR=$(dirname $(dirname $(dirname $SCRIPT_PATH)))

  local PKG_NAME=$(node -p "require('$BASE_DIR/package.json').name")
  local PKG_VER=$(node -p "require('$BASE_DIR/package.json').version")
  local CMD="cd $BASE_DIR && docker build -t $PKG_NAME:$PKG_VER  ."

  eval "$CMD"
}

main

The last three lines or so is the good stuff …

  local PKG_NAME=$(node -p "require('$BASE_DIR/package.json').name")
  local PKG_VER=$(node -p "require('$BASE_DIR/package.json').version")
  local CMD="cd $BASE_DIR && docker build -t $PKG_NAME:$PKG_VER  ."

The first two lines load the Node package and version into variables PKG_NAME and PKG_VER. That last line creates a proper command for Docker …

docker build -t my-cool-app:1.2.3

And, finally, I call this from my package.json file …

{
  "name": "my-cool-app",
  "version": "1.2.3",
  "description": "My Cool App",
  "main": "src/server.js",
  "scripts": {
    "build": "./scripts/dev/build.sh"
  },
  "author": "Fred Lackey <fred.lackey@gmail.com>",
  "dependencies": {
    "cleaner-node": "^0.10.0",
    "express": "^4.17.1"
  }}
}

The end result is I am able to build my app into a Docker image by simply running …

npm run build

… with the result of having a Docker image built using the name and version of my app …

result example

… aaaand, a quick docker images shows it is available with the Node app and version as the Docker tag.

result images

I hope this helps.

Categories
Productivity Programming

Ugly Date & File Date Organizer

Photos, screenshots, audio recordings … there are countless files that are stored (or should be stored) with the event’s date in the name. And, as it becomes easier to create these, they accumulate at an ever-increasing rate… usually in one folder without any type of organization. Of course, we could take the time to organize those folders, move files into proper folders, and delete what we don’t … oh, nevermind. Who am I kidding? Nobody does that.

For me, one simple step to greatly improve the value of these files is to organize them by their event date. This would at least help me find them if I need them. Grouping all files from the same day would help narrow down what may be relevant to that specific time frame. Sadly, there is no magical command, or even a utility, that will do this easily. And, even if one exists, it surely won’t work on all of the machines I use.

Well, now there is! Enter File Date Organizer and Ugly Date!

Of course, I chose to write these two utilities using NodeJS to ensure I can use them on macOS, Windows, and Linux. That’s a no-brainer.

Writing File Date Organizer came to a screeching halt the moment I pulled in the first few files and noticed that every utility I use to create screenshots formats the file names with a completely different convention…

Screen Shot 2016-07-29 at 6.11.png
Screenshot 2014-09-07 13.36.45.png
Snapshot-3208-2016-10-11-08-31-16.JPG

Even worse was the error I received when I tried to use MomentJS (the de facto utility for untangling these odd formats) to untangle those formats…

Deprecation warning: value provided is not in a recognized ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info. After doing a bit of research, and seeing what options exist out there for detecting date formats, I understood why MomentJS decided to pull out their detection logic. Virtually every plugin or library out there uses basic RegEx (at best) to find four-digit years, two-digit minutes, or similar and fails miserably. They seem to all want so badly to return a value that they make assumptions along the way. In the end, most of them return bad values instead of no values at all… which, in my opinion, is the worst possible scenario. This is where Ugly Date comes into play.

Ugly Date is a bit of an experiment and takes a slightly different approach to parsing. Instead of simply using a series of RegEx patterns, Ugly Date contains groups of patterns and validators with the intent on locating possible matches, within the value, and then scores and compares those results with each other to return the best pattern versus returning any qualifying pattern. The change feels like a bit of a tradeoff. In the beginning, it will mean more maintenance and adding of patterns. However, over time, it should mean a better result when detecting more diverse patterns. Basically, you supply a string and Ugly Date parses it and returns both the date as well as a slew of potentially helpful information:

{
  "date": "2015-07-09T17:33:25.000Z",
  "hasDate": true,
  "hasDay": false,
  "hasTime": true,
  "pattern": "Screen Shot YYYY-MM-DD at hh.mm.ss a",
  "value": "Screen Shot 2015-07-09 at 1.33.25 PM",
  "values": {
    "YYYY": 2015,
    "MM": 7,
    "DD": 9,
    "h": 1,
    "mm": 33,
    "ss": 25,
    "aa": "PM"
  },
  "locations": [
    {
      "formal": "YYYY-MM-DD",
      "pattern": "YYYY-MM-DD",
      "position": 12,
      "type": "DATE",
      "value": "2015-07-09",
      "values": {
        "YYYY": 2015,
        "MM": 7,
        "DD": 9
      }
    },
    {
      "formal": "hh.mm.ss a",
      "pattern": "h:mm:ss aa",
      "position": 26,
      "type": "TIME",
      "value": "1.33.25 PM",
      "values": {
        "h": 1,
        "mm": 33,
        "ss": 25,
        "aa": "PM"
      }
    }
  ]
}

Unlike its sister, File Date Organizer is far simpler than Ugly Date. There’s really nothing magical happening under the hood. You supply the source & target folders, tell it if you want to move or copy, overwrite or ignore, and let it go. In turn, it uses the logic within Ugly Date to parse each file and move them into a folder structure with a property date hierarchy:

The command itself is fairly logical with many “either / or” type of choices. Other than the source and target folder paths, the rest is somewhat a la carte. The basic command…

file-date-organizer \
  --source "/Users/flackey/Documents/Screenshots" \
  --target "/Volumes/MPHD01/Screenshots" \
  --use-name \
  --move

…can be swapped out with several other options. For example…

--move or --copy
--ignore or --overwrite
--use-created or --use-modified (for filenames not having a date)

It will also build your target folder structure using almost any of the date sections by using various --add switches. For example, adding --add-second causes the entire folder structure to be built all the way down to the seconds in the date value (ie, /YYYY/MM/dd/HH/mm/ss). There is a full list of switches on the project page. And, of course, the library can be used programmatically by pulling it into a Node project.

Granted, none of this is a perfect solution. And, Ugly Date is taking a very different approach to parsing dates compared to more traditional libraries. If nothing else, this satisfied the anal-retentive side of my brain.

Categories
Programming

Cool Utility – Live Server

I just stumbled across one of those “it’s about time” utilities for front-end app development: Live Server. Long story short, you issue the command live-server from your application’s current directory and… well… that’s it. A browser pops open, your web app is loaded, and the lil’ utility watches for changes. Any changes that are made are instantly pushed to the browser.

Installation is ridiculously easy via NPM:

npm install -g live-server Of course, there’s a slew of command line switches and parameters to make even the geekiest geek happy:

--port=NUMBER – select port to use, default: PORT env var or 8080 --host=ADDRESS – select host address to bind to, default: IP env var or 0.0.0.0 (“any address”) --no-browser – suppress automatic web browser launching --browser=BROWSER – specify browser to use instead of system default --quiet | -q – suppress logging --verbose | -V – more logging (logs all requests, shows all listening IPv4 interfaces, etc.) --open=PATH – launch browser to PATH instead of server root --watch=PATH – comma-separated string of paths to exclusively watch for changes (default: watch everything) --ignore=PATH – comma-separated string of paths to ignore (anymatch-compatible definition) --ignorePattern=RGXP – Regular expression of files to ignore (ie .*.jade) (DEPRECATED in favor of --ignore) --middleware=PATH – path to .js file exporting a middleware function to add; can be a name without path nor extension to reference bundled middlewares in middleware folder --entry-file=PATH – serve this file (server root relative) in place of missing files (useful for single page apps) --mount=ROUTE:PATH – serve the paths contents under the defined route (multiple definitions possible) --spa – translate requests from /abc to /#/abc (handy for Single Page Apps) --wait=MILLISECONDS – (default 100ms) wait for all changes, before reloading --htpasswd=PATH – Enables http-auth expecting htpasswd file located at PATH --cors – Enables CORS for any origin (reflects request origin, requests with credentials are supported) --https=PATH – PATH to a HTTPS configuration module --proxy=ROUTE:URL – proxy all requests for ROUTE to URL --help | -h – display terse usage hint and exit --version | -v – display version and exit

If you’re building web-based apps, or even if you’re just starting out in web development, this little gem will save you a tonne of time up front.

Enjoy! =)