Adding an Ubuntu Machine to a Windows Domain

If you run a Linux server alongside Windows servers long enough, you'll eventually have the need (or request) to add that machine to a Windows domain. Thankfully, it's a rather easy process. Assuming you run Ubuntu, you can simply run the following commands, substituting the domain and a domain admin in place of EXAMPLE.COM and jsmith, respectively.

  1. sudo apt-get install likewise-open
  2. sudo domainjoin-cli join EXAMPLE.COM jsmith
  3. sudo lwconfig AssumeDefaultDomain true

Out of the above lines, the first two are probably self-explanatory, but the third is likely a bit more opaque. After running the second line, our machine is on the domain, but domain logons need to be fully-qualifed. (e.g. EXAMPLE.COM\jsmith). This last line allows Likewise to accept just the username, by assuming that we are going to be using EXAMPLE.COM for domain logins.

With this complete, the only thing that is left is to give "Domain Admins" the ability to sudo. Otherwise, admins only have the ability to login, but not the ability to actually administer. On Windows, the name of the group to add would be "Domain Admins". To figure out the name for Linux, we convert to lower case and replace spaces with carets. Thus "Domain Admins" on Windows is "domain^admins" on Linux. With this knowledge in hand, we can allow sudo privileges.

With your favorite text editor1, add the following line to /etc/sudoers

%domain^admins   ALL=(ALL:ALL) ALL


1 Vim. Your favorite text editor is Vim.


MCEdit Surface Circle Filter

Glowstone Perimeter

Just wanted to share a quick MCEdit filter that I put together. Given a selection, this replaces the top layer of the perimeter circle with glowstone. On our server we use this to mark off private land borders so that people don't accidentally interfere with one another or set up camp on top of one another. Feel free to use it as you like.

  1. from pymclevel.materials import alphaMaterials
  2. import math
  4. displayName = "Player Boundary"
  6. inputs = (
  7. )
  9. replacableblocks = [
  10. alphaMaterials.Grass,
  11. alphaMaterials.Dirt,
  12. alphaMaterials.Stone,
  13. alphaMaterials.Sand,
  14. alphaMaterials.Gravel
  15. ]
  16. replacableIDs = [b.ID for b in replacableblocks]
  18. def replacable(block):
  19. return block in replacableIDs
  21. def borderblock(x, z, radius):
  22. distance = math.sqrt(math.pow(radius - x, 2) + math.pow(radius - z, 2))
  23. return math.fabs(radius - distance) < .5
  25. def replaceblock(level, box, x, z):
  26. x += box.minx
  27. z += box.minz
  28. for y in xrange(box.maxy, box.miny, -1):
  29. block = level.blockAt(x, y, z)
  30. if replacable(block):
  31. level.setBlockAt(x, y, z, alphaMaterials.Glowstone.ID)
  32. return y
  34. def perform(level, box, options):
  35. width = box.maxx - box.minx
  36. depth = box.maxz - box.minz
  37. radius = width / 2
  39. for x in xrange(width):
  40. for z in xrange(depth):
  41. if borderblock(x, z, radius):
  42. replaceblock(level, box, x, z)


Find All Issues Referenced in Commit Messages

Software is constantly changing. Bugs are fixed, features are added, performance is increased, and finally binaries are built. With this constant cycle of change come people wanting to know exactly what the changes are. Between major versions, and minor versions, we normally have release notes to give us this information. However, between release builds the list of items is in constant flux with no let up in the people wanting to know what the changes are. So, how do we fill these requests? How can we tell what issues have been addressed between two arbitrary branches? 1

For our purposes, we'll try to see what changed between Release/2.1 and RC/2.1/Candidate-8. Let's start by examining the commit log.

  1. git log RC/2.1/Candidate-8

commit 4e1a63c733507921ff7be480084106816a37c9fc
Author: John Doe <>
Date:   Fri May 17 13:49:14 2013 -0500
    OW-397: Added export functionality to the UI.

Now things are looking good: the log messages follow a defined format: "PROJECT-NUMBER: Brief description of the commit." If we modify the command slightly, we can filter the results to only show log entries that exist in one branch that dont exist in the other.

  1. git log origin/Release/2.1...origin/RC/2.1/Candidate-8

commit 4e1a63c733507921ff7be480084106816a37c9fc
Author: John Doe <>
Date:   Fri May 17 13:49:14 2013 -0500
    OW-397: Added export functionality to the UI.
commit 779e41d3881703a1f8ada527de5fbcc29dd1bba0
Author: John Smith <>
Date:   Wed May 15 15:38:40 2013 -0500
    OW-404: Reflect changes to the model in the sidebar.

This is great information for a human and follows a well defined format, but it isn't really kind to parsers. We can fix this by adding the argument --oneline to git log.

  1. git log origin/Release/2.1...origin/RC/2.1/Candidate-8 --oneline

