Page Menu
Home
Software Heritage
Search
Configure Global Search
Log In
Files
F9696518
revision.py
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
19 KB
Subscribers
None
revision.py
View Options
# Copyright (C) 2017-2018 The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU Affero 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
,
redirect
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_snapshot_context
,
gen_snapshot_directory_link
,
get_revision_log_url
,
get_directory_entries
,
gen_directory_link
,
request_content
,
prepare_content_for_display
,
content_display_max_size
,
gen_snapshot_link
,
get_readme_to_display
)
def
_gen_content_url
(
revision
,
query_string
,
path
,
snapshot_context
):
if
snapshot_context
:
url_args
=
snapshot_context
[
'url_args'
]
url_args
[
'path'
]
=
path
query_params
=
snapshot_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
,
snapshot_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
snapshot_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'
],
snapshot_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'
],
snapshot_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'
],
snapshot_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'
],
snapshot_context
)
link_text
=
change
[
'from_path'
]
+
' → '
+
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
)
snapshot_context
=
None
origin_type
=
request
.
GET
.
get
(
'origin_type'
,
None
)
origin_url
=
request
.
GET
.
get
(
'origin_url'
,
None
)
if
not
origin_url
:
origin_url
=
request
.
GET
.
get
(
'origin'
,
None
)
timestamp
=
request
.
GET
.
get
(
'timestamp'
,
None
)
visit_id
=
request
.
GET
.
get
(
'visit_id'
,
None
)
if
origin_url
:
snapshot_context
=
get_snapshot_context
(
None
,
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
,
snapshot_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'
)
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/`.
"""
# 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-default btn-sm'
,
'role'
:
'button'
})
return
render
(
request
,
'revision-log.html'
,
{
'empty_browse'
:
False
,
'heading'
:
'Revision history'
,
'swh_object_name'
:
'Revision history'
,
'swh_object_metadata'
:
None
,
'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
,
'snapshot_context'
:
None
,
'vault_cooking'
:
None
,
'show_actions_menu'
:
True
})
@browse_route
(
r'revision/(?P<sha1_git>[0-9a-f]+)/'
,
r'revision/(?P<sha1_git>[0-9a-f]+)/(?P<extra_path>.+)/'
,
view_name
=
'browse-revision'
)
def
revision_browse
(
request
,
sha1_git
,
extra_path
=
None
):
"""
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)/`.
"""
try
:
revision
=
service
.
lookup_revision
(
sha1_git
)
# some readme files can reference assets reachable from the
# browsed directory, handle that special case in order to
# correctly displayed them
if
extra_path
:
dir_info
=
\
service
.
lookup_directory_with_path
(
revision
[
'directory'
],
extra_path
)
if
dir_info
and
dir_info
[
'type'
]
==
'file'
:
file_raw_url
=
reverse
(
'browse-content-raw'
,
kwargs
=
{
'query_string'
:
dir_info
[
'checksums'
][
'sha1'
]})
return
redirect
(
file_raw_url
)
origin_info
=
None
snapshot_context
=
None
origin_type
=
request
.
GET
.
get
(
'origin_type'
,
None
)
origin_url
=
request
.
GET
.
get
(
'origin_url'
,
None
)
if
not
origin_url
:
origin_url
=
request
.
GET
.
get
(
'origin'
,
None
)
timestamp
=
request
.
GET
.
get
(
'timestamp'
,
None
)
visit_id
=
request
.
GET
.
get
(
'visit_id'
,
None
)
snapshot_id
=
request
.
GET
.
get
(
'snapshot_id'
,
None
)
path
=
request
.
GET
.
get
(
'path'
,
None
)
dir_id
=
None
dirs
,
files
=
None
,
None
content_data
=
None
if
origin_url
:
snapshot_context
=
get_snapshot_context
(
None
,
origin_type
,
origin_url
,
timestamp
,
visit_id
)
origin_info
=
snapshot_context
[
'origin_info'
]
snapshot_id
=
snapshot_context
[
'snapshot_id'
]
elif
snapshot_id
:
snapshot_context
=
get_snapshot_context
(
snapshot_id
)
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'
],
snapshot_context
)
revision_data
[
'committer'
]
=
\
gen_person_link
(
revision
[
'committer'
][
'id'
],
revision
[
'committer'
][
'name'
],
snapshot_context
)
revision_data
[
'committer date'
]
=
format_utc_iso_date
(
revision
[
'committer_date'
])
revision_data
[
'date'
]
=
format_utc_iso_date
(
revision
[
'date'
])
if
snapshot_context
:
revision_data
[
'snapshot id'
]
=
snapshot_id
revision_data
[
'directory'
]
=
\
gen_snapshot_directory_link
(
snapshot_context
,
sha1_git
,
link_text
=
'Browse'
,
link_attrs
=
{
'class'
:
'btn btn-default btn-sm'
,
# noqa
'role'
:
'button'
})
else
:
revision_data
[
'directory'
]
=
\
gen_directory_link
(
revision
[
'directory'
],
link_text
=
'Browse'
,
link_attrs
=
{
'class'
:
'btn btn-default btn-sm'
,
'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-default btn-sm'
,
'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'
])
browse_snapshot_link
=
\
gen_snapshot_link
(
snapshot_id
,
link_text
=
'Browse'
,
link_attrs
=
{
'class'
:
'btn btn-default btn-sm'
,
'role'
:
'button'
})
revision_data
[
'snapshot'
]
=
browse_snapshot_link
parents
=
''
for
p
in
revision
[
'parents'
]:
parent_link
=
gen_revision_link
(
p
,
snapshot_context
=
snapshot_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
,
snapshot_context
=
snapshot_context
)
parents_links
+=
parent_link
if
p
!=
revision
[
'parents'
][
-
1
]:
parents_links
+=
' + '
path_info
=
gen_path_info
(
path
)
query_params
=
{
'snapshot_id'
:
snapshot_id
,
'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
readmes
=
{}
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'
):
readmes
[
f
[
'name'
]]
=
f
[
'checksums'
][
'sha1'
]
readme_name
,
readme_url
,
readme_html
=
get_readme_to_display
(
readmes
)
top_right_link
=
get_revision_log_url
(
sha1_git
,
snapshot_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'
,
'swh_object_name'
:
'Revision'
,
'swh_object_metadata'
:
revision_data
,
'message_header'
:
message_lines
[
0
],
'message_body'
:
'
\n
'
.
join
(
message_lines
[
1
:]),
'parents_links'
:
mark_safe
(
parents_links
),
'snapshot_context'
:
snapshot_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
,
'readme_html'
:
readme_html
,
'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
})
File Metadata
Details
Attached
Mime Type
text/x-python
Expires
Mon, Aug 18, 8:25 PM (3 h, 20 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3397936
Attached To
rDWAPPS Web applications
Event Timeline
Log In to Comment