Fork me on GitHub
14 May 2009

BucketWise v1.1.0

Posted by Jamis on Thursday, May 14

So, I’ve now been using BucketWise for almost two months, and it’s been fantastic. Admittedly, as the author of the application, I’m willing to overlook a lot of the warts and inconsistencies, but I can honestly say I’ve felt more control over my finances these last two months than I’ve felt in the last 10 years. It’s an awesome feeling!

Tonight, I tagged version 1.1.0 of BucketWise, which (if you haven’t been following along) fixes a few bugs and adds several new features (account reconciliation, memorized transactions, actor name autocompletion, simple budget reporting, and more; I’ll just refer you to the changelog for the full list). It’s really been a fun project to tinker on. The last feature I myself really want is scheduled transactions; I may be hacking on that one in the near future.

I figured this might be a good time to talk a little about how I, personally, am using BucketWise. I’ve been surprised by a few things, both good and bad: some features I’ve found to be less useful than I anticipated, and others have been surprisingly handy!

Firstly, when you log into BucketWise, you see a short list at the top, called “Recent transactions”. This list was intended to let you see, at a glace, what you most recently had entered. (It also provided a handy landing place for newly entered transactions.) It hasn’t been very useful, though; I find that what I really want is to see the register of transactions for my checking account. I may be reworking that dashboard view soon.

Also, bucket reallocations haven’t been quite as useful as I expected. I do use them, and they are definitely handy, but I find that if you shuffle money around too much, it muddies your register. The reallocations are basically noise, especially when viewing transactions at the account level. I’m going to be pondering ways to reduce their visibility.

Buckets, though, I’ve found to be spectacularly useful. I’ve got my savings account partitioned into three buckets (short term, medium term, and long term), and that’s been a great way to keep track of how those savings funds are earmarked. Also, I’m trying to save 10% of each paycheck (trying, but not very successfully yet!), so I’ve got a “savings” bucket in my checking account, too. When the funds get to a certain threshold, I transfer the money to my savings account. (Yeah, I could just do a transfer with each paycheck…but I find I’m more likely to do it if I do it infrequently. Not sure why that is.)

Buckets are also great for indicating money that was given as a gift. My wife and I share the same checking account, so when it was her birthday, I transfered money from my Paypal account and put it in a “Tarasine” bucket. She was then welcome to record whatever purchases she wanted against that bucket. Similarly, when I receive money as a gift (birthday, Christmas, whatever) I just deposit it into a “Jamis” bucket.

Lastly, having credit card debt repayment built into the application has been awesome. I’ve loved being able to immediately indicate which checking account bucket a credit card purchase will be repaid from, and seeing that those funds are set aside, inviolate, ready for when the credit card bill comes.

My checking account currently has 35 buckets, and I can see my wife and I adding more. Most are purely for budgeting purposes (“groceries”, “auto fuel”, etc.), but they are so handy as ways to arbitrarily earmark money. Tithes, charitable offerings, savings, and credit card repayment are just some of the ways I’ve used them. (In fact, I’ve found myself wishing I could mark additional buckets as being “aside” buckets; I’m still pondering ways to make that happen, if it needs to.)

I’ll probably blog more about BucketWise down the road, and talk about specific use cases and how it’s helped me with them. However, I’d love to hear from others, too. Are you using BucketWise? If so, what do you like and dislike about it? I’m definitely only writing this application for me, but I’m curious to hear what the experience is like for others.

Lastly, if you’re interested in giving BucketWise a test drive, I’ve set up a demo account that you are welcome to log into and play with. I’ll reset the data there periodically, so feel free to try out all the features! Just go to http://www.bucketwise.com, and log in with the “bw.demo” user (password “demo”). Note that this is hosted on a modest Linode host, and will almost certainly be swamped into unusability with any significant traffic, but you’re welcome to try it out.

Posted in Announcements Projects | 16 comments

08 Apr 2009

BucketWise: Preview #2

Posted by Jamis on Wednesday, April 8

“Buckets” is now “BucketWise”. The name was more unique, easier to identify as an application, and just felt better than “Buckets”.

