Index: test/functional/test_copy.py =================================================================== --- test/functional/test_copy.py (revision 7052) +++ test/functional/test_copy.py (revision 7054) @@ -1,6 +1,5 @@ import unittest import utils -import shutil import os from base import TestBase @@ -113,5 +112,24 @@ os.unlink(dst_path) os.rmdir('/tmp/make/') + def test_copy_pseudotty(self): + """ + Regression test for DMC-522 + Trick gfal-copy into thinking it is inside a tty so we trigger some logic that would not + be executed otherwise + """ + ffname3 = self.ffname1 + "_copy" + self.assertFalse(os.path.isfile(ffname3)) + + (ret, out, err) = utils.run_command_pty('gfal-copy', \ + 'file://' + self.ffname1 + ' file://' + ffname3) + + self.assertTrue(os.path.isfile(ffname3)) + self.assertNotEqual(len(out), 0) # this makes sure the interactive mode works! + self.assertEqual(ret, 0) + + if os.path.isfile(ffname3): + os.remove(ffname3) + if __name__ == '__main__': unittest.main() Index: test/functional/utils.py =================================================================== --- test/functional/utils.py (revision 7052) +++ test/functional/utils.py (revision 7054) @@ -1,6 +1,8 @@ import subprocess import datetime import os +import pty +import select import stat import inspect @@ -8,22 +10,48 @@ fout = open(path, 'w') fout.write(os.urandom(size)) fout.close() - - + + def create_random_suffix(): return datetime.datetime.now().strftime("%y%m%d_%H%M%S") def remove_file(path): os.remove(path) - + def run_command(cmd, args): script_path = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) cmd = script_path + '/../../src/' + cmd p = subprocess.Popen([cmd] + args.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out,err = p.communicate() - + out, err = p.communicate() + return (p.returncode, out, err) +def run_command_pty(cmd, args): + script_path = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) + cmd = script_path + '/../../src/' + cmd + + master, slave = pty.openpty() + p = subprocess.Popen([cmd] + args.split(), stdout=slave, stderr=slave, close_fds=True) + os.close(slave) + + output = '' + while True: + ready, _, _ = select.select([master], [], [], 1) + if ready: + try: + data = os.read(ready[0], 512) + except: + data = None + if data: + output += data + else: + break + os.close(master) + + rstatus = p.wait() + + return (rstatus, output, None) + def num_entries(directory): return len([name for name in os.listdir(directory)]) Index: src/gfal2_util/progress.py =================================================================== --- src/gfal2_util/progress.py (revision 7052) +++ src/gfal2_util/progress.py (revision 7054) @@ -3,7 +3,7 @@ @author: Duarte Meneses """ -import os +import subprocess import sys import datetime import math @@ -47,8 +47,10 @@ if self.stopped or not self.started: break - self._update() - self.lock.release() + try: + self._update() + finally: + self.lock.release() time.sleep(0.5) self.lock.release() @@ -163,7 +165,7 @@ if not self.started: return - if self.t_main.is_alive(): + if self.t_main.isAlive(): self.lock.acquire() if self.stopped: self.lock.release() @@ -194,7 +196,11 @@ @staticmethod def _get_width(): - return int(os.popen('stty size', 'r').read().split()[1]) + p = subprocess.Popen(['stty', 'size'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = p.communicate() + if p.returncode != 0: + return 80 # Asume default + return int(out.split()[1]) @staticmethod def _clean():