-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
241 additions
and
0 deletions.
There are no files selected for viewing
186 changes: 186 additions & 0 deletions
186
tests/fixtures/07b9bf1540305153ceeb4519a50b588c35a35464.diff
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
diff --git a/api.py b/api.py | ||
new file mode 100644 | ||
index 0000000..ae9d907 | ||
--- /dev/null | ||
+++ b/api.py | ||
@@ -0,0 +1,179 @@ | ||
+from flask import Flask, url_for | ||
+from werkzeug.exceptions import NotFound | ||
+app = Flask(__name__) | ||
+from pygit2 import Repository, GIT_OBJ_COMMIT, GIT_OBJ_TREE, GIT_OBJ_BLOB, GIT_REF_SYMBOLIC | ||
+from datetime import datetime, tzinfo, timedelta | ||
+import json | ||
+from base64 import b64encode | ||
+ | ||
+class FixedOffset(tzinfo): | ||
+ ZERO = timedelta(0) | ||
+ def __init__(self, offset): | ||
+ self._offset = timedelta(minutes = offset) | ||
+ | ||
+ def utcoffset(self, dt): | ||
+ return self._offset | ||
+ | ||
+ def dst(self, dt): | ||
+ return self.ZERO | ||
+ | ||
+REPO_BASE = '/Users/rajiv/Code/' | ||
+ | ||
+def _get_repo(repo_key): | ||
+ path = REPO_BASE + repo_key | ||
+ try: | ||
+ return Repository(path) | ||
+ except KeyError: | ||
+ raise NotFound("repository not found") | ||
+ | ||
+def _convert_signature(sig): | ||
+ return { | ||
+ "name" : sig.name, | ||
+ "email" : sig.email, | ||
+ "date" : datetime.fromtimestamp(sig.time, FixedOffset(sig.offset)) | ||
+ } | ||
+ | ||
+def _convert_commit(repo_key, commit): | ||
+ return { | ||
+ "url": url_for('get_commit', _external=True, repo_key=repo_key, sha=commit.hex), | ||
+ "sha": commit.hex, | ||
+ "author": _convert_signature(commit.author), | ||
+ "committer": _convert_signature(commit.committer), | ||
+ "message": commit.message, | ||
+ "tree" : { | ||
+ "sha": commit.tree.hex, | ||
+ "url": url_for('get_tree', _external=True, repo_key=repo_key, sha=commit.tree.hex), | ||
+ }, | ||
+ "parents" : [{ | ||
+ "sha": c.hex, | ||
+ "url": url_for('get_commit', _external=True, repo_key=repo_key, sha=c.hex) | ||
+ } for c in commit.parents] | ||
+ } | ||
+ | ||
+def _convert_tree(repo_key, tree): | ||
+ entry_list = [] | ||
+ for entry in tree: | ||
+ obj = entry.to_object() | ||
+ entry_data = { | ||
+ "path": entry.name, | ||
+ "sha": entry.hex, | ||
+ } | ||
+ if obj.type == GIT_OBJ_BLOB: | ||
+ entry_data['type'] = "blob" | ||
+ entry_data['size'] = obj.size | ||
+ entry_data['url'] = url_for('get_blob', _external=True, repo_key=repo_key, sha=entry.hex) | ||
+ elif obj.type == GIT_OBJ_TREE: | ||
+ entry_data['type'] = "tree" | ||
+ entry_data['url'] = url_for('get_tree', _external=True, repo_key=repo_key, sha=entry.hex) | ||
+ entry_list.append(entry_data) | ||
+ | ||
+ return { | ||
+ "url": url_for('get_tree', _external=True, repo_key=repo_key, sha=tree.hex), | ||
+ "sha": tree.hex, | ||
+ "tree": entry_list, | ||
+ #"mode": todo, | ||
+ } | ||
+ | ||
+def _linkobj_for_gitobj(repo_key, obj, include_type=False): | ||
+ data = {} | ||
+ data['sha'] = obj.hex | ||
+ obj_type = None | ||
+ if obj.type == GIT_OBJ_COMMIT: | ||
+ obj_type = 'commit' | ||
+ elif obj.type == GIT_OBJ_TREE: | ||
+ obj_type = 'tree' | ||
+ elif obj.type == GIT_OBJ_BLOB: | ||
+ obj_type = 'blob' | ||
+ if obj_type is not None: | ||
+ data['url'] = url_for('get_' + obj_type, _external=True, repo_key=repo_key, sha=obj.hex) | ||
+ if include_type: | ||
+ data['type'] = obj_type | ||
+ return data | ||
+ | ||
+def _encode_blob_data(data): | ||
+ try: | ||
+ return 'utf-8', data.decode('utf-8') | ||
+ except UnicodeDecodeError: | ||
+ return 'base64', b64encode(data) | ||
+ | ||
+def _convert_blob(repo_key, blob): | ||
+ encoding, data = _encode_blob_data(blob.data) | ||
+ return { | ||
+ "url": url_for('get_blob', _external=True, repo_key=repo_key, sha=blob.hex), | ||
+ "sha": blob.hex, | ||
+ "size": blob.size, | ||
+ "encoding": encoding, | ||
+ "data": data, | ||
+ } | ||
+ | ||
+def _convert_ref(repo_key, ref, obj): | ||
+ return { | ||
+ "url": url_for('get_ref_list', _external=True, repo_key=repo_key, ref_path=ref.name[5:]), #[5:] to cut off the redundant refs/ | ||
+ "ref": ref.name, | ||
+ "object": _linkobj_for_gitobj(repo_key, obj, include_type=True), | ||
+ } | ||
+ | ||
+def dthandler(obj): | ||
+ if hasattr(obj, 'isoformat'): | ||
+ return obj.isoformat() | ||
+ | ||
+def _json_dump(obj): | ||
+ return json.dumps(obj, default=dthandler) | ||
+ | ||
+@app.route('/repos/<repo_key>/git/commits/<sha>') | ||
+def get_commit(repo_key, sha): | ||
+ repo = _get_repo(repo_key) | ||
+ try: | ||
+ commit = repo[unicode(sha)] | ||
+ except KeyError: | ||
+ raise NotFound("commit not found") | ||
+ if commit.type != GIT_OBJ_COMMIT: | ||
+ raise NotFound("sha not a commit") | ||
+ return _json_dump(_convert_commit(repo_key, commit)) | ||
+ | ||
+ | ||
+@app.route('/repos/<repo_key>/git/trees/<sha>') | ||
+def get_tree(repo_key, sha): | ||
+ repo = _get_repo(repo_key) | ||
+ try: | ||
+ tree = repo[unicode(sha)] | ||
+ except KeyError: | ||
+ raise NotFound("tree not found") | ||
+ if tree.type != GIT_OBJ_TREE: | ||
+ raise NotFound("sha not a tree") | ||
+ return _json_dump(_convert_tree(repo_key, tree)) | ||
+ | ||
+@app.route('/repos/<repo_key>/git/blobs/<sha>') | ||
+def get_blob(repo_key, sha): | ||
+ repo = _get_repo(repo_key) | ||
+ try: | ||
+ blob = repo[unicode(sha)] | ||
+ except KeyError: | ||
+ raise NotFound("blob not found") | ||
+ if blob.type != GIT_OBJ_BLOB: | ||
+ raise NotFound("sha not a blob") | ||
+ return _json_dump(_convert_blob(repo_key, blob)) | ||
+ | ||
+ | ||
+ | ||
+@app.route('/repos/<repo_key>/git/refs') | ||
+@app.route('/repos/<repo_key>/git/refs/<path:ref_path>') | ||
+def get_ref_list(repo_key, ref_path=None): | ||
+ if ref_path is not None: | ||
+ ref_path = "refs/" + ref_path | ||
+ else: | ||
+ ref_path = "" | ||
+ repo = _get_repo(repo_key) | ||
+ ref_data = [ | ||
+ _convert_ref(repo_key, reference, repo[reference.oid]) for reference in filter(lambda x: x.type != GIT_REF_SYMBOLIC, [repo.lookup_reference(r) for r in filter(lambda x: x.startswith(ref_path), repo.listall_references())]) | ||
+ ] | ||
+ if len(ref_data) == 1: | ||
+ ref_data = ref_data[0] | ||
+ return _json_dump(ref_data) | ||
+ | ||
+ | ||
+if __name__ == '__main__': | ||
+ app.debug = True | ||
+ app.run(host="0.0.0.0") | ||
+ | ||
+application = app | ||
\ No newline at end of file |
27 changes: 27 additions & 0 deletions
27
tests/fixtures/d408fc2428bc6444cabd7f7b46edbe70b6992b16.diff
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
diff --git a/README.md b/README.md | ||
index 1b51a0e..c65dc8c 100644 | ||
--- a/README.md | ||
+++ b/README.md | ||
@@ -4,6 +4,11 @@ REST API for Git data | ||
Provides a read-only restful interface for accessing data from Git repositories (local to the server). | ||
Modeled off the GitHub Git DB API for compatibility (see http://developer.github.com/v3/git/). | ||
|
||
+Requires: flask, pygit2 (>= 0.18.1), libgit2 (>= 0.18). | ||
+Must modify: REPO_BASE (root path for repositories, note only repositories immediately under this path are currently supported). | ||
+ | ||
+api.py is a valid WSGI application. | ||
+ | ||
-- | ||
|
||
All of these routes return JSON unless otherwise specified. | ||
diff --git a/requirements.txt b/requirements.txt | ||
new file mode 100644 | ||
index 0000000..da23f6c | ||
--- /dev/null | ||
+++ b/requirements.txt | ||
@@ -0,0 +1,5 @@ | ||
+Flask==0.9 | ||
+Jinja2==2.6 | ||
+Werkzeug==0.8.3 | ||
+pygit2==0.18.1 | ||
+wsgiref==0.1.2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters