Page MenuHomeSoftware Heritage

No OneTemporary

diff --git a/swh/web/browse/views/content.py b/swh/web/browse/views/content.py
index 7c55f5eb2..de00d6099 100644
--- a/swh/web/browse/views/content.py
+++ b/swh/web/browse/views/content.py
@@ -1,267 +1,244 @@
# Copyright (C) 2017-2018 The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU General Public License version 3, or any later version
# See top-level LICENSE file for more information
import difflib
import json
from distutils.util import strtobool
from django.http import HttpResponse
from django.utils.safestring import mark_safe
from django.shortcuts import render
from django.template.defaultfilters import filesizeformat
from swh.model.hashutil import hash_to_hex
from swh.web.common import query
from swh.web.common.utils import reverse, gen_path_info
from swh.web.common.exc import handle_view_exception
from swh.web.browse.utils import (
request_content, prepare_content_for_display,
content_display_max_size
)
from swh.web.browse.browseurls import browse_route
@browse_route(r'content/(?P<query_string>.+)/raw/',
view_name='browse-content-raw')
def content_raw(request, query_string):
"""Django view that produces a raw display of a SWH content identified
by its hash value.
The url that points to it is :http:get:`/browse/content/[(algo_hash):](hash)/raw/`
-
- Args:
- request: input django http request
- query_string: a string of the form "[ALGO_HASH:]HASH" where
- optional ALGO_HASH can be either *sha1*, *sha1_git*, *sha256*,
- or *blake2s256* (default to *sha1*) and HASH the hexadecimal
- representation of the hash value
-
- Returns:
- The raw bytes of the content.
-
-
""" # noqa
try:
algo, checksum = query.parse_hash(query_string)
checksum = hash_to_hex(checksum)
content_data = request_content(query_string, max_size=None)
except Exception as exc:
return handle_view_exception(request, exc)
filename = request.GET.get('filename', None)
if not filename:
filename = '%s_%s' % (algo, checksum)
if content_data['mimetype'].startswith('text/') or \
content_data['mimetype'] == 'inode/x-empty':
response = HttpResponse(content_data['raw_data'],
content_type="text/plain")
response['Content-disposition'] = 'filename=%s' % filename
else:
response = HttpResponse(content_data['raw_data'],
content_type='application/octet-stream')
response['Content-disposition'] = 'attachment; filename=%s' % filename
return response
_auto_diff_size_limit = 20000
@browse_route(r'content/(?P<from_query_string>.*)/diff/(?P<to_query_string>.*)', # noqa
view_name='diff-contents')
def _contents_diff(request, from_query_string, to_query_string):
"""
Browse endpoint used to compute unified diffs between two contents.
Diffs are generated only if the two contents are textual.
By default, diffs whose size are greater than 20 kB will
not be generated. To force the generation of large diffs,
the 'force' boolean query parameter must be used.
Args:
request: input django http request
from_query_string: a string of the form "[ALGO_HASH:]HASH" where
optional ALGO_HASH can be either *sha1*, *sha1_git*, *sha256*,
or *blake2s256* (default to *sha1*) and HASH the hexadecimal
representation of the hash value identifying the first content
to_query_string: same as above for identifying the second content
Returns:
A JSON object containing the unified diff.
"""
diff_data = {}
content_from = None
content_to = None
content_from_size = 0
content_to_size = 0
content_from_lines = []
content_to_lines = []
force = request.GET.get('force', 'false')
path = request.GET.get('path', None)
language = 'nohighlight-swh'
force = bool(strtobool(force))
if from_query_string == to_query_string:
diff_str = 'File renamed without changes'
else:
text_diff = True
if from_query_string:
content_from = request_content(from_query_string, max_size=None)
content_from_display_data = prepare_content_for_display(
content_from['raw_data'], content_from['mimetype'], path)
language = content_from_display_data['language']
content_from_size = content_from['length']
if not (content_from['mimetype'].startswith('text/') or
content_from['mimetype'] == 'inode/x-empty'):
text_diff = False
if text_diff and to_query_string:
content_to = request_content(to_query_string, max_size=None)
content_to_display_data = prepare_content_for_display(
content_to['raw_data'], content_to['mimetype'], path)
language = content_to_display_data['language']
content_to_size = content_to['length']
if not (content_to['mimetype'].startswith('text/') or
content_to['mimetype'] == 'inode/x-empty'):
text_diff = False
diff_size = abs(content_to_size - content_from_size)
if not text_diff:
diff_str = 'Diffs are not generated for non textual content'
language = 'nohighlight-swh'
elif not force and diff_size > _auto_diff_size_limit:
diff_str = 'Large diffs are not automatically computed'
language = 'nohighlight-swh'
else:
if content_from:
content_from_lines = content_from['raw_data'].decode('utf-8')\
.splitlines(True)
if content_from_lines and content_from_lines[-1][-1] != '\n':
content_from_lines[-1] += '[swh-no-nl-marker]\n'
if content_to:
content_to_lines = content_to['raw_data'].decode('utf-8')\
.splitlines(True)
if content_to_lines and content_to_lines[-1][-1] != '\n':
content_to_lines[-1] += '[swh-no-nl-marker]\n'
diff_lines = difflib.unified_diff(content_from_lines,
content_to_lines)
diff_str = ''.join(list(diff_lines)[2:])
diff_data['diff_str'] = diff_str
diff_data['language'] = language
diff_data_json = json.dumps(diff_data, separators=(',', ': '))
return HttpResponse(diff_data_json, content_type='application/json')
@browse_route(r'content/(?P<query_string>.+)/',
view_name='browse-content')
def content_display(request, query_string):
"""Django view that produces an HTML display of a SWH content identified
by its hash value.
The url that points to it is :http:get:`/browse/content/[(algo_hash):](hash)/`
-
- Args:
- request: input django http request
- query_string: a string of the form "[ALGO_HASH:]HASH" where
- optional ALGO_HASH can be either *sha1*, *sha1_git*, *sha256*,
- or *blake2s256* (default to *sha1*) and HASH the hexadecimal
- representation of the hash value
-
- Returns:
- The HTML rendering of the requested content.
-
""" # noqa
try:
algo, checksum = query.parse_hash(query_string)
checksum = hash_to_hex(checksum)
content_data = request_content(query_string)
except Exception as exc:
return handle_view_exception(request, exc)
path = request.GET.get('path', None)
content = None
language = None
if content_data['raw_data'] is not None:
content_display_data = prepare_content_for_display(
content_data['raw_data'], content_data['mimetype'], path)
content = content_display_data['content_data']
language = content_display_data['language']
root_dir = None
filename = None
path_info = None
breadcrumbs = []
if path:
split_path = path.split('/')
root_dir = split_path[0]
filename = split_path[-1]
path = path.replace(root_dir + '/', '')
path = path[:-len(filename)]
path_info = gen_path_info(path)
breadcrumbs.append({'name': root_dir[:7],
'url': reverse('browse-directory',
kwargs={'sha1_git': root_dir})})
for pi in path_info:
breadcrumbs.append({'name': pi['name'],
'url': reverse('browse-directory',
kwargs={'sha1_git': root_dir,
'path': pi['path']})})
breadcrumbs.append({'name': filename,
'url': None})
query_params = None
if filename:
query_params = {'filename': filename}
content_raw_url = reverse('browse-content-raw',
kwargs={'query_string': query_string},
query_params=query_params)
content_metadata = {
'sha1 checksum': content_data['checksums']['sha1'],
'sha1_git checksum': content_data['checksums']['sha1_git'],
'sha256 checksum': content_data['checksums']['sha256'],
'blake2s256 checksum': content_data['checksums']['blake2s256'],
'mime type': content_data['mimetype'],
'encoding': content_data['encoding'],
'size': filesizeformat(content_data['length']),
'language': content_data['language'],
'licenses': content_data['licenses']
}
return render(request, 'content.html',
{'empty_browse': False,
'heading': 'Content information',
'top_panel_visible': True,
'top_panel_collapsible': True,
'top_panel_text': 'SWH object: Content',
'swh_object_metadata': content_metadata,
'main_panel_visible': True,
'content': content,
'content_size': content_data['length'],
'max_content_size': content_display_max_size,
'mimetype': content_data['mimetype'],
'language': language,
'breadcrumbs': breadcrumbs,
'top_right_link': content_raw_url,
'top_right_link_text': mark_safe(
'<i class="fa fa-file-text fa-fw" aria-hidden="true">'
'</i>Raw File'),
'origin_context': None,
'vault_cooking': None,
'show_actions_menu': False
})
diff --git a/swh/web/browse/views/directory.py b/swh/web/browse/views/directory.py
index 456e00e71..1753c96fd 100644
--- a/swh/web/browse/views/directory.py
+++ b/swh/web/browse/views/directory.py
@@ -1,115 +1,106 @@
# Copyright (C) 2017-2018 The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU General Public License version 3, or any later version
# See top-level LICENSE file for more information
from django.shortcuts import render
from django.template.defaultfilters import filesizeformat
from swh.web.common import service
from swh.web.common.utils import reverse, gen_path_info
from swh.web.common.exc import handle_view_exception
from swh.web.browse.utils import get_directory_entries
from swh.web.browse.browseurls import browse_route
@browse_route(r'directory/(?P<sha1_git>[0-9a-f]+)/',
r'directory/(?P<sha1_git>[0-9a-f]+)/(?P<path>.+)/',
view_name='browse-directory')
def directory_browse(request, sha1_git, path=None):
"""Django view for browsing the content of a SWH directory identified
by its sha1_git value.
The url that points to it is :http:get:`/browse/directory/(sha1_git)/[(path)/]`
-
- Args:
- request: input django http request
- sha1_git: swh sha1_git identifer of the directory to browse
- path: optionnal path parameter used to navigate in directories
- reachable from the provided root one
-
- Returns:
- The HTML rendering for the content of the provided directory.
""" # noqa
root_sha1_git = sha1_git
try:
if path:
dir_info = service.lookup_directory_with_path(sha1_git, path)
sha1_git = dir_info['target']
dirs, files = get_directory_entries(sha1_git)
except Exception as exc:
return handle_view_exception(request, exc)
path_info = gen_path_info(path)
breadcrumbs = []
breadcrumbs.append({'name': root_sha1_git[:7],
'url': reverse('browse-directory',
kwargs={'sha1_git': root_sha1_git})})
for pi in path_info:
breadcrumbs.append({'name': pi['name'],
'url': reverse('browse-directory',
kwargs={'sha1_git': root_sha1_git,
'path': pi['path']})})
path = '' if path is None else (path + '/')
for d in dirs:
d['url'] = reverse('browse-directory',
kwargs={'sha1_git': root_sha1_git,
'path': path + d['name']})
sum_file_sizes = 0
readme_name = None
readme_url = None
for f in files:
query_string = 'sha1_git:' + f['target']
f['url'] = reverse('browse-content',
kwargs={'query_string': query_string},
query_params={'path': root_sha1_git + '/' +
path + f['name']})
sum_file_sizes += f['length']
f['length'] = filesizeformat(f['length'])
if f['name'].lower().startswith('readme'):
readme_name = f['name']
readme_sha1 = f['checksums']['sha1']
readme_url = reverse('browse-content-raw',
kwargs={'query_string': readme_sha1})
sum_file_sizes = filesizeformat(sum_file_sizes)
dir_metadata = {'id': sha1_git,
'number of regular files': len(files),
'number of subdirectories': len(dirs),
'sum of regular file sizes': sum_file_sizes}
vault_cooking = {
'directory_context': True,
'directory_id': sha1_git,
'revision_context': False,
'revision_id': None
}
return render(request, 'directory.html',
{'empty_browse': False,
'heading': 'Directory information',
'top_panel_visible': True,
'top_panel_collapsible': True,
'top_panel_text': 'SWH object: Directory',
'swh_object_metadata': dir_metadata,
'main_panel_visible': True,
'dirs': dirs,
'files': files,
'breadcrumbs': breadcrumbs,
'top_right_link': None,
'top_right_link_text': None,
'readme_name': readme_name,
'readme_url': readme_url,
'origin_context': None,
'vault_cooking': vault_cooking,
'show_actions_menu': True})
diff --git a/swh/web/browse/views/identifiers.py b/swh/web/browse/views/identifiers.py
index 47a96617c..8ff74ca18 100644
--- a/swh/web/browse/views/identifiers.py
+++ b/swh/web/browse/views/identifiers.py
@@ -1,59 +1,52 @@
# Copyright (C) 2017-2018 The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU General Public License version 3, or any later version
# See top-level LICENSE file for more information
from django.shortcuts import redirect
from swh.model.identifiers import parse_persistent_identifier
from swh.web.browse.browseurls import browse_route
from swh.web.common.utils import reverse
from swh.web.common.exc import BadInputExc, handle_view_exception
@browse_route(r'(?P<swh_id>swh:[0-9]+:[a-z]+:[0-9a-f]+)/',
view_name='browse-swh-id')
def swh_id_browse(request, swh_id):
"""
Django view enabling to browse the SWH archive using
:ref:`persistent-identifiers`.
The url that points to it is :http:get:`/browse/(swh_id)/`.
-
- Args:
- swh_id: A SWH persistent identifier
-
- Returns:
- A redirection to the adequate view to browse the
- requested SWH object
"""
try:
swh_id_parsed = parse_persistent_identifier(swh_id)
object_type = swh_id_parsed['object_type']
object_id = swh_id_parsed['object_id']
view_url = None
if object_type == 'cnt':
query_string = 'sha1_git:' + object_id
view_url = reverse('browse-content',
kwargs={'query_string': query_string},
query_params=request.GET)
elif object_type == 'dir':
view_url = reverse('browse-directory',
kwargs={'sha1_git': object_id},
query_params=request.GET)
elif object_type == 'rel':
view_url = reverse('browse-release',
kwargs={'sha1_git': object_id},
query_params=request.GET)
elif object_type == 'rev':
view_url = reverse('browse-revision',
kwargs={'sha1_git': object_id},
query_params=request.GET)
else:
msg = '\'%s\' is not a valid SWH persistent identifier!' % swh_id
raise BadInputExc(msg)
except Exception as exc:
return handle_view_exception(request, exc)
return redirect(view_url)
diff --git a/swh/web/browse/views/origin.py b/swh/web/browse/views/origin.py
index c3e60abb5..d1f6297f5 100644
--- a/swh/web/browse/views/origin.py
+++ b/swh/web/browse/views/origin.py
@@ -1,896 +1,829 @@
# Copyright (C) 2017-2018 The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU General Public License version 3, or any later version
# See top-level LICENSE file for more information
import json
from distutils.util import strtobool
from django.http import HttpResponse
from django.shortcuts import render
from django.utils.safestring import mark_safe
from django.template.defaultfilters import filesizeformat
from swh.web.common import service
from swh.web.common.utils import (
gen_path_info, reverse, format_utc_iso_date,
parse_timestamp
)
from swh.web.common.exc import NotFoundExc, handle_view_exception
from swh.web.browse.utils import (
get_origin_visits,
get_directory_entries, request_content,
prepare_content_for_display,
prepare_revision_log_for_display,
get_origin_context, gen_directory_link,
gen_revision_link, gen_revision_log_link,
gen_content_link, gen_origin_directory_link,
content_display_max_size
)
from swh.web.browse.browseurls import browse_route
def _branch_not_found(origin_info, timestamp,
branch_type, branch, branches,
visit_id=None):
"""
Utility function to raise an exception when a specified branch/release
can not be found.
"""
if branch_type:
occ_type = 'Branch'
occ_type_plural = 'branches'
else:
occ_type = 'Release'
occ_type_plural = 'releases'
if visit_id:
if len(branches) == 0:
raise NotFoundExc('Origin with type %s and url %s'
' for visit with id %s has an empty list'
' of %s!' % (origin_info['type'],
origin_info['url'], visit_id,
occ_type_plural))
else:
raise NotFoundExc('%s %s associated to visit with'
' id %s for origin with type %s and url %s'
' not found!' % (occ_type, branch, visit_id,
origin_info['type'],
origin_info['url']))
else:
if len(branches) == 0:
raise NotFoundExc('Origin with type %s and url %s'
' for visit with timestamp %s has an empty list'
' of %s!' % (origin_info['type'],
origin_info['url'],
timestamp, occ_type_plural))
else:
raise NotFoundExc('%s %s associated to visit with'
' timestamp %s for origin with type %s'
' and url %s not found!' % (occ_type, branch,
timestamp,
origin_info['type'],
origin_info['url']))
def _get_branch(branches, branch_name):
"""
Utility function to get a specific branch from an origin branches list.
Its purpose is to get the default HEAD branch as some SWH origin
(e.g those with svn type) does not have it. In that latter case, check
if there is a master branch instead and returns it.
"""
filtered_branches = \
[b for b in branches if b['name'].endswith(branch_name)]
if len(filtered_branches) > 0:
return filtered_branches[0]
elif branch_name == 'HEAD':
filtered_branches = \
[b for b in branches if b['name'].endswith('master')]
if len(filtered_branches) > 0:
return filtered_branches[0]
elif len(branches) > 0:
return branches[0]
return None
def _get_release(releases, release_name):
filtered_releases = \
[r for r in releases if r['name'] == release_name]
if len(filtered_releases) > 0:
return filtered_releases[0]
else:
return None
def _process_origin_request(request, origin_type, origin_url,
timestamp, path, browse_view_name):
"""
Utility function to perform common input request processing
for origin context views.
"""
visit_id = request.GET.get('visit_id', None)
origin_context = get_origin_context(origin_type, origin_url,
timestamp, visit_id)
for b in origin_context['branches']:
branch_url_args = dict(origin_context['url_args'])
if path:
b['path'] = path
branch_url_args['path'] = path
b['url'] = reverse(browse_view_name,
kwargs=branch_url_args,
query_params={'branch': b['name'],
'visit_id': visit_id})
for r in origin_context['releases']:
release_url_args = dict(origin_context['url_args'])
if path:
r['path'] = path
release_url_args['path'] = path
r['url'] = reverse(browse_view_name,
kwargs=release_url_args,
query_params={'release': r['name'],
'visit_id': visit_id})
root_sha1_git = None
query_params = origin_context['query_params']
revision_id = request.GET.get('revision', None)
release_name = request.GET.get('release', None)
branch_name = None
if revision_id:
revision = service.lookup_revision(revision_id)
root_sha1_git = revision['directory']
origin_context['branches'].append({'name': revision_id,
'revision': revision_id,
'directory': root_sha1_git,
'url': None})
branch_name = revision_id
query_params['revision'] = revision_id
elif release_name:
release = _get_release(origin_context['releases'], release_name)
if release:
root_sha1_git = release['directory']
query_params['release'] = release_name
revision_id = release['target']
else:
_branch_not_found(origin_context['origin_info'], timestamp,
False, release_name,
origin_context['releases'], visit_id)
else:
branch_name = request.GET.get('branch', None)
if branch_name:
query_params['branch'] = branch_name
branch = _get_branch(origin_context['branches'], branch_name or 'HEAD')
if branch:
branch_name = branch['name']
root_sha1_git = branch['directory']
revision_id = branch['revision']
else:
_branch_not_found(origin_context['origin_info'], timestamp,
True, branch_name,
origin_context['branches'], visit_id)
origin_context['root_sha1_git'] = root_sha1_git
origin_context['revision_id'] = revision_id
origin_context['branch'] = branch_name
origin_context['release'] = release_name
return origin_context
@browse_route(r'origin/(?P<origin_type>[a-z]+)/url/(?P<origin_url>.+)/visit/(?P<timestamp>.+)/directory/', # noqa
r'origin/(?P<origin_type>[a-z]+)/url/(?P<origin_url>.+)/visit/(?P<timestamp>.+)/directory/(?P<path>.+)/', # noqa
r'origin/(?P<origin_type>[a-z]+)/url/(?P<origin_url>.+)/directory/', # noqa
r'origin/(?P<origin_type>[a-z]+)/url/(?P<origin_url>.+)/directory/(?P<path>.+)/', # noqa
view_name='browse-origin-directory')
def origin_directory_browse(request, origin_type, origin_url,
timestamp=None, path=None):
"""Django view for browsing the content of a SWH directory associated
to an origin for a given visit.
The url scheme that points to it is the following:
* :http:get:`/browse/origin/(origin_type)/url/(origin_url)/directory/[(path)/]`
* :http:get:`/browse/origin/(origin_type)/url/(origin_url)/visit/(timestamp)/directory/[(path)/]`
-
- Args:
- request: input django http request
- origin_type: the type of swh origin (git, svn, hg, ...)
- origin_url: the url of the swh origin
- timestamp: optional swh visit timestamp parameter
- (the last one will be used by default)
- path: optional path parameter used to navigate in directories
- reachable from the origin root one
- branch: optional query parameter that specifies the origin branch
- from which to retrieve the directory
- release: optional query parameter that specifies the origin release
- from which to retrieve the directory
- revision: optional query parameter to specify the origin revision
- from which to retrieve the directory
-
- Returns:
- The HTML rendering for the content of the directory associated
- to the provided origin and visit.
""" # noqa
try:
origin_context = _process_origin_request(
request, origin_type, origin_url, timestamp, path,
'browse-origin-directory')
root_sha1_git = origin_context['root_sha1_git']
sha1_git = root_sha1_git
if path:
dir_info = service.lookup_directory_with_path(root_sha1_git, path)
sha1_git = dir_info['target']
dirs, files = get_directory_entries(sha1_git)
except Exception as exc:
return handle_view_exception(request, exc)
origin_info = origin_context['origin_info']
visit_info = origin_context['visit_info']
url_args = origin_context['url_args']
query_params = origin_context['query_params']
revision_id = origin_context['revision_id']
path_info = gen_path_info(path)
breadcrumbs = []
breadcrumbs.append({'name': root_sha1_git[:7],
'url': reverse('browse-origin-directory',
kwargs=url_args,
query_params=query_params)})
for pi in path_info:
bc_url_args = dict(url_args)
bc_url_args['path'] = pi['path']
breadcrumbs.append({'name': pi['name'],
'url': reverse('browse-origin-directory',
kwargs=bc_url_args,
query_params=query_params)})
path = '' if path is None else (path + '/')
for d in dirs:
bc_url_args = dict(url_args)
bc_url_args['path'] = path + d['name']
d['url'] = reverse('browse-origin-directory',
kwargs=bc_url_args,
query_params=query_params)
sum_file_sizes = 0
readme_name = None
readme_url = None
for f in files:
bc_url_args = dict(url_args)
bc_url_args['path'] = path + f['name']
f['url'] = reverse('browse-origin-content',
kwargs=bc_url_args,
query_params=query_params)
sum_file_sizes += f['length']
f['length'] = filesizeformat(f['length'])
if f['name'].lower().startswith('readme'):
readme_name = f['name']
readme_sha1 = f['checksums']['sha1']
readme_url = reverse('browse-content-raw',
kwargs={'query_string': readme_sha1})
history_url = reverse('browse-origin-log',
kwargs=url_args,
query_params=query_params)
sum_file_sizes = filesizeformat(sum_file_sizes)
browse_dir_link = \
gen_directory_link(sha1_git, link_text='Browse',
link_attrs={'class': 'btn btn-md btn-swh',
'role': 'button'})
browse_rev_link = \
gen_revision_link(revision_id,
origin_context=origin_context,
link_text='Browse',
link_attrs={'class': 'btn btn-md btn-swh',
'role': 'button'})
dir_metadata = {'id': sha1_git,
'context-independent directory': browse_dir_link,
'number of regular files': len(files),
'number of subdirectories': len(dirs),
'sum of regular file sizes': sum_file_sizes,
'origin id': origin_info['id'],
'origin type': origin_info['type'],
'origin url': origin_info['url'],
'origin visit date': format_utc_iso_date(visit_info['date']), # noqa
'origin visit id': visit_info['visit'],
'path': '/' + path,
'revision id': revision_id,
'revision': browse_rev_link}
vault_cooking = {
'directory_context': True,
'directory_id': sha1_git,
'revision_context': True,
'revision_id': revision_id
}
return render(request, 'directory.html',
{'empty_browse': False,
'heading': 'Directory information',
'top_panel_visible': True,
'top_panel_collapsible': True,
'top_panel_text': 'SWH object: Directory',
'swh_object_metadata': dir_metadata,
'main_panel_visible': True,
'dirs': dirs,
'files': files,
'breadcrumbs': breadcrumbs,
'top_right_link': history_url,
'top_right_link_text': mark_safe(
'<i class="fa fa-history fa-fw" aria-hidden="true"></i>'
'History'
),
'readme_name': readme_name,
'readme_url': readme_url,
'origin_context': origin_context,
'vault_cooking': vault_cooking,
'show_actions_menu': True})
@browse_route(r'origin/(?P<origin_type>[a-z]+)/url/(?P<origin_url>.+)/visit/(?P<timestamp>.+)/content/(?P<path>.+)/', # noqa
r'origin/(?P<origin_type>[a-z]+)/url/(?P<origin_url>.+)/content/(?P<path>.+)/', # noqa
view_name='browse-origin-content')
def origin_content_display(request, origin_type, origin_url, path,
timestamp=None):
"""Django view that produces an HTML display of a SWH content
associated to an origin for a given visit.
The url scheme that points to it is the following:
* :http:get:`/browse/origin/(origin_type)/url/(origin_url)/content/(path)/`
* :http:get:`/browse/origin/(origin_type)/url/(origin_url)/visit/(timestamp)/content/(path)/`
- Args:
- request: input django http request
- origin_type: the type of swh origin (git, svn, hg, ...)
- origin_url: the url of the swh origin
- path: path of the content relative to the origin root directory
- timestamp: optional swh visit timestamp parameter
- (the last one will be used by default)
- branch: optional query parameter that specifies the origin branch
- from which to retrieve the content
- release: optional query parameter that specifies the origin release
- from which to retrieve the content
- revision: optional query parameter to specify the origin revision
- from which to retrieve the content
-
- Returns:
- The HTML rendering of the requested content associated to
- the provided origin and visit.
-
""" # noqa
try:
origin_context = _process_origin_request(
request, origin_type, origin_url, timestamp, path,
'browse-origin-content')
root_sha1_git = origin_context['root_sha1_git']
content_info = service.lookup_directory_with_path(root_sha1_git, path)
sha1_git = content_info['target']
query_string = 'sha1_git:' + sha1_git
content_data = request_content(query_string)
except Exception as exc:
return handle_view_exception(request, exc)
url_args = origin_context['url_args']
query_params = origin_context['query_params']
revision_id = origin_context['revision_id']
origin_info = origin_context['origin_info']
visit_info = origin_context['visit_info']
content = None
language = None
if content_data['raw_data'] is not None:
content_display_data = prepare_content_for_display(
content_data['raw_data'], content_data['mimetype'], path)
content = content_display_data['content_data']
language = content_display_data['language']
filename = None
path_info = None
breadcrumbs = []
split_path = path.split('/')
filename = split_path[-1]
path = path[:-len(filename)]
path_info = gen_path_info(path)
breadcrumbs.append({'name': root_sha1_git[:7],
'url': reverse('browse-origin-directory',
kwargs=url_args,
query_params=query_params)})
for pi in path_info:
bc_url_args = dict(url_args)
bc_url_args['path'] = pi['path']
breadcrumbs.append({'name': pi['name'],
'url': reverse('browse-origin-directory',
kwargs=bc_url_args,
query_params=query_params)})
breadcrumbs.append({'name': filename,
'url': None})
browse_content_link = \
gen_content_link(sha1_git, link_text='Browse',
link_attrs={'class': 'btn btn-md btn-swh',
'role': 'button'})
content_raw_url = reverse('browse-content-raw',
kwargs={'query_string': query_string},
query_params={'filename': filename})
browse_rev_link = \
gen_revision_link(revision_id,
origin_context=origin_context,
link_text='Browse',
link_attrs={'class': 'btn btn-md btn-swh',
'role': 'button'})
content_metadata = {
'context-independent content': browse_content_link,
'sha1 checksum': content_data['checksums']['sha1'],
'sha1_git checksum': content_data['checksums']['sha1_git'],
'sha256 checksum': content_data['checksums']['sha256'],
'blake2s256 checksum': content_data['checksums']['blake2s256'],
'mime type': content_data['mimetype'],
'encoding': content_data['encoding'],
'size': filesizeformat(content_data['length']),
'language': content_data['language'],
'licenses': content_data['licenses'],
'origin id': origin_info['id'],
'origin type': origin_info['type'],
'origin url': origin_info['url'],
'origin visit date': format_utc_iso_date(visit_info['date']),
'origin visit id': visit_info['visit'],
'path': '/' + path,
'filename': filename,
'revision id': revision_id,
'revision': browse_rev_link
}
return render(request, 'content.html',
{'empty_browse': False,
'heading': 'Content information',
'top_panel_visible': True,
'top_panel_collapsible': True,
'top_panel_text': 'SWH object: Content',
'swh_object_metadata': content_metadata,
'main_panel_visible': True,
'content': content,
'content_size': content_data['length'],
'max_content_size': content_display_max_size,
'mimetype': content_data['mimetype'],
'language': language,
'breadcrumbs': breadcrumbs,
'top_right_link': content_raw_url,
'top_right_link_text': mark_safe(
'<i class="fa fa-file-text fa-fw" aria-hidden="true">'
'</i>Raw File'),
'origin_context': origin_context,
'vault_cooking': None,
'show_actions_menu': False})
PER_PAGE = 20
@browse_route(r'origin/(?P<origin_type>[a-z]+)/url/(?P<origin_url>.+)/visit/(?P<timestamp>.+)/log/', # noqa
r'origin/(?P<origin_type>[a-z]+)/url/(?P<origin_url>.+)/log/',
view_name='browse-origin-log')
def origin_log_browse(request, origin_type, origin_url, timestamp=None):
"""Django view that produces an HTML display of revisions history (aka
the commit log) associated to a SWH origin.
The url scheme that points to it is the following:
* :http:get:`/browse/origin/(origin_type)/url/(origin_url)/log/`
* :http:get:`/browse/origin/(origin_type)/url/(origin_url)/visit/(timestamp)/log/`
-
- Args:
- request: input django http request
- origin_type: the type of swh origin (git, svn, hg, ...)
- origin_url: the url of the swh origin
- timestamp: optional visit timestamp parameter
- (the last one will be used by default)
- revs_breadcrumb: query parameter used internally to store
- the navigation breadcrumbs (i.e. the list of descendant revisions
- visited so far).
- per_page: optional query parameter used to specify the number of
- log entries per page
- branch: optional query parameter that specifies the origin branch
- from which to retrieve the commit log
- release: optional query parameter that specifies the origin release
- from which to retrieve the commit log
- revision: optional query parameter to specify the origin revision
- from which to retrieve the commit log
-
- Returns:
- The HTML rendering of revisions history for a given SWH visit.
-
""" # noqa
try:
origin_context = _process_origin_request(
request, origin_type, origin_url, timestamp, None,
'browse-origin-log')
revision_id = origin_context['revision_id']
current_rev = revision_id
per_page = int(request.GET.get('per_page', PER_PAGE))
revs_breadcrumb = request.GET.get('revs_breadcrumb', None)
if revs_breadcrumb:
current_rev = revs_breadcrumb.split('/')[-1]
revision_log = service.lookup_revision_log(current_rev,
limit=per_page+1)
revision_log = list(revision_log)
except Exception as exc:
return handle_view_exception(request, exc)
origin_info = origin_context['origin_info']
visit_info = origin_context['visit_info']
url_args = origin_context['url_args']
query_params = origin_context['query_params']
query_params['per_page'] = per_page
revision_log_display_data = prepare_revision_log_for_display(
revision_log, per_page, revs_breadcrumb, origin_context)
prev_rev = revision_log_display_data['prev_rev']
prev_revs_breadcrumb = revision_log_display_data['prev_revs_breadcrumb']
prev_log_url = None
query_params['revs_breadcrumb'] = prev_revs_breadcrumb
if prev_rev:
prev_log_url = \
reverse('browse-origin-log',
kwargs=url_args,
query_params=query_params)
next_rev = revision_log_display_data['next_rev']
next_revs_breadcrumb = revision_log_display_data['next_revs_breadcrumb']
next_log_url = None
query_params['revs_breadcrumb'] = next_revs_breadcrumb
if next_rev:
next_log_url = \
reverse('browse-origin-log',
kwargs=url_args,
query_params=query_params)
revision_log_data = revision_log_display_data['revision_log_data']
for i, log in enumerate(revision_log_data):
params = {
'revision': revision_log[i]['id'],
}
if 'visit_id' in query_params:
params['visit_id'] = query_params['visit_id']
log['directory'] = gen_origin_directory_link(
origin_context, revision_log[i]['id'],
link_text='<i class="fa fa-folder-open fa-fw" aria-hidden="true">'
'</i>Browse files',
link_attrs={'class': 'btn btn-md btn-swh',
'role': 'button'})
browse_log_link = \
gen_revision_log_link(revision_id, link_text='Browse',
link_attrs={'class': 'btn btn-md btn-swh',
'role': 'button'})
revision_metadata = {
'context-independent revision history': browse_log_link,
'origin id': origin_info['id'],
'origin type': origin_info['type'],
'origin url': origin_info['url'],
'origin visit date': format_utc_iso_date(visit_info['date']),
'origin visit id': visit_info['visit']
}
return render(request, 'revision-log.html',
{'empty_browse': False,
'heading': 'Revision history information',
'top_panel_visible': True,
'top_panel_collapsible': True,
'top_panel_text': 'SWH object: Revision history',
'swh_object_metadata': revision_metadata,
'main_panel_visible': True,
'revision_log': revision_log_data,
'next_log_url': next_log_url,
'prev_log_url': prev_log_url,
'breadcrumbs': None,
'top_right_link': None,
'top_right_link_text': None,
'origin_context': origin_context,
'vault_cooking': None,
'show_actions_menu': False})
@browse_route(r'origin/(?P<origin_type>[a-z]+)/url/(?P<origin_url>.+)/visit/(?P<timestamp>.+)/branches/', # noqa
r'origin/(?P<origin_type>[a-z]+)/url/(?P<origin_url>.+)/branches/', # noqa
view_name='browse-origin-branches')
def origin_branches_browse(request, origin_type, origin_url, timestamp=None):
"""Django view that produces an HTML display of the list of branches
associated to an origin for a given visit.
The url scheme that points to it is the following:
* :http:get:`/browse/origin/(origin_type)/url/(origin_url)/branches/`
* :http:get:`/browse/origin/(origin_type)/url/(origin_url)/visit/(timestamp)/branches/`
""" # noqa
try:
origin_context = _process_origin_request(
request, origin_type, origin_url, timestamp, None,
'browse-origin-directory')
except Exception as exc:
return handle_view_exception(request, exc)
branches_offset = int(request.GET.get('branches_offset', 0))
origin_info = origin_context['origin_info']
url_args = origin_context['url_args']
query_params = origin_context['query_params']
branches = origin_context['branches']
displayed_branches = \
branches[branches_offset:branches_offset+PER_PAGE]
for branch in displayed_branches:
revision_url = reverse(
'browse-revision', kwargs={'sha1_git': branch['revision']},
query_params={'origin_type': origin_info['type'],
'origin_url': origin_info['url']})
query_params['branch'] = branch['name']
directory_url = reverse('browse-origin-directory',
kwargs=url_args,
query_params=query_params)
del query_params['branch']
branch['revision_url'] = revision_url
branch['directory_url'] = directory_url
prev_branches_url = None
next_branches_url = None
next_offset = branches_offset + PER_PAGE
prev_offset = branches_offset - PER_PAGE
if next_offset < len(branches):
query_params['branches_offset'] = next_offset
next_branches_url = reverse('browse-origin-branches',
kwargs=url_args, query_params=query_params)
query_params['branches_offset'] = None
if prev_offset >= 0:
if prev_offset != 0:
query_params['branches_offset'] = prev_offset
prev_branches_url = reverse('browse-origin-branches',
kwargs=url_args, query_params=query_params)
return render(request, 'branches.html',
{'empty_browse': False,
'heading': 'Origin branches list',
'top_panel_visible': False,
'top_panel_collapsible': False,
'top_panel_text': 'SWH object: Origin branches list',
'swh_object_metadata': {},
'main_panel_visible': True,
'top_right_link': None,
'top_right_link_text': None,
'displayed_branches': displayed_branches,
'prev_branches_url': prev_branches_url,
'next_branches_url': next_branches_url,
'origin_context': origin_context})
@browse_route(r'origin/(?P<origin_type>[a-z]+)/url/(?P<origin_url>.+)/visit/(?P<timestamp>.+)/releases/', # noqa
r'origin/(?P<origin_type>[a-z]+)/url/(?P<origin_url>.+)/releases/', # noqa
view_name='browse-origin-releases')
def origin_releases_browse(request, origin_type, origin_url, timestamp=None):
"""Django view that produces an HTML display of the list of releases
associated to an origin for a given visit.
The url scheme that points to it is the following:
* :http:get:`/browse/origin/(origin_type)/url/(origin_url)/releases/`
* :http:get:`/browse/origin/(origin_type)/url/(origin_url)/visit/(timestamp)/releases/`
""" # noqa
try:
origin_context = _process_origin_request(
request, origin_type, origin_url, timestamp, None,
'browse-origin-directory')
except Exception as exc:
return handle_view_exception(request, exc)
releases_offset = int(request.GET.get('releases_offset', 0))
origin_info = origin_context['origin_info']
url_args = origin_context['url_args']
query_params = origin_context['query_params']
releases = origin_context['releases']
displayed_releases = \
releases[releases_offset:releases_offset+PER_PAGE]
for release in displayed_releases:
release_url = reverse('browse-release',
kwargs={'sha1_git': release['id']},
query_params={'origin_type': origin_info['type'],
'origin_url': origin_info['url']})
query_params['release'] = release['name']
del query_params['release']
release['release_url'] = release_url
prev_releases_url = None
next_releases_url = None
next_offset = releases_offset + PER_PAGE
prev_offset = releases_offset - PER_PAGE
if next_offset < len(releases):
query_params['releases_offset'] = next_offset
next_releases_url = reverse('browse-origin-releases',
kwargs=url_args, query_params=query_params)
query_params['releases_offset'] = None
if prev_offset >= 0:
if prev_offset != 0:
query_params['releases_offset'] = prev_offset
prev_releases_url = reverse('browse-origin-releases',
kwargs=url_args, query_params=query_params)
return render(request, 'releases.html',
{'empty_browse': False,
'heading': 'Origin releases list',
'top_panel_visible': False,
'top_panel_collapsible': False,
'top_panel_text': 'SWH object: Origin releases list',
'swh_object_metadata': {},
'main_panel_visible': True,
'top_right_link': None,
'top_right_link_text': None,
'displayed_releases': displayed_releases,
'prev_releases_url': prev_releases_url,
'next_releases_url': next_releases_url,
'origin_context': origin_context,
'vault_cooking': None,
'show_actions_menu': False})
@browse_route(r'origin/(?P<origin_type>[a-z]+)/url/(?P<origin_url>.+)/',
view_name='browse-origin')
def origin_browse(request, origin_type=None, origin_url=None):
"""Django view that produces an HTML display of a swh origin identified
by its id or its url.
The url scheme that points to it is :http:get:`/browse/origin/(origin_type)/url/(origin_url)/`.
-
- Args:
- request: input django http request
- origin_type: type of origin (git, svn, ...)
- origin_url: url of the origin (e.g. https://github.com/<user>/<repo>)
-
- Returns:
- The HMTL rendering for the metadata of the provided origin.
""" # noqa
try:
origin_info = service.lookup_origin({
'type': origin_type,
'url': origin_url
})
origin_visits = get_origin_visits(origin_info)
origin_visits.reverse()
except Exception as exc:
return handle_view_exception(request, exc)
origin_info['last swh visit browse url'] = \
reverse('browse-origin-directory',
kwargs={'origin_type': origin_type,
'origin_url': origin_url})
origin_visits_data = []
visits_splitted = []
visits_by_year = {}
for i, visit in enumerate(origin_visits):
visit_date = parse_timestamp(visit['date'])
visit_year = str(visit_date.year)
url_date = format_utc_iso_date(visit['date'], '%Y-%m-%dT%H:%M:%SZ')
visit['fmt_date'] = format_utc_iso_date(visit['date'])
query_params = {}
if i < len(origin_visits) - 1:
if visit['date'] == origin_visits[i+1]['date']:
query_params = {'visit_id': visit['visit']}
if i > 0:
if visit['date'] == origin_visits[i-1]['date']:
query_params = {'visit_id': visit['visit']}
visit['browse_url'] = reverse('browse-origin-directory',
kwargs={'origin_type': origin_type,
'origin_url': origin_url,
'timestamp': url_date},
query_params=query_params)
origin_visits_data.insert(0, {'date': visit_date.timestamp()})
if visit_year not in visits_by_year:
# display 3 years by row in visits list view
if len(visits_by_year) == 3:
visits_splitted.append(visits_by_year)
visits_by_year = {}
visits_by_year[visit_year] = []
visits_by_year[visit_year].append(visit)
if len(visits_by_year) > 0:
visits_splitted.append(visits_by_year)
return render(request, 'origin.html',
{'empty_browse': False,
'heading': 'Origin information',
'top_panel_visible': False,
'top_panel_collapsible': False,
'top_panel_text': 'SWH object: Visits history',
'swh_object_metadata': origin_info,
'main_panel_visible': True,
'origin_visits_data': origin_visits_data,
'visits_splitted': visits_splitted,
'origin_info': origin_info,
'browse_url_base': '/browse/origin/%s/url/%s/' %
(origin_type, origin_url),
'vault_cooking': None,
'show_actions_menu': False})
@browse_route(r'origin/search/(?P<url_pattern>.+)/',
view_name='browse-origin-search')
def origin_search(request, url_pattern):
"""Search for origins whose urls contain a provided string pattern
or match a provided regular expression.
The search is performed in a case insensitive way.
"""
offset = int(request.GET.get('offset', '0'))
limit = int(request.GET.get('limit', '50'))
regexp = request.GET.get('regexp', 'false')
results = service.search_origin(url_pattern, offset, limit,
bool(strtobool(regexp)))
results = json.dumps(list(results), sort_keys=True, indent=4,
separators=(',', ': '))
return HttpResponse(results, content_type='application/json')
@browse_route(r'origin/(?P<origin_id>[0-9]+)/latest_snapshot/',
view_name='browse-origin-latest-snapshot')
def _origin_latest_snapshot(request, origin_id):
"""
Internal browse endpoint used to check if an origin has already
been visited by Software Heritage and has at least one full visit.
"""
result = service.lookup_latest_origin_snapshot(origin_id,
allowed_statuses=['full'])
result = json.dumps(result, sort_keys=True, indent=4,
separators=(',', ': '))
return HttpResponse(result, content_type='application/json')
diff --git a/swh/web/browse/views/person.py b/swh/web/browse/views/person.py
index 9b082dbc7..f0953d785 100644
--- a/swh/web/browse/views/person.py
+++ b/swh/web/browse/views/person.py
@@ -1,43 +1,36 @@
# Copyright (C) 2017-2018 The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU General Public License version 3, or any later version
# See top-level LICENSE file for more information
from django.shortcuts import render
from swh.web.common import service
from swh.web.common.exc import handle_view_exception
from swh.web.browse.browseurls import browse_route
@browse_route(r'person/(?P<person_id>[0-9]+)/',
view_name='browse-person')
def person_browse(request, person_id):
"""
Django view that produces an HTML display of a swh person
identified by its id.
The url that points to it is :http:get:`/browse/person/(person_id)/`.
-
- Args:
- request: input django http request
- person_id (int): a swh person id
-
- Returns:
- The HMTL rendering for the metadata of the provided person.
"""
try:
person = service.lookup_person(person_id)
except Exception as exc:
return handle_view_exception(request, exc)
return render(request, 'person.html',
{'empty_browse': False,
'heading': 'Person information',
'top_panel_visible': True,
'top_panel_collapsible': False,
'top_panel_text': 'SWH object: Person',
'swh_object_metadata': person,
'main_panel_visible': False,
'vault_cooking': None,
'show_actions_menu': False})
diff --git a/swh/web/browse/views/release.py b/swh/web/browse/views/release.py
index d926f1e8d..a453c7613 100644
--- a/swh/web/browse/views/release.py
+++ b/swh/web/browse/views/release.py
@@ -1,99 +1,92 @@
# Copyright (C) 2017-2018 The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU General Public License version 3, or any later version
# See top-level LICENSE file for more information
from django.shortcuts import render
from django.utils.safestring import mark_safe
from swh.web.common import service
from swh.web.common.utils import reverse, format_utc_iso_date
from swh.web.common.exc import handle_view_exception
from swh.web.browse.browseurls import browse_route
from swh.web.browse.utils import (
gen_person_link, gen_revision_link,
get_origin_context, gen_link
)
@browse_route(r'release/(?P<sha1_git>[0-9a-f]+)/',
view_name='browse-release')
def release_browse(request, sha1_git):
"""
Django view that produces an HTML display of a SWH release
identified by its id.
The url that points to it is :http:get:`/browse/release/(sha1_git)/`.
-
- Args:
- request: input django http request
- sha1_git: a SWH release id
-
- Returns:
- The HMTL rendering for the metadata of the provided release.
"""
try:
release = service.lookup_release(sha1_git)
origin_context = None
origin_type = request.GET.get('origin_type', None)
origin_url = request.GET.get('origin_url', None)
timestamp = request.GET.get('timestamp', None)
visit_id = request.GET.get('visit_id', None)
if origin_type and origin_url:
origin_context = get_origin_context(origin_type, origin_url,
timestamp, visit_id)
except Exception as exc:
return handle_view_exception(request, exc)
release_data = {}
release_data['author'] = gen_person_link(
release['author']['id'], release['author']['name'])
release_data['date'] = format_utc_iso_date(release['date'])
release_data['id'] = sha1_git
release_data['name'] = release['name']
release_data['synthetic'] = release['synthetic']
release_data['target type'] = release['target_type']
if release['target_type'] == 'revision':
release_data['target'] = \
gen_revision_link(release['target'],
origin_context=origin_context)
elif release['target_type'] == 'content':
content_url = \
reverse('browse-content',
kwargs={'query_string': 'sha1_git:' + release['target']})
release_data['target'] = gen_link(content_url, release['target'])
elif release['target_type'] == 'directory':
directory_url = \
reverse('browse-directory',
kwargs={'sha1_git': release['target']})
release_data['target'] = gen_link(directory_url, release['target'])
elif release['target_type'] == 'release':
release_url = \
reverse('browse-release',
kwargs={'sha1_git': release['target']})
release_data['target'] = gen_link(release_url, release['target'])
release_note_lines = release['message'].split('\n')
release_target_link = '<b>Target:</b> '
if release['target_type'] == 'revision':
release_target_link += '<i class="octicon octicon-git-commit fa-fw"></i>' # noqa
else:
release_target_link += release['target_type']
release_target_link += ' ' + release_data['target']
return render(request, 'release.html',
{'empty_browse': False,
'heading': 'Release information',
'top_panel_visible': True,
'top_panel_collapsible': True,
'top_panel_text': 'SWH object: Release',
'swh_object_metadata': release_data,
'main_panel_visible': True,
'release_name': release['name'],
'release_note_header': release_note_lines[0],
'release_note_body': '\n'.join(release_note_lines[1:]),
'release_target_link': mark_safe(release_target_link),
'origin_context': origin_context})
diff --git a/swh/web/browse/views/revision.py b/swh/web/browse/views/revision.py
index dfbe5c4f4..0a12dcf08 100644
--- a/swh/web/browse/views/revision.py
+++ b/swh/web/browse/views/revision.py
@@ -1,462 +1,448 @@
# Copyright (C) 2017-2018 The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU General Public License version 3, or any later version
# See top-level LICENSE file for more information
import hashlib
import json
from django.http import HttpResponse
from django.shortcuts import render
from django.template.defaultfilters import filesizeformat
from django.utils.safestring import mark_safe
from swh.web.common import service
from swh.web.common.utils import reverse, format_utc_iso_date, gen_path_info
from swh.web.common.exc import handle_view_exception
from swh.web.browse.browseurls import browse_route
from swh.web.browse.utils import (
gen_link, gen_person_link, gen_revision_link,
prepare_revision_log_for_display,
get_origin_context, gen_origin_directory_link,
get_revision_log_url, get_directory_entries,
gen_directory_link, request_content, prepare_content_for_display,
content_display_max_size
)
def _gen_content_url(revision, query_string, path, origin_context):
if origin_context:
url_args = origin_context['url_args']
url_args['path'] = path
query_params = origin_context['query_params']
query_params['revision'] = revision['id']
content_url = reverse('browse-origin-content',
kwargs=url_args,
query_params=query_params)
else:
content_path = '%s/%s' % (revision['directory'], path)
content_url = reverse('browse-content',
kwargs={'query_string': query_string},
query_params={'path': content_path})
return content_url
def _gen_diff_link(idx, diff_anchor, link_text):
if idx < _max_displayed_file_diffs:
return gen_link(diff_anchor, link_text)
else:
return link_text
# TODO: put in conf
_max_displayed_file_diffs = 1000
def _gen_revision_changes_list(revision, changes, origin_context):
"""
Returns a HTML string describing the file changes
introduced in a revision.
As this string will be displayed in the browse revision view,
links to adequate file diffs are also generated.
Args:
revision (str): hexadecimal representation of a revision identifier
changes (list): list of file changes in the revision
origin_context (dict): optional origin context used to reverse
the content urls
Returns:
A string to insert in a revision HTML view.
"""
changes_msg = []
for i, change in enumerate(changes):
hasher = hashlib.sha1()
from_query_string = ''
to_query_string = ''
diff_id = 'diff-'
if change['from']:
from_query_string = 'sha1_git:' + change['from']['target']
diff_id += change['from']['target'] + '-' + change['from_path']
diff_id += '-'
if change['to']:
to_query_string = 'sha1_git:' + change['to']['target']
diff_id += change['to']['target'] + change['to_path']
change['path'] = change['to_path'] or change['from_path']
url_args = {'from_query_string': from_query_string,
'to_query_string': to_query_string}
query_params = {'path': change['path']}
change['diff_url'] = reverse('diff-contents',
kwargs=url_args,
query_params=query_params)
hasher.update(diff_id.encode('utf-8'))
diff_id = hasher.hexdigest()
change['id'] = diff_id
panel_diff_link = '#panel_' + diff_id
if change['type'] == 'modify':
change['content_url'] = \
_gen_content_url(revision, to_query_string,
change['to_path'], origin_context)
changes_msg.append('modified: %s' %
_gen_diff_link(i, panel_diff_link,
change['to_path']))
elif change['type'] == 'insert':
change['content_url'] = \
_gen_content_url(revision, to_query_string,
change['to_path'], origin_context)
changes_msg.append('new file: %s' %
_gen_diff_link(i, panel_diff_link,
change['to_path']))
elif change['type'] == 'delete':
parent = service.lookup_revision(revision['parents'][0])
change['content_url'] = \
_gen_content_url(parent,
from_query_string,
change['from_path'], origin_context)
changes_msg.append('deleted: %s' %
_gen_diff_link(i, panel_diff_link,
change['from_path']))
elif change['type'] == 'rename':
change['content_url'] = \
_gen_content_url(revision, to_query_string,
change['to_path'], origin_context)
link_text = change['from_path'] + ' &rarr; ' + change['to_path']
changes_msg.append('renamed: %s' %
_gen_diff_link(i, panel_diff_link, link_text))
if not changes:
changes_msg.append('No changes')
return mark_safe('\n'.join(changes_msg))
@browse_route(r'revision/(?P<sha1_git>[0-9a-f]+)/diff/',
view_name='diff-revision')
def _revision_diff(request, sha1_git):
"""
Browse internal endpoint to compute revision diff
"""
try:
revision = service.lookup_revision(sha1_git)
origin_context = None
origin_type = request.GET.get('origin_type', None)
origin_url = request.GET.get('origin_url', None)
timestamp = request.GET.get('timestamp', None)
visit_id = request.GET.get('visit_id', None)
if origin_type and origin_url:
origin_context = get_origin_context(origin_type, origin_url,
timestamp, visit_id)
except Exception as exc:
return handle_view_exception(request, exc)
changes = service.diff_revision(sha1_git)
changes_msg = _gen_revision_changes_list(revision, changes, origin_context)
diff_data = {
'total_nb_changes': len(changes),
'changes': changes[:_max_displayed_file_diffs],
'changes_msg': changes_msg
}
diff_data_json = json.dumps(diff_data, separators=(',', ': '))
return HttpResponse(diff_data_json, content_type='application/json')
@browse_route(r'revision/(?P<sha1_git>[0-9a-f]+)/',
view_name='browse-revision')
def revision_browse(request, sha1_git):
"""
Django view that produces an HTML display of a SWH revision
identified by its id.
The url that points to it is :http:get:`/browse/revision/(sha1_git)/`.
-
- Args:
- request: input django http request
- sha1_git: a SWH revision id
-
- Returns:
- The HMTL rendering for the metadata of the provided revision.
"""
try:
revision = service.lookup_revision(sha1_git)
origin_info = None
origin_context = None
origin_type = request.GET.get('origin_type', None)
origin_url = request.GET.get('origin_url', None)
timestamp = request.GET.get('timestamp', None)
visit_id = request.GET.get('visit_id', None)
path = request.GET.get('path', None)
dir_id = None
dirs, files = None, None
content_data = None
if origin_type and origin_url:
origin_context = get_origin_context(origin_type, origin_url,
timestamp, visit_id)
origin_info = origin_context['origin_info']
if path:
path_info = \
service.lookup_directory_with_path(revision['directory'], path)
if path_info['type'] == 'dir':
dir_id = path_info['target']
else:
query_string = 'sha1_git:' + path_info['target']
content_data = request_content(query_string)
else:
dir_id = revision['directory']
if dir_id:
path = '' if path is None else (path + '/')
dirs, files = get_directory_entries(dir_id)
except Exception as exc:
return handle_view_exception(request, exc)
revision_data = {}
revision_data['author'] = gen_person_link(
revision['author']['id'], revision['author']['name'])
revision_data['committer'] = gen_person_link(
revision['committer']['id'], revision['committer']['name'])
revision_data['committer date'] = format_utc_iso_date(
revision['committer_date'])
revision_data['date'] = format_utc_iso_date(revision['date'])
if origin_context:
revision_data['directory'] = \
gen_origin_directory_link(origin_context, sha1_git,
link_text='Browse',
link_attrs={'class': 'btn btn-md btn-swh', # noqa
'role': 'button'})
else:
revision_data['directory'] = \
gen_directory_link(revision['directory'], link_text='Browse',
link_attrs={'class': 'btn btn-md btn-swh',
'role': 'button'})
revision_data['id'] = sha1_git
revision_data['merge'] = revision['merge']
revision_data['metadata'] = json.dumps(revision['metadata'],
sort_keys=True,
indent=4, separators=(',', ': '))
if origin_info:
revision_data['context-independent revision'] = \
gen_revision_link(sha1_git, link_text='Browse',
link_attrs={'class': 'btn btn-md btn-swh',
'role': 'button'})
revision_data['origin id'] = origin_info['id']
revision_data['origin type'] = origin_info['type']
revision_data['origin url'] = gen_link(origin_info['url'],
origin_info['url'])
parents = ''
for p in revision['parents']:
parent_link = gen_revision_link(p, origin_context=origin_context)
parents += parent_link + '<br/>'
revision_data['parents'] = mark_safe(parents)
revision_data['synthetic'] = revision['synthetic']
revision_data['type'] = revision['type']
message_lines = revision['message'].split('\n')
parents_links = '<b>%s parent%s</b> ' % \
(len(revision['parents']),
'' if len(revision['parents']) == 1 else 's')
parents_links += '<i class="octicon octicon-git-commit fa-fw"></i> '
for p in revision['parents']:
parent_link = gen_revision_link(p, shorten_id=True,
origin_context=origin_context)
parents_links += parent_link
if p != revision['parents'][-1]:
parents_links += ' + '
path_info = gen_path_info(path)
query_params = {'origin_type': origin_type,
'origin_url': origin_url,
'timestamp': timestamp,
'visit_id': visit_id}
breadcrumbs = []
breadcrumbs.append({'name': revision['directory'][:7],
'url': reverse('browse-revision',
kwargs={'sha1_git': sha1_git},
query_params=query_params)})
for pi in path_info:
query_params['path'] = pi['path']
breadcrumbs.append({'name': pi['name'],
'url': reverse('browse-revision',
kwargs={'sha1_git': sha1_git},
query_params=query_params)})
vault_cooking = {
'directory_context': False,
'directory_id': None,
'revision_context': True,
'revision_id': sha1_git
}
content = None
content_size = None
mimetype = None
language = None
readme_name = None
readme_url = None
if content_data:
breadcrumbs[-1]['url'] = None
content_size = content_data['length']
mimetype = content_data['mimetype']
if content_data['raw_data']:
content_display_data = prepare_content_for_display(
content_data['raw_data'], content_data['mimetype'], path)
content = content_display_data['content_data']
language = content_display_data['language']
query_params = {}
if path:
query_params['filename'] = path_info[-1]['name']
top_right_link = reverse('browse-content-raw',
kwargs={'query_string': query_string},
query_params=query_params)
top_right_link_text = mark_safe(
'<i class="fa fa-file-text fa-fw" aria-hidden="true">'
'</i>Raw File')
else:
for d in dirs:
query_params['path'] = path + d['name']
d['url'] = reverse('browse-revision',
kwargs={'sha1_git': sha1_git},
query_params=query_params)
for f in files:
query_params['path'] = path + f['name']
f['url'] = reverse('browse-revision',
kwargs={'sha1_git': sha1_git},
query_params=query_params)
f['length'] = filesizeformat(f['length'])
if f['name'].lower().startswith('readme'):
readme_name = f['name']
readme_sha1 = f['checksums']['sha1']
readme_url = reverse('browse-content-raw',
kwargs={'query_string': readme_sha1})
top_right_link = get_revision_log_url(sha1_git, origin_context)
top_right_link_text = mark_safe(
'<i class="fa fa-history fa-fw" aria-hidden="true"></i>'
'History')
vault_cooking['directory_context'] = True
vault_cooking['directory_id'] = dir_id
diff_revision_url = reverse('diff-revision', kwargs={'sha1_git': sha1_git},
query_params={'origin_type': origin_type,
'origin_url': origin_url,
'timestamp': timestamp,
'visit_id': visit_id})
return render(request, 'revision.html',
{'empty_browse': False,
'heading': 'Revision information',
'top_panel_visible': True,
'top_panel_collapsible': True,
'top_panel_text': 'SWH object: Revision',
'swh_object_metadata': revision_data,
'message_header': message_lines[0],
'message_body': '\n'.join(message_lines[1:]),
'parents_links': mark_safe(parents_links),
'main_panel_visible': True,
'origin_context': origin_context,
'dirs': dirs,
'files': files,
'content': content,
'content_size': content_size,
'max_content_size': content_display_max_size,
'mimetype': mimetype,
'language': language,
'readme_name': readme_name,
'readme_url': readme_url,
'breadcrumbs': breadcrumbs,
'top_right_link': top_right_link,
'top_right_link_text': top_right_link_text,
'vault_cooking': vault_cooking,
'diff_revision_url': diff_revision_url,
'show_actions_menu': True})
NB_LOG_ENTRIES = 20
@browse_route(r'revision/(?P<sha1_git>[0-9a-f]+)/log/',
view_name='browse-revision-log')
def revision_log_browse(request, sha1_git):
"""
Django view that produces an HTML display of the history
log for a SWH revision identified by its id.
The url that points to it is :http:get:`/browse/revision/(sha1_git)/log/`.
-
- Args:
- request: input django http request
- sha1_git: a SWH revision id
-
- Returns:
- The HMTL rendering of the revision history log.
""" # noqa
try:
per_page = int(request.GET.get('per_page', NB_LOG_ENTRIES))
revision_log = service.lookup_revision_log(sha1_git,
limit=per_page+1)
revision_log = list(revision_log)
except Exception as exc:
return handle_view_exception(request, exc)
revs_breadcrumb = request.GET.get('revs_breadcrumb', None)
revision_log_display_data = prepare_revision_log_for_display(
revision_log, per_page, revs_breadcrumb)
prev_rev = revision_log_display_data['prev_rev']
prev_revs_breadcrumb = revision_log_display_data['prev_revs_breadcrumb']
prev_log_url = None
if prev_rev:
prev_log_url = \
reverse('browse-revision-log',
kwargs={'sha1_git': prev_rev},
query_params={'revs_breadcrumb': prev_revs_breadcrumb,
'per_page': per_page})
next_rev = revision_log_display_data['next_rev']
next_revs_breadcrumb = revision_log_display_data['next_revs_breadcrumb']
next_log_url = None
if next_rev:
next_log_url = \
reverse('browse-revision-log',
kwargs={'sha1_git': next_rev},
query_params={'revs_breadcrumb': next_revs_breadcrumb,
'per_page': per_page})
revision_log_data = revision_log_display_data['revision_log_data']
for log in revision_log_data:
log['directory'] = gen_directory_link(
log['directory'],
link_text='<i class="fa fa-folder-open fa-fw" aria-hidden="true">'
'</i>Browse files',
link_attrs={'class': 'btn btn-md btn-swh',
'role': 'button'})
return render(request, 'revision-log.html',
{'empty_browse': False,
'heading': 'Revision history information',
'top_panel_visible': False,
'top_panel_collapsible': False,
'top_panel_text': 'SWH object: Revision history',
'swh_object_metadata': None,
'main_panel_visible': True,
'revision_log': revision_log_data,
'next_log_url': next_log_url,
'prev_log_url': prev_log_url,
'breadcrumbs': None,
'top_right_link': None,
'top_right_link_text': None,
'origin_context': None,
'vault_cooking': None,
'show_actions_menu': False})

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jul 3, 11:39 AM (6 d, 11 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3282431

Event Timeline