|
|
|
# Copyright 2016 The Meson development team
|
|
|
|
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
|
|
|
logfile = 'meson-logs/install-log.txt'
|
|
|
|
|
|
|
|
def do_uninstall(log):
|
|
|
|
failures = 0
|
|
|
|
successes = 0
|
|
|
|
for line in open(log):
|
|
|
|
if line.startswith('#'):
|
|
|
|
continue
|
|
|
|
fname = line.strip()
|
|
|
|
try:
|
Remove directories created by ninja install
Introduce a DirMaker class that disassembles the path up to '/' and stores all
directories in a list. That list is in creation order and pre-existing
directories are ignored, i.e. creating the two paths
'/usr/share/foo/bar/baz' and '/usr/share/foo/bar/boo' is stored as
[ '/usr/share/foo',
'/usr/share/foo/bar',
'/usr/share/foo/bar/baz',
'/usr/share/foo/bar/boo' ]
This is on the assumption that /usr/share already existed.
After all files have been installed, the list of created directories is
appended in reverse order to the install log. The uninstall script then
triggers rmdir on all directories.
If a custom install script drops files into the directories, removing those
will fail. This matches the current expectation, see the existing warning
"Remember that files created by custom scripts have not been removed."
Unfortunately, this makes the behavior on uninstall inconsistent. Assuming a
non-existing prefix,
ninja install && ninja uninstall
removes all traces of the install.
However,
ninja install && ninja install && ninja uninstall
removes the files only, not the directories as they already existed.
This could be fixed by just unconditionally removing any (emtpy) directories
that we drop files into, at the risk of removing system directories if empty.
For example, one could imagine /etc/foo.conf.d/ to be removed in that case if
it is empty.
https://github.com/mesonbuild/meson/issues/2032
8 years ago
|
|
|
if os.path.isdir(fname) and not os.path.islink(fname):
|
|
|
|
os.rmdir(fname)
|
|
|
|
else:
|
|
|
|
os.unlink(fname)
|
|
|
|
print('Deleted:', fname)
|
|
|
|
successes += 1
|
|
|
|
except Exception as e:
|
|
|
|
print('Could not delete %s: %s.' % (fname, e))
|
|
|
|
failures += 1
|
|
|
|
print('\nUninstall finished.\n')
|
|
|
|
print('Deleted:', successes)
|
|
|
|
print('Failed:', failures)
|
|
|
|
print('\nRemember that files created by custom scripts have not been removed.')
|
|
|
|
|
|
|
|
def run(args):
|
Don't use len() to test emptiness vs not emptiness
Meson has a common pattern of using 'if len(foo) == 0:' or
'if len(foo) != 0:', however, this is a common anti-pattern in python.
Instead tests for emptiness/non-emptiness should be done with a simple
'if foo:' or 'if not foo:'
Consider the following:
>>> import timeit
>>> timeit.timeit('if len([]) == 0: pass')
0.10730923599840025
>>> timeit.timeit('if not []: pass')
0.030033907998586074
>>> timeit.timeit('if len(['a', 'b', 'c', 'd']) == 0: pass')
0.1154778649979562
>>> timeit.timeit("if not ['a', 'b', 'c', 'd']: pass")
0.08259823200205574
>>> timeit.timeit('if len("") == 0: pass')
0.089759664999292
>>> timeit.timeit('if not "": pass')
0.02340641999762738
>>> timeit.timeit('if len("foo") == 0: pass')
0.08848102600313723
>>> timeit.timeit('if not "foo": pass')
0.04032287199879647
And for the one additional case of 'if len(foo.strip()) == 0', which can
be replaced with 'if not foo.isspace()'
>>> timeit.timeit('if len(" ".strip()) == 0: pass')
0.15294511600222904
>>> timeit.timeit('if " ".isspace(): pass')
0.09413968399894657
>>> timeit.timeit('if len(" abc".strip()) == 0: pass')
0.2023209120015963
>>> timeit.timeit('if " abc".isspace(): pass')
0.09571301700270851
In other words, it's always a win to not use len(), when you don't
actually want to check the length.
8 years ago
|
|
|
if args:
|
|
|
|
print('Weird error.')
|
|
|
|
return 1
|
|
|
|
if not os.path.exists(logfile):
|
|
|
|
print('Log file does not exist, no installation has been done.')
|
|
|
|
return 0
|
|
|
|
do_uninstall(logfile)
|
|
|
|
return 0
|