Bartek Lipinski

@blipinsk

Why writing open-source is so beneficial.

A story of a one-hour side project that took half of the night.

Easy! That sounds like AT MOST hour worth of work!

That’s how it all started.

Fast-forward half of the night later, I am figuring out how to upload a library snapshot for every single of my 22 commits in the repository.

Story background.

Okay, let’s back up a little.

Ever heard of ExoPlayer? That’s a pretty awesome player library from Google. Yes, the one that has a demo app, which used to be able to play Youtube videos in background (anyone paying for YouTube Red for that feature 😉?).

When Google developers released ExoPlayer 2.x.x they thought about releasing ExoPlayer 2 with a different package name, but they seemed to forgot to change the artifactId of the published snapshot. All this made it:

  1. Possible to use ExoPlayer 1 and 2 side by side (for the time of migrating to the newer version).
  2. Impossible to import both ExoPlayer 1.x.x and ExoPlayer 2.x.x at the same time 😐. So you can’t do this:
compile ‘com.google.android.exoplayer:exoplayer:r1.3.1’
compile ‘com.google.android.exoplayer:exoplayer:r2.5.3’

Even though the code inside those two dependencies is shipped in two different packages (com.google.android.exoplayer1 and com.google.android.exoplayer2 respectively).

One of the apps I was working on back in the day (it happened ~10 months ago), was using ExoPlayer 1. I really wanted to migrate it to ExoPlayer 2 in as small code increments as possible (that’s a pretty big app). I didn’t want to migrate it all at once.

I thought:

That’s actually pretty easy to fix. In the end Google did release ExoPlayer 2 under a different package. So there isn’t any work to be done with the code. I will just create my own “library” that will repack the original code, without any additions of mine and will release it under a different artifactId.
Easy! That sounds like AT MOST hour worth of work!

So I started doing that… but in a very typical manner to me, in the middle of work I thought:

Well, if I need that, someone else might need it as well. And I can’t really be sure that the other person is using exactly the same version of ExoPlayer 1, that I’m migrating from. I need to create snapshots from every released ExoPlayer 1 versions…

The manual beginnings.

I created a library project with ExoPlayer dependency + a sample project to test if that works. The sample project was depending on the library project and on the official artifact of ExoPlayer 2. Everything was running nicely in parallel. I had a nicely repackaged ExoPlayer 1 at my hands.

I decided to go for a very simple git structure for that: just one branch, one commit for every single ExoPlayer 1 version. This means 22 commits in the entire repo (23 right now).

Let me tell you upfront one thing. I’m not a git master. I learn more and more about it, but I don’t know every possible command. Bare that in mind reading further…

So I started adding commits.

  1. I uploaded the version to Bintray.
  2. Made the Initial commit.
  3. Added a git tag r1.3.1 in the repo.

Then I moved forward.

  1. Code changed to r1.3.2.
  2. Upload to Bintray.
  3. New commit: Version r.1.3.2.
  4. Added a git tag r1.3.1 in the repo.

The beginning of issues.

Then I repeated the same steps for 4 or 5 more versions. Groundhog Day… Until I spotted the issue with the naming of my commits. Did you spot the extra . after the r? Yea, I didn’t make a mistake here writing the story… I did it back then when I was committing my changes.

I could keep it the way it was and just make sure the next commits were correct, but I thought:

Those are just few commits, let’s correct that and make the repo clean and sweeeeet.

Thank god I’m relatively familiar with git rebase -i. I quickly changed the wrong names. No problem… until I spotted that I lost my tags on the way.

Alright, no problem, let’s just re-tag those commits.

I did that as well. I needed to be sure the next commits are correct. I started looking into a way of “automating” the commit name. The commit template was the simplest and perfectly fine solution for my case.

I created a simple Version r1. template and added it to /.git/config of the repo.

[commit]
template = /path/to/my/simple/template.txt

As long as I was able to think just a little bit while committing, this solution made sure my future commits were following the same rule.

After that it really felt like I got it under control. Although I did some work I could’ve avoided (rebasing and re-tagging), overall I wasn’t that far off my initial time-schedule for this “library”.

The approach change.

I actually finished manually adding all 22 commits… I know, right?

Then I saw that I messed up something in my Initial commit… Messed up big time.

