##// END OF EJS Templates
helpers: do not include microseconds in parsing
marcink -
r3692:5bf6d157 new-ui
parent child Browse files
Show More
@@ -1,160 +1,161 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2014-2019 RhodeCode GmbH
3 # Copyright (C) 2014-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 Utilities aimed to help achieve mostly basic tasks.
22 Utilities aimed to help achieve mostly basic tasks.
23 """
23 """
24
24
25
25
26 from __future__ import division
26 from __future__ import division
27
27
28 import re
28 import re
29 import os
29 import os
30 import time
30 import time
31 import datetime
31 import datetime
32 import logging
32 import logging
33
33
34 from rhodecode.lib.vcs.conf import settings
34 from rhodecode.lib.vcs.conf import settings
35 from rhodecode.lib.vcs.exceptions import VCSError, VCSBackendNotSupportedError
35 from rhodecode.lib.vcs.exceptions import VCSError, VCSBackendNotSupportedError
36
36
37
37
38 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
39
39
40
40
41 def get_scm(path):
41 def get_scm(path):
42 """
42 """
43 Returns one of alias from ``ALIASES`` (in order of precedence same as
43 Returns one of alias from ``ALIASES`` (in order of precedence same as
44 shortcuts given in ``ALIASES``) and working dir path for the given
44 shortcuts given in ``ALIASES``) and working dir path for the given
45 argument. If no scm-specific directory is found or more than one scm is
45 argument. If no scm-specific directory is found or more than one scm is
46 found at that directory, ``VCSError`` is raised.
46 found at that directory, ``VCSError`` is raised.
47 """
47 """
48 if not os.path.isdir(path):
48 if not os.path.isdir(path):
49 raise VCSError("Given path %s is not a directory" % path)
49 raise VCSError("Given path %s is not a directory" % path)
50
50
51 found_scms = [(scm, path) for scm in get_scms_for_path(path)]
51 found_scms = [(scm, path) for scm in get_scms_for_path(path)]
52
52
53 if len(found_scms) > 1:
53 if len(found_scms) > 1:
54 found = ', '.join((x[0] for x in found_scms))
54 found = ', '.join((x[0] for x in found_scms))
55 raise VCSError(
55 raise VCSError(
56 'More than one [%s] scm found at given path %s' % (found, path))
56 'More than one [%s] scm found at given path %s' % (found, path))
57
57
58 if len(found_scms) is 0:
58 if len(found_scms) is 0:
59 raise VCSError('No scm found at given path %s' % path)
59 raise VCSError('No scm found at given path %s' % path)
60
60
61 return found_scms[0]
61 return found_scms[0]
62
62
63
63
64 def get_scm_backend(backend_type):
64 def get_scm_backend(backend_type):
65 from rhodecode.lib.vcs.backends import get_backend
65 from rhodecode.lib.vcs.backends import get_backend
66 return get_backend(backend_type)
66 return get_backend(backend_type)
67
67
68
68
69 def get_scms_for_path(path):
69 def get_scms_for_path(path):
70 """
70 """
71 Returns all scm's found at the given path. If no scm is recognized
71 Returns all scm's found at the given path. If no scm is recognized
72 - empty list is returned.
72 - empty list is returned.
73
73
74 :param path: path to directory which should be checked. May be callable.
74 :param path: path to directory which should be checked. May be callable.
75
75
76 :raises VCSError: if given ``path`` is not a directory
76 :raises VCSError: if given ``path`` is not a directory
77 """
77 """
78 from rhodecode.lib.vcs.backends import get_backend
78 from rhodecode.lib.vcs.backends import get_backend
79 if hasattr(path, '__call__'):
79 if hasattr(path, '__call__'):
80 path = path()
80 path = path()
81 if not os.path.isdir(path):
81 if not os.path.isdir(path):
82 raise VCSError("Given path %r is not a directory" % path)
82 raise VCSError("Given path %r is not a directory" % path)
83
83
84 result = []
84 result = []
85 for key in settings.available_aliases():
85 for key in settings.available_aliases():
86 try:
86 try:
87 backend = get_backend(key)
87 backend = get_backend(key)
88 except VCSBackendNotSupportedError:
88 except VCSBackendNotSupportedError:
89 log.warning('VCSBackendNotSupportedError: %s not supported', key)
89 log.warning('VCSBackendNotSupportedError: %s not supported', key)
90 continue
90 continue
91 if backend.is_valid_repository(path):
91 if backend.is_valid_repository(path):
92 result.append(key)
92 result.append(key)
93 return result
93 return result
94
94
95
95
96 def parse_datetime(text):
96 def parse_datetime(text):
97 """
97 """
98 Parses given text and returns ``datetime.datetime`` instance or raises
98 Parses given text and returns ``datetime.datetime`` instance or raises
99 ``ValueError``.
99 ``ValueError``.
100
100
101 :param text: string of desired date/datetime or something more verbose,
101 :param text: string of desired date/datetime or something more verbose,
102 like *yesterday*, *2weeks 3days*, etc.
102 like *yesterday*, *2weeks 3days*, etc.
103 """
103 """
104 if not text:
104 if not text:
105 raise ValueError('Wrong date: "%s"' % text)
105 raise ValueError('Wrong date: "%s"' % text)
106
106
107 if isinstance(text, datetime.datetime):
107 if isinstance(text, datetime.datetime):
108 return text
108 return text
109
109
110 text = text.strip().lower()
110 # we limit a format to no include microseconds e.g 2017-10-17t17:48:23.XXXX
111 text = text.strip().lower()[:19]
111
112
112 input_formats = (
113 input_formats = (
113 '%Y-%m-%d %H:%M:%S',
114 '%Y-%m-%d %H:%M:%S',
114 '%Y-%m-%dt%H:%M:%S',
115 '%Y-%m-%dt%H:%M:%S',
115 '%Y-%m-%d %H:%M',
116 '%Y-%m-%d %H:%M',
116 '%Y-%m-%dt%H:%M',
117 '%Y-%m-%dt%H:%M',
117 '%Y-%m-%d',
118 '%Y-%m-%d',
118 '%m/%d/%Y %H:%M:%S',
119 '%m/%d/%Y %H:%M:%S',
119 '%m/%d/%Yt%H:%M:%S',
120 '%m/%d/%Yt%H:%M:%S',
120 '%m/%d/%Y %H:%M',
121 '%m/%d/%Y %H:%M',
121 '%m/%d/%Yt%H:%M',
122 '%m/%d/%Yt%H:%M',
122 '%m/%d/%Y',
123 '%m/%d/%Y',
123 '%m/%d/%y %H:%M:%S',
124 '%m/%d/%y %H:%M:%S',
124 '%m/%d/%yt%H:%M:%S',
125 '%m/%d/%yt%H:%M:%S',
125 '%m/%d/%y %H:%M',
126 '%m/%d/%y %H:%M',
126 '%m/%d/%yt%H:%M',
127 '%m/%d/%yt%H:%M',
127 '%m/%d/%y',
128 '%m/%d/%y',
128 )
129 )
129 for format_def in input_formats:
130 for format_def in input_formats:
130 try:
131 try:
131 return datetime.datetime(*time.strptime(text, format_def)[:6])
132 return datetime.datetime(*time.strptime(text, format_def)[:6])
132 except ValueError:
133 except ValueError:
133 pass
134 pass
134
135
135 # Try descriptive texts
136 # Try descriptive texts
136 if text == 'tomorrow':
137 if text == 'tomorrow':
137 future = datetime.datetime.now() + datetime.timedelta(days=1)
138 future = datetime.datetime.now() + datetime.timedelta(days=1)
138 args = future.timetuple()[:3] + (23, 59, 59)
139 args = future.timetuple()[:3] + (23, 59, 59)
139 return datetime.datetime(*args)
140 return datetime.datetime(*args)
140 elif text == 'today':
141 elif text == 'today':
141 return datetime.datetime(*datetime.datetime.today().timetuple()[:3])
142 return datetime.datetime(*datetime.datetime.today().timetuple()[:3])
142 elif text == 'now':
143 elif text == 'now':
143 return datetime.datetime.now()
144 return datetime.datetime.now()
144 elif text == 'yesterday':
145 elif text == 'yesterday':
145 past = datetime.datetime.now() - datetime.timedelta(days=1)
146 past = datetime.datetime.now() - datetime.timedelta(days=1)
146 return datetime.datetime(*past.timetuple()[:3])
147 return datetime.datetime(*past.timetuple()[:3])
147 else:
148 else:
148 days = 0
149 days = 0
149 matched = re.match(
150 matched = re.match(
150 r'^((?P<weeks>\d+) ?w(eeks?)?)? ?((?P<days>\d+) ?d(ays?)?)?$', text)
151 r'^((?P<weeks>\d+) ?w(eeks?)?)? ?((?P<days>\d+) ?d(ays?)?)?$', text)
151 if matched:
152 if matched:
152 groupdict = matched.groupdict()
153 groupdict = matched.groupdict()
153 if groupdict['days']:
154 if groupdict['days']:
154 days += int(matched.groupdict()['days'])
155 days += int(matched.groupdict()['days'])
155 if groupdict['weeks']:
156 if groupdict['weeks']:
156 days += int(matched.groupdict()['weeks']) * 7
157 days += int(matched.groupdict()['weeks']) * 7
157 past = datetime.datetime.now() - datetime.timedelta(days=days)
158 past = datetime.datetime.now() - datetime.timedelta(days=days)
158 return datetime.datetime(*past.timetuple()[:3])
159 return datetime.datetime(*past.timetuple()[:3])
159
160
160 raise ValueError('Wrong date: "%s"' % text)
161 raise ValueError('Wrong date: "%s"' % text)
General Comments 0
You need to be logged in to leave comments. Login now