To celebrate the new name, I’ve also made another screencast, this one demonstrating BucketWise’s anti-debt features. It’s a bit more long-winded than the first one: five and a half minutes of me talk-talk-talking:

BucketWise Preview #2 (QuickTime, 5:30, 10MB)

I’m slowly working my way through the list of things that I want done before I release the code. For the curious, here’s what I’m wanting done before I open it up:

Existing bugs:

  • after saving a reallocation event, the line items don’t reset
  • green “your transaction has been recorded” notice doesn’t disappear when starting a new event
  • date column for event row is squashed in safari
  • “Add a new bucket” should set focus on new bucket line
  • check number and “select repayment options” links are out of whack when editing an event
  • deleting event from account perma results in ajax error (maybe only when there is only a single event in the account?)
  • Reallocating a bucket doesn’t change the updated_at field for the bucket?
  • “move in” and “move out” links on dashboard don’t use existing form—they go to events/new
  • make all autocompleting fields refresh their source array after event creation

Remaining features:

  • tag delete (optionally move transactions to different tag, e.g. “tag merge”)
  • tag rename
  • API
  • validations
  • rake tasks for user and subscription creation
  • change style for event detail view: “window shade” style isn’t really working
  • attr_protected everywhere (perhaps implement an update_override method or something for places where it would be useful to do mass updates despite protected attrs?)
  • spinner for ajax actions
  • user info page (for password change)
  • password reset from login page
  • cache balances on events (?)
  • README with installation instructions
  • CHANGELOG

Those lists are straight from my TODO file. But for those who think I’m waiting for too much to be finished, never fear. I’ve got plenty that I want to implement, but which I’m willing to wait until post-release to work on:

  • signup process
  • exception notifier (?)
  • /subscriptions index
  • autocomplete actor field in event form
  • better 404 and 500 error pages
  • searching & reporting
  • account reconciliation
  • transaction templates (“saved” or “memorized” transactions)
  • scheduled transactions (occur automatically at specified intervals)
  • show check numbers in event detail view
  • add a memo field for events
  • print stylesheet
  • oauth authentication for API
  • filter event views to show only events with a non-zero balance for the account in question
  • filter event views to show only deposits, or only expenses
  • normalize ‘actor’ so we can do actor-centric queries more efficiently
  • full-text searching on the memo field
  • show bucket and account balances next to names in drop-downs
  • make bucket reallocation work from bucket perma

Depending on how soon my bank sends the next statement for my checking account, I may or may not need to have “account reconciliation” done before launch, too.

As before, let me state: I’m writing this application for myself, and really only for myself. If other people like it, that’s cool. I’m more than happy to share and let other people hack on it. I may even release it into the public domain (I haven’t yet decided what license I’ll use). But BucketWise will always be very opinionated. If you prefer having your finance app download your transactions from your bank, you’ll be disappointed by BucketWise. If you need currencies other than the US dollar, you’ll be disappointed by BucketWise. If you need pretty charts and graphs to analyze your cash flow, or if you want to track investments, or any number of other things, you’ll be disappointed by BucketWise.

Just FYI. :)

Posted in Projects | 12 comments

24 Mar 2009

Buckets: Preview

Posted by Jamis on Tuesday, March 24

So, yeah. With Capistrano and friends off my plate, I’ve actually found time to work on a project that has been in the works for years (and that’s no exaggeration, I first mentioned it in a blog post in October 2004). I’ve named it and renamed it (“Penny Pincher”, “Chump Change”, “Make Me Rich”, and “BudgetWise”) but its current incarnation is “Buckets”.

Buckets is a simple web-based personal finance application that I’ve been working on, written specifically for my wife and me. Its focus is on simple budgeting, and reducing debt, and It is intentionally “feature-poor”. It is loosely based on an envelope budgeting strategy, and while it definitely isn’t the only web-based finance app using such a strategy, it just may be the simplest.

I recorded a screencast demonstrating the budgeting aspect of Buckets; it’s a 5M QuickTime movie, 2:42 in length. Click here to view it, if you care to..

Buckets is still private: it has been deployed and my wife and I are using it, but that’s it. The source code is in a private repository on GitHub, and the production instance of the app is currently only accessible to me. That will change eventually (maybe a couple of weeks, depending on how initial testing goes), but I want to make sure it’s actually going to be useful before I open it up.

