Skip to content

Instantly share code, notes, and snippets.

@weisk
Forked from mdp/README.md
Created March 24, 2021 15:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save weisk/ece65441b324ab12da823e2316560dd7 to your computer and use it in GitHub Desktop.
Save weisk/ece65441b324ab12da823e2316560dd7 to your computer and use it in GitHub Desktop.
Clone/Sync all gists

Clone all your gists

Stolen from mbostok and improved upon

node cloneAllGists.js username token [outputDir]

#!/usr/bin/env node
var fs = require("fs"),
https = require("https"),
exec = require("child_process").exec;
// TODO --pull or --push
var user = process.argv[2],
token = process.argv[3],
outputDir = process.argv[4];
outputDir = outputDir || "gists"
var clonedGists = []
exec("mkdir -p "+outputDir, function(err) {
clonedGists = fs.readdirSync(outputDir)
fetchAndClone(1, function callback(error, nextPage) {
if (error) throw error;
if (nextPage > 0) fetchAndClone(nextPage, callback);
});
})
function fetchAndClone(page, callback) {
fetch(page, function(error, gists) {
if (error) return callback(error);
if (gists.length) ++page; else page = -1;
cloneNext(gists.pop());
function cloneNext(gist) {
if (!gist) return callback(null, page);
repoDst = outputDir + '/' + gistDirName(gist)
if (directoryExists(repoDst)) {
console.log("Skipping " + gist.id + " - " + repoDst);
return cloneNext(gists.pop())
}
console.log("cloning " + gist.id + " into " + repoDst);
exec("git clone git@gist.github.com:" + gist.id + ".git " + repoDst, function(error, stdout, stderr) {
if (error) {
console.log("Error cloning " + gist.id + " into " + repoDst);
console.log(error);
}
cloneNext(gists.pop());
});
}
});
}
function fetch(page, callback) {
var request = https.request({
hostname: "api.github.com",
port: 443,
path: "/users/" + encodeURIComponent(user) + "/gists?page=" + page,
method: "GET",
headers: {
"Accept": "application/vnd.github.v3+json",
"Authorization": "token " + token,
"User-Agent": "mbostock/gist-clone-all"
}
}, function(response) {
var chunks = [];
response.setEncoding("utf8");
response.on("data", function(chunk) { chunks.push(chunk); });
response.on("end", function() { callback(null, JSON.parse(chunks.join(""))); });
});
request.on("error", callback);
request.end();
}
function directoryExists(path) {
try {
return fs.lstatSync(path).isDirectory();
} catch (ignored) {
return false;
}
}
function gistDirName(gist) {
var date = gist.created_at.split('T')[0].replace(/\-/g,'.')
var hash = gist.id.substr(0,5)
var title = toCamelCase(gist.description) || "unknown"
var existing = clonedGists.filter(function(g){
if (g.indexOf(date+"-"+hash) === 0) {
return true
}
return false
})
if (existing.length > 0) {
return existing[0]
}
return date + "-" + hash + "-" + title
}
function preserveCamelCase(str) {
let isLastCharLower = false;
let isLastCharUpper = false;
let isLastLastCharUpper = false;
for (let i = 0; i < str.length; i++) {
const c = str[i];
if (isLastCharLower && /[a-zA-Z]/.test(c) && c.toUpperCase() === c) {
str = str.substr(0, i) + '-' + str.substr(i);
isLastCharLower = false;
isLastLastCharUpper = isLastCharUpper;
isLastCharUpper = true;
i++;
} else if (isLastCharUpper && isLastLastCharUpper && /[a-zA-Z]/.test(c) && c.toLowerCase() === c) {
str = str.substr(0, i - 1) + '-' + str.substr(i - 1);
isLastLastCharUpper = isLastCharUpper;
isLastCharUpper = false;
isLastCharLower = true;
} else {
isLastCharLower = c.toLowerCase() === c;
isLastLastCharUpper = isLastCharUpper;
isLastCharUpper = c.toUpperCase() === c;
}
}
return str;
}
function toCamelCase(str) {
if (!str) {
return '';
}
if (str.length === 0) {
return '';
}
if (str.length === 1) {
return str.toLowerCase();
}
if (/^[a-z0-9]+$/.test(str)) {
return str;
}
const hasUpperCase = str !== str.toLowerCase();
if (hasUpperCase) {
str = preserveCamelCase(str);
}
str = str
.replace(/^[_.\- ]+/, '')
.toLowerCase()
.replace(/[_.\- ]+(\w|$)/g, (m, p1) => p1.toUpperCase());
str = str.split(" ")[0]
return str.replace(/[^a-zA-Z0-9]/g,'').substr(0,40)
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment