summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggleton <paul.eggleton@linux.intel.com>2015-06-16 17:16:51 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2015-06-18 09:14:06 +0100
commit2054b29dd7be74d09b53df178ef87c69b15a809e (patch)
tree980b4727db3176e15d6bcb9fe373cb791a565af3
parente22c18113b11f557c4502738ccdfbb06093a759a (diff)
downloadpoky-2054b29dd7be74d09b53df178ef87c69b15a809e.tar.gz
devtool: deploy: fix preservation of symlinks and permissions/ownership
It turns out that scp can't be used to copy symlinks because it follows them instead of copying them, and this is by design (since it emulates rcp which also behaved this way); the unfortunate result is that symlinks that point to valid files on the host translate into the host file being copied to the target (yuck). The simplest alternative that does not have this undesirable behaviour is to use tar and pipe it over ssh. At the same time, it would be even better if we properly reflect file permissions and ownership on the target that have been established within the pseudo environment. We can do this by executing the copy process under pseudo, which turns out to be quite easy with access to the pseudo environment set up by the build system. Fixes [YOCTO #7868]. (From OE-Core rev: 69adaed0e982d627ebfa57b360b0ee049ea7a276) Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--meta/lib/oeqa/selftest/devtool.py48
-rw-r--r--scripts/lib/devtool/__init__.py16
-rw-r--r--scripts/lib/devtool/deploy.py10
3 files changed, 69 insertions, 5 deletions
diff --git a/meta/lib/oeqa/selftest/devtool.py b/meta/lib/oeqa/selftest/devtool.py
index 4e22e1dfe4..c4a0399832 100644
--- a/meta/lib/oeqa/selftest/devtool.py
+++ b/meta/lib/oeqa/selftest/devtool.py
@@ -60,6 +60,27 @@ class DevtoolBase(oeSelfTest):
60 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir) 60 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
61 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir) 61 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
62 62
63 def _process_ls_output(self, output):
64 """
65 Convert ls -l output to a format we can reasonably compare from one context
66 to another (e.g. from host to target)
67 """
68 filelist = []
69 for line in output.splitlines():
70 splitline = line.split()
71 # Remove trailing . on perms
72 splitline[0] = splitline[0].rstrip('.')
73 # Remove leading . on paths
74 splitline[-1] = splitline[-1].lstrip('.')
75 # Drop fields we don't want to compare
76 del splitline[7]
77 del splitline[6]
78 del splitline[5]
79 del splitline[4]
80 del splitline[1]
81 filelist.append(' '.join(splitline))
82 return filelist
83
63 84
64class DevtoolTests(DevtoolBase): 85class DevtoolTests(DevtoolBase):
65 86
@@ -796,9 +817,32 @@ class DevtoolTests(DevtoolBase):
796 console.expect("login:", timeout=120) 817 console.expect("login:", timeout=120)
797 # Now really test deploy-target 818 # Now really test deploy-target
798 result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, testhost)) 819 result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, testhost))
799 result = runCmd('ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no root@%s %s' % (testhost, testcommand)) 820 # Run a test command to see if it was installed properly
821 sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
822 result = runCmd('ssh %s root@%s %s' % (sshargs, testhost, testcommand))
823 # Check if it deployed all of the files with the right ownership/perms
824 # First look on the host - need to do this under pseudo to get the correct ownership/perms
825 installdir = get_bb_var('D', testrecipe)
826 fakerootenv = get_bb_var('FAKEROOTENV', testrecipe)
827 fakerootcmd = get_bb_var('FAKEROOTCMD', testrecipe)
828 result = runCmd('%s %s find . -type f -exec ls -l {} \;' % (fakerootenv, fakerootcmd), cwd=installdir)
829 filelist1 = self._process_ls_output(result.output)
830
831 # Now look on the target
832 tempdir2 = tempfile.mkdtemp(prefix='devtoolqa')
833 self.track_for_cleanup(tempdir2)
834 tmpfilelist = os.path.join(tempdir2, 'files.txt')
835 with open(tmpfilelist, 'w') as f:
836 for line in filelist1:
837 splitline = line.split()
838 f.write(splitline[-1] + '\n')
839 result = runCmd('cat %s | ssh -q %s root@%s \'xargs ls -l\'' % (tmpfilelist, sshargs, testhost))
840 filelist2 = self._process_ls_output(result.output)
841 filelist1.sort(key=lambda item: item.split()[-1])
842 filelist2.sort(key=lambda item: item.split()[-1])
843 self.assertEqual(filelist1, filelist2)
800 # Test undeploy-target 844 # Test undeploy-target
801 result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, testhost)) 845 result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, testhost))
802 result = runCmd('ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no root@%s %s' % (testhost, testcommand), ignore_status=True) 846 result = runCmd('ssh %s root@%s %s' % (sshargs, testhost, testcommand), ignore_status=True)
803 self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have') 847 self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have')
804 console.close() 848 console.close()
diff --git a/scripts/lib/devtool/__init__.py b/scripts/lib/devtool/__init__.py
index ea0b63e767..61b810c938 100644
--- a/scripts/lib/devtool/__init__.py
+++ b/scripts/lib/devtool/__init__.py
@@ -80,6 +80,22 @@ def exec_watch(cmd, **options):
80 80
81 return buf, None 81 return buf, None
82 82
83def exec_fakeroot(d, cmd, **kwargs):
84 """Run a command under fakeroot (pseudo, in fact) so that it picks up the appropriate file permissions"""
85 # Grab the command and check it actually exists
86 fakerootcmd = d.getVar('FAKEROOTCMD', True)
87 if not os.path.exists(fakerootcmd):
88 logger.error('pseudo executable %s could not be found - have you run a build yet? pseudo-native should install this and if you have run any build then that should have been built')
89 return 2
90 # Set up the appropriate environment
91 newenv = dict(os.environ)
92 fakerootenv = d.getVar('FAKEROOTENV', True)
93 for varvalue in fakerootenv.split():
94 if '=' in varvalue:
95 splitval = varvalue.split('=', 1)
96 newenv[splitval[0]] = splitval[1]
97 return subprocess.call("%s %s" % (fakerootcmd, cmd), env=newenv, **kwargs)
98
83def setup_tinfoil(): 99def setup_tinfoil():
84 """Initialize tinfoil api from bitbake""" 100 """Initialize tinfoil api from bitbake"""
85 import scriptpath 101 import scriptpath
diff --git a/scripts/lib/devtool/deploy.py b/scripts/lib/devtool/deploy.py
index ca74a8e51d..448db9637d 100644
--- a/scripts/lib/devtool/deploy.py
+++ b/scripts/lib/devtool/deploy.py
@@ -19,7 +19,7 @@
19import os 19import os
20import subprocess 20import subprocess
21import logging 21import logging
22from devtool import exec_build_env_command, setup_tinfoil, DevtoolError 22from devtool import exec_fakeroot, setup_tinfoil, DevtoolError
23 23
24logger = logging.getLogger('devtool') 24logger = logging.getLogger('devtool')
25 25
@@ -73,9 +73,13 @@ def deploy(args, config, basepath, workspace):
73 extraoptions = '' 73 extraoptions = ''
74 if args.no_host_check: 74 if args.no_host_check:
75 extraoptions += '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' 75 extraoptions += '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
76 if not args.show_status: 76 if args.show_status:
77 tarextractopts = 'xv'
78 else:
79 tarextractopts = 'x'
77 extraoptions += ' -q' 80 extraoptions += ' -q'
78 ret = subprocess.call('scp -r %s %s/* %s:%s' % (extraoptions, recipe_outdir, args.target, destdir), shell=True) 81 # We cannot use scp here, because it doesn't preserve symlinks
82 ret = exec_fakeroot(rd, 'tar cf - . | ssh %s %s \'tar %s -C %s -f -\'' % (extraoptions, args.target, tarextractopts, destdir), cwd=recipe_outdir, shell=True)
79 if ret != 0: 83 if ret != 0:
80 raise DevtoolError('Deploy failed - rerun with -s to get a complete ' 84 raise DevtoolError('Deploy failed - rerun with -s to get a complete '
81 'error message') 85 'error message')