Actions: use local plinth in development mode

Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
Michael Pimmer 2018-10-24 00:45:13 +00:00 committed by James Valleroy
parent 487dca4f43
commit 525638357f
No known key found for this signature in database
GPG Key ID: 77C0C75E7B650808
3 changed files with 82 additions and 8 deletions

24
actions/test_path Executable file
View File

@ -0,0 +1,24 @@
#!/usr/bin/python3
# -*- mode: python -*-
#
# This file is part of FreedomBox.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
"""
Helper to test whether action scripts use the correct PYTHONPATH.
"""
import plinth
print(plinth.__file__)

View File

@ -168,17 +168,33 @@ def _run(action, options=None, input=None, run_in_background=False,
cmd += list(options) # No escaping necessary
# Contract 1: commands can run via sudo.
sudo_call = []
if run_as_root:
cmd = ['sudo', '-n'] + cmd
sudo_call = ['sudo', '-n']
elif become_user:
cmd = ['sudo', '-n', '-u', become_user] + cmd
sudo_call = ['sudo', '-n', '-u', become_user]
if cfg.develop and sudo_call:
# Passing 'env' does not work with sudo, so append the PYTHONPATH
# as part of the command
pythonpath = _get_local_pythonpath()
sudo_call += ["PYTHONPATH=%s" % pythonpath]
if sudo_call:
cmd = sudo_call + cmd
LOGGER.info('Executing command - %s', cmd)
# Contract 3C: don't interpret shell escape sequences.
# Contract 5 (and 6-ish).
proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, shell=False)
kwargs = {
"stdin": subprocess.PIPE,
"stdout": subprocess.PIPE,
"stderr": subprocess.PIPE,
"shell": False,
}
if cfg.develop:
# In development mode pass on local pythonpath to access Plinth
kwargs['env'] = {'PYTHONPATH': _get_local_pythonpath()}
proc = subprocess.Popen(cmd, **kwargs)
if not run_in_background:
output, error = proc.communicate(input=input)
@ -192,3 +208,17 @@ def _run(action, options=None, input=None, run_in_background=False,
return output
else:
return proc
def _get_local_pythonpath():
"""Use local plinth folder in pythonpath instead of system plinth"""
pythonpath = cfg.root
try:
current_pythonpath = os.environ['PYTHONPATH']
except KeyError:
pass
else:
current_pythonpath = current_pythonpath.strip(os.path.pathsep)
if current_pythonpath:
pythonpath += os.path.pathsep.join([pythonpath,
current_pythonpath])
return pythonpath

View File

@ -44,11 +44,11 @@ class TestActions(unittest.TestCase):
"""Initial setup for all the classes."""
cls.action_directory = tempfile.TemporaryDirectory()
cfg.actions_dir = cls.action_directory.name
actions_dir = os.path.join(os.path.dirname(__file__), '..', '..',
'actions')
shutil.copy(
os.path.join(
os.path.dirname(__file__), '..', '..', 'actions', 'packages'),
cfg.actions_dir)
shutil.copy(os.path.join(actions_dir, 'packages'), cfg.actions_dir)
shutil.copy(os.path.join(actions_dir, 'test_path'), cfg.actions_dir)
shutil.copy('/bin/echo', cfg.actions_dir)
shutil.copy('/usr/bin/id', cfg.actions_dir)
@ -166,3 +166,23 @@ class TestActions(unittest.TestCase):
# An ActionError is raised in this case.
with self.assertRaises(ActionError):
superuser_run('packages', ['is-package-manager-busy'])
@unittest.skipUnless(euid == 0, 'Needs to be root')
def test_action_path(self):
"""Test that in development mode, python action scripts get the
correct PYTHONPATH"""
try:
cfg.develop = True
self._clear_env()
plinth_path = run('test_path').strip()
su_plinth_path = superuser_run('test_path').strip()
self.assertTrue(plinth_path.startswith(cfg.root))
self.assertEquals(plinth_path, su_plinth_path)
finally:
cfg.develop = False
def _clear_env(self):
try:
del os.environ['PYTHONPATH']
except KeyError:
pass