1 /** 2 Support for GitLab repositories. 3 4 Copyright: © 2015-2016 rejectedsoftware e.K. 5 License: Subject to the terms of the GNU GPLv3 license, as written in the included LICENSE.txt file. 6 Authors: Sönke Ludwig 7 */ 8 module dubregistry.repositories.gitlab; 9 10 import dubregistry.cache; 11 import dubregistry.dbcontroller : DbRepository; 12 import dubregistry.repositories.repository; 13 import std.string : startsWith; 14 import std.typecons; 15 import vibe.core.log; 16 import vibe.core.stream; 17 import vibe.data.json; 18 import vibe.inet.url; 19 import vibe.textfilter.urlencode; 20 21 22 class GitLabRepository : Repository { 23 private { 24 string m_owner; 25 string m_project; 26 URL m_baseURL; 27 string m_authToken; 28 } 29 30 static void register(string auth_token, string url) 31 { 32 Repository factory(DbRepository info){ 33 return new GitLabRepository(info.owner, info.project, auth_token, url.length ? URL(url) : URL("https://gitlab.com/")); 34 } 35 addRepositoryFactory("gitlab", &factory); 36 } 37 38 this(string owner, string project, string auth_token, URL base_url) 39 { 40 m_owner = owner; 41 m_project = project; 42 m_authToken = auth_token; 43 m_baseURL = base_url; 44 } 45 46 RefInfo[] getTags() 47 { 48 import std.datetime : SysTime; 49 50 Json tags; 51 try tags = readJson(getAPIURLPrefix()~"repository/tags?private_token="~m_authToken); 52 catch( Exception e ) { throw new Exception("Failed to get tags: "~e.msg); } 53 RefInfo[] ret; 54 foreach_reverse (tag; tags) { 55 try { 56 auto tagname = tag["name"].get!string; 57 Json commit = readJson(getAPIURLPrefix()~"repository/commits/"~tag["commit"]["id"].get!string~"?private_token="~m_authToken, true, true); 58 ret ~= RefInfo(tagname, tag["commit"]["id"].get!string, SysTime.fromISOExtString(commit["committed_date"].get!string)); 59 logDebug("Found tag for %s/%s: %s", m_owner, m_project, tagname); 60 } catch( Exception e ){ 61 throw new Exception("Failed to process tag "~tag["name"].get!string~": "~e.msg); 62 } 63 } 64 return ret; 65 } 66 67 RefInfo[] getBranches() 68 { 69 import std.datetime : SysTime; 70 71 Json branches = readJson(getAPIURLPrefix()~"repository/branches?private_token="~m_authToken); 72 RefInfo[] ret; 73 foreach_reverse( branch; branches ){ 74 auto branchname = branch["name"].get!string; 75 Json commit = readJson(getAPIURLPrefix()~"repository/commits/"~branch["commit"]["id"].get!string~"?private_token="~m_authToken, true, true); 76 ret ~= RefInfo(branchname, branch["commit"]["id"].get!string, SysTime.fromISOExtString(commit["committed_date"].get!string)); 77 logDebug("Found branch for %s/%s: %s", m_owner, m_project, branchname); 78 } 79 return ret; 80 } 81 82 RepositoryInfo getInfo() 83 { 84 RepositoryInfo ret; 85 auto nfo = readJson(getAPIURLPrefix()~"?private_token="~m_authToken); 86 ret.isFork = false; // not reported by API 87 ret.stats.stars = nfo["star_count"].opt!uint; // might mean watchers for Gitlab 88 ret.stats.forks = nfo["forks_count"].opt!uint; 89 ret.stats.issues = nfo["open_issues_count"].opt!uint; 90 return ret; 91 } 92 93 void readFile(string commit_sha, Path path, scope void delegate(scope InputStream) reader) 94 { 95 assert(path.absolute, "Passed relative path to readFile."); 96 auto url = m_baseURL.toString() ~ (m_owner ~ "/" ~ m_project ~ "/raw/" ~ commit_sha) ~ path.toString() ~ "?private_token="~m_authToken; 97 downloadCached(url, (scope input) { 98 reader(input); 99 }, true); 100 } 101 102 string getDownloadUrl(string ver) 103 { 104 if (m_authToken.length > 0) return null; // don't make private token public 105 if( ver.startsWith("~") ) ver = ver[1 .. $]; 106 else ver = ver; 107 return m_baseURL.toString()~m_owner~"/"~m_project~"/repository/archive.zip?ref="~ver; 108 } 109 110 void download(string ver, scope void delegate(scope InputStream) del) 111 { 112 if( ver.startsWith("~") ) ver = ver[1 .. $]; 113 else ver = ver; 114 auto url = m_baseURL.toString()~m_owner~"/"~m_project~"/repository/archive.zip?ref="~ver~"&private_token="~m_authToken; 115 downloadCached(url, del); 116 } 117 118 private string getAPIURLPrefix() { 119 return m_baseURL.toString() ~ "api/v3/projects/" ~ (m_owner ~ "/" ~ m_project).urlEncode ~ "/"; 120 } 121 }