jarn.mkrelease 6.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jarn/mkrelease/__init__.py +1 -0
- jarn/mkrelease/__main__.py +10 -0
- jarn/mkrelease/chdir.py +39 -0
- jarn/mkrelease/colors.py +25 -0
- jarn/mkrelease/configparser.py +178 -0
- jarn/mkrelease/exit.py +36 -0
- jarn/mkrelease/mkrelease.py +640 -0
- jarn/mkrelease/process.py +30 -0
- jarn/mkrelease/python.py +22 -0
- jarn/mkrelease/scm.py +801 -0
- jarn/mkrelease/scp.py +78 -0
- jarn/mkrelease/setup.py +122 -0
- jarn/mkrelease/setuptools.py +280 -0
- jarn/mkrelease/tee.py +296 -0
- jarn/mkrelease/testing.py +360 -0
- jarn/mkrelease/twine.py +174 -0
- jarn/mkrelease/urlparser.py +76 -0
- jarn/mkrelease/utils.py +83 -0
- jarn_mkrelease-6.0.dist-info/METADATA +1077 -0
- jarn_mkrelease-6.0.dist-info/RECORD +24 -0
- jarn_mkrelease-6.0.dist-info/WHEEL +5 -0
- jarn_mkrelease-6.0.dist-info/entry_points.txt +2 -0
- jarn_mkrelease-6.0.dist-info/licenses/LICENSE +24 -0
- jarn_mkrelease-6.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# 23
|
jarn/mkrelease/chdir.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import functools
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ChdirStack(object):
|
|
6
|
+
"""Stack of current working directories."""
|
|
7
|
+
|
|
8
|
+
def __init__(self):
|
|
9
|
+
self.stack = []
|
|
10
|
+
|
|
11
|
+
def __len__(self):
|
|
12
|
+
return len(self.stack)
|
|
13
|
+
|
|
14
|
+
def push(self, dir):
|
|
15
|
+
"""Push cwd on stack and change to 'dir'.
|
|
16
|
+
"""
|
|
17
|
+
self.stack.append(os.getcwd())
|
|
18
|
+
os.chdir(dir or os.getcwd())
|
|
19
|
+
|
|
20
|
+
def pop(self):
|
|
21
|
+
"""Pop dir off stack and change to it.
|
|
22
|
+
"""
|
|
23
|
+
if len(self.stack):
|
|
24
|
+
os.chdir(self.stack.pop())
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def chdir(method):
|
|
28
|
+
"""Decorator executing method in directory 'dir'.
|
|
29
|
+
"""
|
|
30
|
+
def wrapper(self, dir, *args, **kw):
|
|
31
|
+
dirstack = ChdirStack()
|
|
32
|
+
dirstack.push(dir)
|
|
33
|
+
try:
|
|
34
|
+
return method(self, dir, *args, **kw)
|
|
35
|
+
finally:
|
|
36
|
+
dirstack.pop()
|
|
37
|
+
|
|
38
|
+
return functools.wraps(method)(wrapper)
|
|
39
|
+
|
jarn/mkrelease/colors.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import functools
|
|
3
|
+
import blessed
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def color(func):
|
|
7
|
+
assignments = functools.WRAPPER_ASSIGNMENTS
|
|
8
|
+
if not hasattr(func, '__name__'):
|
|
9
|
+
assignments = [x for x in assignments if x != '__name__']
|
|
10
|
+
|
|
11
|
+
@functools.wraps(func, assignments)
|
|
12
|
+
def wrapper(string):
|
|
13
|
+
if os.environ.get('JARN_NO_COLOR') == '1':
|
|
14
|
+
return string
|
|
15
|
+
return func(string)
|
|
16
|
+
return wrapper
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
term = blessed.Terminal()
|
|
20
|
+
|
|
21
|
+
bold = color(term.bold)
|
|
22
|
+
blue = color(term.bold_blue)
|
|
23
|
+
green = color(term.bold_green)
|
|
24
|
+
red = color(term.bold_red)
|
|
25
|
+
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
from configparser import Error
|
|
4
|
+
from configparser import MissingSectionHeaderError
|
|
5
|
+
from configparser import ConfigParser as _BaseParser
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class MultipleValueError(Error):
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class errors2warnings(object):
|
|
13
|
+
"""Turn ConfigParser.Errors into warnings."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, parser):
|
|
16
|
+
self.parser = parser
|
|
17
|
+
|
|
18
|
+
def __enter__(self):
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
def __exit__(self, type, value, tb):
|
|
22
|
+
if isinstance(value, MissingSectionHeaderError):
|
|
23
|
+
self._reformat_exception(value)
|
|
24
|
+
if isinstance(value, Error):
|
|
25
|
+
self.parser.warn(str(value))
|
|
26
|
+
return True
|
|
27
|
+
|
|
28
|
+
def _reformat_exception(self, value):
|
|
29
|
+
value.message = 'File contains no section headers: %r\n\t[line %2d]: %r' % (
|
|
30
|
+
value.source,
|
|
31
|
+
value.lineno,
|
|
32
|
+
value.line)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ConfigParser(object):
|
|
36
|
+
|
|
37
|
+
def __init__(self, warn_func=None, raw=True):
|
|
38
|
+
self.warnings = []
|
|
39
|
+
self.warn_func = warn_func
|
|
40
|
+
self.raw = raw
|
|
41
|
+
self._valid = False
|
|
42
|
+
self._base = _BaseParser()
|
|
43
|
+
self._base.optionxform = lambda x: x.lower().replace('-', '_')
|
|
44
|
+
# Python < 3.2
|
|
45
|
+
if hasattr(self._base, '_boolean_states'):
|
|
46
|
+
self._base.BOOLEAN_STATES = self._base._boolean_states
|
|
47
|
+
|
|
48
|
+
def warn(self, msg):
|
|
49
|
+
self.warnings.append(msg)
|
|
50
|
+
if self.warn_func is not None:
|
|
51
|
+
self.warn_func(msg)
|
|
52
|
+
|
|
53
|
+
def read(self, filenames):
|
|
54
|
+
self.warnings = []
|
|
55
|
+
with errors2warnings(self):
|
|
56
|
+
self._base.read(filenames)
|
|
57
|
+
self._valid = not self.warnings
|
|
58
|
+
return self._valid
|
|
59
|
+
|
|
60
|
+
def has_section(self, section):
|
|
61
|
+
return self._base.has_section(section) and self._valid
|
|
62
|
+
|
|
63
|
+
def has_option(self, section, option):
|
|
64
|
+
return self._base.has_option(section, option) and self._valid
|
|
65
|
+
|
|
66
|
+
def sections(self, default=None):
|
|
67
|
+
return self._base.sections() if self._valid else default
|
|
68
|
+
|
|
69
|
+
def options(self, section, default=None):
|
|
70
|
+
return self._base.options(section) if self._valid else default
|
|
71
|
+
|
|
72
|
+
def items(self, section, default=None):
|
|
73
|
+
if self.has_section(section):
|
|
74
|
+
with errors2warnings(self):
|
|
75
|
+
value = self._base.items(section, raw=self.raw)
|
|
76
|
+
return value
|
|
77
|
+
return default
|
|
78
|
+
|
|
79
|
+
def get(self, section, option, default=None):
|
|
80
|
+
if self.has_option(section, option):
|
|
81
|
+
with errors2warnings(self):
|
|
82
|
+
value = self._base.get(section, option, raw=self.raw)
|
|
83
|
+
return value
|
|
84
|
+
return default
|
|
85
|
+
|
|
86
|
+
def getlist(self, section, option, default=None):
|
|
87
|
+
if self.has_option(section, option):
|
|
88
|
+
with errors2warnings(self):
|
|
89
|
+
value = self._base.get(section, option, raw=self.raw)
|
|
90
|
+
return self.to_list(value)
|
|
91
|
+
return default
|
|
92
|
+
|
|
93
|
+
def getstring(self, section, option, default=None):
|
|
94
|
+
if self.has_option(section, option):
|
|
95
|
+
with errors2warnings(self):
|
|
96
|
+
value = self._base.get(section, option, raw=self.raw)
|
|
97
|
+
try:
|
|
98
|
+
return self.to_string(value)
|
|
99
|
+
except MultipleValueError as e:
|
|
100
|
+
self.warn("Multiple values not allowed: %s = %r" % (option, self._value_from_exc(e)))
|
|
101
|
+
return default
|
|
102
|
+
|
|
103
|
+
def getboolean(self, section, option, default=None):
|
|
104
|
+
if self.has_option(section, option):
|
|
105
|
+
with errors2warnings(self):
|
|
106
|
+
value = self._base.get(section, option, raw=self.raw)
|
|
107
|
+
try:
|
|
108
|
+
return self.to_boolean(value)
|
|
109
|
+
except MultipleValueError as e:
|
|
110
|
+
self.warn("Multiple values not allowed: %s = %r" % (option, self._value_from_exc(e)))
|
|
111
|
+
except ValueError as e:
|
|
112
|
+
self.warn('Not a boolean: %s = %r' % (option, self._value_from_exc(e)))
|
|
113
|
+
return default
|
|
114
|
+
|
|
115
|
+
def getint(self, section, option, default=None):
|
|
116
|
+
if self.has_option(section, option):
|
|
117
|
+
with errors2warnings(self):
|
|
118
|
+
value = self._base.get(section, option, raw=self.raw)
|
|
119
|
+
try:
|
|
120
|
+
return self.to_int(value)
|
|
121
|
+
except MultipleValueError as e:
|
|
122
|
+
self.warn('Multiple values not allowed: %s = %r' % (option, self._value_from_exc(e)))
|
|
123
|
+
except ValueError as e:
|
|
124
|
+
self.warn('Not an integer: %s = %r' % (option, self._value_from_exc(e)))
|
|
125
|
+
return default
|
|
126
|
+
|
|
127
|
+
def getfloat(self, section, option, default=None):
|
|
128
|
+
if self.has_option(section, option):
|
|
129
|
+
with errors2warnings(self):
|
|
130
|
+
value = self._base.get(section, option, raw=self.raw)
|
|
131
|
+
try:
|
|
132
|
+
return self.to_float(value)
|
|
133
|
+
except MultipleValueError as e:
|
|
134
|
+
self.warn('Multiple values not allowed: %s = %r' % (option, self._value_from_exc(e)))
|
|
135
|
+
except ValueError as e:
|
|
136
|
+
self.warn('Not a float: %s = %r' % (option, self._value_from_exc(e)))
|
|
137
|
+
return default
|
|
138
|
+
|
|
139
|
+
def to_list(self, value):
|
|
140
|
+
v = re.split(r',\s*|\s+', value)
|
|
141
|
+
return [x for x in v if x]
|
|
142
|
+
|
|
143
|
+
def to_string(self, value):
|
|
144
|
+
v = self._single_value(value)
|
|
145
|
+
return v
|
|
146
|
+
|
|
147
|
+
def to_boolean(self, value):
|
|
148
|
+
v = self._single_value(value).lower()
|
|
149
|
+
if v not in self._base.BOOLEAN_STATES:
|
|
150
|
+
raise ValueError('Not a boolean: %s' % v)
|
|
151
|
+
return self._base.BOOLEAN_STATES[v]
|
|
152
|
+
|
|
153
|
+
def to_int(self, value):
|
|
154
|
+
v = self._single_value(value)
|
|
155
|
+
return int(v)
|
|
156
|
+
|
|
157
|
+
def to_float(self, value):
|
|
158
|
+
v = self._single_value(value)
|
|
159
|
+
return float(v)
|
|
160
|
+
|
|
161
|
+
def _single_value(self, value):
|
|
162
|
+
v = value.strip()
|
|
163
|
+
if len(v.split()) > 1:
|
|
164
|
+
raise MultipleValueError('Multiple values not allowed: %s' % v)
|
|
165
|
+
return v
|
|
166
|
+
|
|
167
|
+
def _value_from_exc(self, exc):
|
|
168
|
+
# e.g.: invalid literal for int() with base 10: 'a'
|
|
169
|
+
msg = str(exc)
|
|
170
|
+
colon = msg.find(':')
|
|
171
|
+
if colon >= 0:
|
|
172
|
+
value = msg[colon+1:].lstrip()
|
|
173
|
+
if (value.startswith("'") and value.endswith("'")) or \
|
|
174
|
+
(value.startswith('"') and value.endswith('"')):
|
|
175
|
+
value = value[1:-1]
|
|
176
|
+
return value
|
|
177
|
+
return ''
|
|
178
|
+
|
jarn/mkrelease/exit.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
from .colors import red
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def msg_exit(msg, rc=0):
|
|
8
|
+
"""Print msg to stdout and exit with rc.
|
|
9
|
+
"""
|
|
10
|
+
print(msg)
|
|
11
|
+
sys.exit(rc)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def err_exit(msg, rc=1):
|
|
15
|
+
"""Print msg to stderr and exit with rc.
|
|
16
|
+
"""
|
|
17
|
+
if '\033[' not in msg:
|
|
18
|
+
lines = msg.split('\n')
|
|
19
|
+
lines[0] = red(lines[0])
|
|
20
|
+
msg = '\n'.join(lines)
|
|
21
|
+
print(msg, file=sys.stderr)
|
|
22
|
+
sys.exit(rc)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def warn(msg):
|
|
26
|
+
"""Print a warning message to stderr.
|
|
27
|
+
"""
|
|
28
|
+
print('WARNING:', msg, file=sys.stderr)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def trace(msg):
|
|
32
|
+
"""Print a trace message to stderr if environment variable is set.
|
|
33
|
+
"""
|
|
34
|
+
if os.environ.get('JARN_TRACE') == '1':
|
|
35
|
+
print('TRACE:', msg, file=sys.stderr)
|
|
36
|
+
|