mirror of https://github.com/lukechilds/node.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
208 lines
7.5 KiB
208 lines
7.5 KiB
"use strict"
|
|
var url = require("url")
|
|
|
|
var GitHost = exports = module.exports = function (type, user, project, comittish) {
|
|
this.type = type
|
|
this.domain = gitHosts[type].domain
|
|
this.filetemplate = gitHosts[type].filetemplate
|
|
this.sshtemplate = gitHosts[type].sshtemplate
|
|
this.sshurltemplate = gitHosts[type].sshurltemplate
|
|
this.browsetemplate = gitHosts[type].browsetemplate
|
|
this.docstemplate = gitHosts[type].docstemplate
|
|
this.bugstemplate = gitHosts[type].bugstemplate
|
|
this.gittemplate = gitHosts[type].gittemplate
|
|
this.httpstemplate = gitHosts[type].httpstemplate
|
|
this.treepath = gitHosts[type].treepath
|
|
this.user = user
|
|
this.project = project
|
|
this.comittish = comittish
|
|
}
|
|
GitHost.prototype = {}
|
|
|
|
exports.fromUrl = function (giturl) {
|
|
if (giturl == null || giturl == "") return
|
|
var parsed = parseGitUrl(maybeGitHubShorthand(giturl) ? "github:" + giturl : giturl)
|
|
var matches = Object.keys(gitHosts).map(function(V) {
|
|
var gitHost = gitHosts[V]
|
|
var comittish = parsed.hash ? decodeURIComponent(parsed.hash.substr(1)) : null
|
|
if (parsed.protocol == V + ":") {
|
|
return new GitHost(V,
|
|
decodeURIComponent(parsed.host), decodeURIComponent(parsed.path.replace(/^[/](.*?)(?:[.]git)?$/, "$1")), comittish)
|
|
}
|
|
if (parsed.host != gitHost.domain) return
|
|
if (! gitHost.protocols_re.test(parsed.protocol)) return
|
|
var matched = parsed.path.match(gitHost.pathmatch)
|
|
if (! matched) return
|
|
return new GitHost(
|
|
V,
|
|
matched[1]!=null && decodeURIComponent(matched[1]),
|
|
matched[2]!=null && decodeURIComponent(matched[2]),
|
|
comittish)
|
|
}).filter(function(V){ return V })
|
|
if (matches.length != 1) return
|
|
return matches[0]
|
|
}
|
|
|
|
function maybeGitHubShorthand(arg) {
|
|
// Note: This does not fully test the git ref format.
|
|
// See https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html
|
|
//
|
|
// The only way to do this properly would be to shell out to
|
|
// git-check-ref-format, and as this is a fast sync function,
|
|
// we don't want to do that. Just let git fail if it turns
|
|
// out that the commit-ish is invalid.
|
|
// GH usernames cannot start with . or -
|
|
return /^[^:@%/\s.-][^:@%/\s]*[/][^:@\s/%]+(?:#.*)?$/.test(arg)
|
|
}
|
|
|
|
var parseGitUrl = function (giturl) {
|
|
if (typeof giturl != "string") giturl = "" + giturl
|
|
var matched = giturl.match(/^([^@]+)@([^:]+):[/]?((?:[^/]+[/])?[^/]+?)(?:[.]git)?(#.*)?$/)
|
|
if (! matched) return url.parse(giturl)
|
|
return {
|
|
protocol: "git+ssh:",
|
|
slashes: true,
|
|
auth: matched[1],
|
|
host: matched[2],
|
|
port: null,
|
|
hostname: matched[2],
|
|
hash: matched[4],
|
|
search: null,
|
|
query: null,
|
|
pathname: "/" + matched[3],
|
|
path: "/" + matched[3],
|
|
href: "git+ssh://" + matched[1] + "@" + matched[2] + "/" + matched[3] + (matched[4]||"")
|
|
}
|
|
}
|
|
|
|
var gitHostDefaults = {
|
|
"sshtemplate": "git@{domain}:{user}/{project}.git{#comittish}",
|
|
"sshurltemplate": "git+ssh://git@{domain}/{user}/{project}.git{#comittish}",
|
|
"browsetemplate": "https://{domain}/{user}/{project}{/tree/comittish}",
|
|
"docstemplate": "https://{domain}/{user}/{project}{/tree/comittish}#readme",
|
|
"httpstemplate": "https://{domain}/{user}/{project}.git{#comittish}",
|
|
"filetemplate": "https://{domain}/{user}/{project}/raw/{comittish}/{path}"
|
|
}
|
|
var gitHosts = {
|
|
github: {
|
|
// First two are insecure and generally shouldn't be used any more, but
|
|
// they are still supported.
|
|
"protocols": [ "git", "http", "git+ssh", "git+https", "ssh", "https" ],
|
|
"domain": "github.com",
|
|
"pathmatch": /^[/]([^/]+)[/]([^/]+?)(?:[.]git)?$/,
|
|
"treepath": "tree",
|
|
"filetemplate": "https://raw.githubusercontent.com/{user}/{project}/{comittish}/{path}",
|
|
"bugstemplate": "https://{domain}/{user}/{project}/issues",
|
|
"gittemplate": "git://{domain}/{user}/{project}.git{#comittish}"
|
|
},
|
|
bitbucket: {
|
|
"protocols": [ "git+ssh", "git+https", "ssh", "https" ],
|
|
"domain": "bitbucket.org",
|
|
"pathmatch": /^[/]([^/]+)[/]([^/]+?)(?:[.]git)?$/,
|
|
"treepath": "src"
|
|
},
|
|
gitlab: {
|
|
"protocols": [ "git+ssh", "git+https", "ssh", "https" ],
|
|
"domain": "gitlab.com",
|
|
"pathmatch": /^[/]([^/]+)[/]([^/]+?)(?:[.]git)?$/,
|
|
"treepath": "tree",
|
|
"docstemplate": "https://{domain}/{user}/{project}{/tree/comittish}#README",
|
|
"bugstemplate": "https://{domain}/{user}/{project}/issues"
|
|
},
|
|
gist: {
|
|
"protocols": [ "git", "git+ssh", "git+https", "ssh", "https" ],
|
|
"domain": "gist.github.com",
|
|
"pathmatch": /^[/](?:([^/]+)[/])?([a-z0-9]+)(?:[.]git)?$/,
|
|
"filetemplate": "https://gist.githubusercontent.com/{user}/{project}/raw{/comittish}/{path}",
|
|
"bugstemplate": "https://{domain}/{project}",
|
|
"gittemplate": "git://{domain}/{project}.git{#comittish}",
|
|
"sshtemplate": "git@{domain}:/{project}.git{#comittish}",
|
|
"sshurltemplate": "git+ssh://git@{domain}/{project}.git{#comittish}",
|
|
"browsetemplate": "https://{domain}/{project}{/comittish}",
|
|
"docstemplate": "https://{domain}/{project}{/comittish}",
|
|
"httpstemplate": "https://{domain}/{project}.git{#comittish}",
|
|
},
|
|
}
|
|
|
|
Object.keys(gitHosts).forEach(function(host) {
|
|
gitHosts[host].protocols_re = RegExp("^(" +
|
|
gitHosts[host].protocols.map(function(P){
|
|
return P.replace(/([\\+*{}()\[\]$^|])/g, "\\$1")
|
|
}).join("|") + "):$")
|
|
})
|
|
|
|
GitHost.prototype.shortcut = function () {
|
|
return this.type + ":" + this.path()
|
|
}
|
|
|
|
GitHost.prototype.hash = function () {
|
|
return this.comittish ? "#" + this.comittish : ""
|
|
}
|
|
|
|
GitHost.prototype.path = function () {
|
|
return this.user + "/" + this.project + this.hash()
|
|
}
|
|
|
|
GitHost.prototype._fill = function (template, vars) {
|
|
if (!template) throw new Error("Tried to fill without template")
|
|
if (!vars) vars = {}
|
|
var self = this
|
|
Object.keys(this).forEach(function(K){ if (self[K]!=null && vars[K]==null) vars[K] = self[K] })
|
|
var rawComittish = vars.comittish
|
|
Object.keys(vars).forEach(function(K){ (K[0]!='#') && (vars[K] = encodeURIComponent(vars[K])) })
|
|
vars["#comittish"] = rawComittish ? "#" + rawComittish : ""
|
|
vars["/tree/comittish"] = vars.comittish ? "/"+vars.treepath+"/" + vars.comittish : "",
|
|
vars["/comittish"] = vars.comittish ? "/" + vars.comittish : ""
|
|
vars.comittish = vars.comittish || "master"
|
|
var res = template
|
|
Object.keys(vars).forEach(function(K){
|
|
res = res.replace(new RegExp("[{]" + K + "[}]", "g"), vars[K])
|
|
})
|
|
return res
|
|
}
|
|
|
|
GitHost.prototype.ssh = function () {
|
|
var sshtemplate = this.sshtemplate || gitHostDefaults.sshtemplate
|
|
return this._fill(sshtemplate)
|
|
}
|
|
|
|
GitHost.prototype.sshurl = function () {
|
|
var sshurltemplate = this.sshurltemplate || gitHostDefaults.sshurltemplate
|
|
return this._fill(sshurltemplate)
|
|
}
|
|
|
|
GitHost.prototype.browse = function () {
|
|
var browsetemplate = this.browsetemplate || gitHostDefaults.browsetemplate
|
|
return this._fill(browsetemplate)
|
|
}
|
|
|
|
GitHost.prototype.docs = function () {
|
|
var docstemplate = this.docstemplate || gitHostDefaults.docstemplate
|
|
return this._fill(docstemplate)
|
|
}
|
|
|
|
GitHost.prototype.bugs = function() {
|
|
if (! this.bugstemplate) return
|
|
return this._fill(this.bugstemplate)
|
|
}
|
|
|
|
GitHost.prototype.https = function () {
|
|
var httpstemplate = this.httpstemplate || gitHostDefaults.httpstemplate
|
|
return this._fill(httpstemplate)
|
|
}
|
|
|
|
GitHost.prototype.git = function () {
|
|
if (! this.gittemplate) return
|
|
return this._fill(this.gittemplate)
|
|
}
|
|
|
|
GitHost.prototype.file = function (P) {
|
|
var filetemplate = this.filetemplate || gitHostDefaults.filetemplate
|
|
return this._fill(filetemplate, {
|
|
path: P.replace(/^[/]+/g, "")
|
|
})
|
|
}
|
|
|
|
GitHost.prototype.toString = function () {
|
|
return this[this.default||"sshurl"]()
|
|
}
|
|
|