#!/usr/bin/env node var Chalk = require('chalk') var DHT = require('bittorrent-dht') var exec = require('child_process').exec var fs = require('fs') var magnet = require('magnet-uri') var spawn = require('child_process').spawn var Swarm = require('bittorrent-swarm') var ut_gitswarm = require('ut_gitswarm') var WebTorrent = require('webtorrent') function die (error) { console.error(error) process.exit(1) } // Gotta enable color manually because stdout isn't a tty. var chalk = new Chalk.constructor({enabled: true}); var dht = new DHT({ bootstrap: ['three.printf.net:6882'] }) var url = process.argv[3] var matches = url.match(/gitswarm:\/\/([a-f0-9]{40})\/(.*)/) if (matches) { var key = matches[1] var reponame = matches[2] dht.on('ready', function () { var val = new Buffer(key, 'hex') dht.get(val, function (err, res) { if (err) { return console.error(err) } var json = res.v.toString() var repos = JSON.parse(json) console.warn('\nMutable key ' + chalk.green(key) + ' returned:\n' + chalk.yellow(json)) get_infohash(repos.repositories[reponame].master) }) }) } else { url = url.replace(/^gitswarm:/i, 'git:') exec('git ls-remote ' + url + ' HEAD', function (err, stdout, stderr) { if (err !== null) { die(err) } var lines = stdout.split('\n') if (lines.length !== 2) { die("Didn't get back a single HEAD ref: " + lines) } var line = lines[0].split('\t') var ref = line[0] var head = line[1] if (head !== 'HEAD') { die("Couldn't parse the ref line: " + ref, head) } if (ref.length !== 40) { die('Was expecting a 40-byte sha: ' + ref) } dht.on('ready', function () { get_infohash(ref) }) }) } function get_infohash (ref) { // We use console.warn (stderr) because git ignores our writes to stdout. console.warn('\nOkay, we want to get: ' + chalk.green(ref) + '\n') process.stdin.setEncoding('utf8') process.stdin.on('readable', function () { var chunk = process.stdin.read() if (chunk === 'capabilities\n') { process.stdout.write('fetch\n\n') } if (chunk === 'list\n') { process.stdout.write(ref + ' refs/heads/master\n\n') } }) process.stdout.on('error', function () { // stdout was closed }) var magnetUri = 'magnet:?xt=urn:btih:' + ref var parsed = magnet(magnetUri) dht.lookup(parsed.infoHash) dht.on('peer', function (addr, hash, from) { swarm.addPeer(addr) }) var swarm = new Swarm(parsed.infoHash, 'cafebabecafebabecafecafebabecafebabecafe') swarm.on('wire', function (wire, addr) { console.warn('Adding swarm peer: ' + chalk.green(addr) + '\n') wire.use(ut_gitswarm()) wire.ut_gitswarm.on('handshake', function () { wire.ut_gitswarm.ask(parsed.infoHash) }) wire.ut_gitswarm.on('receivedTorrent', function (infoHash) { var client = new WebTorrent({ dht: { bootstrap: ['three.printf.net:6882'] }, tracker: false }) client.download(infoHash, function (torrent) { console.warn('Downloading git pack with infohash: ' + chalk.green(infoHash) + '\n') torrent.on('done', function (done) { var filename = torrent.storage.path + '/' + torrent.files[0].path var unpack = spawn('git', ['index-pack', '--stdin', '-v', '--fix-thin']) var stream = fs.createReadStream(filename) stream.on('open', function () { stream.pipe(unpack.stdin) }) unpack.stderr.pipe(process.stderr) unpack.on('exit', function (code) { var targetdir = process.env['GIT_DIR'] var stream = fs.createWriteStream(targetdir + '/refs/heads/master') stream.once('open', function (fd) { stream.write(ref + '\n') stream.end() // These writes are actually necessary for git to finish checkout. process.stdout.write('\n\n') process.exit() }) }) }) }) }) }) }