Apparently the aar library will not be bundled within another aar simply by adding it to the dependencies. Something I didn’t know back then. Somehow the the sample project was working correctly, but the assembled aar did not include ExoPlayer 1.

😐 🔫

That’s exactly what I thought about the whole thing. I knew I had to:

  1. Correct the Initial commit.
  2. Re-upload library snapshots of every single version.
  3. Re-tag everything.

The first step didn’t worry me that much. I found the solution fairly quickly. It was something called a “fat-aar”. Thankfully, it wasn’t that difficult to create. This solved the issue and made it work correctly.

I knew I had to find some other solutions for steps 2. and 3.

I couldn’t do it manually once again, because I knew that in the end, the “library” wouldn’t be shipped at all. I was too lazy for all the manual work. I knew that if I had to do it the third time (if something goes wrong again), I would throw my laptop through the window.

You need to be at least a little lazy to be a good developer…

Uploading library snapshots

I had to figure out that first. If after fixing the Initial commit there’s something wrong with any of the uploads, I will lose tags once again (when correcting the base code again).

I was using a script for Bintray uploading. It was as simple as running a terminal command. “Simple” if you didn’t have to do that 22 times. In that case instead of “simple” it becomes “simply annoying”.

Fortunately, I quickly found out that you can run a terminal command for commits using git rebase -i using x option.

At this point even using git rebase -i and adding command to be run on commits was too much of work. Thankfully, you can also use a non-interactive version of rebase with a handy --root parameter that will perform the same operation on every single commit until it reaches the root. That was exactly what I needed:

git rebase -x "./gradlew clean bintrayUpload" --root

A moment later everything was done. I wish I knew that when I was adding commits initially.

Adding git tags

This was a bit more difficult. I needed the commit message information. I needed something that will give me a formatted version of the commit body. After a quick “googling session”, I came up with this:

git log -1 --pretty=format:”%B”

This gave me the body of the current commit (e.g. Version r1.3.2). I just had to trim first 8 characters (I wanted a simple r1.X.Y tags).

Apart from that I needed a commit hash to add the tag (Not really sure why though… I should be able to add tags to the current commit… nvm).

git log -1 --pretty=format:”%h”

Those two commands in a simple bash script:

#!/bin/bash
messageName=$(git log -1 --pretty=format:"%B")
shortHash=$(git log -1 --pretty=format:"%h")
if [ "$messageName" = "Initial commit" ]; then
tagName="r1.3.1"
else
tagName=${messageName:8}
fi;
git tag $tagName $shortHash

and I could simply use git rebase -x "script.sh" --root once again.

Few seconds later… all tags are added. I wish I knew that before, as well.

Final thoughts.

Reading the story once again, I feel like the most time-consuming part of the process, seems like something I just went through easily. Well, it wasn’t like that. I actually spent most of the time trying to figure out how to upload 22 snapshots and how to tag all commits automatically. Let’s be clear on that.

Although I spent a good portion of my evening googling and testing different solutions for what I needed, I don’t look at all this time as “wasted”.

Initially I thought that essentially it was a simple project of uploading a library with a single dependency.

I ended up learning in the process:

  1. What a “fat-aar” was.
  2. How to use a commit template with a git repository.
  3. How to use git rebase -x "cmd".
  4. How to rebase all commits until the --root.
  5. How to format git log output.
  6. How to substring in bash.

Those are 6 things I would not be “exposed” to, if I didn’t decide to write the library.

A large portion of what I had to do, was caused by the fact that I didn’t want to ship the library inelegant (not to say “imperfect”). I wanted to keep the repo as clean as possible.

Although I was aware that nobody would see how much work went into this project, subconsciously I knew it was a representation of how neat and elegant I can keep my repository while working.

That’s the thing with open-source: it exposes your skills to the world. On one hand it can make you feel uncomfortable and vulnerable. On the other: it creates pressure to do better and forces you to improve as you ship stuff. With better quality you gain more audience for what you do. The greater audience you get, the bigger the expectations for more products and their quality.

All this is just like using an automatic wristwatch. With few movements of your wrist, you can make the watch run for days.

The perpetuum-mobile of self-improvement.

If you enjoyed this post, please show your support! Clap, follow, comment, share.

This really means a lot!

More by Bartek Lipinski

Topics of interest

More Related Stories