Posted in Projects | 31 comments

24 Feb 2009

Net::SSH, Capistrano, and Saying Goodbye

Posted by Jamis on Tuesday, February 24

It is with mixed emotions that I announce two things this evening.

First, I’m announcing the final release of both Net::SSH (2.0.11) and Capistrano (2.5.5). Both are minor changes: Net::SSH 2.0.11 adds support for a :key_data option, so you can supply raw PEM-formatted key data. Capistrano 2.5.5 enhances the role() method so you can now declare empty roles. Either way, not much to get excited about, but the changes were pending and deserved releasing.

Secondly: I’m ceasing development on SQLite/Ruby, SQLite3/Ruby, Net::SSH (and related libs, Net::SFTP, Net::SCP, etc.) and Capistrano. I will no longer be accepting patches, bug reports, support requests, feature requests, or general emails related to any of these projects. For Capistrano, I will continue to follow the mailing list, and might appear in the #capistrano irc channel from time to time, but I am no longer the maintainer of these projects. I will continue to host the capify.org site and wiki for as long as they are of use to people.

This was a very hard decision, and one that has taken me months to come to grips with. I cannot express how much I appreciate the huge support from everyone that has found value in Capistrano, in particular. Your kind words and encouragement have meant a lot to me. But I’m burning out, and I have to drop these before things get worse. Maybe after some period of time I’ll come back to them—I don’t know. But I’m not planning on it.

So where do these projects go from here? That’s entirely up to the community. If you have a neat idea for any of these, please feel free to fork the project on GitHub (see my profile page for the links to the individual projects) and release updates on your own schedule. If no one steps forward, that’s fine—I’m not asking for volunteers. But if someone feels passionately that any of these are not “finished”, and has ideas for how they could be further improved, I will not stand in the way.

However, please know that I am not available for questions about the code, or for advice on how to implement changes. I’m trying to cut as cleanly as I can. Any emails I get asking about the code will likely be ignored. I’m not trying to be rude; I’m just setting expectations.

I won’t disappear, though. These libraries were just becoming millstones around my neck; without their weight dragging me down, I look forward to being able to experiment and play with new projects and new ideas. We’ll see what the future holds!

So, thanks all for a fantastic couple of years.

Posted in Projects | 146 comments

28 Jan 2009

The future of FuzzyFinder-TextMate

Posted by Jamis on Wednesday, January 28

Back in October I released a Vim extension for mimicking TextMate’s cmd-T file lookup feature. I use it heavily now, and it works great for me.

Sadly, the author of the FuzzyFinder Vim script, upon which my extension depends, keeps changing internal implementation details that I had to hook into to make my extension work. The result? Every few weeks my extension breaks with the latest FuzzyFinder.

Needless to say, this is work I don’t need. The fuzzyfinder-textmate stuff works fine for me. It works fine for people on older versions of FuzzyFinder. And I really don’t care to support this anymore.

If you’re passionate about this, please feel free to fork the project on GitHub and release your changes independently. Feel free to post your changes on the vim script page, even! I hereby release that code into the public domain. Do with it as you please!

Posted in Projects | 12 comments

06 Dec 2008

SQlite3-Ruby Windows Builds

Posted by Jamis on Saturday, December 6

So, I’ve got a new sqlite3-ruby release pending (just a minor bug fix, is all), but I’ve learned my lesson about releasing a new version without a windows version pre-built.

The problem is, I’m not a Windows guy. My build environment for Windows is cobbled together and painful to use, when it works at all. I’ve decided that I won’t put myself through that pain anymore.

If you are a developer on Windows, and you have a sqlite3 build environment, and would be willing to compile the sqlite3-ruby extension for me, please do the following:

  1. Add a comment to this post, indicating your name, and what platform you would be willing to build for (cygwin, native windows, whatever. I don’t even know the right names.)
  2. Reload the page, and make sure no one commented before you, claiming those platforms.
  3. Grab the latest version of sqlite3-ruby here: http://github.com/jamis/sqlite3-ruby/tree/master.
  4. Build the extension, and email it to me at jamis at 37signals dot com.

