Skip to content
This repository has been archived by the owner on May 20, 2021. It is now read-only.

Commit

Permalink
introduce a yarn.lock patch phase
Browse files Browse the repository at this point in the history
For resources loaded directly from github, add the missing SHA1 when
invoking yarn2nix.

yarn doesn't touch entries unless they are modified directly so
it should only be needed when bumping the dependencies directly.

Ideally this would be supported by upstream.
  • Loading branch information
zimbatm committed Dec 18, 2017
1 parent 4cad3b2 commit a9cf17c
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 12 deletions.
97 changes: 91 additions & 6 deletions bin/yarn2nix.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,35 @@
#!/usr/bin/env node
"use strict";

const crypto = require('crypto');
const fs = require("fs");
const lockfile = require('@yarnpkg/lockfile')
const https = require("https");
const path = require("path");
const util = require("util");

const lockfile = require("@yarnpkg/lockfile")
const docopt = require("docopt").docopt;

////////////////////////////////////////////////////////////////////////////////

const USAGE = `
Usage: yarn2nix [options]
Options:
-h --help Shows this help.
--no-nix Hide the nix output
--no-patch Don't patch the lockfile if hashes are missing
--lockfile=FILE Specify path to the lockfile [default: ./yarn.lock].
`

const HEAD = `
{fetchurl, linkFarm}: rec {
offline_cache = linkFarm "offline" packages;
packages = [
`.trim();

////////////////////////////////////////////////////////////////////////////////

function generateNix(lockedDependencies) {
let found = {};

Expand Down Expand Up @@ -45,15 +64,81 @@ function generateNix(lockedDependencies) {
console.log("}")
}

// Main

const yarnLock = process.argv[2] || "yarn.lock";
function getSha1(url) {
return new Promise((resolve, reject) => {
https.get(url, (res) => {
const { statusCode } = res;
const hash = crypto.createHash('sha1');
if (statusCode !== 200) {
const err = new Error('Request Failed.\n' +
`Status Code: ${statusCode}`);
// consume response data to free up memory
res.resume();
reject(err);
}

let file = fs.readFileSync(yarnLock, 'utf8')
let json = lockfile.parse(file)
res.on('data', (chunk) => { hash.update(chunk); });
res.on('end', () => { resolve(hash.digest('hex')) });
res.on('error', reject);
});
});
};

function updateResolvedSha1(pkg) {
// local dependency
if (!pkg.resolved) { return Promise.resolve(); }
let [url, sha1] = pkg.resolved.split("#", 2)
if (!sha1) {
return new Promise((resolve, reject) => {
getSha1(url).then(sha1 => {
pkg.resolved = `${url}#${sha1}`;
resolve();
}).catch(reject);
});
} else {
// nothing to do
return Promise.resolve();
};
}

function values(obj) {
var entries = [];
for (let key in obj) {
entries.push(obj[key]);
}
return entries;
}

////////////////////////////////////////////////////////////////////////////////
// Main
////////////////////////////////////////////////////////////////////////////////

var options = docopt(USAGE);

let data = fs.readFileSync(options['--lockfile'], 'utf8')
let json = lockfile.parse(data)
if (json.type != "success") {
throw new Error("yarn.lock parse error")
}

generateNix(json.object);
// Check fore missing hashes in the yarn.lock and patch if necessary
var pkgs = values(json.object);
Promise.all(pkgs.map(updateResolvedSha1)).then(() => {
let newData = lockfile.stringify(json.object);

if (newData != data) {
console.error("found changes in the lockfile", options["--lockfile"]);

if (options["--no-patch"]) {
console.error("...aborting");
process.exit(1);
}

fs.writeFileSync(options['--lockfile'], newData);
}

if (!options['--no-nix']) {
generateNix(json.object);
}
})
2 changes: 1 addition & 1 deletion default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ in rec {
# Generates the yarn.nix from the yarn.lock file
mkYarnNix = yarnLock:
pkgs.runCommand "yarn.nix" {}
"${yarn2nix}/bin/yarn2nix ${yarnLock} > $out";
"${yarn2nix}/bin/yarn2nix --lockfile ${yarnLock} --no-patch > $out";

# Loads the generated offline cache. This will be used by yarn as
# the package source.
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"yarn2nix": "bin/yarn2nix.js"
},
"dependencies": {
"@yarnpkg/lockfile": "^1.0.0"
"@yarnpkg/lockfile": "^1.0.0",
"docopt": "^0.6.2"
}
}
4 changes: 4 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@
"@yarnpkg/lockfile@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.0.0.tgz#33d1dbb659a23b81f87f048762b35a446172add3"

docopt@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/docopt/-/docopt-0.6.2.tgz#b28e9e2220da5ec49f7ea5bb24a47787405eeb11"
8 changes: 4 additions & 4 deletions yarn.nix
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
}

{
name = "yarn-lockfile-1.1.1.tgz";
name = "docopt-0.6.2.tgz";
path = fetchurl {
name = "yarn-lockfile-1.1.1.tgz";
url = "https://registry.yarnpkg.com/yarn-lockfile/-/yarn-lockfile-1.1.1.tgz";
sha1 = "3e58898c601f3d2511e2b2abb4638088918849e9";
name = "docopt-0.6.2.tgz";
url = "https://registry.yarnpkg.com/docopt/-/docopt-0.6.2.tgz";
sha1 = "b28e9e2220da5ec49f7ea5bb24a47787405eeb11";
};
}
];
Expand Down

0 comments on commit a9cf17c

Please sign in to comment.