diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index b43977ea1..2f81c3d96 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -2141,6 +2141,12 @@ rule FORTRAN_DEP_HACK elem.add_item('COMMAND', cmd) elem.add_item('pool', 'console') elem.write(outfile) + cmd = [sys.executable, self.environment.get_build_command(), + '--internal', 'uninstall'] + elem = NinjaBuildElement(self.all_outputs, 'uninstall', 'CUSTOM_COMMAND', 'PHONY') + elem.add_item('COMMAND', cmd) + elem.add_item('pool', 'console') + elem.write(outfile) def generate_ending(self, outfile): targetlist = [] diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 4b0d0c472..8d63a229c 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -249,6 +249,7 @@ forbidden_target_names = {'clean': None, 'test:': None, 'benchmark': None, 'install': None, + 'uninstall': None, 'build.ninja': None, 'scan-build': None, 'reconfigure': None, diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py index e85ef172d..98d072b02 100644 --- a/mesonbuild/mesonmain.py +++ b/mesonbuild/mesonmain.py @@ -237,6 +237,9 @@ def run_script_command(args): elif cmdname == 'yelphelper': import mesonbuild.scripts.yelphelper as abc cmdfunc = abc.run + elif cmdname == 'uninstall': + import mesonbuild.scripts.uninstall as abc + cmdfunc = abc.run else: raise MesonException('Unknown internal command {}.'.format(cmdname)) return cmdfunc(cmdargs) diff --git a/mesonbuild/scripts/uninstall.py b/mesonbuild/scripts/uninstall.py new file mode 100644 index 000000000..85c4bbad8 --- /dev/null +++ b/mesonbuild/scripts/uninstall.py @@ -0,0 +1,46 @@ +# 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: + 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): + if len(args) != 0: + 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 diff --git a/run_unittests.py b/run_unittests.py index 3d5a237ea..8f1f1554e 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -92,6 +92,9 @@ class LinuxlikeTests(unittest.TestCase): os.environ['DESTDIR'] = self.installdir self._run(self.ninja_command + ['install']) + def uninstall(self): + self._run(self.ninja_command + ['uninstall']) + def run_target(self, target): self.output += subprocess.check_output(self.ninja_command + [target]) @@ -361,6 +364,16 @@ class LinuxlikeTests(unittest.TestCase): Oargs = [arg for arg in cmd if arg.startswith('-O')] self.assertEqual(Oargs, [Oflag, '-O0']) + def test_uninstall(self): + exename = os.path.join(self.installdir, 'usr/bin/prog') + testdir = os.path.join(self.common_test_dir, '8 install') + self.init(testdir) + self.assertFalse(os.path.exists(exename)) + self.install() + self.assertTrue(os.path.exists(exename)) + self.uninstall() + self.assertFalse(os.path.exists(exename)) + class RewriterTests(unittest.TestCase): def setUp(self):