Half-Elf on Tech

Thoughts From a Professional Lesbian

Category: How To

  • Porting Jekyll to Hugo

    Porting Jekyll to Hugo

    Importing content is always the bane of moving systems.

    Now one of the things Hugo has is a cool command called $ hugo import jekyll – and yes, it does exactly what you think it does. This was interesting to me since I wondered if I could switch my library from Jekyll to Hugo and yes, yes I can.

    The site I have on Jekyll has a few more posts than the first one I built on Hugo. This one has around 1500 pages. Excited, I ran the command:

    Importing...
    Congratulations! 0 posts imported!
    

    That’s not right. I spent a few hours trying to run it in various permutations, but I was never able to get it to run right. Thankfully, I didn’t need to since I could just copy my content over. There was no translation needed, as I was already using yaml headers in my .md files so that actually was a pretty painless transition.

    The theme on the other hand… Well. I had a complex site with data files and weird junk being thrown around. That was just learning how to translate for-loops for ranges, with some where clauses tossed in.

    Was it hard? Yes. But that’s not what you’re really asking.

    Was it worth it?

    Excuse me while I whip this out:

    Change detected, rebuilding site
    2015-12-11 21:42 -0800
    0 draft content
    0 future content
    1479 pages created
    0 paginator pages created
    16 categories created
    66 tags created
    in 4611 ms
    

    Yes. The site builds faster, which is a win. It also creates tags and categories that can automatically cross link. I can make ‘sections’ without having to define them in my config file, just by making folders. I can spin up templates quickly. I have a little more redundancy than I’d like, but as I master GoLang, this becomes less and less.

    Build time ranges from 11737 ms to 2116 ms. Milliseconds. They were into the minutes with Jekyll, even though Jekyll 3 was notably faster than version 2. It was still taking me about 2 minutes to rebuild the Jekyll site, even with incremental builds working. Plus I had to build and rsync every time, in addition to Git pushing. Now I just Git and done.

    Oh and JSON works remotely out of the box. I just have to get better at my range calls now.

    What’s Different?

    Making a ‘static front page’ with Hugo is harder. In fact there’s still an open trac ticket on it. I was able to use an idea I already had, a custom post param called “type” for tagging ‘index’ posts in the news pages so I didn’t get a list of my indexes when I wanted to list all news from 2002. I leveraged that and tagged my primary index ‘mainindex’ and put a quick check in my index.html in my theme:

    {{ range .Data.Pages }}
        {{if eq .Type "mainindex" }} 
            {{ partial "content.html" . }}
        {{end}}
    {{ end }}
    

    Instead of doing a normal loop where, like a blog it shows me posts in reverse order, it just showed that specific content.

    But…

    If there’s a file in that Section with the type of ‘Index’ then it shows that. Of course… While index.md doesn’t get used in the main content folder, it does in Sections. If I have a file named index.md in a section, that makes index.html like I expected. Since I still wanted lists in the majority of cases, I tweaked the content of my default list file (list.html) so that I could always show a ‘main’ file:

        {{ range .Data.Pages.ByTitle }}
            {{ if eq .Type "index" }}
                {{ .Content }}
            {{ end }}
        {{ end }}
    
        <ul>
        {{ range .Data.Pages.ByTitle }}
            {{ if ne .Type "index" }}
                <li><a href="{{ .Permalink }}">{{ .Title }}</a></li>
            {{ end }}
        {{ end }}
        </ul>
    

    Then I renamed all the index.md files in the Sections to main.md but this created another issue. Now I had two URLs that worked. I could have put this into the template for the section to avoid this, but I want to separate content and theme as much as humanly possible. WordPress habits. For now, I’ve left this alone. If someone is clever enough to go to a non-linked, non-sitemaped page instead of the index, I think my SEO will live. It’s more than I wanted to play around with loops.

    Speaking of the loops and lists, getting a list of a ‘sub section’ is not currently possible either. Rather, they do work, but there’s no default templates for sub-sections. This was a small problem since I structured my site like this:

    .
    └── content
        ├── news
        |   ├── index.md          // /news/
        |   ├── 2001
        |   |   ├── loch-ness.md  // /news/2001/loch-ness/
        |   |   └── monster.md    // /news/2001/monster/
        |   └── 2002
        |       ├── nessie.md     // /news/2002/nessie/
        |       └── spock.md      // /news/2002/spock/
        └── posts
    

    Now, I don’t need a custom template for each sub-section, but I did want to use my custom list template for each sub-section. To work around this, I made a template in /layout/section/news.html that had this:

    	{{ range .Data.Pages.ByTitle }}
    		{{ if and (eq .Type "index") (ne .Params.topic "index") }}
    			{{ .Content }}
    		{{ end }}
    	{{ end }}
    

    I know this is weird. The Type of index means “I am the main index file of the section” while the topic index means “I am an indexing file and not a normal news article. This gives me my main index of /news/ giving me a custom content page with information like I wanted, using the main.md format I use in all sections.

    Then in each sub-section, I use a very simple index.md file:

    ---
    title: News Articles (1992)
    author: Mika Epstein
    layout: news
    topic: index
    date: 1992-01-01
    permalink: /news/1992/
    categories: ["News"]
    tags: ["1992"]
    ---
    
    {{< news >}}
    

    That weird bit in the content is a shortcode ala Hugo, which calls the file /layouts/shortcode/news.html that has this:

    {{ $date := $.Page.Date.Format "2006" }}
    
    <table class="infobox">
    
        <thead><tr>
            <th>Date</th>
            <th>Source</th>
        </tr></thead>
    
        <tbody>
        {{ range where $.Page.Site.Pages.ByDate "Section" "news" }}
            {{ $thisdate := .Date.Format "2006" }}
    
            {{ if and (eq $date $thisdate) (ne .Params.topic "index") }}
    
                <tr>
                    <td>{{ .Date.Format "01 January" }}</td>
                    <td><a href="{{ .Permalink }}">{{ .Title }}</a></td>
                </tr>
    
            {{ end }}
        {{ end }}
        </tbody>
    </table>
    

    That spits out a table of all the pages in that section by date.

    What’s Next?

    It took a lot to get here, or so it may seem. This took me two nights to work out. That’s it. So now I have to figure out the next steps that have vexed me:

    1. How do I properly mimic a for-loop with range?
    2. Can I make a responsive gallery out of Hugo?
    3. Can I power a Hugo site with WordPress JSON?

    And that’s a whole ‘nother story.

  • Deploying with Hugo

    Deploying with Hugo

    One of my headaches with Jeykll was the deployment. It wasn’t until I found Octopress that I had any success. Hugo wants you to use Wrecker for automated deployment. I don’t want to since I don’t host on GitHub.

    Deploying (v1)

    The first method I could use is a script like I have with Octopress, which runs an rsync, but instead I went with a git post-update hook:

    GIT_REPO=$HOME/repositories/my-repo.git
    TMP_GIT_CLONE=$HOME/tmp/my-repo
    PUBLIC_WWW=$HOME/public_html/
    
    git clone $GIT_REPO $TMP_GIT_CLONE
    rm -rf $PUBLIC_WWW/*
    cp -r $TMP_GIT_CLONE/public/* $PUBLIC_WWW
    rm -Rf $TMP_GIT_CLONE
    exit
    

    And that copies things over nice and fast. I could do this for Jekyll as well, since now I’m version controlling my site content (in public) as well as my source code. There are downsides to this. I don’t want to sync my site folder. It’s going to get very large and messy and annoying.

    The workaround for Jekyll people is to install on the server and that didn’t work for me.

    Install on the Server

    But Wait! There’s More!

    I actually like Hugo better than Jekyll,. It feels slicker and faster and more … app like. Also since it’s not Ruby, I was able to install it properly on my server. Yes, unlike Ruby which was a crime, GoLang was incredibly easy to install on CentOS 6.

    First install Go and it’s dependancies:

    $ yum install golang
    $ yum install hg
    

    Now install Hugo. No you can’t yum it up:

    $ export GOPATH=/usr/local/go
    $ go get -v github.com/spf13/hugo
    

    This puts it in /usr/local/go/bin/hugo and I can run Hugo commands natively.

    Which brings me to …

    Deployment (v2)

    Change the aforementioned script to this:

    GIT_REPO=$HOME/repositories/my-repo.git
    TMP_GIT_CLONE=$HOME/tmp/my-repo
    PUBLIC_WWW=$HOME/public_html/
    
    git clone $GIT_REPO $TMP_GIT_CLONE
    /usr/local/go/bin/hugo -s $TMP_GIT_CLONE -d $PUBLIC_WWW 
    rm -Rf $TMP_GIT_CLONE
    exit
    

    Works perfectly. Unlike Ruby which is just a brat.

    Now the Magic

    When I’m ready to write a new post, I can locally spin up my hugo site with hugo server, write my post, make sure it looks nice, and then commit my changes to git and push.

    cd ~/Development/my-repos/hugo-site/
    hugo new content/some-file.md
    vi content/some-file.md
    git add content/some-file.md
    git commit -m "revised some-file"
    git push deploy master
    

    And it all works.

    Massive hattip to Andrew Codispiti for detailing his work which made mine easier.

  • One Direction: Sanely

    One Direction: Sanely

    In my ongoing saga of moving from MediaWiki to Jekyll, I decided to be smart and rename all my URLs.

    Stop.

    I know that’s the worst thing you can do. Please put down the pitchforks. I didn’t do this without redirections and I didn’t do it without deep thought. You see, the issue with MediaWiki is that it was a pretty flat file representation of the site. This doesn’t have to be the case. You can choose to put pages as sub-pages on MediaWiki very easily, but few people do. I didn’t. That means I had around 1000 pages that, in Jekyll land, would all be in one folder. And that sucked. Like I mentioned before, I made Collections.

    This meant I was moving from example.com/PAGE to example.com/folder/PAGE/ (and yes, the backslash matters, MediaWiki doesn’t do that). Now, from a structural standpoint, this makes a lot more sense. You want to have a collection of interviews, you have example.com/interviews/year/interviewname/ and that’s ridiculously easy to understand. But. When you’re moving from no structure to some structure, you have to accept a bit of a loss.

    So here’s how to redirect sanely:

    1. Make a list of what has a direct relation to a new page
    2. Look at your page visits to see what’s hit the most and make sure that’s redirected
    3. Have a catch-all at the end

    That’s it! Three simple steps to do it. But how did I do it?

    On the Wiki, I had a whole subsection called “Encyclopedia” which had all my internal documents like the about page, the policy pages, and so on and so forth. Those were all moved to the WordPress blog. Most had a new page, but the category itself did not so I added this the .htaccess in root:

    Redirect 301 /wiki/Category:Wiki /
    Redirect 301 /wiki/Encyclopedia:About /about/
    Redirect 301 /wiki/Encyclopedia:Policy /policy/
    RewriteRule ^wiki/Encyclopedia:Copy(.*)$  /copyrights/   [L,R=301]
    RewriteRule ^wiki/Encyclopedia:Terms(.*)$ /terms-of-use/ [L,R=301]
    RewriteRule ^wiki/Encyclopedia:(.*)isclaimer /disclaimer/ [L,R=301]
    

    That’s all incredibly straightforward for .htaccess rules. The first three are one-to-one direct links and the last three are with variables to handle URL strings like “Terms_Of_Use” and “Terms_of_use”, both of which were Wiki-forwarded to the correct “Terms of Use.” Similarly, I wanted to redirect “General_Disclaimer” and “Disclaimer” to one page, simplifying things.

    This pattern of one-to-ones continued on through my .htaccess. Pages that I could link like that I did. But then I hit on a couple big sections, the Interviews and News Articles. Those I had, for years, broken apart into pages by year. So I cleverly used tricks remembered from changing my WordPress date permalinks to do this:

    Redirect 301 /wiki/Interviews /library/transcript/
    RewriteRule ^wiki/Interviews_\((.*)\)$ /library/transcript/$1 [L,R=301]
    RedirectMatch 301 /wiki/(News|News_Articles) /library/news/
    RewriteRule ^wiki/News_Articles_\((.*)\)$ /library/news/$1 [L,R=301]
    

    The main URLs were directed to the new main locations, but the per-year ones were sent, logically, to their new year locations. But that was the easy part. When I moved things over, I got rid of ‘character’ pages (which I had only sporadically updated anyway) and I wanted to combine a lot of the redundant pages:

    RedirectMatch 301 /wiki/(The_West_Wing|West_Wing|west_wing|ww|Jed_Bartlett) /library/show/west-wing/
    RewriteRule ^wiki/The_West_Wing_\((.*)\)$ /library/show/west-wing-episodes/ [L,R=301]
    

    That’s starting to look a lot better. I did a lot of those. I tried to make them as dynamic as possible, but there were limits. In the end, I had about a dozen popular links I had to do manually. I don’t like that, but that’s the world I got myself into. I wanted to be able to redirect news and interviews to at the very least their year page, but as it turned out, I used the same naming conventions.

    Redirect 301 /wiki/Yahoo_News_(01_January_2000) /library/news/2000/yahoo-1/
    Redirect 301 /wiki/EOnline_(01_January_2011) /library/transcripts/2011/eonline-1/
    

    See the problem? There’s no way to really point those around. I played with a lot of options before I ran a search my recent traffic to see what pages were popular that people were going to in the /wiki/ folder and redirected them as best I could.

    Finally I had my fall back:

    RewriteRule ^wiki/(.*)$ /where-has-the-wiki-gone/ [L,R=301]
    

    This is the last rule. If anything gets through the others and down to this one, it sends them to a new page that explains where the wiki went and links to the popular pages.

    The most important thing to remember in all this is to put things in order. Your .htaccess is a top-down file. It starts at the top, it processes rules in order, until it’s done.

  • Jekyll Table of Contents

    Jekyll Table of Contents

    One of the cool things about MediaWiki, about the only thing I missed, was the built in table of contents display. With Jekyll, since this was a static sort of site, you would have to tell it ‘When you build this page, include a table of contents.’

    And I found a brilliant Jekyll plugin, Jekyll ToC Generator, that added in a beautiful jquery based table of contents with a click back to top feature. But there was a problem. When I installed it and ran a build to test it, my Jekyll site took nine times as long to build.

    In order to generate a Jekyll site, you run the command jekyll build and, on Jekyll 3.0, that gives you the output “done in 8.493 seconds” or so on. Now, if I do a full build on a site I’ve cleaned (there’s a clean command you can run to scrub the site and ensure you get a clean rebuild), it generally takes about a minute. That’s to build a thousand files with a lot of weird trickery. If I’m just rebuilding the changed files, it takes about 10 seconds. Much more reasonable.

    With the ToC Plugin, it took 98 to 100 seconds, every single time. Right away, I knew why. I had included a plugin that had to check every single page on the site on that rebuild, see if it needed a table of contents, and then build the page. Of course that took a long time!

    I’m always talking about needs and wants when I work on websites. It’s a basic principle my high school drilled into me. Understand what you need and how it’s different from your wants. Don’t compromise on needs. Well, I knew that I didn’t need a table of contents, not on every page, so it clearly had to be a ‘mostly want.’

    By contrast, having my site build quickly was a need. A fast build ensured less overhead, less weight, and less time spent. Time is a massive factor in websites. The rendered site has to be fast for users, this much is obvious to everyone. But having your build be fast means you, the site maintainer, spends less time on the parts that don’t make the site better, freeing you to develop and write.

    Also speed is something Jekyll wants to work on. The build different between the 2.3 version of Jeykll and the 3.0-pre beta, is incredible. In 2013, a site with “362 articles with 660 words in average” took around 10 minutes for a full build. I have double the articles, about the same amount of words, and it’s a minute for a full build. It’s faster on my faster laptop (duh).

    The decision tree for Jekyll is more obvious on build than the same one is for WordPress (or MediaWiki) on render. The basic concept is simple. The more complex your site, the longer it takes to generate pages. For WordPress (or MediaWiki, or Drupal, or Joomla, etc etc), the render happens when someone visits your site. For Jekyll and other static site generators, the render occurs when you build the site. That means with Jekyll I can see right away, before I get close to deployment, which means I make the decisions well before the ‘stage’ step of my deployment process.

    What’s more important? The complexities that make your site personal or a fast build?

    Here’s an example from a Jekyll discussion on the matter. Someone had the following code in the templates, which made the date output rather pretty:

    <span>{% assign d = page.date | date: "%d" | plus:'0' %}
        {{ page.date | date: "%B" }} 
        {% case d %}
            {% when 1 or 21 or 31 %}{{ d }}st
            {% when 2 or 22 %}{{ d }}nd
            {% when 3 or 23 %}{{ d }}rd
            {% else %}{{ d }}th
        {% endcase %}, 
        {{ page.date | date: "%Y" }}
    </span>
    

    But that had to run on page builds, which naturally was going to make a site slower. One of the ways Jekyll has improve this was to introduce incremental updates. Only update the pages that need updating. That is a big “baboom!” moment and it let me run the plugin jekyll-last-modified-at (which spits out a last modified date on pages) without any performance hit except on the clean build. Since that only gets called when a page is built, and a page is only built when it changes, it’s a massive improvement for me.

    What does all this have to do with the table of contents?

    Once I pushed it into a ‘want’ and not a ‘need’ I opened my mind to other possibilities. I stopped looking for a Jekyll or Ruby or Liquid based table of contents, and I asked myself “Can Markdown make a table of contents?”

    Markdown is a ‘language’ like HTML that is actually faster to write in than raw HTML but can be read, rendered, and output as HTML. I’m a big fan of HTML and part of why I picked WordPress back in the beginning was that I stumbled on a post where Matt Mullenweg talked about how he didn’t like bbCode and didn’t want it in WordPress. HTML was something we knew. Why make people learn something new?

    It wasn’t until I started blogging more on my iPad and phone that Markdown made sense. Now I’m quite the fan. But I knew that I didn’t know a whole lot about Markdown. I did know that Jekyll used a flavor called ‘kramdown’ (all lowercase) so I read up on that and found that kramdown has a built in built in table of contents generator that was incredibly easy to implement.

    * TOC will be output here
    {:toc}
    

    It’s not something I want (or need) on every page, so I just put that on a few pages. No real overhead added and it’s easy enough to style with CSS. Suddenly I have my cake and I can eat it too.

  • Deploy Jekyll Without Ruby

    Deploy Jekyll Without Ruby

    This is a bit of a lie. I do have Ruby, it’s just on my laptop.

    I don’t have it on my server, though. I have my git repo there, though. I could, but there are a couple reasons I don’t, and because I don’t, I can’t just run a jekyll build on my server. I’m not the only one with this particular issue. A lot of people on shared hosts can’t do it, for example. And people on cloud based tools can’t really either.

    Option one, which is very common, is what I have been doing. I added _site (the Jekyll output folder) to Git and I copy that over on a post commit hook. For what it was, that worked just fine. It only ran when I did a git commit, and if I wanted to work on a version I could totally do that in a branch, edit it, and bring it back in without accidentally deploying things.

    But option two would be rsync and that appealed to me more.

    I found the gem I was looking for eventually. It’s called (simply) Jekyll deploy and you add it to your Gemfile with this:

    group :jekyll_plugins do
      gem 'jekyll_deploy'
    end
    

    Then run the bundle command:

    $ bundle

    Now you have a new command called deploy which runs first a build and then it deploys based on the configuration options you put in. In my case it’s an rsync deploy, but you can do Git too. There was just one problem with it. The build every time made it such that my site would rebuild every time, which meant the rysnc would always be 100% new and that was more traffic than I really wanted.

    So I did what you always do here and I made a fork of Jekyll Deploy and changed my Gemfile to this:

    group :jekyll_plugins do
    	gem 'jekyll_deploy', :git => 'https://github.com/ipstenu/jekyll_deploy.git', :branch => 'develop'
    end
    

    Now my deploy only runs a deploy.

    A better solution would have been to put in some options and create jekyll deploy --build to allow me to run a build first, but I actually kind of like having them separate.

    The only question left was if I should keep _site under version control. I decided that I should, since the git repository would keep the file dates under control, assuring me that only the files I changed would be pushed with a deploy.

    I will note that the only reason it’s so simple for me is that I have passwordless SSH set up, where I don’t have to put in my passwords when I connect from a trusted computer. And since I only have this installed on a trusted server, and if I didn’t, I’d have to have a password to get access to the git repo anyway, I felt it was safe.

  • App Review: iStat Menus

    App Review: iStat Menus

    It’s a simple question. If the meeting is held at noon Pacific time, what time is it UTC? The answer is 1900 hours.

    The reason for the question is complicated. I work with people around the world. My family lives in a multitude of timezones, some across the date line. I travel a lot. I need to know when ‘now’ is, and I need to know when ‘now’ is for someone else all the time.

    Enter iStat Menus for Mac.

    It’s not actually meant for what I use it for. iStat Menus is to help you make a menu item on your Mac that shows you some interesting stats. I can see, at a glance, how strong my wifi really is, or my computer’s temperature (I’m on a MacBook Air, so this is important). I can look at how much memory I’m using to quickly see why things are slow. It gives me quick links to deep dive into things. It’s wonderful when I’m testing new apps and I can see that, yes that one is slow slow slow.

    An example of iStat Menu showing me my CPU details

    But the side benefit for me is how it replaces the Time and Date Menu in my Apple menu bar. When I click on the time, I get this:

    Time and Date menu replacement in my toolbar

    I get my month at a glance, a list of everything for today (including birthdays which I blocked out for you) and then it lists what time it is now in various place. If I hover over each time, I get more details including a Mercator map showing where daylight is right now and relative other places people care about. For $18 I’m able to keep track and know “Oh, maybe I shouldn’t ping someone on social media when it’s 2am for them…” For that alone it would be worth it, but the rest have become invaluable to debugging why my laptop was rebooting randomly.

    If you just need the basic stats, iStat Mini is pretty brilliant. And it’s free.