def get_contents(repo_key, file_path=''): repo = get_repo(repo_key) refspec = request.args.get('ref', 'master') commit = get_commit_for_refspec(repo, refspec) tree = get_tree(repo, commit.tree.id) obj = get_object_from_path(repo, tree, file_path) return _get_contents(repo_key, repo, refspec, file_path, obj)
def get_tags(repo_key): repo = get_repo(repo_key) ref_names = ifilter(lambda ref_name: ref_name.startswith(TAG_REF_PREFIX), repo.listall_references()) tags = (repo.lookup_reference(ref_name) for ref_name in ref_names) return [ { "name": tag.shorthand, "commit": { "sha": unicode(tag.get_object().id), "url": url_for( "porcelain.get_commit", _external=True, repo_key=repo_key, branch_or_tag_or_sha=unicode(tag.get_object().id), ), }, "url": url_for( "porcelain.get_tag", _external=True, # NOTE: This is RestfulGit extension repo_key=repo_key, tag_name=tag.shorthand, ), } for tag in tags ]
def get_tags(repo_key): repo = get_repo(repo_key) ref_names = ifilter(lambda ref_name: ref_name.startswith(TAG_REF_PREFIX), repo.listall_references()) tags = (repo.lookup_reference(ref_name) for ref_name in ref_names) return [ { "name": tag.shorthand, "commit": { "sha": unicode(tag.get_object().id), "url": url_for('porcelain.get_commit', _external=True, repo_key=repo_key, branch_or_tag_or_sha=unicode(tag.get_object().id)), }, "url": url_for( 'porcelain.get_tag', _external=True, # NOTE: This is RestfulGit extension repo_key=repo_key, tag_name=tag.shorthand), } for tag in tags ]
def get_zip_file(repo_key, branch_or_tag_or_sha): """ Serves a ZIP file of a working copy of the repo at the given commit. Note: This endpoint is relatively slow, and the ZIP file is generated from-scratch on each request (no caching is done). """ repo = get_repo(repo_key) commit = get_commit_for_refspec(repo, branch_or_tag_or_sha) tree = get_tree(repo, commit.tree_id) wrapper_dir = _wrapper_dir_name_for(repo_key, commit) temp_file = _make_temp_file(suffix=ZIP_EXTENSION) with zipfile.ZipFile(temp_file, mode='w', compression=ZIP_COMPRESSION_METHOD, allowZip64=True) as zip_file: for filepath, _, blob in _walk_tree_recursively(repo, tree, blobs_only=True): filepath = os.path.join(wrapper_dir, filepath) zip_file.writestr(filepath, blob.data) temp_file.seek(0) return _send_transient_file_as_attachment( temp_file, _archive_filename_for(repo_key, refspec=branch_or_tag_or_sha, ext=ZIP_EXTENSION), mime_types.ZIP)
def get_commit_list(repo_key): ref_name = request.args.get('ref_name') or None start_sha = request.args.get('start_sha') or None limit = request.args.get('limit') or current_app.config['RESTFULGIT_DEFAULT_COMMIT_LIST_LIMIT'] try: limit = int(limit) except ValueError: raise BadRequest("invalid limit") if limit < 0: raise BadRequest("invalid limit") repo = get_repo(repo_key) start_commit_id = None if start_sha is not None: start_commit_id = start_sha else: if ref_name is None: ref_name = "HEAD" ref = lookup_ref(repo, ref_name) if ref is None: raise NotFound("reference not found") start_commit_id = lookup_ref(repo, ref_name).resolve().target try: walker = repo.walk(start_commit_id, GIT_SORT_TIME) except ValueError: raise BadRequest("invalid start_sha") except KeyError: raise NotFound("commit not found") commits = [convert_commit(repo_key, commit) for commit in islice(walker, limit)] return commits
def get_raw(repo_key, branch_or_tag_or_sha, file_path): repo = get_repo(repo_key) commit = get_commit_for_refspec(repo, branch_or_tag_or_sha) tree = get_tree(repo, commit.tree.id) data = get_raw_file_content(repo, tree, file_path) mime_type = guess_mime_type(os.path.basename(file_path), data) if mime_type is None: mime_type = mime_types.OCTET_STREAM return Response(data, mimetype=mime_type)
def get_commits_unique_to_branch(repo_key, branch_name, sort): # NOTE: This endpoint is a RestfulGit extension repo = get_repo(repo_key) branch = _get_branch(repo, branch_name) if sort == "chronological": sort = GIT_SORT_TIME | GIT_SORT_REVERSE else: sort = GIT_SORT_TOPOLOGICAL | GIT_SORT_REVERSE commits = list(_get_commits_unique_to_branch(repo, branch, sort)) return {"commits": [convert_commit(repo_key, repo, commit) for commit in commits]}
def get_merged_branches(repo_key, branch_name): # NOTE: This endpoint is a RestfulGit extension repo = get_repo(repo_key) branch = _get_branch(repo, branch_name) other_branches = ( repo.lookup_branch(other_branch_name) for other_branch_name in repo.listall_branches() if other_branch_name != branch_name ) merged_branches = (other_branch for other_branch in other_branches if _is_merged(repo, branch, other_branch)) return [convert_branch_summary(repo_key, merged_branch) for merged_branch in merged_branches]
def get_merge_base_for_commits(repo_key, left_sha, right_sha): # NOTE: RestfulGit extension repo = get_repo(repo_key) left_commit = _get_commit(repo, left_sha) right_commit = _get_commit(repo, right_sha) try: merge_base_oid = repo.merge_base(left_commit.id, right_commit.id) merge_base_commit = repo[merge_base_oid] except KeyError: return None else: return convert_commit(repo_key, merge_base_commit)
def get_commits_unique_to_branch(repo_key, branch_name, sort): # NOTE: This endpoint is a RestfulGit extension repo = get_repo(repo_key) branch = _get_branch(repo, branch_name) if sort == 'chronological': sort = GIT_SORT_TIME | GIT_SORT_REVERSE else: sort = GIT_SORT_TOPOLOGICAL | GIT_SORT_REVERSE commits = list(_get_commits_unique_to_branch(repo, branch, sort)) return { "commits": [convert_commit(repo_key, repo, commit) for commit in commits] }
def get_merge_base_for_commits(repo_key, left_sha, right_sha): # NOTE: RestfulGit extension repo = get_repo(repo_key) left_commit = _get_commit(repo, left_sha) right_commit = _get_commit(repo, right_sha) try: merge_base_oid = repo.merge_base(left_commit.id, right_commit.id) merge_base_commit = repo[merge_base_oid] except TypeError: return None else: return convert_commit(repo_key, merge_base_commit)
def get_tarball(repo_key, branch_or_tag_or_sha): """ Serves a TAR file of a working copy of the repo at the given commit. If Python's zlib bindings are available, the TAR file will be gzip-ed. The limited permissions information that git stores is honored in the TAR file. The commit SHA is included as a PAX header field named "comment". Note: This endpoint is relatively slow, and the TAR file is generated from-scratch on each request (no caching is done). """ repo = get_repo(repo_key) commit = get_commit_for_refspec(repo, branch_or_tag_or_sha) tree = get_tree(repo, commit.tree_id) wrapper_dir = _wrapper_dir_name_for(repo_key, commit) extension = (TGZ_EXTENSION if ZLIB_SUPPORT else TAR_EXTENSION) timestamp = int( (datetime.utcnow() - EPOCH_START ).total_seconds()) # FIX ME: use committer/author timestamp? temp_file = _make_temp_file(suffix=extension) with tarfile.open(fileobj=temp_file, mode=TARFILE_WRITE_MODE, encoding='utf-8') as tar_file: tar_file.pax_headers = {u'comment': unicode(commit.id)} for path, filemode, obj in _walk_tree_recursively(repo, tree): tar_info = tarfile.TarInfo(os.path.join(wrapper_dir, path)) tar_info.mtime = timestamp if obj.type == GIT_OBJ_BLOB: tar_info.size = obj.size if obj.type == GIT_OBJ_TREE: filemode = 0o755 # git doesn't store meaningful directory perms tar_info.mode = filemode if obj.type == GIT_OBJ_BLOB: tar_info.type = tarfile.REGTYPE content = StringIO(obj.data) elif obj.type == GIT_OBJ_TREE: tar_info.type = tarfile.DIRTYPE content = None # FIX ME: handle submodules & symlinks tar_file.addfile(tar_info, content) temp_file.seek(0) return _send_transient_file_as_attachment( temp_file, _archive_filename_for(repo_key, refspec=branch_or_tag_or_sha, ext=extension), (mime_types.GZIP if ZLIB_SUPPORT else mime_types.TAR))
def get_compare_diff(repo_key, old_branch_or_tag_or_sha, new_branch_or_tag_or_sha): context = request.args.get('context', 3) # NOTE: The `context` parameter is a RestfulGit extension try: context = int(context) except ValueError: raise BadRequest("context was not a valid integer") if context < 0: raise BadRequest("context must not non negative") repo = get_repo(repo_key) old_commit = get_commit_for_refspec(repo, old_branch_or_tag_or_sha) new_commit = get_commit_for_refspec(repo, new_branch_or_tag_or_sha) diff = _get_diff(repo, new_commit, against=old_commit, context_lines=context) return Response(diff.patch, mimetype=mime_types.DIFF)
def get_branches(repo_key): repo = get_repo(repo_key) branches = (repo.lookup_branch(branch_name) for branch_name in repo.listall_branches()) return [ { "name": branch.branch_name, "commit": { "sha": unicode(branch.target), "url": url_for('porcelain.get_commit', _external=True, repo_key=repo_key, branch_or_tag_or_sha=unicode(branch.target)), }, } for branch in branches ]
def get_tag(repo_key, tag_name): # NOTE: This endpoint is a RestfulGit extension repo = get_repo(repo_key) tag = lookup_ref(repo, TAG_REF_PREFIX + tag_name) if tag is None: raise NotFound("tag not found") result = { "name": tag.shorthand, "commit": convert_commit(repo_key, repo, tag.get_object()), "url": url_for("porcelain.get_tag", _external=True, repo_key=repo_key, tag_name=tag.shorthand), } # simple tag if tag.target != tag.get_object().id: tag_obj = repo[tag.target] result["tag"] = convert_tag(repo_key, repo, tag_obj) return result
def get_branches(repo_key): repo = get_repo(repo_key) branches = (repo.lookup_branch(branch_name) for branch_name in repo.listall_branches()) return [{ "name": branch.branch_name, "commit": { "sha": unicode(branch.target), "url": url_for('porcelain.get_commit', _external=True, repo_key=repo_key, branch_or_tag_or_sha=unicode(branch.target)), }, } for branch in branches]
def get_tag(repo_key, tag_name): # NOTE: This endpoint is a RestfulGit extension repo = get_repo(repo_key) tag = lookup_ref(repo, TAG_REF_PREFIX + tag_name) if tag is None: raise NotFound("tag not found") result = { "name": tag.shorthand, "commit": convert_commit(repo_key, repo, tag.peel()), "url": url_for('porcelain.get_tag', _external=True, repo_key=repo_key, tag_name=tag.shorthand), } # simple tag if tag.target != tag.peel().id: tag_obj = repo[tag.target] result['tag'] = convert_tag(repo_key, repo, tag_obj) return result
def get_refs(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_names = ifilter(lambda x: x.startswith(ref_path), repo.listall_references()) references = (repo.lookup_reference(ref_name) for ref_name in ref_names) nonsymbolic_refs = ifilter(lambda x: x.type != GIT_REF_SYMBOLIC, references) ref_data = [ convert_ref(repo_key, reference, repo[reference.target]) for reference in nonsymbolic_refs ] if len(ref_data) == 1 and ref_data[0]['ref'] == ref_path: # exact match ref_data = ref_data[0] return ref_data
def get_refs(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_names = filter(lambda x: x.startswith(ref_path), repo.listall_references()) references = (repo.lookup_reference(ref_name) for ref_name in ref_names) nonsymbolic_refs = filter(lambda x: x.type != GIT_REF_SYMBOLIC, references) ref_data = [ convert_ref(repo_key, reference, repo[reference.target]) for reference in nonsymbolic_refs ] if len(ref_data) == 1 and ref_data[0]['ref'] == ref_path: # exact match ref_data = ref_data[0] return ref_data
def get_contributors(repo_key): repo = get_repo(repo_key) authors = get_authors(repo) email_to_name = {} commit_counts = defaultdict(int) for author in authors: email = author.email email_to_name.setdefault(email, author.name) commit_counts[email] += 1 leaderboard = commit_counts.items() leaderboard.sort(key=(lambda pair: pair[1]), reverse=True) return [ { "email": email, # NOTE: This is RestfulGit extension "name": email_to_name[email], "contributions": commit_count, } for email, commit_count in leaderboard ]
def get_blame(repo_key, branch_or_tag_or_sha, file_path): min_line = request.args.get('firstLine') if min_line is None: min_line = 1 try: min_line = int(min_line) except ValueError: raise BadRequest("firstLine was not a valid integer") if min_line < 1: raise BadRequest("firstLine must be positive") max_line = request.args.get('lastLine') if max_line is not None: try: max_line = int(max_line) except ValueError: raise BadRequest("lastLine was not a valid integer") if max_line < 1: raise BadRequest("lastLine must be positive") if min_line > max_line: raise BadRequest("firstLine cannot be greater than lastLine") repo = get_repo(repo_key) newest_commit = get_commit_for_refspec(repo, branch_or_tag_or_sha) tree = get_tree(repo, newest_commit.tree_id) raw_lines = get_raw_file_content(repo, tree, file_path).splitlines() if min_line > len(raw_lines): raise BadRequest("firstLine out of bounds") if max_line is not None and max_line > len(raw_lines): raise BadRequest("lastLine out of bounds") raw_lines = raw_lines[(min_line - 1):max_line] blame = _get_blame( repo, file_path, newest_commit, oldest_refspec=request.args.get('oldest'), min_line=min_line, max_line=max_line, ) return convert_blame(repo_key, repo, blame, raw_lines, min_line)
def get_tarball(repo_key, branch_or_tag_or_sha): """ Serves a TAR file of a working copy of the repo at the given commit. If Python's zlib bindings are available, the TAR file will be gzip-ed. The limited permissions information that git stores is honored in the TAR file. The commit SHA is included as a PAX header field named "comment". Note: This endpoint is relatively slow, and the TAR file is generated from-scratch on each request (no caching is done). """ repo = get_repo(repo_key) commit = get_commit_for_refspec(repo, branch_or_tag_or_sha) tree = get_tree(repo, commit.tree.hex) wrapper_dir = _wrapper_dir_name_for(repo_key, commit) extension = (TGZ_EXTENSION if ZLIB_SUPPORT else TAR_EXTENSION) timestamp = int((datetime.utcnow() - EPOCH_START).total_seconds()) # FIX ME: use committer/author timestamp? temp_file = _make_temp_file(suffix=extension) with tarfile.open(fileobj=temp_file, mode=TARFILE_WRITE_MODE, encoding='utf-8') as tar_file: tar_file.pax_headers = {u'comment': commit.hex.decode('ascii')} for path, filemode, obj in _walk_tree_recursively(repo, tree): tar_info = tarfile.TarInfo(os.path.join(wrapper_dir, path)) tar_info.mtime = timestamp if obj.type == GIT_OBJ_BLOB: tar_info.size = obj.size if obj.type == GIT_OBJ_TREE: filemode = 0o755 # git doesn't store meaningful directory perms tar_info.mode = filemode if obj.type == GIT_OBJ_BLOB: tar_info.type = tarfile.REGTYPE content = StringIO(obj.data) elif obj.type == GIT_OBJ_TREE: tar_info.type = tarfile.DIRTYPE content = None # FIX ME: handle submodules & symlinks tar_file.addfile(tar_info, content) temp_file.seek(0) return _send_transient_file_as_attachment(temp_file, _archive_filename_for(repo_key, refspec=branch_or_tag_or_sha, ext=extension), (mime_types.GZIP if ZLIB_SUPPORT else mime_types.TAR))
def get_zip_file(repo_key, branch_or_tag_or_sha): """ Serves a ZIP file of a working copy of the repo at the given commit. Note: This endpoint is relatively slow, and the ZIP file is generated from-scratch on each request (no caching is done). """ repo = get_repo(repo_key) commit = get_commit_for_refspec(repo, branch_or_tag_or_sha) tree = get_tree(repo, commit.tree.hex) wrapper_dir = _wrapper_dir_name_for(repo_key, commit) temp_file = _make_temp_file(suffix=ZIP_EXTENSION) with zipfile.ZipFile(temp_file, mode='w', compression=ZIP_COMPRESSION_METHOD, allowZip64=True) as zip_file: for filepath, _, blob in _walk_tree_recursively(repo, tree, blobs_only=True): filepath = os.path.join(wrapper_dir, filepath) zip_file.writestr(filepath, blob.data) temp_file.seek(0) return _send_transient_file_as_attachment(temp_file, _archive_filename_for(repo_key, refspec=branch_or_tag_or_sha, ext=ZIP_EXTENSION), mime_types.ZIP)
def get_commit_list(repo_key): ref_name = request.args.get('ref_name') or None start_sha = request.args.get('start_sha') or None limit = request.args.get( 'limit') or current_app.config['RESTFULGIT_DEFAULT_COMMIT_LIST_LIMIT'] try: limit = int(limit) except ValueError: raise BadRequest("invalid limit") if limit < 0: raise BadRequest("invalid limit") repo = get_repo(repo_key) start_commit_id = None if start_sha is not None: start_commit_id = start_sha else: if ref_name is None: ref_name = "HEAD" ref = lookup_ref(repo, ref_name) if ref is None: raise NotFound("reference not found") start_ref = lookup_ref(repo, ref_name) try: start_commit_id = start_ref.resolve().target except KeyError: if ref_name == "HEAD": return [] else: raise NotFound("reference not found") try: walker = repo.walk(start_commit_id, GIT_SORT_TIME) except ValueError: raise BadRequest("invalid start_sha") except KeyError: raise NotFound("commit not found") commits = [ convert_commit(repo_key, commit) for commit in islice(walker, limit) ] return commits
def get_blob(repo_key, sha): repo = get_repo(repo_key) blob = _get_blob(repo, sha) return convert_blob(repo_key, blob)
def get_commit(repo_key, branch_or_tag_or_sha): repo = get_repo(repo_key) commit = get_commit_for_refspec(repo, branch_or_tag_or_sha) return convert_commit(repo_key, repo, commit, include_diff=True)
def get_tree(repo_key, sha): recursive = request.args.get('recursive') == '1' repo = get_repo(repo_key) tree = _get_tree(repo, sha) return convert_tree(repo_key, repo, tree, recursive)
def get_branches(repo_key): repo = get_repo(repo_key) branches = (repo.lookup_branch(branch_name) for branch_name in repo.listall_branches()) return [convert_branch_summary(repo_key, branch) for branch in branches]
def get_tag(repo_key, sha): repo = get_repo(repo_key) tag = _get_tag(repo, sha) return convert_tag(repo_key, repo, tag)
def get_diff(repo_key, branch_or_tag_or_sha=None): repo = get_repo(repo_key) commit = get_commit_for_refspec(repo, branch_or_tag_or_sha) diff = _get_diff(repo, commit) return Response(diff.patch, mimetype=mime_types.DIFF)
def get_commit(repo_key, sha): repo = get_repo(repo_key) commit = _get_commit(repo, sha) return convert_commit(repo_key, commit)
def get_repo_info(repo_key): get_repo(repo_key) # check repo_key validity return convert_repo(repo_key)
def fetch_origin(repo_key): get_repo(repo_key) # check repo_key validity result = remote_update(repo_key) return result
def get_branch(repo_key, branch_name): repo = get_repo(repo_key) branch = _get_branch(repo, branch_name) return convert_branch(repo_key, repo, branch)
def get_branch(repo_key, branch_name): repo = get_repo(repo_key) branch = _get_branch(repo, branch_name) return convert_branch_verbose(repo_key, repo, branch)