PneumaticTube Update

Last year around this time I created a little command-line application to upload files to Dropbox from Windows. Since then I've added a few features, so I figured it was time to post an update.

The biggest change is support for chunked uploading. Dropbox requires chunked uploading for files larger than 150MB, and even for smaller files it's a nice feature to have because you can get progress updates on your upload. This feature took a little work, because the original library PneumaticTube was based on, DropNet, didn't have any async support and its successor, DropNetRT didn't have any chunked uploading support. But after a little porting work, PneumaticTube can handle uploading large files just fine and now has a couple of different progress indicator options.

The other big feature change is the ability to upload a whole folder to Dropbox. This makes PT a much more convenient tool for backup operations. Right now it only supports the top level of a folder (no recursion), but that may change in the future.

There've also been several bug fixes. One of these bugs was somewhat surprising: the progress indicators during chunked uploading caused crashes under PowerShell ISE. I'm posting a little more about this bug because info about it was scarce on Google, and maybe this will help someone else who has a similar problem.

In order to show upload progress indicators in-place (rather than writing "X % Complete" on a new line over and over again), I use Console.SetCursorPosition to move the cursor back to the beginning of the line and overwrite the old value. It turns out that the PowerShell console in PS ISE isn't a real console; among the differences between the standard terminal and ISE is the fact that ISE doesn't support SetCursorPosition or other cursor operations. Calls to those methods will throw IOExceptions.

PneumaticTube now handles this case by trying to access Console.CursorTop in the constructor of each progress display implementation. If access to CursorTop throws an exception, the progress display classes stop trying to report progress using those methods. This keeps scripts which call PneumaticTube under ISE (or another console which doesn't support those cursor operations) from failing. I also added command line switches for disabling progress reporting entirely as a workaround for other possible console support issues.

If you want to give PneumaticTube a try, you can download it directly from the releases page or install it using chocolatey. Happy uploading!

Upload to Dropbox from the command line in Windows

I've got an instance of TeamCity running on an Azure VM that I use for build and deployment automation, and a few weeks ago I finally got around to setting up the build, tests, and packaging of a Windows desktop application I've been working on for a while. Up to this point I'd been building the installers manually and shipping them to my partners for testing via a shared Dropbox folder. Once I had the project building on check-ins and running all the automated tests, I really wanted to get to the point where I could release a new version with a button push. My partners are already comfortable with receiving installers via Dropbox and I didn't feel like setting up and maintaining an FTP server (in addition to setting them up with FTP clients). So I needed a way to get TeamCity build artifacts into Dropbox easily.

The obvious option is to install the Dropbox client on the build server and simply copy the installer artifact to the shared folder. The problem with that scenario is that the Dropbox user needs to be logged into the machine for the sync to take place. I'm not willing to leave my account logged in all the time, so that's a non-starter. (Plus, what happens when the build server needs to reboot for maintenance/updates?)

Some googling reveals a few articles about installing the Dropbox client to run as a Windows Service, but in addition to being kludgy I'd have to run the service with my credentials. It seemed like there had to be a better way.

After some more googling I found a project for a command-line Dropbox-Uploader project; it's basically a shell script for handling the upload through Dropbox's REST API. Which is a good start, but it would require me to set up a Dropbox API application entry and, since I want this to run on Windows, would also require a Cygwin install. Cygwin is nice and all, but in these days where most of what Cygwin offers is available in Powershell anyway, I hate installing it on a machine just to handle one small requirement like this.

In the end, I decided to write my own dead-simple Windows command-line Dropbox uploader: PneumaticTube. PneumaticTube1 literally does just that one thing - once you've authorized it with your account, you can upload a file to any path in your Dropbox folder. Using it with TeamCity is a snap - just set up a shell command step in your build to call it with the artifact you want to upload.

The only catch is that you have to do the authorization2 as the account your build agent runs under, which means you actually have to run your agent under a user account (as opposed to running the agent under System, for example)3.

If you want to use it, there's a chocolatey package available to make installation easy. Suggestions, bug reports, questions, and pull requests are welcome - just hit up the issues page and let me know. I hope this helps someone else whose deployment pipeline includes Dropbox.

  1. Dropbox app naming guidelines basically make you pick a name that doesn't include "Dropbox", so "Dropbox Uploader For Windows" was out. The first thing that came to mind when I thought about "put something in and it goes to a destination" were those tube systems at the banks. I love those things. 

  2. It uses the standard pattern of popping open a browser window so you can enter your Dropbox credentials and authorize the app. 

  3. I'll probably fix this in future versions by allowing you to specify the user secret and user token on the command line (instead of getting them from the user's settings), allowing you to store the secret and token in the build settings. Or maybe someone else will take care of it (pull requests are always welcome).