def commits(branch_or_ref): """ Lists all commits of a given git branch. Returns: HTTP Response 200: a list of commits HTTP Response 403: unknown branch or ref HTTP Response 406: Unsupported Mimetype requested """ quit = current_app.config['quit'] if not branch_or_ref: branch_or_ref = quit.getDefaultBranch() try: current_app.logger.debug(branch_or_ref) if not quit.repository.is_empty: results = quit.repository.revisions(branch_or_ref, order=pygit2.GIT_SORT_TIME) else: results = [] if 'Accept' in request.headers: mimetype = parse_accept_header(request.headers['Accept']).best else: mimetype = '*/*' if mimetype in ['text/html', 'application/xhtml_xml', '*/*']: data = generate_graph_data(CommitGraph.gets(results)) response = make_response(render_template('commits.html', results=results, data=data, current_ref=branch_or_ref, isLoggedIn=isLoggedIn, githubEnabled=githubEnabled)) response.headers['Content-Type'] = 'text/html' return response elif mimetype in ['application/json', 'application/sparql-results+json']: res = [] for revision in results: res.append({"id": revision.id, "author_name": revision.author.name, "author_email": revision.author.email, "author_time": str(git_timestamp(revision.author.time, revision.author.offset)), "committer_name": revision.committer.name, "committer_email": revision.committer.email, "committer_time": str(git_timestamp(revision.committer.time, revision.committer.offset)), "committer_offset": revision.committer.offset, "message": revision.message, "parrents": [parent.id for parent in revision.parents]}) response = make_response(json.dumps(res), 200) response.headers['Content-Type'] = 'application/json' return response else: return "<pre>Unsupported Mimetype: {}</pre>".format(mimetype), 406 except Exception as e: current_app.logger.error(e) current_app.logger.error(traceback.format_exc()) return "<pre>" + traceback.format_exc() + "</pre>", 403
def blame(branch_or_ref): quit = current_app.config['quit'] default_branch = quit.config.getDefaultBranch() or 'master' if not branch_or_ref and not quit.repository.is_empty: branch_or_ref = default_branch blame = current_app.config['blame'] if 'Accept' in request.headers: mimetype = parse_accept_header(request.headers['Accept']).best else: mimetype = 'application/sparql-results+json' try: res = blame.run(branch_or_ref=branch_or_ref) if mimetype in ['text/html', 'application/xhtml_xml', '*/*']: results = [{ 'commit': quit.repository.revision(row['hex']), 'blame': row } for row in res] response = make_response( render_template("blame.html", results=results, current_ref=branch_or_ref)) response.headers['Content-Type'] = 'text/html' return response elif mimetype in [ 'application/json', 'application/sparql-results+json' ]: response = make_response(res.serialize(format='json'), 200) response.headers['Content-Type'] = 'application/json' return response elif mimetype in [ 'application/rdf+xml', 'application/xml', 'application/sparql-results+xml' ]: response = make_response(res.serialize(format='xml'), 200) response.headers['Content-Type'] = 'application/rdf+xml' return response elif mimetype in ['application/csv', 'text/csv']: response = make_response(res.serialize(format='csv'), 200) response.headers['Content-Type'] = 'text/csv' return response except Exception as e: current_app.logger.error(e) current_app.logger.error(traceback.format_exc()) return "<pre>" + traceback.format_exc() + "</pre>", 400
def provenance(): """Process a SPARQL query (Select only) against Provenance endpoint. Returns: HTTP Response with query result: If query was a valid select query. HTTP Response 200: If request contained a valid update query. HTTP Response 400: If request doesn't contain a valid sparql query. HTTP Response 406: If accept header is not acceptable. """ quit = current_app.config['quit'] q = request.values.get('query', None) logger.info('Received provenance query: {}'.format(q)) if 'Accept' in request.headers: mimetype = parse_accept_header(request.headers['Accept']).best else: mimetype = '*/*' if q: try: queryType, parsedQuery = parse_query_type(q) except UnSupportedQueryType as e: logger.exception(e) return make_response('Unsupported Query Type', 400) graph = quit.store.store if queryType not in [ 'SelectQuery', 'AskQuery', 'ConstructQuery', 'DescribeQuery' ]: return make_response('Unsupported Query Type', 400) res = graph.query(q) try: if queryType in ['SelectQuery', 'AskQuery']: return create_result_response(res, resultSetMimetypes[mimetype]) elif queryType in ['ConstructQuery', 'DescribeQuery']: return create_result_response(res, rdfMimetypes[mimetype]) except KeyError as e: return make_response( "Mimetype: {} not acceptable".format(mimetype), 406) else: if mimetype == 'text/html': return render_template('provenance.html')
def del_branch(refspec): """Branch two commits and set the result to branch_or_ref. merge branch into target and set branch_or_ref to the resulting commit - if only branch_or_ref is given, do nothing - if branch_or_ref and branch is given, merge branch into branch_or_ref and set branch_or_ref to the resulting commit - if branch_or_ref, branch and target are given, merge branch into target and set branch_or_ref to the resulting commit Returns: HTTP Response 200: If requesting the HTML interface HTTP Response 201: If branch was possible HTTP Response 400: If branching did not work or unsupported mimetype """ quit = current_app.config['quit'] try: if 'Accept' in request.headers: mimetype = parse_accept_header(request.headers['Accept']).best else: mimetype = '*/*' refspec = re.sub("^refs/heads/", "", refspec) branch = quit.repository._repository.branches.get(refspec) if branch: branch.delete() message = "{} deleted".format(refspec) status = 200 else: message = "{} not found".format(refspec) status = 404 if mimetype in ['text/html', 'application/xhtml_xml', '*/*']: response = make_response( render_template('message.html', message=message)) response.headers['Content-Type'] = 'text/html' return response, status else: return "<pre>Unsupported Mimetype: {}</pre>".format(mimetype), 400 except Exception as e: current_app.logger.error(e) current_app.logger.error(traceback.format_exc()) return "<pre>" + traceback.format_exc() + "</pre>", 400
def del_branch(refspec): """Branch two commits and set the result to branch_or_ref. merge branch into target and set branch_or_ref to the resulting commit - if only branch_or_ref is given, do nothing - if branch_or_ref and branch is given, merge branch into branch_or_ref and set branch_or_ref to the resulting commit - if branch_or_ref, branch and target are given, merge branch into target and set branch_or_ref to the resulting commit Returns: HTTP Response 200: If requesting the HTML interface HTTP Response 201: If branch was possible HTTP Response 400: If branching did not work or unsupported mimetype """ quit = current_app.config['quit'] try: if 'Accept' in request.headers: mimetype = parse_accept_header(request.headers['Accept']).best else: mimetype = '*/*' refspec = re.sub("^refs/heads/", "", refspec) branch = quit.repository._repository.branches.get(refspec) if branch: branch.delete() message = "{} deleted".format(refspec) status = 200 else: message = "{} not found".format(refspec) status = 404 if mimetype in ['text/html', 'application/xhtml_xml', '*/*']: response = make_response(render_template('message.html', message=message)) response.headers['Content-Type'] = 'text/html' return response, status else: return "<pre>Unsupported Mimetype: {}</pre>".format(mimetype), 400 except Exception as e: current_app.logger.error(e) current_app.logger.error(traceback.format_exc()) return "<pre>" + traceback.format_exc() + "</pre>", 400
def branch(refspec): """Branch two commits and set the result to branch_or_ref. merge branch into target and set branch_or_ref to the resulting commit - if only branch_or_ref is given, do nothing - if branch_or_ref and branch is given, merge branch into branch_or_ref and set branch_or_ref to the resulting commit - if branch_or_ref, branch and target are given, merge branch into target and set branch_or_ref to the resulting commit Returns: HTTP Response 200: If requesting the HTML interface HTTP Response 201: If branch was possible HTTP Response 400: If branching did not work or unsupported mimetype """ quit = current_app.config['quit'] try: if 'Accept' in request.headers: mimetype = parse_accept_header(request.headers['Accept']).best else: mimetype = '*/*' status = 200 if refspec: oldbranch, newbranch = refspec.split(":") else: oldbranch = request.values.get('oldbranch') newbranch = request.values.get('newbranch') if newbranch: quit.repository.branch(oldbranch, newbranch) status = 201 if mimetype in ['text/html', 'application/xhtml_xml', '*/*']: response = make_response(render_template('branch.html')) response.headers['Content-Type'] = 'text/html' return response, status else: return "<pre>Unsupported Mimetype: {}</pre>".format(mimetype), 400 except Exception as e: current_app.logger.error(e) current_app.logger.error(traceback.format_exc()) return "<pre>" + traceback.format_exc() + "</pre>", 400
def provenance(): """Process a SPARQL query (Select only) against Provenance endpoint. Returns: HTTP Response with query result: If query was a valid select query. HTTP Response 200: If request contained a valid update query. HTTP Response 400: If request doesn't contain a valid sparql query. HTTP Response 406: If accept header is not acceptable. """ quit = current_app.config['quit'] query, type, default_graph, named_graph = parse_sparql_request(request) logger.info('Received provenance query: {}'.format(query)) if query is not None and type == 'query': if len(named_graph) > 0: return make_response('Unsupported Query, "FROM NAMED not supported, yet"', 400) try: queryType, parsedQuery = parse_query_type(query) except UnSupportedQuery: return make_response('Unsupported Query', 400) except NonAbsoluteBaseError: return make_response('Non absolute Base URI given', 400) except SparqlProtocolError: return make_response('Sparql Protocol Error', 400) graph = quit.store.store if queryType not in ['SelectQuery', 'AskQuery', 'ConstructQuery', 'DescribeQuery']: return make_response('Unsupported Query Type', 400) res = graph.query(query) mimetype = _getBestMatchingMimeType(request, queryType) if not mimetype: return make_response("Mimetype: {} not acceptable".format(mimetype), 406) return create_result_response(res, mimetype) else: if request.accept_mimetypes.best_match(['text/html']) == 'text/html': return render_template('sparql.html', mode='provenance')
def blame(branch_or_ref): quit = current_app.config['quit'] if not branch_or_ref and not quit.repository.is_empty: branch_or_ref = quit.getDefaultBranch() blame = current_app.config['blame'] if 'Accept' in request.headers: mimetype = parse_accept_header(request.headers['Accept']).best else: mimetype = 'application/sparql-results+json' try: res = blame.run(branch_or_ref=branch_or_ref) if mimetype in ['text/html', 'application/xhtml_xml', '*/*']: results = [{'commit': quit.repository.revision( row['hex']), 'blame': row} for row in res] response = make_response(render_template("blame.html", results=results, current_ref=branch_or_ref)) response.headers['Content-Type'] = 'text/html' return response elif mimetype in ['application/json', 'application/sparql-results+json']: response = make_response(res.serialize(format='json'), 200) response.headers['Content-Type'] = 'application/json' return response elif mimetype in [ 'application/rdf+xml', 'application/xml', 'application/sparql-results+xml' ]: response = make_response(res.serialize(format='xml'), 200) response.headers['Content-Type'] = 'application/rdf+xml' return response elif mimetype in ['application/csv', 'text/csv']: response = make_response(res.serialize(format='csv'), 200) response.headers['Content-Type'] = 'text/csv' return response except Exception as e: current_app.logger.error(e) current_app.logger.error(traceback.format_exc()) return "<pre>" + traceback.format_exc() + "</pre>", 400
def commits(branch_or_ref): """ Lists all commits of a given git branch. Returns: HTTP Response 200: a list of commits HTTP Response 403: unknown branch or ref HTTP Response 406: Unsupported Mimetype requested """ quit = current_app.config['quit'] default_branch = quit.config.getDefaultBranch() if not branch_or_ref and not quit.repository.is_empty: branch_or_ref = default_branch try: results = quit.repository.revisions( branch_or_ref, order=pygit2.GIT_SORT_TIME) if branch_or_ref else [] if 'Accept' in request.headers: mimetype = parse_accept_header(request.headers['Accept']).best else: mimetype = '*/*' if mimetype in ['text/html', 'application/xhtml_xml', '*/*']: data = generate_graph_data(CommitGraph.gets(results)) response = make_response( render_template('commits.html', results=results, data=data)) response.headers['Content-Type'] = 'text/html' return response elif mimetype in [ 'application/json', 'application/sparql-results+json' ]: res = [] for revision in results: res.append({ "id": revision.id, "author_name": revision.author.name, "author_email": revision.author.email, "author_time": str( git_timestamp(revision.author.time, revision.author.offset)), "committer_name": revision.committer.name, "committer_email": revision.committer.email, "committer_time": str( git_timestamp(revision.committer.time, revision.committer.offset)), "committer_offset": revision.committer.offset, "message": revision.message, "parrents": [parent.id for parent in revision.parents] }) response = make_response(json.dumps(res), 200) response.headers['Content-Type'] = 'application/json' return response else: return "<pre>Unsupported Mimetype: {}</pre>".format(mimetype), 406 except Exception as e: current_app.logger.error(e) current_app.logger.error(traceback.format_exc()) return "<pre>" + traceback.format_exc() + "</pre>", 403
def sparql(branch_or_ref): """Process a SPARQL query (Select or Update). Returns: HTTP Response with query result: If query was a valid select query. HTTP Response 200: If request contained a valid update query. HTTP Response 406: If accept header is not acceptable. """ quit = current_app.config['quit'] default_branch = quit.getDefaultBranch() if not branch_or_ref and not quit.repository.is_empty: branch_or_ref = default_branch logger.debug("Request method: {}".format(request.method)) query, type, default_graph, named_graph = parse_sparql_request(request) if query is None: if request.accept_mimetypes.best_match(['text/html']) == 'text/html': return render_template('sparql.html', current_ref=branch_or_ref or default_branch, mode='query') else: return make_response('No Query was specified or the Content-Type is not set according' + 'to the SPARQL 1.1 standard', 400) else: # TODO allow USING NAMED when fixed in rdflib if len(named_graph) > 0: return make_response('FROM NAMED and USING NAMED not supported, yet', 400) parse_type = getattr(helpers, 'parse_' + type + '_type') try: queryType, parsedQuery = parse_type( query, quit.config.namespace, default_graph, named_graph) except UnSupportedQuery: return make_response('Unsupported Query', 400) except NonAbsoluteBaseError: return make_response('Non absolute Base URI given', 400) except SparqlProtocolError: return make_response('Sparql Protocol Error', 400) if queryType in ['InsertData', 'DeleteData', 'Modify', 'DeleteWhere', 'Load']: if branch_or_ref: commit_id = quit.repository.revision(branch_or_ref).id else: commit_id = None parent_commit_id = request.values.get('parent_commit_id', None) or None if parent_commit_id and parent_commit_id != commit_id: resolution_method = request.values.get('resolution_method', None) or None if resolution_method == "reject": logger.debug("rejecting update because {} is at {} but {} was expected".format( branch_or_ref, commit_id, parent_commit_id)) return make_response('reject', 409) # alternative 412 elif resolution_method in ("merge", "branch"): logger.debug(("writing update to a branch of {} because it is at {} but {} was " "expected").format(branch_or_ref, commit_id, parent_commit_id)) try: quit.repository.lookup(parent_commit_id) except RevisionNotFound: return make_response("The provided parent commit (parent_commit_id={}) " "could not be found.".format(parent_commit_id), 400) time = datetime.datetime.now().strftime('%Y-%m-%d-%H%M%S') shortUUID = (base64.urlsafe_b64encode(uuid.uuid1().bytes).decode("utf-8") ).rstrip('=\n').replace('/', '_') target_branch = "tmp/{}_{}".format(time, shortUUID) target_ref = "refs/heads/" + target_branch logger.debug("target ref is: {}".format(target_ref)) oid = quit.applyQueryOnCommit(parsedQuery, parent_commit_id, target_ref, query=query, default_graph=default_graph, named_graph=named_graph) if resolution_method == "merge": logger.debug(("going to merge update into {} because it is at {} but {} was " "expected").format(branch_or_ref, commit_id, parent_commit_id)) try: quit.repository.merge(target=branch_or_ref, branch=target_ref) oid = quit.repository.revision(branch_or_ref).id # delete temporary branch tmp_branch = quit.repository._repository.branches.get(target_branch) tmp_branch.delete() response = make_response('success', 200) target_branch = branch_or_ref except QuitMergeConflict as e: response = make_response('merge failed', 400) else: response = make_response('branched', 200) response.headers["X-CurrentBranch"] = target_branch response.headers["X-CurrentCommit"] = oid return response # Add info about temporary branch else: graph, commitid = quit.instance(parent_commit_id) target_head = request.values.get('target_head', branch_or_ref) or default_branch target_ref = 'refs/heads/{}'.format(target_head) try: oid = quit.applyQueryOnCommit(parsedQuery, branch_or_ref, target_ref, query=query, default_graph=default_graph, named_graph=named_graph) response = make_response('', 200) response.headers["X-CurrentBranch"] = target_head if oid is not None: response.headers["X-CurrentCommit"] = oid else: response.headers["X-CurrentCommit"] = commitid return response except Exception as e: # query ok, but unsupported query type or other problem during commit logger.exception(e) return make_response('Error after executing the update query.', 400) elif queryType in ['SelectQuery', 'DescribeQuery', 'AskQuery', 'ConstructQuery']: try: graph, commitid = quit.instance(branch_or_ref) except Exception as e: logger.exception(e) return make_response('No branch or reference given.', 400) try: res = graph.query(parsedQuery) except FromNamedError: return make_response('FROM NAMED not supported, yet', 400) except UnSupportedQuery: return make_response('Unsupported Query', 400) mimetype = _getBestMatchingMimeType(request, queryType) if not mimetype: return make_response("Mimetype: {} not acceptable".format(mimetype), 406) response = create_result_response(res, mimetype) if branch_or_ref: response.headers["X-CurrentBranch"] = branch_or_ref if commitid: response.headers["X-CurrentCommit"] = commitid return response else: logger.debug("Unsupported Type: {}".format(queryType)) return make_response("Unsupported Query Type: {}".format(queryType), 400)
def sparql(branch_or_ref): """Process a SPARQL query (Select or Update). Returns: HTTP Response with query result: If query was a valid select query. HTTP Response 200: If request contained a valid update query. HTTP Response 406: If accept header is not acceptable. """ quit = current_app.config['quit'] default_branch = quit.config.getDefaultBranch() if not branch_or_ref and not quit.repository.is_empty: branch_or_ref = default_branch logger.debug("Request method: {}".format(request.method)) query = None if request.method == "GET": default_graph = request.args.get('default-graph-uri', None) named_graph = request.args.get('named-graph-uri', None) query = request.args.get('query', None) elif request.method == "POST": if 'Content-Type' in request.headers: contentMimeType, options = parse_options_header( request.headers['Content-Type']) if contentMimeType == "application/x-www-form-urlencoded": if 'query' in request.form: default_graph = request.form.get('default-graph-uri', None) named_graph = request.form.get('named-graph-uri', None) query = request.form.get('query', None) elif 'update' in request.form: default_graph = request.form.get('using-graph-uri', None) named_graph = request.form.get('using-named-graph-uri', None) query = request.form.get('update', None) elif contentMimeType == "application/sparql-query": default_graph = request.args.get('default-graph-uri', None) named_graph = request.args.get('named-graph-uri', None) query = request.data.decode("utf-8") elif contentMimeType == "application/sparql-update": default_graph = request.args.get('using-graph-uri', None) named_graph = request.args.get('using-named-graph-uri', None) query = request.data.decode("utf-8") if 'Accept' in request.headers: logger.info('Received query via {}: {} with accept header: {}'.format( request.method, query, request.headers['Accept'])) mimetype = parse_accept_header(request.headers['Accept']).best else: logger.info('Received query via {}: {} with no accept header.'.format( request.method, query)) mimetype = '*/*' if query is None: if mimetype == 'text/html': return render_template('sparql.html', current_ref=branch_or_ref) else: return make_response( 'No Query was specified or the Content-Type is not set according' + 'to the SPARQL 1.1 standard', 400) try: queryType, parsedQuery = parse_query_type(query, quit.config.namespace) graph = quit.instance(branch_or_ref) except UnSupportedQueryType as e: logger.exception(e) return make_response('Unsupported Query Type', 400) except Exception as e: logger.exception(e) return make_response('No branch or reference given.', 400) if queryType in ['InsertData', 'DeleteData', 'Modify', 'DeleteWhere']: res = graph.update(parsedQuery) try: ref = request.values.get('ref', None) or default_branch ref = 'refs/heads/{}'.format(ref) quit.commit(graph, res, 'New Commit from QuitStore', branch_or_ref, ref, query=query) return '', 200 except Exception as e: # query ok, but unsupported query type or other problem during commit logger.exception(e) return make_response('Error after executing the update query.', 400) elif queryType in [ 'SelectQuery', 'DescribeQuery', 'AskQuery', 'ConstructQuery' ]: res = graph.query(parsedQuery) else: logger.debug("Unsupported Type: {}".format(queryType)) return make_response("Unsupported Query Type: {}".format(queryType), 400) try: if queryType in ['SelectQuery', 'AskQuery']: return create_result_response(res, resultSetMimetypes[mimetype]) elif queryType in ['ConstructQuery', 'DescribeQuery']: return create_result_response(res, rdfMimetypes[mimetype]) except KeyError as e: return make_response("Mimetype: {} not acceptable".format(mimetype), 406)
def merge(refspec): """Merge branch into target (refspec=<branch>:<target>). Merge 'branch' into 'target' and set 'target' to the resulting commit. Returns: HTTP Response 200: If merge was possible HTTP Response 201: If merge was possible and a merge commit was created HTTP Response 202: If merge was possible and a fast-forward happened HTTP Response 400: If merge did not work HTTP Response 409: If merge produces a conflict """ quit = current_app.config['quit'] try: if 'Accept' in request.headers: mimetype = parse_accept_header(request.headers['Accept']).best else: mimetype = '*/*' if mimetype in ['text/html', 'application/xhtml_xml']: response = make_response(render_template('merge.html')) response.headers['Content-Type'] = 'text/html' return response elif mimetype in ['application/json', '*/*']: # Actual Merge if refspec is None: refspec = request.values.get('refspec', None) if refspec: try: branch, target = refspec.split(":") except ValueError: branch = refspec target = None else: branch = request.values.get('branch', None) target = request.values.get('target', None) method = request.values.get('method', None) try: result = quit.repository.merge(target=target, branch=branch, method=method) except QuitMergeConflict as mergeconflict: response = make_response(json.dumps(mergeconflict.getObject()), 409) response.headers['Content-Type'] = 'application/json' return response resultMessage = "" resultCode = 200 if (result & pygit2.GIT_MERGE_ANALYSIS_FASTFORWARD and result & pygit2.GIT_MERGE_ANALYSIS_UNBORN): resultMessage = "{target} was unborn and is now set to {branch}".format( target=target, branch=branch) resultCode = 202 elif result & pygit2.GIT_MERGE_ANALYSIS_FASTFORWARD: resultMessage = "{target} could be fast-forwarded to {branch}".format( target=target, branch=branch) resultCode = 202 elif result & pygit2.GIT_MERGE_ANALYSIS_UP_TO_DATE: resultMessage = "{target} is already up-to-date with {branch}".format( target=target, branch=branch) resultCode = 200 elif result & pygit2.GIT_MERGE_ANALYSIS_NORMAL: resultMessage = "{branch} was merged into {target}, merge commit created".format( target=target, branch=branch) resultCode = 201 else: resultMessage = "don't know what happened to {target} and {branch}".format( target=target, branch=branch) result_object = {"status": result, "result_message": resultMessage} quit.syncAll() response = make_response(json.dumps(result_object), resultCode) response.headers['Content-Type'] = 'application/json' return response else: return "<pre>Unsupported Mimetype: {}</pre>".format(mimetype), 406 except Exception as e: logger.error(e) logger.error(traceback.format_exc()) return "<pre>" + traceback.format_exc() + "</pre>", 400