Skip to content

Commit c702552

Browse files
authored
Refactor file stat and ensure Linux gets correct ctime (#338)
Look for birthtime if supported on systems. Also, move file attribute functions to util.
1 parent cb2cbd8 commit c702552

File tree

10 files changed

+67
-116
lines changed

10 files changed

+67
-116
lines changed

.coveragerc

-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@
22
omit=
33
rummage/__main__.py
44
rummage/lib/gui/*
5-
rummage/lib/rumcore/file_stat.py
65

76
[report]
87
omit=
98
rummage/__main__.py
109
rummage/lib/gui/*
11-
rummage/lib/rumcore/file_stat.py

docs/src/markdown/changelog.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## Current
4+
5+
- **FIX**: Better attempt to get appropriate creation on all Linux systems.
6+
37
## 4.6.3
48

59
- **FIX**: Notification audio failures should be handled gracefully.

rummage/lib/gui/data/docs/.dochash

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
faa2ffe1ce652963b312fbd75e6d4f21
1+
28779be569f92b6d78c94b5e98470719

rummage/lib/gui/data/docs/changelog.html

+4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525

2626
<!-- Table of Content (Don't show for static sites) -->
2727
<h1 id="changelog">Changelog</h1>
28+
<h2 id="current">Current</h2>
29+
<ul>
30+
<li><strong>FIX</strong>: Better attempt to get appropriate creation on all Linux systems.</li>
31+
</ul>
2832
<h2 id="463">4.6.3</h2>
2933
<ul>
3034
<li><strong>FIX</strong>: Notification audio failures should be handled gracefully.</li>

rummage/lib/gui/dialogs/rummage_dialog.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@
6363
from .. import gui
6464
from .. import data
6565
from .. import notify
66-
from ...rumcore import epoch_timestamp
6766
from ... import __meta__
6867
from ... import rumcore
6968
from .. import util
@@ -1355,15 +1354,15 @@ def set_arguments(self, chain, replace):
13551354
if cmp_modified:
13561355
args.modified_compare = (
13571356
LIMIT_COMPARE[cmp_modified],
1358-
epoch_timestamp.local_time_to_epoch_timestamp(
1357+
rumcore.util.local_time_to_epoch_timestamp(
13591358
self.m_modified_date_picker.GetValue().Format("%m/%d/%Y"),
13601359
self.m_modified_time_picker.GetValue()
13611360
)
13621361
)
13631362
if cmp_created:
13641363
args.created_compare = (
13651364
LIMIT_COMPARE[cmp_created],
1366-
epoch_timestamp.local_time_to_epoch_timestamp(
1365+
rumcore.util.local_time_to_epoch_timestamp(
13671366
self.m_modified_date_picker.GetValue().Format("%m/%d/%Y"),
13681367
self.m_modified_time_picker.GetValue()
13691368
)

rummage/lib/rumcore/__init__.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
from collections import deque
3333
from . import text_decode
3434
from wcmatch import wcmatch
35-
from .file_stat import get_stat
3635
from . import util
3736
try:
3837
from backrefs import bregex
@@ -1257,7 +1256,7 @@ def on_validate_file(self, base, name):
12571256

12581257
valid = not self._is_backup(name)
12591258
fullname = os.path.join(base, name)
1260-
self.created_time, self.modified_time, self.current_size = get_stat(fullname)
1259+
self.created_time, self.modified_time, self.current_size = util.get_stat(fullname)
12611260
if valid:
12621261
valid = self._is_size_okay(fullname)
12631262
if valid:
@@ -1398,7 +1397,7 @@ def __init__(
13981397
)
13991398
elif not self.buffer_input and os.path.isfile(self.target):
14001399
try:
1401-
c_time, m_time = get_stat(self.target)
1400+
c_time, m_time = util.get_stat(self.target)
14021401
self.files.append(
14031402
FileAttrRecord(
14041403
self.target,

rummage/lib/rumcore/epoch_timestamp.py

-44
This file was deleted.

rummage/lib/rumcore/file_stat.py

-57
This file was deleted.

rummage/lib/rumcore/util.py

+49
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
"""Compatibility module."""
22
import sys
3+
import os
4+
from datetime import datetime, timedelta, tzinfo
5+
36

47
if sys.platform.startswith('win'):
58
_PLATFORM = "windows"
@@ -8,8 +11,54 @@
811
else:
912
_PLATFORM = "linux"
1013

14+
ZERO = timedelta(0)
15+
1116

1217
def platform():
1318
"""Get Platform."""
1419

1520
return _PLATFORM
21+
22+
23+
def get_stat(pth):
24+
"""Get file status."""
25+
26+
st = os.stat(pth)
27+
try:
28+
st_ctime = st.st_birthtime if platform() != "windows" else st.st_ctime
29+
except AttributeError:
30+
st_ctime = st.st_ctime
31+
return st_ctime, st.st_mtime, st.st_size
32+
33+
34+
class UTCTimezone(tzinfo):
35+
"""Epoch UTC time zone object."""
36+
37+
def utcoffset(self, dt):
38+
"""Return UTC offset."""
39+
40+
return ZERO
41+
42+
def tzname(self, dt):
43+
"""Return timezone name."""
44+
45+
return "UTC"
46+
47+
def dst(self, dt):
48+
"""Return `dst`."""
49+
50+
return ZERO
51+
52+
53+
UTC = UTCTimezone()
54+
EPOCH = datetime(1970, 1, 1, tzinfo=UTC)
55+
56+
57+
def local_time_to_epoch_timestamp(date, time):
58+
"""Take a local date and time and convert it to an epoch timestamp."""
59+
60+
d = date.split("/")
61+
t = time.split(":")
62+
dt = datetime(int(d[2]), int(d[0]), int(d[1]), int(t[0]), int(t[1]), int(t[2]), 0, UTC)
63+
delta = dt - EPOCH
64+
return (delta.microseconds + (delta.seconds + delta.days * 24 * 3600) * 10 ** 6) / 1e6

tests/test_rumcore.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from backrefs import bre
1111
from backrefs import bregex
1212
from rummage.lib import rumcore as rc
13-
from rummage.lib.rumcore import epoch_timestamp as epoch
1413
from rummage.lib.rumcore import text_decode as td
1514
from wcmatch import wcmatch
1615
from . import util
@@ -748,7 +747,7 @@ def test_time_modified_less(self):
748747
r'*.*', None,
749748
self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN,
750749
False, False,
751-
None, ("lt", epoch.local_time_to_epoch_timestamp(date, '00:00:00')), None,
750+
None, ("lt", rc.util.local_time_to_epoch_timestamp(date, '00:00:00')), None,
752751
None, False
753752
)
754753

@@ -766,7 +765,7 @@ def test_time_modified_greater(self):
766765
r'*.*', None,
767766
self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN,
768767
False, False,
769-
None, ("gt", epoch.local_time_to_epoch_timestamp('07/07/1980', '00:00:00')), None,
768+
None, ("gt", rc.util.local_time_to_epoch_timestamp('07/07/1980', '00:00:00')), None,
770769
None, False
771770
)
772771

@@ -787,7 +786,7 @@ def test_time_created_less(self):
787786
r'*.*', None,
788787
self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN,
789788
False, False,
790-
None, None, ("lt", epoch.local_time_to_epoch_timestamp(date, '00:00:00')),
789+
None, None, ("lt", rc.util.local_time_to_epoch_timestamp(date, '00:00:00')),
791790
None, False
792791
)
793792

@@ -805,7 +804,7 @@ def test_time_created_greater(self):
805804
r'*.*', None,
806805
self.default_flags | wcmatch.RECURSIVE | wcmatch.HIDDEN,
807806
False, False,
808-
None, None, ("gt", epoch.local_time_to_epoch_timestamp('07/07/1980', '00:00:00')),
807+
None, None, ("gt", rc.util.local_time_to_epoch_timestamp('07/07/1980', '00:00:00')),
809808
None, False
810809
)
811810

@@ -885,7 +884,7 @@ def get_file_attr(self, *path):
885884
"""Get the file attributes."""
886885

887886
name = self.norm(*path)
888-
c_time, m_time = rc.get_stat(name)[:2]
887+
c_time, m_time = rc.util.get_stat(name)[:2]
889888
return rc.FileAttrRecord(
890889
name,
891890
os.path.splitext(name)[1].lower().lstrip('.'),

0 commit comments

Comments
 (0)