Once I have a build of sqlite3-ruby for windows, I’ll release the new gem. (It amazes me how painful Windows makes this process. Mac OS X, Linux, BSD, etc. —you just gem install and build the source. No such luck in the Windows realm, apparently.)

Posted in Projects | 16 comments

26 Aug 2008

Cap 1.4.1? Go 1.4.2. Now.

Posted by Jamis on Tuesday, August 26

Are you currently using Capistrano 1.4.1? If so, drop everything (I mean it, do this RIGHT NOW) and install Capistrano 1.4.2.

Why, you ask?

Capistrano 1.4.1 will work just fine, right up until you decide you want to experiment with Capistrano 2. When you do that, Cap 2.3+ will install net-ssh 2.x, which kills Capistrano 1.4.1 in all kinds of really obscure ways.

The good news is that Cap 1.4.2 is completely compatible with Cap 1.4.1. It adds no new features. The only “bug” it fixes is that if you ever install net-ssh 2.x, Cap 1.4.2 will still happily continue to work.

Ultimately, an upgrade to Cap 2 is recommended, but I understand it’s not feasible for everyone. So, if you’re one of those who can’t go cap2 yet, please please please PLEASE PLEASE FOR THE LOVE OF ALL THAT IS HOLY upgrade to Cap 1.4.2. It’ll make your life easier, and it’ll make my life easier (because I won’t have to keep troubleshooting the same issues over and over). Thanks!

Posted in Projects | 6 comments

10 Apr 2008

More preview releases from the Net::SSH family

Posted by Jamis on Thursday, April 10

I’ve got lots of code to share with you all today:

Net::SSH 2.0 Preview Release #3

Not very many external changes, but channels now have an on_open_failure callback that you can employ to be told when a channel could not be opened.

1
2
3
4
5
6
7
channel = ssh.open_channel do |ch|
  # ...
end

channel.on_open_failure do |ch, code, reason|
  puts "could not open channel because #{reason.inspect} #{code}"
end

This change was necessary to make port forwarding a bit more reliable for Net::SSH::Gateway (see below).

Also, individual Net::SSH sessions may contain their own custom properties, much as Net::SSH channel objects do, which can be quite handy when you need to keep some state associated with the session.

ssh[:key] = "value"

This change (and several other internal refactorings) was necessary for the correct working of the Net::SSH::Multi library (see below).

To get the preview release #3 (version 1.99.2):

gem install --source http://gems.jamisbuck.org net-ssh

You can follow development via GitHub:

http://github.com/jamis/net-ssh/tree/master

Net::SFTP 2.0 Preview Release #2

All that was added in this preview release was custom properties on Upload instances:

1
2
3
uploader = sftp.upload("local.file", "remote.file")
uploader[:failed] = false
# ...

This was necessary to get Capistrano file transfers to work with Net::SFTP 2.0.

To get the preview release #2 (version 1.99.1):

gem install --source http://gems.jamisbuck.org net-sftp

You can follow development via GitHub:

http://github.com/jamis/net-sftp/tree/master

Net::SSH::Gateway 1.0 Preview Release #1

Net::SSH::Gateway is (in essence) the extraction of the gateway code from Capistrano into its own library. It lets you tunnel SSH connections through some “gateway” server to servers that would be otherwise inaccessible.

1
2
3
4
5
6
require 'net/ssh/gateway'

gateway = Net::SSH::Gateway.new('gateway.host', 'username')
gateway.ssh('remote.host', 'user') do |ssh|
  # ...
end

You can also use it as a general facilitator for forwarding connections over a local port, when you don’t care what port is to be used—you just want to connect to a remote server.

1
2
3
gateway.open('remote.host', 80) do |port|
  Net::HTTP.get_print '127.0.0.1', '/path', port
end

The current thinking is that the next release of Capistrano will ditch its own gateway implementation in favor of Net::SSH::Gateway. To get this first preview release (version 0.99.0):

gem install --source http://gems.jamisbuck.org net-ssh-gateway

You can follow development via GitHub:

http://github.com/jamis/net-ssh-gateway/tree/master

Net::SSH::Multi 1.0 Preview Release #1

