• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Gallopsled / pwntools / 10356727828

12 Aug 2024 05:27PM UTC coverage: 73.972% (-0.05%) from 74.017%
10356727828

push

github

peace-maker
Release 4.14.0beta0

4533 of 7366 branches covered (61.54%)

1 of 1 new or added line in 1 file covered. (100.0%)

10 existing lines in 3 files now uncovered.

13187 of 17827 relevant lines covered (73.97%)

0.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.0
/pwnlib/update.py
1
"""
2
# Pwntools Update
3

4
In order to ensure that Pwntools users always have the latest and
5
greatest version, Pwntools automatically checks for updates.
6

7
Since this update check takes a moment, it is only performed once
8
every week.  It can be permanently disabled via:
9

10
::
11

12
    $ echo never > ~/.cache/.pwntools-cache-*/update
13

14
Or adding the following lines to ~/.pwn.conf (or system-wide /etc/pwn.conf):
15

16
::
17

18
    [update]
19
    interval=never
20

21
"""
22
from __future__ import absolute_import
1✔
23
from __future__ import division
1✔
24

25
import datetime
1✔
26
import json
1✔
27
import os
1✔
28
import time
1✔
29

30
import packaging.version
1✔
31

32
from pwnlib.args import args
1✔
33
from pwnlib.config import register_config
1✔
34
from pwnlib.context import context
1✔
35
from pwnlib.log import getLogger
1✔
36
from pwnlib.util.misc import read
1✔
37
from pwnlib.util.misc import write
1✔
38
from pwnlib.util.web import wget
1✔
39
from pwnlib.version import __version__
1✔
40

41
log = getLogger(__name__)
1✔
42

43
current_version = packaging.version.Version(__version__)
1✔
44
package_name    = 'pwntools'
1✔
45
package_repo    = 'Gallopsled/pwntools'
1✔
46
update_freq     = datetime.timedelta(days=7).total_seconds()
1✔
47
disabled        = False
1✔
48

49
def read_update_config(settings):
1✔
50
    for key, value in settings.items():
×
51
        if key == 'interval':
×
52
            if value == 'never':
×
53
                global disabled
54
                disabled = True
×
55
            else:
56
                try:
×
57
                    value = int(value)
×
58
                except ValueError:
×
59
                    log.warn("Wrong value")
×
60
                else:
61
                    global update_freq
62
                    update_freq = datetime.timedelta(days=value).total_seconds()
×
63
        else:
64
            log.warn("Unknown configuration option %r in section %r" % (key, 'update'))
×
65

66
register_config('update', read_update_config)
1✔
67

68
def available_on_pypi(prerelease=current_version.is_prerelease):
1✔
69
    """Return True if an update is available on PyPI.
70

71
    >>> available_on_pypi() # doctest: +ELLIPSIS
72
    <Version('...')>
73
    >>> available_on_pypi(prerelease=False).is_prerelease
74
    False
75
    """
76
    # Deferred import to save startup time
77
    from six.moves.xmlrpc_client import ServerProxy
1✔
78

79
    versions = getattr(available_on_pypi, 'cached', None)
1✔
80
    if versions is None:
1✔
81
        client = ServerProxy('https://pypi.python.org/pypi')
1✔
82
        versions = client.package_releases('pwntools', True)
1✔
83
        available_on_pypi.cached = versions
1✔
84

85
    versions = map(packaging.version.Version, versions)
1✔
86

87
    if not prerelease:
1✔
88
        versions = filter(lambda v: not v.is_prerelease, versions)
1✔
89

90
    return max(versions)
1✔
91

92
def cache_file():
1✔
93
    """Returns the path of the file used to cache update data, and ensures that it exists."""
94
    cache_dir = context.cache_dir
1✔
95

96
    if not cache_dir:
1!
97
        return None
×
98

99
    cache_file = os.path.join(cache_dir, 'update')
1✔
100

101
    if not os.path.isdir(cache_dir):
1!
102
        os.makedirs(cache_dir)
×
103

104
    if not os.path.exists(cache_file):
1!
105
        write(cache_file, '')
×
106

107
    return cache_file
1✔
108

109
def last_check():
1✔
110
    """Return the date of the last check"""
111
    cache = cache_file()
1✔
112
    if cache:
1!
113
        return os.path.getmtime(cache_file())
1✔
114

115
    # Fallback
116
    return time.time()
×
117

118
def should_check():
1✔
119
    """Return True if we should check for an update"""
120
    filename = cache_file()
1✔
121

122
    if not filename:
1!
123
        return False
×
124

125
    if disabled or read(filename).strip() == b'never':
1✔
126
        return False
1✔
127

128
    return time.time() > (last_check() + update_freq)
1✔
129

130
def perform_check(prerelease=current_version.is_prerelease):
1✔
131
    """Perform the update check, and report to the user.
132

133
    Arguments:
134
        prerelease(bool): Whether or not to include pre-release versions.
135

136
    Returns:
137
        A list of arguments to the update command.
138

139
    >>> from packaging.version import Version
140
    >>> pwnlib.update.current_version = Version("999.0.0")
141
    >>> print(perform_check())
142
    None
143
    >>> pwnlib.update.current_version = Version("0.0.0")
144
    >>> perform_check() # doctest: +ELLIPSIS
145
    ['pip', 'install', '-U', ...]
146

147
    >>> def bail(*a): raise Exception()
148
    >>> pypi   = pwnlib.update.available_on_pypi
149

150
    >>> perform_check(prerelease=False)
151
    ['pip', 'install', '-U', 'pwntools']
152
    >>> perform_check(prerelease=True)  # doctest: +ELLIPSIS
153
    ['pip', 'install', '-U', 'pwntools...']
154
    """
155
    pypi = current_version
1✔
156
    try:
1✔
157
        pypi = available_on_pypi(prerelease)
1✔
158
    except Exception:
×
159
        log.warning("An issue occurred while checking PyPI")
×
160

161
    best = max(pypi, current_version)
1✔
162
    where = None
1✔
163
    command = None
1✔
164

165
    cache = cache_file()
1✔
166

167
    if cache:
1!
168
        os.utime(cache, None)
1✔
169

170
    if best == current_version:
1✔
171
        log.info("You have the latest version of Pwntools (%s)" % best)
1✔
172
        return
1✔
173

174
    command = [
1✔
175
        'pip',
176
        'install',
177
        '-U'
178
    ]
179

180
    if best == pypi:
1!
181
        where = 'pypi'
1✔
182
        pypi_package = package_name
1✔
183
        if best.is_prerelease:
1!
UNCOV
184
            pypi_package += '==%s' % (best)
×
185
        command += [pypi_package]
1✔
186

187
    command_str = ' '.join(command)
1✔
188

189
    log.info("A newer version of %s is available on %s (%s --> %s).\n" % (package_name, where, current_version, best) +
1✔
190
             "Update with: $ %s" % command_str)
191

192
    return command
1✔
193

194
def check_automatically():
1✔
195
    xdg_config_home = os.environ.get('XDG_CONFIG_HOME') or "~/.config"
1✔
196

197
    if should_check():
1!
198
        message  = ["Checking for new versions of %s" % package_name]
×
199
        message += ["To disable this functionality, set the contents of %s to 'never' (old way)." % cache_file()]
×
200
        message += ["Or add the following lines to ~/.pwn.conf or %s/pwn.conf (or /etc/pwn.conf system-wide):" % xdg_config_home]
×
201
        message += ["""\
×
202
    [update]
203
    interval=never"""]
204
        log.info("\n".join(message))
×
205
        perform_check()
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc