##// END OF EJS Templates
retar correctly xz
Matthias Bussonnier -
Show More
@@ -1,108 +1,108 b''
1 [metadata]
1 [metadata]
2 name = ipython
2 name = ipython
3 version = attr: IPython.core.release.__version__
3 version = attr: IPython.core.release.__version__
4 url = https://ipython.org
4 url = https://ipython.org
5 description = IPython: Productive Interactive Computing
5 description = IPython: Productive Interactive Computing
6 long_description_content_type = text/x-rst
6 long_description_content_type = text/x-rst
7 long_description = IPython provides a rich toolkit to help you make the most out of using Python
7 long_description = IPython provides a rich toolkit to help you make the most out of using Python
8 interactively. Its main components are:
8 interactively. Its main components are:
9
9
10 * A powerful interactive Python shell
10 * A powerful interactive Python shell
11 * A `Jupyter <https://jupyter.org/>`_ kernel to work with Python code in Jupyter
11 * A `Jupyter <https://jupyter.org/>`_ kernel to work with Python code in Jupyter
12 notebooks and other interactive frontends.
12 notebooks and other interactive frontends.
13
13
14 The enhanced interactive Python shells have the following main features:
14 The enhanced interactive Python shells have the following main features:
15
15
16 * Comprehensive object introspection.
16 * Comprehensive object introspection.
17
17
18 * Input history, persistent across sessions.
18 * Input history, persistent across sessions.
19
19
20 * Caching of output results during a session with automatically generated
20 * Caching of output results during a session with automatically generated
21 references.
21 references.
22
22
23 * Extensible tab completion, with support by default for completion of python
23 * Extensible tab completion, with support by default for completion of python
24 variables and keywords, filenames and function keywords.
24 variables and keywords, filenames and function keywords.
25
25
26 * Extensible system of 'magic' commands for controlling the environment and
26 * Extensible system of 'magic' commands for controlling the environment and
27 performing many tasks related either to IPython or the operating system.
27 performing many tasks related either to IPython or the operating system.
28
28
29 * A rich configuration system with easy switching between different setups
29 * A rich configuration system with easy switching between different setups
30 (simpler than changing $PYTHONSTARTUP environment variables every time).
30 (simpler than changing $PYTHONSTARTUP environment variables every time).
31
31
32 * Session logging and reloading.
32 * Session logging and reloading.
33
33
34 * Extensible syntax processing for special purpose situations.
34 * Extensible syntax processing for special purpose situations.
35
35
36 * Access to the system shell with user-extensible alias system.
36 * Access to the system shell with user-extensible alias system.
37
37
38 * Easily embeddable in other Python programs and GUIs.
38 * Easily embeddable in other Python programs and GUIs.
39
39
40 * Integrated access to the pdb debugger and the Python profiler.
40 * Integrated access to the pdb debugger and the Python profiler.
41
41
42 The latest development version is always available from IPython's `GitHub
42 The latest development version is always available from IPython's `GitHub
43 site <http://github.com/ipython>`_.
43 site <http://github.com/ipython>`_.
44
44
45 license_file = LICENSE
45 license_file = LICENSE
46 project_urls =
46 project_urls =
47 Documentation = https://ipython.readthedocs.io/
47 Documentation = https://ipython.readthedocs.io/
48 Funding = https://numfocus.org/
48 Funding = https://numfocus.org/
49 Source = https://github.com/ipython/ipython
49 Source = https://github.com/ipython/ipython
50 Tracker = https://github.com/ipython/ipython/issues
50 Tracker = https://github.com/ipython/ipython/issues
51 keywords = Interactive, Interpreter, Shell, Embedding
51 keywords = Interactive, Interpreter, Shell, Embedding
52 platforms = Linux, Mac OSX, Windows
52 platforms = Linux, Mac OSX, Windows
53 classifiers =
53 classifiers =
54 Framework :: IPython
54 Framework :: IPython
55 Intended Audience :: Developers
55 Intended Audience :: Developers
56 Intended Audience :: Science/Research
56 Intended Audience :: Science/Research
57 License :: OSI Approved :: BSD License
57 License :: OSI Approved :: BSD License
58 Programming Language :: Python
58 Programming Language :: Python
59 Programming Language :: Python :: 3
59 Programming Language :: Python :: 3
60 Programming Language :: Python :: 3 :: Only
60 Programming Language :: Python :: 3 :: Only
61 Topic :: System :: Shell
61 Topic :: System :: Shells
62
62
63
63
64 [options]
64 [options]
65 packages = find:
65 packages = find:
66 python_requires = >=3.8
66 python_requires = >=3.8
67 zip_safe = False
67 zip_safe = False
68 install_requires =
68 install_requires =
69 setuptools>=18.5
69 setuptools>=18.5
70 jedi>=0.16
70 jedi>=0.16
71 decorator
71 decorator
72 pickleshare
72 pickleshare
73 traitlets>=5
73 traitlets>=5
74 prompt_toolkit>=2.0.0,<3.1.0,!=3.0.0,!=3.0.1
74 prompt_toolkit>=2.0.0,<3.1.0,!=3.0.0,!=3.0.1
75 pygments
75 pygments
76 backcall
76 backcall
77 stack_data
77 stack_data
78 matplotlib-inline
78 matplotlib-inline
79 pexpect>4.3; sys_platform != "win32"
79 pexpect>4.3; sys_platform != "win32"
80 appnope; sys_platform == "darwin"
80 appnope; sys_platform == "darwin"
81 colorama; sys_platform == "win32"
81 colorama; sys_platform == "win32"
82
82
83 [options.packages.find]
83 [options.packages.find]
84 exclude =
84 exclude =
85 setupext
85 setupext
86
86
87 [options.package_data]
87 [options.package_data]
88 IPython.core = profile/README*
88 IPython.core = profile/README*
89 IPython.core.tests = *.png, *.jpg, daft_extension/*.py
89 IPython.core.tests = *.png, *.jpg, daft_extension/*.py
90 IPython.lib.tests = *.wav
90 IPython.lib.tests = *.wav
91 IPython.testing.plugin = *.txt
91 IPython.testing.plugin = *.txt
92
92
93 [options.entry_points]
93 [options.entry_points]
94 console_scripts =
94 console_scripts =
95 ipython = IPython:start_ipython
95 ipython = IPython:start_ipython
96 ipython3 = IPython:start_ipython
96 ipython3 = IPython:start_ipython
97 pygments.lexers =
97 pygments.lexers =
98 ipythonconsole = IPython.lib.lexers:IPythonConsoleLexer
98 ipythonconsole = IPython.lib.lexers:IPythonConsoleLexer
99 ipython = IPython.lib.lexers:IPythonLexer
99 ipython = IPython.lib.lexers:IPythonLexer
100 ipython3 = IPython.lib.lexers:IPython3Lexer
100 ipython3 = IPython.lib.lexers:IPython3Lexer
101
101
102 [velin]
102 [velin]
103 ignore_patterns =
103 ignore_patterns =
104 IPython/core/tests
104 IPython/core/tests
105 IPython/testing
105 IPython/testing
106
106
107 [tool.black]
107 [tool.black]
108 exclude = 'timing\.py'
108 exclude = 'timing\.py'
@@ -1,22 +1,23 b''
1 #!/usr/bin/env python3
1 #!/usr/bin/env python3
2 """IPython release build script.
2 """IPython release build script.
3 """
3 """
4 import os
4 import os
5 import sys
5 import sys
6 from shutil import rmtree
6 from shutil import rmtree
7
7
8 from toollib import sh, pjoin, get_ipdir, cd, sdists, buildwheels
8 from toollib import sh, pjoin, get_ipdir, cd, sdists, buildwheels
9
9
10 def build_release():
10 def build_release():
11
11
12 # Get main ipython dir, this will raise if it doesn't pass some checks
12 # Get main ipython dir, this will raise if it doesn't pass some checks
13 ipdir = get_ipdir()
13 ipdir = get_ipdir()
14 cd(ipdir)
14 cd(ipdir)
15
15
16 # Build source and binary distros
16 # Build source and binary distros
17 sh(sdists)
17 sh(sdists)
18 buildwheels()
18 buildwheels()
19 sh(' '.join([sys.executable, 'tools/retar.py', 'dist/*.gz']))
19 sh(' '.join([sys.executable, 'tools/retar.py', 'dist/*.gz']))
20 sh(' '.join([sys.executable, 'tools/retar.py', 'dist/*.xz']))
20
21
21 if __name__ == '__main__':
22 if __name__ == '__main__':
22 build_release()
23 build_release()
@@ -1,93 +1,93 b''
1 #!/usr/bin/env python3
1 #!/usr/bin/env python3
2 """IPython release script.
2 """IPython release script.
3
3
4 This should ONLY be run at real release time.
4 This should ONLY be run at real release time.
5 """
5 """
6 from __future__ import print_function
6 from __future__ import print_function
7
7
8 import os
8 import os
9 from glob import glob
9 from glob import glob
10 from subprocess import call
10 from subprocess import call
11 import sys
11 import sys
12
12
13 from toollib import (get_ipdir, pjoin, cd, execfile, sh, archive,
13 from toollib import (get_ipdir, pjoin, cd, execfile, sh, archive,
14 sdists, archive_user, archive_dir, buildwheels)
14 sdists, archive_user, archive_dir, buildwheels)
15 from gh_api import post_download
15 from gh_api import post_download
16
16
17 # Get main ipython dir, this will raise if it doesn't pass some checks
17 # Get main ipython dir, this will raise if it doesn't pass some checks
18 ipdir = get_ipdir()
18 ipdir = get_ipdir()
19 tooldir = pjoin(ipdir, 'tools')
19 tooldir = pjoin(ipdir, 'tools')
20 distdir = pjoin(ipdir, 'dist')
20 distdir = pjoin(ipdir, 'dist')
21
21
22 # Where I keep static backups of each release
22 # Where I keep static backups of each release
23 ipbackupdir = os.path.expanduser('~/ipython/backup')
23 ipbackupdir = os.path.expanduser('~/ipython/backup')
24 if not os.path.exists(ipbackupdir):
24 if not os.path.exists(ipbackupdir):
25 os.makedirs(ipbackupdir)
25 os.makedirs(ipbackupdir)
26
26
27 # Start in main IPython dir
27 # Start in main IPython dir
28 cd(ipdir)
28 cd(ipdir)
29
29
30 # Load release info
30 # Load release info
31 version = None
31 version = None
32 execfile(pjoin('IPython','core','release.py'), globals())
32 execfile(pjoin('IPython','core','release.py'), globals())
33
33
34 # Build site addresses for file uploads
34 # Build site addresses for file uploads
35 release_site = '%s/release/%s' % (archive, version)
35 release_site = '%s/release/%s' % (archive, version)
36 backup_site = '%s/backup/' % archive
36 backup_site = '%s/backup/' % archive
37
37
38 # Start actual release process
38 # Start actual release process
39 print()
39 print()
40 print('Releasing IPython')
40 print('Releasing IPython')
41 print('=================')
41 print('=================')
42 print()
42 print()
43 print('Version:', version)
43 print('Version:', version)
44 print()
44 print()
45 print('Source IPython directory:', ipdir)
45 print('Source IPython directory:', ipdir)
46 print()
46 print()
47
47
48 # Perform local backup, go to tools dir to run it.
48 # Perform local backup, go to tools dir to run it.
49 cd(tooldir)
49 cd(tooldir)
50
50
51 if 'upload' in sys.argv:
51 if 'upload' in sys.argv:
52 cd(distdir)
52 cd(distdir)
53
53
54 # do not upload OS specific files like .DS_Store
54 # do not upload OS specific files like .DS_Store
55 to_upload = glob('*.whl')+glob('*.tar.gz')
55 to_upload = glob('*.whl')+glob('*.tar.gz')
56 for fname in to_upload:
56 for fname in to_upload:
57 # TODO: update to GitHub releases API
57 # TODO: update to GitHub releases API
58 continue
58 continue
59 print('uploading %s to GitHub' % fname)
59 print('uploading %s to GitHub' % fname)
60 desc = "IPython %s source distribution" % version
60 desc = "IPython %s source distribution" % version
61 post_download("ipython/ipython", fname, description=desc)
61 post_download("ipython/ipython", fname, description=desc)
62
62
63 # Make target dir if it doesn't exist
63 # Make target dir if it doesn't exist
64 print('1. Uploading IPython to archive.ipython.org')
64 print('1. Uploading IPython to archive.ipython.org')
65 sh('ssh %s "mkdir -p %s/release/%s" ' % (archive_user, archive_dir, version))
65 sh('ssh %s "mkdir -p %s/release/%s" ' % (archive_user, archive_dir, version))
66 sh('scp *.tar.gz *.whl %s' % release_site)
66 sh('scp *.tar.gz *.tar.xz *.whl %s' % release_site)
67
67
68 print('2. Uploading backup files...')
68 print('2. Uploading backup files...')
69 cd(ipbackupdir)
69 cd(ipbackupdir)
70 sh('scp `ls -1tr *tgz | tail -1` %s' % backup_site)
70 sh('scp `ls -1tr *tgz | tail -1` %s' % backup_site)
71
71
72 print('3. Uploading to PyPI using twine')
72 print('3. Uploading to PyPI using twine')
73 cd(distdir)
73 cd(distdir)
74 call(['twine', 'upload'] + to_upload)
74 call(['twine', 'upload'] + to_upload)
75
75
76 else:
76 else:
77 # Build, but don't upload
77 # Build, but don't upload
78
78
79 # Make backup tarball
79 # Make backup tarball
80 sh('./make_tarball.py')
80 sh('./make_tarball.py')
81 sh('mv ipython-*.tgz %s' % ipbackupdir)
81 sh('mv ipython-*.tgz %s' % ipbackupdir)
82
82
83 # Build release files
83 # Build release files
84 sh('./build_release')
84 sh('./build_release')
85
85
86 cd(ipdir)
86 cd(ipdir)
87
87
88 buildwheels()
88 buildwheels()
89 print("`./release upload` to upload source distribution on PyPI and ipython archive")
89 print("`./release upload` to upload source distribution on PyPI and ipython archive")
90 sys.exit(0)
90 sys.exit(0)
91
91
92
92
93
93
@@ -1,68 +1,83 b''
1 """
1 """
2 Un-targz and retargz a targz file to ensure reproducible build.
2 Un-targz and retargz a targz file to ensure reproducible build.
3
3
4 usage:
4 usage:
5
5
6 $ export SOURCE_DATE_EPOCH=$(date +%s)
6 $ export SOURCE_DATE_EPOCH=$(date +%s)
7 ...
7 ...
8 $ python retar.py <tarfile.gz>
8 $ python retar.py <tarfile.gz>
9
9
10 The process of creating an sdist can be non-reproducible:
10 The process of creating an sdist can be non-reproducible:
11 - directory created during the process get a mtime of the creation date;
11 - directory created during the process get a mtime of the creation date;
12 - gziping files embed the timestamp of zip creation.
12 - gziping files embed the timestamp of zip creation.
13
13
14 This will untar-retar; ensuring that all mtime > SOURCE_DATE_EPOCH will be set
14 This will untar-retar; ensuring that all mtime > SOURCE_DATE_EPOCH will be set
15 equal to SOURCE_DATE_EPOCH.
15 equal to SOURCE_DATE_EPOCH.
16
16
17 """
17 """
18
18
19 import tarfile
19 import tarfile
20 import sys
20 import sys
21 import os
21 import os
22 import gzip
22 import gzip
23 import io
23 import io
24
24
25 from pathlib import Path
25 from pathlib import Path
26
26
27 if len(sys.argv) > 2:
27 if len(sys.argv) > 2:
28 raise ValueError("Too many arguments")
28 raise ValueError("Too many arguments")
29
29
30
30
31 timestamp = int(os.environ["SOURCE_DATE_EPOCH"])
31 timestamp = int(os.environ["SOURCE_DATE_EPOCH"])
32
32
33 path = Path(sys.argv[1])
33 path = Path(sys.argv[1])
34 old_buf = io.BytesIO()
34 old_buf = io.BytesIO()
35 with open(path, "rb") as f:
35 with open(path, "rb") as f:
36 old_buf.write(f.read())
36 old_buf.write(f.read())
37 old_buf.seek(0)
37 old_buf.seek(0)
38 old = tarfile.open(fileobj=old_buf, mode="r:gz")
38 if path.name.endswith("gz"):
39 r_mode = "r:gz"
40 if path.name.endswith(("xz", "xz2")):
41 r_mode = "r:xz"
42 old = tarfile.open(fileobj=old_buf, mode=r_mode)
39
43
40 buf = io.BytesIO()
44 buf = io.BytesIO()
41 new = tarfile.open(fileobj=buf, mode="w", format=tarfile.GNU_FORMAT)
45 new = tarfile.open(fileobj=buf, mode="w", format=tarfile.GNU_FORMAT)
42 for i, m in enumerate(old):
46 for i, m in enumerate(old):
43 data = None
47 data = None
44 # mutation does not work, copy
48 # mutation does not work, copy
45 if m.name.endswith('.DS_Store'):
49 if m.name.endswith('.DS_Store'):
46 continue
50 continue
47 m2 = tarfile.TarInfo(m.name)
51 m2 = tarfile.TarInfo(m.name)
48 m2.mtime = min(timestamp, m.mtime)
52 m2.mtime = min(timestamp, m.mtime)
53 m2.pax_headers["mtime"] = m2.mtime
49 m2.size = m.size
54 m2.size = m.size
50 m2.type = m.type
55 m2.type = m.type
51 m2.linkname = m.linkname
56 m2.linkname = m.linkname
52 m2.mode = m.mode
57 m2.mode = m.mode
53 if m.isdir():
58 if m.isdir():
54 new.addfile(m2)
59 new.addfile(m2)
55 else:
60 else:
56 data = old.extractfile(m)
61 data = old.extractfile(m)
57 new.addfile(m2, data)
62 new.addfile(m2, data)
58 new.close()
63 new.close()
59 old.close()
64 old.close()
60
65
61 buf.seek(0)
66 buf.seek(0)
62 with open(path, "wb") as f:
67
63 with gzip.GzipFile('', "wb", fileobj=f, mtime=timestamp) as gzf:
68 if r_mode == "r:gz":
64 gzf.write(buf.read())
69 with open(path, "wb") as f:
70 with gzip.GzipFile("", "wb", fileobj=f, mtime=timestamp) as gzf:
71 gzf.write(buf.read())
72 elif r_mode == "r:xz":
73 import lzma
74
75 with lzma.open(path, "wb") as f:
76 f.write(buf.read())
77
78 else:
79 assert False
65
80
66 # checks the archive is valid.
81 # checks the archive is valid.
67 archive = tarfile.open(path)
82 archive = tarfile.open(path)
68 names = archive.getnames()
83 names = archive.getnames()
@@ -1,51 +1,51 b''
1 """Various utilities common to IPython release and maintenance tools.
1 """Various utilities common to IPython release and maintenance tools.
2 """
2 """
3
3
4 # Library imports
4 # Library imports
5 import os
5 import os
6 import sys
6 import sys
7
7
8 # Useful shorthands
8 # Useful shorthands
9 pjoin = os.path.join
9 pjoin = os.path.join
10 cd = os.chdir
10 cd = os.chdir
11
11
12 # Constants
12 # Constants
13
13
14 # SSH root address of the archive site
14 # SSH root address of the archive site
15 archive_user = 'ipython@archive.ipython.org'
15 archive_user = 'ipython@archive.ipython.org'
16 archive_dir = 'archive.ipython.org'
16 archive_dir = 'archive.ipython.org'
17 archive = '%s:%s' % (archive_user, archive_dir)
17 archive = '%s:%s' % (archive_user, archive_dir)
18
18
19 # Build commands
19 # Build commands
20 # Source dists
20 # Source dists
21 sdists = "{python} setup.py sdist --formats=xztar".format(python=sys.executable)
21 sdists = "{python} setup.py sdist --formats=xztar,gztar".format(python=sys.executable)
22 # Binary dists
22 # Binary dists
23 def buildwheels():
23 def buildwheels():
24 sh("{python} setup.py bdist_wheel".format(python=sys.executable))
24 sh("{python} setup.py bdist_wheel".format(python=sys.executable))
25
25
26
26
27 # Utility functions
27 # Utility functions
28 def sh(cmd):
28 def sh(cmd):
29 """Run system command in shell, raise SystemExit if it returns an error."""
29 """Run system command in shell, raise SystemExit if it returns an error."""
30 print("$", cmd)
30 print("$", cmd)
31 stat = os.system(cmd)
31 stat = os.system(cmd)
32 #stat = 0 # Uncomment this and comment previous to run in debug mode
32 #stat = 0 # Uncomment this and comment previous to run in debug mode
33 if stat:
33 if stat:
34 raise SystemExit("Command %s failed with code: %s" % (cmd, stat))
34 raise SystemExit("Command %s failed with code: %s" % (cmd, stat))
35
35
36 def get_ipdir():
36 def get_ipdir():
37 """Get IPython directory from command line, or assume it's the one above."""
37 """Get IPython directory from command line, or assume it's the one above."""
38
38
39 # Initialize arguments and check location
39 # Initialize arguments and check location
40 ipdir = pjoin(os.path.dirname(__file__), os.pardir)
40 ipdir = pjoin(os.path.dirname(__file__), os.pardir)
41
41
42 ipdir = os.path.abspath(ipdir)
42 ipdir = os.path.abspath(ipdir)
43
43
44 cd(ipdir)
44 cd(ipdir)
45 if not os.path.isdir('IPython') and os.path.isfile('setup.py'):
45 if not os.path.isdir('IPython') and os.path.isfile('setup.py'):
46 raise SystemExit('Invalid ipython directory: %s' % ipdir)
46 raise SystemExit('Invalid ipython directory: %s' % ipdir)
47 return ipdir
47 return ipdir
48
48
49 def execfile(fname, globs, locs=None):
49 def execfile(fname, globs, locs=None):
50 locs = locs or globs
50 locs = locs or globs
51 exec(compile(open(fname).read(), fname, "exec"), globs, locs)
51 exec(compile(open(fname).read(), fname, "exec"), globs, locs)
General Comments 0
You need to be logged in to leave comments. Login now