Kishore Vancheeshwaran
Resume in yaml and orgmode
100DaystoOffload resume orgmode plaintext

In my previous post we created the resume using orgmode. Although it was very versatile and friendly with version control, I noticed that I had trouble with blocks of text having tables like below where I had to mix in the latex and html settings along with the content which wasn’t very pretty with git diff.

* FirstName LastName
#+attr_html: :class mytable meta :rules all :border nil :cellspacing nil :cellpadding nil :frame nil
#+attr_latex: :align c|c|c|c
| [[mailto:email@gmail.com][email@gmail.com]] | [[https://linkedin.com/in/username][linkedin.com/in/username]] | +91-9876543210 | City, Country |
** Experience
*** Company 1
#+attr_html: :class mytable exp :rules nil :border nil :cellspacing nil :cellpadding nil :frame nil
#+attr_latex: :align L{0.27\textwidth}C{0.40\textwidth}R{0.25\textwidth}
| *Software Engineer* | *Company Inc.* | *Feb 2015 -- Present* |
| Software Team       | City           |                       |

In addition to that, to get anonymized resume reviews, I had to manually copy paste parts of the content into another org file and anonymize the relevant info before publishing it. I don’t find this to be that efficient use of my time. I ended up doing what the programmer stereotype does - automate this task of generating my resume which plays well with version control.

Yaml seemed to be the popular format which is (al)most human readable and easy to parse.

The gist of this automation is as follows.

  • Write resume in yaml
  • Parse yaml with python. Python code will have string snippets for org mode. Write this to an org file
  • Run emacs from the command line with a custom init set up and export to both html and pdf
  • Have a Makefile to automate all of this.

Seems straightforward enough.

Yaml structure

resume.yaml

name: Kishore Vancheeshwaran
contact:
  email: personal.email@gmail.com
  linkedin: linkedin.com/in/kishvanchee
  phone: +91-0000000000
  location: Bangalore, IN
experience:
  - company: Company 2
    position: Software Engineer
    team: Awesome
    start_date: Jan 2015
    location: Bangalore
    summary:
      - I did something awesome
      - I automated some work
  - company: Company 1
    position: Software Engineer
    team: Awesome
    start_date: Jan 2005
    to_date: Dec 2014
    location: Bangalore
    summary:
      - I did something awesome
      - I automated some work
technical_skills:
  languages: Python
  frameworks: Django
  databases: PostgreSQL
  dev_tools: Git
education:
  - degree: Fancy degree
    university: University of freedom
    from: Jul 2000
    to: Jun 2004

The yaml file is pretty self explanatory. You can have multiple experience/companies, multiple education entries, etc.

Here’s a a not so pretty but works python script which takes care of parsing the yaml and writing it to org file.

Now we have the Makefile which automates the entire process. The recent option is so that you can have your most recent work experience listed in your yaml but not the actual pdf/html. It will be prepopulated with I currently work here as the entry. This way you don’t have to worry about having two separate entries with one having a noexport in the org file or even having two separate org files for the same. I wanted this feature to avoid disclosing what I am currently working on in the current company unless it was necessary.

.PHONY: clean pdf anon recent html

all: clean pdf anon html

pdf:
	python generate_resume.py
	emacs resume_kishore.org --batch -f org-latex-export-to-pdf

html:
	python generate_resume.py
	emacs resume_kishore.org --batch -l custominit.el -f org-html-export-to-html

anon:
	python generate_resume.py -t anon
	emacs resume_anon.org --batch -f org-latex-export-to-pdf

recent:
	python generate_resume.py -t recent
	emacs resume_kishore.org --batch -f org-latex-export-to-pdf
	emacs resume_kishore.org --batch -l custominit.el -f org-html-export-to-html

clean:
	find . -maxdepth 1 ! -iname 'generate_resume.py' ! -iname 'resume.yaml' ! -iname 'Makefile' ! -iname 'latexTemplate.tex' ! -iname 'style.css' ! -iname 'custominit.el' -and -type f -exec rm "{}" \;

The custominit file is below. The file is necessary because -batch mode runs emacs with -q option which means without the default init file. Since we require only parts of the init file, we can have a custom file with the bare necessity to run the command.

;; This function is to run the eval without confirmation, at the top of the org
;; file to generate a link for the pdf file from the html file.
(defun org-confirm-babel-evaluate (lang body)
  (not (or (string= lang "python") )))
(setq org-confirm-babel-evaluate 'org-confirm-babel-evaluate)

(org-babel-do-load-languages 'org-babel-load-languages '((python . t)))

(defun my-org-inline-css-hook (exporter)
  "Insert custom inline css"
  (when (eq exporter 'html)
    (let* ((dir (ignore-errors (file-name-directory (buffer-file-name))))
           (path (concat dir "style.css"))
           (homestyle (or (null dir) (null (file-exists-p path))))
           (final (if homestyle "~/.emacs.d/org-style.css" path)))
      (setq org-html-head-include-default-style nil)
      (setq org-html-head (concat
                           "<style type=\"text/css\">\n"
                           "<!--/*--><![CDATA[/*><!--*/\n"
                           (with-temp-buffer
                             (insert-file-contents final)
                             (buffer-string))
                           "/*]]>*/-->\n"
                           "</style>\n")))))

(add-hook 'org-export-before-processing-hook 'my-org-inline-css-hook)

The style.css and latexTemplate.tex remain the same as in the previous post.

Phew, now we can run make and it automates the entire build. And we have perfect diffs.

If you would like to leave a comment, contact me via email.
Post 7/99 - part of 100DaystoOffload