4e1a63c OW-397: Added export functionality to the UI.
779e41d OW-404: Reflect changes to the model in the sidebar.

This new output always follows the format "hash, space, issue id, colon, message". Thus, the issue number will always be the first string matching "alphanum-num" after the hash. This can be expressed with the regex "^[A-F0-9]+ [A-Z0-9]+-[0-9]+".

At this point, we're going to call on another tool from our command line arsenal: grep. 2 Grep will take an input stream, allow us to search it with a pattern, and return matches to us. Normally grep performs a simple substring search and returns the entire line if there is a match. We're going to modify this behavior a bit by passing grep -i -o -E. The arguments tell it to ignore case, display only the matched portion of the line, and that we want to use a regex for parsing.

  1. git log origin/Release/2.1...origin/RC/2.1/Candidate-8 --pretty=oneline | \
  2. grep -i -o -E "^[A-F0-9]+ [A-Z0-9]+-[0-9]+"

4e1a63c OW-397
779e41d OW-404

Each line now follows the pattern "hash project-number". We can trim this down even more by passing each line to awk. We'll split each line on space and then take the second item by passing each line to awk -F " " '{print $2}'.

  1. git log origin/Release/2.1...origin/RC/2.1/Candidate-8 --pretty=oneline | \
  2. grep -i -o -E "^[A-F0-9]+ [A-Z0-9]+-[0-9]+" | awk -F" " '{print $2}'


At this point it looks like we've got the results that we want, with one important exception: duplicates. Since we're looking at each line individually, we'll see one mention for an issue in every commit it appears in. We'll finish up by cleaning the list with sort and uniq. This will sort all of the issues and then prune any consecutive duplicates from our list.

At this point, we have a quick little script to list all of the issues addressed between two commits.

  1. git log origin/Release/2.1...origin/RC/2.1/Candidate-8 --pretty=oneline | \
  2. grep -i -o -E "^[A-F0-9]+ [A-Z0-9]+-[0-9]+" | awk -F" " '{print $2}' | sort | uniq


1 Ideally the issue tracker would be fully authoritative, but sometimes that just isn't the case. Someone closes an issue prematurely or forgets to close it entirely. That, however, is an issue for another post.
2 All of the tools that we use in this post come preinstalled on Linux and Mac. On Windows they are provided with MSysGit, though they can be installed manually through Cygwin if desired.


Automating Git Branch Cleanup

I'm a huge fan of Git. Used properly, Git's branching system can be immensely powerful. In fact, it forms a core part of our engineering workflow at the office. By providing a healthy degree of isolation between different changes to the codebase, we can provide QA with a clean way to test various change sets in total isolation before we produce a release candidate.

This sounds rather nice until the realization that after we finally get a release candidate that we accept, somebody is left we the rather tedious job of removing all of the source branches from our repo. Well, that or ignoring them and watching the list balloon. Given the choice of doing nothing or manually performing this task time and time again has to be one form of Kobayashi Maru. Time for option three: automating the process.

Okay, that sounds all well and good, but where do we start? Well, a good place would seem to be getting a listing of all the remote branches that are in our repository.

  1. git branch -r

From there, we can loop through them one at a a time so that we can check each of them.

  1. for BRANCH in `git branch -r`
  2. do
  3. done

The names we get from git aren't exactly what we're wanting though: the names are all prefaced by our remote, in this case 'origin/'. This can quickly be fixed by piping $BRANCH and the proper regex through sed. The result will be our branch name with the remote name scrubbed.

  1. CLEAN_BRANCH=`echo "$BRANCH" | sed -e "s/origin\///"`

Once we have the branch name in a variable, we can loop through, passing the name of our branch to git branch --contains $BRANCH to get a listing of all the branches that it has been merged into. We can then pare down that list with grep to see if the current branch has been merged into our release branch.

  1. git branch --contains $BRANCH | grep Release

Depending on the output of grep, we'll either have a result, in which case the branch has been fully merged into our release, or we will have no result at all, in which case no relevant merging has occurred. With this knowledge we can create a conditional using -n to check whether we had a result or not.

  1. if [ -n "`git branch --contains $BRANCH | grep Release`" ]; then
  2. fi

At this point we just have to tell bash what we'd like to do if the branch has been fully merged. Since our goal here is to remove the original remote source branch, we should do that here.

  1. git push origin :$CLEAN_BRANCH

After combining this all together and adding a minimal amount of feedback with echo, we arrive at the final script:

  1. for BRANCH in `git branch -r`
  2. do
  3. CLEAN_BRANCH=`echo "$BRANCH" | sed -e "s/origin\///"`
  4. if [ -n "`git branch --contains $BRANCH | grep Release`" ]; then
  6. git push origin :$CLEAN_BRANCH
  7. else
  9. fi
  10. done

Now that we have the completed script, we can either run it at will or automate it with cron.



3027 days since since I met you..
Powered by Drupal