Net::SSH::Multi is the guts of Capistrano, extracted into a library of their own. It allows you to define and categorize servers, and then execute commands in parallel on them, or on subsets of them, using an interface similar, if not identical, to that of Net::SSH::Connection::Session and Channel.

Eventually, Capistrano will be refactored to take advantage of Net::SSH::Multi, but doing so will require some significant changes to Capistrano’s innards, and would almost certainly break many third-party libraries. Thus, you won’t see Capistrano on Net::SSH::Multi until Capistrano 3.0 or so (which will not be the next release of Capistrano). However, you can use Net::SSH::Multi to implement most of Capistrano’s functionality in whatever form you like. Want Capistrano-in-a-rakefile? Have at it!

1
2
3
4
5
6
7
8
9
require 'net/ssh/multi'

Net::SSH::Multi.start do |session|
  session.use 'jamis@somewhere.com'
  session.use 'jamis@elsewhere.com'

  session.exec 'hostname'
  session.loop
end

Grab the first preview release (version 0.99.0):

gem install --source http://gems.jamisbuck.org net-ssh-multi

You can follow development via GitHub:

http://github.com/jamis/net-ssh-multi/tree/master

For all of these libraries I’ve tried to make the rdoc and ri documentation as informative as possible, so please refer to those to get started. If those aren’t helpful enough, let me know what could make them more useful!

Posted in Announcements Projects | 0 comments

17 Mar 2008

Net::SSH and Thread-safety

Posted by Jamis on Monday, March 17

Net::SSH 1.x is thread-safe. Net::SSH v2, as currently implemented in its pre-release state, is not.

I’ve debated this long and hard with myself. Wrapping code in mutexes and doing all the other stuff that thread-safety requires adds a surprising amount of overhead, and it feels painful to me to have to add all that when the most common use-case of the library will be in single-threaded environments. However, without the mutexes and all that overhead, using Net::SSH in a multi-threaded environment (where multiple threads are hitting the same Net::SSH connection) will result in some rather ugly errors, and would require those programs to add their own mutexes and such to protect the integrity of the connection.

I’m leaning towards leaving the library optimized for the single-thread experience, and requiring the people wanting multiple threads of execution to fend for themselves. However, in the interest of getting feedback from people who might actually use the library, I ask you: which would you prefer? A faster library in single-threaded programs? Or a simple program in multi-threaded ones? Is there a general best-practice in this case?

Posted in Projects | 26 comments

13 Mar 2008

Net::SFTP v2: done?!

Posted by Jamis on Thursday, March 13

I think...I think I’m actually, done, more or less, with Net::SFTP v2!

I just committed a last bit of documentation tweaking, and although I’m sure there’s more of that to come, and bugs to fix and features to add, I’m calling this bit “good enough”, and I’m moving on now to Net::SCP.

I’m not actually releasing Net::SFTP v2 at this point—it’s pretty much useless without a corresponding Net::SSH v2 release. So why am I saying anything about it right now? Because it’s the first significant milestone that I’ve completed in my track to complete the new Net::SSH suite of libraries! And I’m excited! And I’ve learned something significant by finishing Net::SFTP v2 before completely finishing Net::SSH v2: by completing a dependency of the primary library first, I saw first-hand where the deficiencies in the primary library were. This has resulted in a much tigher, much more useful API than the Net::SSH v1 and Net::SFTP v1 libraries.

Now, there is no real release of Net::SSH v2 and friends, but that’s not to say that if you’re brave, and don’t mind exploring a bit, you couldn’t get the new Net::SSH and Net::SFTP to work. The new Net::SSH is actually mostly done—I just need to revisit the documentation and update a few things here and there. The code is all on github. If you don’t have git, you can download a tarball directly from github, even.

So, have at it, if you’re so inclined. (And if you’d like on the github bandwagon, I’ve still got two invites burning a hole in my pocket…email me at (my first name) at jamisbuck.org, and I’ll be happy to send you one.)

Update: my github invites are all gone. Sorry!

Posted in Projects | 1 comment

16 Feb 2008

Dealing with project overload

Posted by Jamis on Saturday, February 16

I’ve got my plate full of projects that need attention, and the stress has been getting to me. Everybody has different ways of dealing with stress, but I think mine is the least effective: ignoring things doesn’t make them go away.

