James Walker

James Walker

Web Developer

ipm dev blog, Part 1 – Documenting a side project

Published on Thursday October 12 2017 at 18:05 in ipm dev blog

This week I started a new side project to streamline my daily development workflow. Provisionally known as ipm, this Python-based utility is designed to offer centralised project generation, build, distribution and deployment capabilities for web and desktop-based software projects. I intend to document my progress and design decisions on the project on a weekly basis, in part for public use but also to force me to reflect on what I'm doing and why. Progress each week is likely to be relatively slow, since I don't have much time to work on the project, and the scope is still somewhat fluid, but I intend to continue this series up until I build the v0.1.0 ipm distribution package. The entire project is open-source under the MIT License and will be published on GitHub once v0.1.0 is reached.

Introduction

The name "ipm" can be interpreted either as Ilmiont Project Manager, Ilmiont Package Manager, or Ilmiont Programming Manager, depending on its usage and application. It's anticipated more roles, and possible acronym interpretations, will be added over time as the software's scope grows.

The project is being designed to consolidate my myriad selection of per-project and global development environment scripts, build files and code file snippets into a centralised location that makes my development process more efficient. It will offer project generation and distribution capabilities for other code, development and general software projects and will be extensible with add-on scripts and templates which form the majority of its main functionality.

The app is intended to simplify development tasks, such as the creation of new source files from templates, deployment of projects to development servers and generation of distributable project files. The true possibilities of ipm are intended to be open and virtually endless since the software is really just a basic script wrapper layer that offers local per-project access to centralised development workflow scripts. It is enabled per-project and uses in-project files to identify directories that are registered with ipm.

Design Requirements

Main Flow

  1. Instantiate the app
  2. Get the directory being called from
  3. Check whether an ipm file exists, if not, abort
  4. Load the ipm file so the project details are now known
  5. Process the command line arguments
  6. Run the command corresponding to the first argument, passing the remaining arguments

Implementation so far

I've so far just established the basic structure and architecture for the project, initialising a few core files. In the top-level of the project's directory, I currently have app.py to store application global variables and ipm.py which is the entrypoint for the application. It gets a new application instance and establishes the current working directory and command line arguments. It's accompanied by main.py, not yet implemented, which will house the main runtime logic used to select and call different registered ipm commands depending on the user input.

ipm.py:

import os, sys
import main, pfile

#'''
#CLASS ipm()
#Main ipm runtime class.
#'''
class ipm():

#'''
#FUNCTION ipm.__init__(self, wd=None, args_cli=None)
#App instantiation, with the working directory and CLI arguments .
#'''
def __init__(self, wd=None, args_cli=None):
#Set up class vars
self.wd = None # App working directory
self.args_cli = None # Arguments from CLI
self.project = None # To hold project definition

#Initialise the app if passed args
if wd and args_cli:
self.init(wd, args_cli)

#'''
#FUNCTION ipm.init(self, wd, args_cli)
#Initialise the app instance for the working directory and CLI arguments .
#'''
def init(self, wd, args_cli):
#Assign class vars
self.wd = wd
self.args_cli = args_cli

#Check ipm is initialised in the directory
if pfile.project_file_exists(self.wd) != True:
sys.exit("ipm aborting: ipm file not found.")

#'''
#FUNCTION ipm.main(self, wd, args_cli)
#App main runtime.
#'''
def main(self, wd, args_cli):
#Initialise the app
self.init(wd, args_cli)
self.project = pfile.load(wd)

if len(args_cli) == 0:
sys.exit("ipm aborting: no command specified.")
else:
command = args_cli[0]
command_args = args_cli[1:]

#Load the main runtime
applet = main.runtime(command, command_args)

#=== MAIN RUNTIME ===#
if __name__ == "__main__":
IPM = ipm()
IPM.main(os.getcwd(), sys.argv[1:])

Another module that already exists is pfile.py, which houses methods related to ipm project file (.ipm) handling. Currently there are only two methods, but you can see they are being used in ipm.py already.

pfile.py:

import json, os

#'''
#FUNCTION load(wd)
#Loads the project file from the location .
#'''
def load(wd):
file = wd + os.sep + ".ipm"
with open(file, "r") as file_handle:
return json.loads(file_handle.read())

#'''
#FUNCTION project_file_exists(wd)
#Checks whether an ipm project file exists in the location .
#'''
def project_file_exists(wd):
return os.path.exists(wd + os.sep + ".ipm")

With this basic architecture in process, I now have a starting point to begin implementing the app's features and expanding its scope.

Next Steps

I next intend to implement the main runtime loop so the app can determine and run different commands depending on the user's input. This will be my focus for the next week. Then I'll begin to look at what the ipm project file should contain, before creating the addon/extension/script structure that allows commands to be created and registered with the app. You should be able to come back next week for the next update in this dev blog series!