npm/npm — pull request #4965 by isaacs (2014-03-29 21:44:30+00:00)
Title: De-blerg the handling of shasums and other metadata by the cache

The cache adding logic doesn't currently preserve shasums and other metadata as well as it ought to.

One could argue that the best way to handle this, indeed probably the only *sane* way, is to rip out the `lib/cache.js` file entirely and replace it. It is certainly at or near the cusp between [grimy and fetid](http://static.izs.me/bryan-cantrill-immaculate-fetid-grimy.html).

However, the hazards and costs involved in swapping this out wholesale are rather large. As such, it has stayed in this condition for far too long. This patch partly addresses the current awfulness in as surgical a manner as possible.

Sadly, fixing it in this way only adds to the grime, but the alternative appears to be worse. This change will open the door to enforce shasums consistency in shrinkwraps, because now they'll *always* appear in the `package.json` of an installed package.

It'd be good if at least another pair of eyeballs read through this change. All tests pass, but it is a very delicate area.

The most relevant semantic changes:

1. At the end of `addRemoteTarball`, instead of unpacking, and then calling `addLocalFolder` on the resulting directory, it *copies* the tgz file into the cache location, and then unpacks it. This keeps the shasum of the tarball from changing between the temp folder and the cache folder. Also, it avoids an extra pack/unpack cycle, so things are a bit faster. It's still not nearly as efficient as it could be – using a tmp folder *at all* is a mistake of history that will hopefully one day be corrected.
2. A shasum is *always* generated, even if we don't have one at the outset to compare against. Clearly, this isn't helpful if we want to verify this particular tarball. However, it means that, later, a shrinkwrap will have the info, and be able to determine if the published tarball was the same one that was shrinkwrapped.
3. The `_from`, `_resolved`, and `_shasum` fields are written to the data, and that is written back to the `$cache/$pkg/$version/package/package.json` file. This ensures that, when installing from a cached package, `npm install` will still have the original metadata that was used the first time.