So, I’m taking a more active approach. Starting immediately, I’m going to be spending one hour, every day, six days a week, clearing away the backlog of projects. I’ll post a comment each day to keep myself honest—if I don’t leave a comment, you may assume I did not do any work that day!

Here is a list of what I’ll be working on, more or less in order of priority:

  1. Capistrano 2.2.0. This will primarily be a maintenance release, and mostly requires that the patches that are pending be tested and applied. It will also update the Net::SSH and Net::SFTP gem dependencies so that they explicitly exclude any 2.0 versions of those gems.
  2. Net::SFTP 1.1.1. This is a super minor release with no new features. All it will do is update the gem dependency on Net::SFTP such that it won’t try to load Net::SSH v2.
  3. Net::SSH v2, Net::SFTP v2, Net::SCP v1. These will be released simultaneously. They are an 80% rewrite of the original code (and yeah, rewrites are evil, but sometimes they are necessary). The API has changed, and scripts written against the existing API will almost certainly be broken by the upgrade, so make sure you are depending on version 1.x.
  4. Capistrano 2.3.0. This is another maintenance release, which simply modifies Capistrano to work with the new Net::SSH and Net::SFTP versions. (Possibly Net::SCP, too, not sure about that yet).
  5. SQLite3/Ruby 1.2.2. A maintenance release. Haven’t seen a release on this for a long, long time. No new features planned, but lots of bug fixes are pending.

I’m not even going to try and give an ETA on these. Just know that I’m working through them, an hour a day, and that progress is finally being made. I’ll post what I worked on in the comments to this thread, for those who want to follow along.

Posted in Projects | 22 comments

21 Aug 2007

Net::SSH 2.0 preview #1

Posted by Jamis on Tuesday, August 21

I’m really pleased with how Net::SSH v2 is turning out. I’ve actually got it to a point where it’s about ready for a first preview release! If you’re an adventurous soul, you can grab the preview release gem (version 1.99.0) here:

Note that Net::SSH v2 is not going to be 100% backwards compatible with 1.x. Many things will work mostly the same, but here are a few of the most significant gotchas:

  • Net::SSH.start now uses a fixed parameter list, instead of the polymorphic monster it was. This makes it much easier to document, and use. The first parameter is always the host you are connecting to, and the second is always the username you’re connecting as. Options always come last.
  • The shell, sync-shell, and open3 services have been dropped. You won’t find them in Net::SSH 2.0. If you want them, I strongly encourage you to write them and release them as third-party extensions to Net::SSH.

There are also a couple of (much needed!) short cuts for executing commands:

1
2
3
4
5
6
Net::SSH.start("localhost", "jamis") do |ssh|
  puts ssh.exec!("echo hello world!")

  ssh.exec("hello world")
  ssh.loop
end

The first, #exec!, will block until the command finishes, and will return the output. The second will return immediately, before executing the command, and will run when the event loop does, writing output to the terminal.

The documentation is pretty much done, too. To see it, just install the gem, change to the net-ssh-1.99.0 gem directory, and run “rake manual”. Then open “doc/out/index.html” in a browser. It includes a brief tutorial, a quick-reference, and an FAQ-style “how do I do X” interface.

So! Give it a try. Remember that the current release of Net::SFTP won’t work with this new version (at all), and neither will Capistrano. But the lovely thing about RubyGems is that you can easily install and uninstall, on demand.

Oh, and before I forget, a couple of little teasers about what’s coming up:

1
2
3
4
5
6
7
8
9
10
require 'net/scp'
Net::SCP.download("localhost", "jamis", "/Users/jamis/.bashrc", "./my-bash-rc") do |name, sent, total|
  if sent == 0
     print "downloading #{name} (#{total}b): "
  elsif sent == total
     puts
  else
     print "."
  end
end

and…

1
2
3
4
require 'uri/open-scp'
open("scp://jamis@localhost/Users/jamis/.bashrc") do |io| 
  puts io.read 
end

Posted in Announcements Projects | 30 comments

29 Jul 2007

Net::SSH revisited

Posted by Jamis on Sunday, July 29

