##// END OF EJS Templates
Merge pull request #11986 from Carreau/vcr...
Min RK -
r25311:ddeee14a merge
parent child Browse files
Show More
@@ -1,226 +1,228 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
3
3
4 Authors:
4 Authors:
5
5
6 * Fernando Perez
6 * Fernando Perez
7 * Brian E. Granger
7 * Brian E. Granger
8 """
8 """
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
11 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
12 # Copyright (C) 2008-2011 The IPython Development Team
12 # Copyright (C) 2008-2011 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 import os
22 import os
23 import sys
23 import sys
24 import traceback
24 import traceback
25 from pprint import pformat
25 from pprint import pformat
26
26
27 from IPython.core import ultratb
27 from IPython.core import ultratb
28 from IPython.core.release import author_email
28 from IPython.core.release import author_email
29 from IPython.utils.sysinfo import sys_info
29 from IPython.utils.sysinfo import sys_info
30 from IPython.utils.py3compat import input
30 from IPython.utils.py3compat import input
31
31
32 from IPython.core.release import __version__ as version
33
32 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
33 # Code
35 # Code
34 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
35
37
36 # Template for the user message.
38 # Template for the user message.
37 _default_message_template = """\
39 _default_message_template = """\
38 Oops, {app_name} crashed. We do our best to make it stable, but...
40 Oops, {app_name} crashed. We do our best to make it stable, but...
39
41
40 A crash report was automatically generated with the following information:
42 A crash report was automatically generated with the following information:
41 - A verbatim copy of the crash traceback.
43 - A verbatim copy of the crash traceback.
42 - A copy of your input history during this session.
44 - A copy of your input history during this session.
43 - Data on your current {app_name} configuration.
45 - Data on your current {app_name} configuration.
44
46
45 It was left in the file named:
47 It was left in the file named:
46 \t'{crash_report_fname}'
48 \t'{crash_report_fname}'
47 If you can email this file to the developers, the information in it will help
49 If you can email this file to the developers, the information in it will help
48 them in understanding and correcting the problem.
50 them in understanding and correcting the problem.
49
51
50 You can mail it to: {contact_name} at {contact_email}
52 You can mail it to: {contact_name} at {contact_email}
51 with the subject '{app_name} Crash Report'.
53 with the subject '{app_name} Crash Report'.
52
54
53 If you want to do it now, the following command will work (under Unix):
55 If you want to do it now, the following command will work (under Unix):
54 mail -s '{app_name} Crash Report' {contact_email} < {crash_report_fname}
56 mail -s '{app_name} Crash Report' {contact_email} < {crash_report_fname}
55
57
56 In your email, please also include information about:
58 In your email, please also include information about:
57 - The operating system under which the crash happened: Linux, macOS, Windows,
59 - The operating system under which the crash happened: Linux, macOS, Windows,
58 other, and which exact version (for example: Ubuntu 16.04.3, macOS 10.13.2,
60 other, and which exact version (for example: Ubuntu 16.04.3, macOS 10.13.2,
59 Windows 10 Pro), and whether it is 32-bit or 64-bit;
61 Windows 10 Pro), and whether it is 32-bit or 64-bit;
60 - How {app_name} was installed: using pip or conda, from GitHub, as part of
62 - How {app_name} was installed: using pip or conda, from GitHub, as part of
61 a Docker container, or other, providing more detail if possible;
63 a Docker container, or other, providing more detail if possible;
62 - How to reproduce the crash: what exact sequence of instructions can one
64 - How to reproduce the crash: what exact sequence of instructions can one
63 input to get the same crash? Ideally, find a minimal yet complete sequence
65 input to get the same crash? Ideally, find a minimal yet complete sequence
64 of instructions that yields the crash.
66 of instructions that yields the crash.
65
67
66 To ensure accurate tracking of this issue, please file a report about it at:
68 To ensure accurate tracking of this issue, please file a report about it at:
67 {bug_tracker}
69 {bug_tracker}
68 """
70 """
69
71
70 _lite_message_template = """
72 _lite_message_template = """
71 If you suspect this is an IPython bug, please report it at:
73 If you suspect this is an IPython {version} bug, please report it at:
72 https://github.com/ipython/ipython/issues
74 https://github.com/ipython/ipython/issues
73 or send an email to the mailing list at {email}
75 or send an email to the mailing list at {email}
74
76
75 You can print a more detailed traceback right now with "%tb", or use "%debug"
77 You can print a more detailed traceback right now with "%tb", or use "%debug"
76 to interactively debug it.
78 to interactively debug it.
77
79
78 Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
80 Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
79 {config}Application.verbose_crash=True
81 {config}Application.verbose_crash=True
80 """
82 """
81
83
82
84
83 class CrashHandler(object):
85 class CrashHandler(object):
84 """Customizable crash handlers for IPython applications.
86 """Customizable crash handlers for IPython applications.
85
87
86 Instances of this class provide a :meth:`__call__` method which can be
88 Instances of this class provide a :meth:`__call__` method which can be
87 used as a ``sys.excepthook``. The :meth:`__call__` signature is::
89 used as a ``sys.excepthook``. The :meth:`__call__` signature is::
88
90
89 def __call__(self, etype, evalue, etb)
91 def __call__(self, etype, evalue, etb)
90 """
92 """
91
93
92 message_template = _default_message_template
94 message_template = _default_message_template
93 section_sep = '\n\n'+'*'*75+'\n\n'
95 section_sep = '\n\n'+'*'*75+'\n\n'
94
96
95 def __init__(self, app, contact_name=None, contact_email=None,
97 def __init__(self, app, contact_name=None, contact_email=None,
96 bug_tracker=None, show_crash_traceback=True, call_pdb=False):
98 bug_tracker=None, show_crash_traceback=True, call_pdb=False):
97 """Create a new crash handler
99 """Create a new crash handler
98
100
99 Parameters
101 Parameters
100 ----------
102 ----------
101 app : Application
103 app : Application
102 A running :class:`Application` instance, which will be queried at
104 A running :class:`Application` instance, which will be queried at
103 crash time for internal information.
105 crash time for internal information.
104
106
105 contact_name : str
107 contact_name : str
106 A string with the name of the person to contact.
108 A string with the name of the person to contact.
107
109
108 contact_email : str
110 contact_email : str
109 A string with the email address of the contact.
111 A string with the email address of the contact.
110
112
111 bug_tracker : str
113 bug_tracker : str
112 A string with the URL for your project's bug tracker.
114 A string with the URL for your project's bug tracker.
113
115
114 show_crash_traceback : bool
116 show_crash_traceback : bool
115 If false, don't print the crash traceback on stderr, only generate
117 If false, don't print the crash traceback on stderr, only generate
116 the on-disk report
118 the on-disk report
117
119
118 Non-argument instance attributes:
120 Non-argument instance attributes:
119
121
120 These instances contain some non-argument attributes which allow for
122 These instances contain some non-argument attributes which allow for
121 further customization of the crash handler's behavior. Please see the
123 further customization of the crash handler's behavior. Please see the
122 source for further details.
124 source for further details.
123 """
125 """
124 self.crash_report_fname = "Crash_report_%s.txt" % app.name
126 self.crash_report_fname = "Crash_report_%s.txt" % app.name
125 self.app = app
127 self.app = app
126 self.call_pdb = call_pdb
128 self.call_pdb = call_pdb
127 #self.call_pdb = True # dbg
129 #self.call_pdb = True # dbg
128 self.show_crash_traceback = show_crash_traceback
130 self.show_crash_traceback = show_crash_traceback
129 self.info = dict(app_name = app.name,
131 self.info = dict(app_name = app.name,
130 contact_name = contact_name,
132 contact_name = contact_name,
131 contact_email = contact_email,
133 contact_email = contact_email,
132 bug_tracker = bug_tracker,
134 bug_tracker = bug_tracker,
133 crash_report_fname = self.crash_report_fname)
135 crash_report_fname = self.crash_report_fname)
134
136
135
137
136 def __call__(self, etype, evalue, etb):
138 def __call__(self, etype, evalue, etb):
137 """Handle an exception, call for compatible with sys.excepthook"""
139 """Handle an exception, call for compatible with sys.excepthook"""
138
140
139 # do not allow the crash handler to be called twice without reinstalling it
141 # do not allow the crash handler to be called twice without reinstalling it
140 # this prevents unlikely errors in the crash handling from entering an
142 # this prevents unlikely errors in the crash handling from entering an
141 # infinite loop.
143 # infinite loop.
142 sys.excepthook = sys.__excepthook__
144 sys.excepthook = sys.__excepthook__
143
145
144 # Report tracebacks shouldn't use color in general (safer for users)
146 # Report tracebacks shouldn't use color in general (safer for users)
145 color_scheme = 'NoColor'
147 color_scheme = 'NoColor'
146
148
147 # Use this ONLY for developer debugging (keep commented out for release)
149 # Use this ONLY for developer debugging (keep commented out for release)
148 #color_scheme = 'Linux' # dbg
150 #color_scheme = 'Linux' # dbg
149 try:
151 try:
150 rptdir = self.app.ipython_dir
152 rptdir = self.app.ipython_dir
151 except:
153 except:
152 rptdir = os.getcwd()
154 rptdir = os.getcwd()
153 if rptdir is None or not os.path.isdir(rptdir):
155 if rptdir is None or not os.path.isdir(rptdir):
154 rptdir = os.getcwd()
156 rptdir = os.getcwd()
155 report_name = os.path.join(rptdir,self.crash_report_fname)
157 report_name = os.path.join(rptdir,self.crash_report_fname)
156 # write the report filename into the instance dict so it can get
158 # write the report filename into the instance dict so it can get
157 # properly expanded out in the user message template
159 # properly expanded out in the user message template
158 self.crash_report_fname = report_name
160 self.crash_report_fname = report_name
159 self.info['crash_report_fname'] = report_name
161 self.info['crash_report_fname'] = report_name
160 TBhandler = ultratb.VerboseTB(
162 TBhandler = ultratb.VerboseTB(
161 color_scheme=color_scheme,
163 color_scheme=color_scheme,
162 long_header=1,
164 long_header=1,
163 call_pdb=self.call_pdb,
165 call_pdb=self.call_pdb,
164 )
166 )
165 if self.call_pdb:
167 if self.call_pdb:
166 TBhandler(etype,evalue,etb)
168 TBhandler(etype,evalue,etb)
167 return
169 return
168 else:
170 else:
169 traceback = TBhandler.text(etype,evalue,etb,context=31)
171 traceback = TBhandler.text(etype,evalue,etb,context=31)
170
172
171 # print traceback to screen
173 # print traceback to screen
172 if self.show_crash_traceback:
174 if self.show_crash_traceback:
173 print(traceback, file=sys.stderr)
175 print(traceback, file=sys.stderr)
174
176
175 # and generate a complete report on disk
177 # and generate a complete report on disk
176 try:
178 try:
177 report = open(report_name,'w')
179 report = open(report_name,'w')
178 except:
180 except:
179 print('Could not create crash report on disk.', file=sys.stderr)
181 print('Could not create crash report on disk.', file=sys.stderr)
180 return
182 return
181
183
182 with report:
184 with report:
183 # Inform user on stderr of what happened
185 # Inform user on stderr of what happened
184 print('\n'+'*'*70+'\n', file=sys.stderr)
186 print('\n'+'*'*70+'\n', file=sys.stderr)
185 print(self.message_template.format(**self.info), file=sys.stderr)
187 print(self.message_template.format(**self.info), file=sys.stderr)
186
188
187 # Construct report on disk
189 # Construct report on disk
188 report.write(self.make_report(traceback))
190 report.write(self.make_report(traceback))
189
191
190 input("Hit <Enter> to quit (your terminal may close):")
192 input("Hit <Enter> to quit (your terminal may close):")
191
193
192 def make_report(self,traceback):
194 def make_report(self,traceback):
193 """Return a string containing a crash report."""
195 """Return a string containing a crash report."""
194
196
195 sec_sep = self.section_sep
197 sec_sep = self.section_sep
196
198
197 report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n']
199 report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n']
198 rpt_add = report.append
200 rpt_add = report.append
199 rpt_add(sys_info())
201 rpt_add(sys_info())
200
202
201 try:
203 try:
202 config = pformat(self.app.config)
204 config = pformat(self.app.config)
203 rpt_add(sec_sep)
205 rpt_add(sec_sep)
204 rpt_add('Application name: %s\n\n' % self.app_name)
206 rpt_add('Application name: %s\n\n' % self.app_name)
205 rpt_add('Current user configuration structure:\n\n')
207 rpt_add('Current user configuration structure:\n\n')
206 rpt_add(config)
208 rpt_add(config)
207 except:
209 except:
208 pass
210 pass
209 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
211 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
210
212
211 return ''.join(report)
213 return ''.join(report)
212
214
213
215
214 def crash_handler_lite(etype, evalue, tb):
216 def crash_handler_lite(etype, evalue, tb):
215 """a light excepthook, adding a small message to the usual traceback"""
217 """a light excepthook, adding a small message to the usual traceback"""
216 traceback.print_exception(etype, evalue, tb)
218 traceback.print_exception(etype, evalue, tb)
217
219
218 from IPython.core.interactiveshell import InteractiveShell
220 from IPython.core.interactiveshell import InteractiveShell
219 if InteractiveShell.initialized():
221 if InteractiveShell.initialized():
220 # we are in a Shell environment, give %magic example
222 # we are in a Shell environment, give %magic example
221 config = "%config "
223 config = "%config "
222 else:
224 else:
223 # we are not in a shell, show generic config
225 # we are not in a shell, show generic config
224 config = "c."
226 config = "c."
225 print(_lite_message_template.format(email=author_email, config=config), file=sys.stderr)
227 print(_lite_message_template.format(email=author_email, config=config, version=version), file=sys.stderr)
226
228
@@ -1,152 +1,156 b''
1 # Simple tool to help for release
1 # Simple tool to help for release
2 # when releasing with bash, simplei source it to get asked questions.
2 # when releasing with bash, simplei source it to get asked questions.
3
3
4 # misc check before starting
4 # misc check before starting
5
5
6 python -c 'import keyring'
6 python -c 'import keyring'
7 python -c 'import twine'
7 python -c 'import twine'
8 python -c 'import sphinx'
8 python -c 'import sphinx'
9 python -c 'import sphinx_rtd_theme'
9 python -c 'import sphinx_rtd_theme'
10 python -c 'import nose'
10 python -c 'import nose'
11
11
12
12
13 BLACK=$(tput setaf 1)
13 BLACK=$(tput setaf 1)
14 RED=$(tput setaf 1)
14 RED=$(tput setaf 1)
15 GREEN=$(tput setaf 2)
15 GREEN=$(tput setaf 2)
16 YELLOW=$(tput setaf 3)
16 YELLOW=$(tput setaf 3)
17 BLUE=$(tput setaf 4)
17 BLUE=$(tput setaf 4)
18 MAGENTA=$(tput setaf 5)
18 MAGENTA=$(tput setaf 5)
19 CYAN=$(tput setaf 6)
19 CYAN=$(tput setaf 6)
20 WHITE=$(tput setaf 7)
20 WHITE=$(tput setaf 7)
21 NOR=$(tput sgr0)
21 NOR=$(tput sgr0)
22
22
23
23
24 echo -n "PREV_RELEASE (X.y.z) [$PREV_RELEASE]: "
24 echo -n "PREV_RELEASE (X.y.z) [$PREV_RELEASE]: "
25 read input
25 read input
26 PREV_RELEASE=${input:-$PREV_RELEASE}
26 PREV_RELEASE=${input:-$PREV_RELEASE}
27 echo -n "MILESTONE (X.y) [$MILESTONE]: "
27 echo -n "MILESTONE (X.y) [$MILESTONE]: "
28 read input
28 read input
29 MILESTONE=${input:-$MILESTONE}
29 MILESTONE=${input:-$MILESTONE}
30 echo -n "VERSION (X.y.z) [$VERSION]:"
30 echo -n "VERSION (X.y.z) [$VERSION]:"
31 read input
31 read input
32 VERSION=${input:-$VERSION}
32 VERSION=${input:-$VERSION}
33 echo -n "BRANCH (master|X.y) [$BRANCH]:"
33 echo -n "BRANCH (master|X.y) [$BRANCH]:"
34 read input
34 read input
35 BRANCH=${input:-$BRANCH}
35 BRANCH=${input:-$BRANCH}
36
36
37 ask_section(){
37 ask_section(){
38 echo
38 echo
39 echo $BLUE"$1"$NOR
39 echo $BLUE"$1"$NOR
40 echo -n $GREEN"Press Enter to continue, S to skip: "$GREEN
40 echo -n $GREEN"Press Enter to continue, S to skip: "$GREEN
41 read -n1 value
41 read -n1 value
42 echo
42 echo
43 if [ -z $value ] || [ $value = 'y' ] ; then
43 if [ -z $value ] || [ $value = 'y' ] ; then
44 return 0
44 return 0
45 fi
45 fi
46 return 1
46 return 1
47 }
47 }
48
48
49
49
50
50
51 echo
51 echo
52 if ask_section "Updating what's new with informations from docs/source/whatsnew/pr"
52 if ask_section "Updating what's new with informations from docs/source/whatsnew/pr"
53 then
53 then
54 python tools/update_whatsnew.py
54 python tools/update_whatsnew.py
55
55
56 echo
56 echo
57 echo $BLUE"please move the contents of "docs/source/whatsnew/development.rst" to version-X.rst"$NOR
57 echo $BLUE"please move the contents of "docs/source/whatsnew/development.rst" to version-X.rst"$NOR
58 echo $GREEN"Press enter to continue"$NOR
58 echo $GREEN"Press enter to continue"$NOR
59 read
59 read
60 fi
60 fi
61
61
62 if ask_section "Gen Stats, and authors"
62 if ask_section "Gen Stats, and authors"
63 then
63 then
64
64
65 echo
65 echo
66 echo $BLUE"here are all the authors that contributed to this release:"$NOR
66 echo $BLUE"here are all the authors that contributed to this release:"$NOR
67 git log --format="%aN <%aE>" $PREV_RELEASE... | sort -u -f
67 git log --format="%aN <%aE>" $PREV_RELEASE... | sort -u -f
68
68
69 echo
69 echo
70 echo $BLUE"If you see any duplicates cancel (Ctrl-C), then edit .mailmap."
70 echo $BLUE"If you see any duplicates cancel (Ctrl-C), then edit .mailmap."
71 echo $GREEN"Press enter to continue:"$NOR
71 echo $GREEN"Press enter to continue:"$NOR
72 read
72 read
73
73
74 echo $BLUE"generating stats"$NOR
74 echo $BLUE"generating stats"$NOR
75 python tools/github_stats.py --milestone $MILESTONE > stats.rst
75 python tools/github_stats.py --milestone $MILESTONE > stats.rst
76
76
77 echo $BLUE"stats.rst files generated."$NOR
77 echo $BLUE"stats.rst files generated."$NOR
78 echo $GREEN"Please merge it with the right file (github-stats-X.rst) and commit."$NOR
78 echo $GREEN"Please merge it with the right file (github-stats-X.rst) and commit."$NOR
79 echo $GREEN"press enter to continue."$NOR
79 echo $GREEN"press enter to continue."$NOR
80 read
80 read
81
81
82 fi
82 fi
83
83
84 echo "Cleaning repository"
84 echo "Cleaning repository"
85 git clean -xfdi
85 git clean -xfdi
86
86
87 echo $GREEN"please update version number in ${RED}IPython/core/release.py${NOR} , Do not commit yet – we'll do it later."$NOR
87 echo $GREEN"please update version number in ${RED}IPython/core/release.py${NOR} , Do not commit yet – we'll do it later."$NOR
88
88
89 echo $GREEN"Press enter to continue"$NOR
89 echo $GREEN"Press enter to continue"$NOR
90 read
90 read
91
91
92 echo
92 echo
93 echo "Attempting to build the docs.."
93 echo "Attempting to build the docs.."
94 make html -C docs
94 make html -C docs
95
95
96 echo
96 echo
97 echo $GREEN"Check the docs, press enter to continue"$NOR
97 echo $GREEN"Check the docs, press enter to continue"$NOR
98 read
98 read
99
99
100 echo
100 echo
101 echo $BLUE"Attempting to build package..."$NOR
101 echo $BLUE"Attempting to build package..."$NOR
102
102
103 tools/build_release
103 tools/build_release
104
104
105 echo
105 echo
106 echo "Let's commit : git commit -am \"release $VERSION\" -S"
106 echo "Let's commit : git commit -am \"release $VERSION\" -S"
107 echo $GREEN"Press enter to commit"$NOR
107 echo $GREEN"Press enter to commit"$NOR
108 read
108 read
109 git commit -am "release $VERSION" -S
109 git commit -am "release $VERSION" -S
110
110
111 echo
111 echo
112 echo $BLUE"git push origin \$BRANCH ($BRANCH)?"$NOR
112 echo $BLUE"git push origin \$BRANCH ($BRANCH)?"$NOR
113 echo $GREEN"Make sure you can push"$NOR
113 echo $GREEN"Make sure you can push"$NOR
114 echo $GREEN"Press enter to continue"$NOR
114 echo $GREEN"Press enter to continue"$NOR
115 read
115 read
116 git push origin $BRANCH
116 git push origin $BRANCH
117
117
118 echo
118 echo
119 echo "Let's tag : git tag -am \"release $VERSION\" \"$VERSION\" -s"
119 echo "Let's tag : git tag -am \"release $VERSION\" \"$VERSION\" -s"
120 echo $GREEN"Press enter to tag commit"$NOR
120 echo $GREEN"Press enter to tag commit"$NOR
121 read
121 read
122 git tag -am "release $VERSION" "$VERSION" -s
122 git tag -am "release $VERSION" "$VERSION" -s
123
123
124 echo
124 echo
125 echo $BLUE"And push the tag: git push origin \$VERSION ?"$NOR
125 echo $BLUE"And push the tag: git push origin \$VERSION ?"$NOR
126 echo $GREEN"Press enter to continue"$NOR
126 echo $GREEN"Press enter to continue"$NOR
127 read
127 read
128 git push origin $VERSION
128 git push origin $VERSION
129
129
130
130
131 echo $GREEN"please update version number and back to .dev in ${RED}IPython/core/release.py"
131 echo $GREEN"please update version number and back to .dev in ${RED}IPython/core/release.py"
132 echo ${BLUE}"Do not commit yet – we'll do it later."$NOR
132 echo ${BLUE}"Do not commit yet – we'll do it later."$NOR
133
133
134 echo $GREEN"Press enter to continue"$NOR
134 echo $GREEN"Press enter to continue"$NOR
135 read
135 read
136
136
137 echo
137 echo
138 echo "Let's commit : git commit -am \"back to dev\" -S"
138 echo "Let's commit : git commit -am \"back to dev\" -S"
139 echo $GREEN"Press enter to commit"$NOR
139 echo $GREEN"Press enter to commit"$NOR
140 read
140 read
141 git commit -am "back to dev" -S
141 git commit -am "back to dev" -S
142
142
143
143
144
144
145
145
146 echo
146 echo
147 echo $BLUE"let's : git checkout $VERSION"$NOR
147 echo $BLUE"let's : git checkout $VERSION"$NOR
148 echo $GREEN"Press enter to continue"$NOR
148 echo $GREEN"Press enter to continue"$NOR
149 read
149 read
150 git checkout $VERSION
150 git checkout $VERSION
151
151
152 # ./tools/release
153 # ls ./dist
154 # shasum -a 256 dist/*
155
152
156
General Comments 0
You need to be logged in to leave comments. Login now