diff --git a/swh/loader/tar/build.py b/swh/loader/tar/build.py index 9869990..a94bc26 100755 --- a/swh/loader/tar/build.py +++ b/swh/loader/tar/build.py @@ -1,101 +1,118 @@ # Copyright (C) 2015-2017 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 os from swh.loader.tar import utils # Static setup EPOCH = 0 UTC_OFFSET = 0 SWH_PERSON = { 'name': 'Software Heritage', 'fullname': 'Software Heritage', 'email': 'robot@softwareheritage.org' } REVISION_MESSAGE = 'synthetic revision message' REVISION_TYPE = 'tar' def compute_origin(url_scheme, url_type, root_dirpath, tarpath): """Compute the origin. Args: - url_scheme: scheme to build the origin's url - url_type: origin's type - root_dirpath: the top level root directory path - tarpath: file's absolute path Returns: Dictionary origin with keys: - url: origin's url - type: origin's type """ relative_path = utils.commonname(root_dirpath, tarpath) return { 'url': ''.join([url_scheme, os.path.dirname(relative_path)]), 'type': url_type, } def occurrence_with_date(date, tarpath): """Compute the occurrence using the tarpath's ctime. Args: authority: the authority's uuid tarpath: file's path Returns: Occurrence dictionary (cf. _build_occurrence) """ return { 'branch': os.path.basename(tarpath), 'date': date } def _time_from_path(tarpath): """Compute the modification time from the tarpath. + Args: + tarpath (str|bytes): Full path to the archive to extract the + date from. + + Returns: + dict representing a timestamp with keys seconds and microseconds keys. + """ - return os.lstat(tarpath).st_mtime + mtime = os.lstat(tarpath).st_mtime + if isinstance(mtime, float): + normalized_time = list(map(int, str(mtime).split('.'))) + else: # assuming int + normalized_time = [mtime, 0] + + return { + 'seconds': normalized_time[0], + 'microseconds': normalized_time[1] + } def compute_revision(tarpath): """Compute a revision. Args: tarpath: absolute path to the tarball Returns: Revision as dict: - - date: the modification timestamp as returned by a fstat call - - committer_date: the modification timestamp as returned by a fstat - call + - date (dict): the modification timestamp as returned by + _time_from_path function + - committer_date: the modification timestamp as returned by + _time_from_path function - author: cf. SWH_PERSON - committer: cf. SWH_PERSON - type: cf. REVISION_TYPE - message: cf. REVISION_MESSAGE """ ts = _time_from_path(tarpath) return { 'date': { 'timestamp': ts, 'offset': UTC_OFFSET, }, 'committer_date': { 'timestamp': ts, 'offset': UTC_OFFSET, }, 'author': SWH_PERSON, 'committer': SWH_PERSON, 'type': REVISION_TYPE, 'message': REVISION_MESSAGE, } diff --git a/swh/loader/tar/tests/test_build.py b/swh/loader/tar/tests/test_build.py index b06bed3..0054997 100644 --- a/swh/loader/tar/tests/test_build.py +++ b/swh/loader/tar/tests/test_build.py @@ -1,71 +1,107 @@ # Copyright (C) 2015-2017 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 unittest from nose.tools import istest from unittest.mock import patch from swh.loader.tar import build class TestBuildUtils(unittest.TestCase): @istest def compute_origin(self): # given expected_origin = { 'url': 'rsync://some/url/package-foo', 'type': 'rsync', } # when actual_origin = build.compute_origin( 'rsync://some/url/', 'rsync', '/some/root/path/', '/some/root/path/package-foo/package-foo-1.2.3.tgz') # then self.assertEquals(actual_origin, expected_origin) @istest def occurrence_with_date(self): # given expected_occurrence = { 'branch': b'package-bar.tgz', 'date': '2015-10-22 08:44:47.422384+00' } # when actual_occurrence = build.occurrence_with_date( '2015-10-22 08:44:47.422384+00', b'/path/to/package-bar.tgz',) # then self.assertEquals(actual_occurrence, expected_occurrence) + @patch('swh.loader.tar.build._time_from_path') @istest - def compute_revision(self): + def compute_revision(self, mock_time_from_path): + mock_time_from_path.return_value = 'some-other-time' + # when - with patch('swh.loader.tar.build._time_from_path', - return_value='some-other-time'): - actual_revision = build.compute_revision('/some/path') + actual_revision = build.compute_revision('/some/path') expected_revision = { 'date': { 'timestamp': 'some-other-time', 'offset': build.UTC_OFFSET, }, 'committer_date': { 'timestamp': 'some-other-time', 'offset': build.UTC_OFFSET, }, 'author': build.SWH_PERSON, 'committer': build.SWH_PERSON, 'type': build.REVISION_TYPE, 'message': build.REVISION_MESSAGE, } # then self.assertEquals(actual_revision, expected_revision) + + mock_time_from_path.assert_called_once_with('/some/path') + + @patch('swh.loader.tar.build.os') + @istest + def time_from_path_with_float(self, mock_os): + class MockStat: + st_mtime = 1445348286.8308342 + mock_os.lstat.return_value = MockStat() + + actual_time = build._time_from_path('some/path') + + self.assertEquals(actual_time, { + 'seconds': 1445348286, + 'microseconds': 8308342 + }) + + mock_os.lstat.assert_called_once_with('some/path') + + @patch('swh.loader.tar.build.os') + @istest + def time_from_path_with_int(self, mock_os): + class MockStat: + st_mtime = 1445348286 + + mock_os.lstat.return_value = MockStat() + + actual_time = build._time_from_path('some/path') + + self.assertEquals(actual_time, { + 'seconds': 1445348286, + 'microseconds': 0 + }) + + mock_os.lstat.assert_called_once_with('some/path')