I cringe whenever I remember those days, three years ago, when I was in the middle of a big Java project at BYU and was learning the ins-and-outs of dependency injection. For Java (and similarly constrained languages), DI is a technique that allows you to write modular code without tightly coupling the components. It seemed like a neat idea. So why do I cringe now?

Because I tried to bring that idea to Ruby, in the form of (first) Copland, and (later) Needle.

But hey, we’re all newbies at some time, right? I’ve since learned my lesson and have come to understand that although DI is a nifty technique that works well in some environments, it is wholly unnecessary in Ruby. Ruby sports an agility that Java will never know, and can get by without such crutches.

My conscience is salved somewhat by the knowledge that neither Copland nor Needle ever caught on. The only notable exception is the Net::SSH library, which I rewrote after RubyConf 2004 to take advantage of Needle, and which I originally held up as a shining example of how DI can help make code “more modular”. So, I cringe yet again, now, realizing that any time someone has installed Capistrano (which has become quite popular), they’ve also had to install Net::SSH, which carries the DI baggage along with it.

My shame has finally reached the pain point, though. I’m rewriting Net::SSH, taking advantage of many of the best-practices I’ve learned in the intervening years. It’s a lot slimmer now. Faster. Cleaner. Better. Even ignoring the ssh.shell and ssh.process services (which I’m not immediately porting to the new version), the code is less than half the size of the bloated DI-based version. It’s actually possible now to read and understand how the library works. And I’ve killed the use of threads to do polling and am doing it right, now, via IO.select. I’m really quite pleased about how it is turning out.

I’ve also managed to write a Net::SCP client library, which works quite well, especially considering that the SCP protocol (which is based on RCP) is apparently completely undocumented, and the canonical implementation from OpenSSH is…well…bad. Effective, but bad.

I’m going to be rewriting Net::SFTP next, which is another beast with its blatant abuses of metaprogramming. Once it is “done”, I’ll be packaging them all up as “version 2”, and releasing them aside a small update to Capistrano (tweaked as necessary to work with the minor API changes). I haven’t enjoyed working on Net::SSH this much in a couple of years! It really has been fun to gut it and rethink the architecture.

If you’re interested in following along at all, you can check out the Subversion repository:

And, after I start on the Net::SFTP rewrite, you’ll be able to follow it here:

The code is entirely undocumented, is lacking any tests at all, and there are a few small API changes that might bite you. Also, as I mentioned, ssh.shell and ssh.process are missing (they may be rereleased eventually as separate libraries). But, if you’re feeling brave and want to peek, I’d appreciate any feedback you might have.

Posted in Projects | 25 comments

12 Jun 2007

Capistrano and Leopard

Posted by Jamis on Tuesday, June 12

So, this was totally news to me, but apparently Mac OS X Leopard will bundle Capistrano. How about that! It’s probably too late for them to bundle cap2, even if I were to release it tomorrow, but at the very least this is motivating me to get things rolling again. I’ll be releasing the third (and final) preview release of Capistrano “soon”, and then the focus will be on getting the capify.org site polished enough for the final release on cap2. I’d expect to see cap2 final out late this month, or early July.

Someone, hold me to that!

Posted in Projects | 11 comments

23 Jan 2007

How would YOU do it?

Posted by Jamis on Tuesday, January 23

I’ve been working on rewiring parts of Capistrano, and I’m making some good progress in a few different areas. One thing that has continued to defy me is actually unit testing Capistrano. I openly admit the existing unit tests for Capistrano are remarkably lame, but I’m at a loss as to how to improve them.

So, I’m opening the floor on this one. How would you do it? Specifically, allow me to point you to the gateway implementation, which uses Net::SSH and sockets, and which has proven particularly tricky for me to see my way through to unit testing. Other areas that I would appreciate suggestions are: what is a good way to go about testing the CLI (command-line interface) module? What would be a technique for actually testing the standard tasks? And how would you test the file transfer abstraction and the capistrano shell?

I know from experience that code which is hard to test is usually poorly designed, so I’m prepared to hear comments like “you’ve misdesigned this thing, you should have done X, Y, and Z.” Of course, the gentler you can break it to me, the happier I’ll be. ;)

So, tell me, how would you do it?

Posted in Projects | 13 comments