Add install_user and install_group to bld.install/bld.install_as/bld.symlink_as

This commit is contained in:
Thomas Nagy 2016-10-08 22:35:05 +02:00
parent 4417a3c8c1
commit f02047b8ea
No known key found for this signature in database
GPG Key ID: 49B4C67C05277AAA
4 changed files with 131 additions and 3 deletions

View File

@ -0,0 +1,73 @@
#! /usr/bin/env python
from waflib import Utils, Build, Logs
import os
GRP = 'adm'
def test_chown(bld):
def create_and_chown(tsk):
tsk.outputs[0].write('test')
Utils.lchown(tsk.outputs[0].abspath(), -1, GRP)
bld.conf.env.CAN_CHOWN = True
bld(rule=create_and_chown, target='foo.txt', always=True)
def test_grp(bld):
def check_path(tsk):
import grp
entry = grp.getgrnam(GRP)
assert entry[0] == GRP
bld.conf.env.CAN_GRP = True
bld(rule=check_path, always=True)
def test_chown_install(bld):
bld.is_install = Build.INSTALL
dest_file = bld.bldnode.make_node('test/foo')
dest_link = bld.bldnode.make_node('test/foo_link')
tmpfile = bld.bldnode.make_node('foo.txt')
tmpfile.write('this is a test')
bld.install_as(dest_file,
tmpfile,
install_group=GRP)
bld.symlink_as(dest_link,
'foo',
install_group=GRP)
bld.add_group()
def check_path(tsk):
import grp
gid = grp.getgrnam(GRP)[2]
assert os.stat(dest_file.abspath()).st_gid == gid
assert os.stat(dest_link.abspath()).st_gid == gid
bld(rule=check_path, always=True)
def configure(conf):
conf.test(build_fun=test_grp,
msg='Checking for the python module grp',
okmsg='ok',
errmsg='grp is missing',
mandatory=False)
if not conf.env.CAN_GRP:
return
conf.test(build_fun=test_chown,
msg='Checking for Utils.lchown',
okmsg='ok',
errmsg='chown does not seem to work',
mandatory=False)
if not conf.env.CAN_CHOWN:
return
Logs.info = Utils.nada
conf.test(build_fun=test_chown_install,
msg='Testing install_group="adm"',
okmsg='ok',
errmsg='there is a regression')
def build(bld):
pass

View File

@ -956,6 +956,8 @@ def add_install_task(self, **kw):
tsk.install_to = tsk.dest = kw['install_to']
tsk.install_from = kw['install_from']
tsk.relative_base = kw.get('cwd') or kw.get('relative_base', self.path)
tsk.install_user = kw.get('install_user')
tsk.install_group = kw.get('install_group')
tsk.init_files()
if not kw.get('postpone', True):
tsk.run_now()
@ -1065,7 +1067,9 @@ class inst(Task.Task):
def copy_fun(self, src, tgt):
"""
Copies a file from src to tgt, preserving permissions and trying to work around path limitations on Windows platforms
Copies a file from src to tgt, preserving permissions and trying to work
around path limitations on Windows platforms. On Unix-like platforms,
the owner/group of the target file may be set through install_user/install_group
:param src: absolute path
:type src: string
@ -1077,7 +1081,7 @@ class inst(Task.Task):
if Utils.is_win32 and len(tgt) > 259 and not tgt.startswith('\\\\?\\'):
tgt = '\\\\?\\' + tgt
shutil.copy2(src, tgt)
os.chmod(tgt, self.chmod)
self.fix_perms(tgt)
def rm_empty_dirs(self, tgt):
"""
@ -1180,6 +1184,32 @@ class inst(Task.Task):
Logs.error('Input %r is not a file', src)
raise Errors.WafError('Could not install the file %r' % tgt, e)
def fix_perms(self, tgt):
"""
Change the ownership of the file/folder/link pointed by the given path
This looks up for `install_user` or `install_group` attributes
on the task or on the task generator::
def build(bld):
bld.install_as('${PREFIX}/wscript',
'wscript',
install_user='nobody', install_group='nogroup')
bld.symlink_as('${PREFIX}/wscript_link',
Utils.subst_vars('${PREFIX}/wscript', bld.env),
install_user='nobody', install_group='nogroup')
"""
if not Utils.is_win32:
user = getattr(self, 'install_user', None) or getattr(self.generator, 'install_user', None)
group = getattr(self, 'install_group', None) or getattr(self.generator, 'install_group', None)
if user or group:
Utils.lchown(tgt, user or -1, group or -1)
if os.path.islink(tgt):
# BSD-specific
if hasattr(os, 'lchmod'):
os.lchmod(tgt, self.chmod)
else:
os.chmod(tgt, self.chmod)
def do_link(self, src, tgt, **kw):
"""
Creates a symlink from tgt to src.
@ -1200,6 +1230,7 @@ class inst(Task.Task):
if not self.generator.bld.progress_bar:
Logs.info('+ symlink %s (to %s)', tgt, src)
os.symlink(src, tgt)
self.fix_perms(tgt)
def do_uninstall(self, src, tgt, lbl, **kw):
"""

View File

@ -283,7 +283,7 @@ class Context(ctx):
if not user_function:
if not mandatory:
continue
raise Errors.WafError('No function %s defined in %s' % (name or self.fun, node.abspath()))
raise Errors.WafError('No function %r defined in %s' % (name or self.fun, node.abspath()))
user_function(self)
finally:
self.post_recurse(node)

View File

@ -860,6 +860,30 @@ def run_prefork_process(cmd, kwargs, cargs):
raise Exception(trace)
return ret, out, err
def lchown(path, user=-1, group=-1):
"""
Change the owner/group of a path, raises an OSError if the
ownership change fails.
:param user: user to change
:type user: int or str
:param group: group to change
:type group: int or str
"""
if isinstance(user, str):
import pwd
entry = pwd.getpwnam(user)
if not entry:
raise OSError('Unknown user %r' % user)
user = entry[2]
if isinstance(group, str):
import grp
entry = grp.getgrnam(group)
if not entry:
raise OSError('Unknown group %r' % group)
group = entry[2]
return os.lchown(path, user, group)
def run_regular_process(cmd, kwargs, cargs={}):
"""
Executes a subprocess command by using subprocess.Popen