From dfef8285d464d6feb3c266054376cf7ad216f60a Mon Sep 17 00:00:00 2001 From: Wei-Ning Huang Date: Sat, 11 May 2024 17:43:57 +0800 Subject: [PATCH] ovl: fix push directory when dest path is absolute Properly fix push when dest dest path is absolute. Also added unitest. Close #1. --- .github/workflows/build.yml | 4 + scripts/__pycache__/ovl.cpython-311.pyc | Bin 0 -> 83481 bytes scripts/ovl.py | 101 +++++++++++++---------- scripts/ovl_unittest.py | 104 ++++++++++++++++++++++++ 4 files changed, 165 insertions(+), 44 deletions(-) create mode 100644 scripts/__pycache__/ovl.cpython-311.pyc create mode 100755 scripts/ovl_unittest.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 351f6bd..5e66e85 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,6 +24,10 @@ jobs: run: git config --global --add safe.directory $PWD - name: test run: go test -v ./... + - name: unittest + run: | + source .venv/bin/activate + ./scripts/ovl_unittest.py - name: e2e_test run: | source .venv/bin/activate diff --git a/scripts/__pycache__/ovl.cpython-311.pyc b/scripts/__pycache__/ovl.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..942a084581b87c1368539bdad6f112926d03d54f GIT binary patch literal 83481 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

jc^nV}glC2RO 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 literal 0 HcmV?d00001 diff --git a/scripts/ovl.py b/scripts/ovl.py index a390870..a8b6818 100755 --- a/scripts/ovl.py +++ b/scripts/ovl.py @@ -686,7 +686,7 @@ def ParseMethodSubCommands(cls): @ParseMethodSubCommands -class OverlordCLIClient: +class OverlordCliClient: """Overlord command line interface client.""" SUBCOMMANDS = [] @@ -1182,50 +1182,63 @@ def Shell(self, command=None): else: raise - @Command('push', 'push a file or directory to remote', [ - Arg('srcs', nargs='+', metavar='SOURCE'), - Arg('dst', metavar='DESTINATION')]) - def Push(self, args): - self.CheckClient() + def _RemoteDirExists(self, path): + return ast.literal_eval(self.CheckOutput( + 'stat %s >/dev/null 2>&1 && echo True || echo False' % path)) - @AutoRetry('push', _RETRY_TIMES) - def _push(src, dst): - src_base = os.path.basename(src) + def _RemoteGetPathType(self, path): + return self.CheckOutput('stat \'%s\' --printf \'%%F\' ' + '2>/dev/null' % path).strip() - # Local file is a link - if os.path.islink(src): - pbar = ProgressBar(src_base) - link_path = os.readlink(src) - self.CheckOutput('mkdir -p %(dirname)s; ' - 'if [ -d "%(dst)s" ]; then ' - 'ln -sf "%(link_path)s" "%(dst)s/%(link_name)s"; ' - 'else ln -sf "%(link_path)s" "%(dst)s"; fi' % - dict(dirname=os.path.dirname(dst), - link_path=link_path, dst=dst, - link_name=src_base)) - pbar.End() - return - - mode = '0%o' % (0x1FF & os.stat(src).st_mode) - url = ('%s:%d/api/agent/upload/%s?dest=%s&perm=%s' % - (self._state.host, self._state.port, - urllib.parse.quote(self._selected_mid), dst, mode)) - try: - UrlOpen(self._state, url + '&filename=%s' % src_base) - except urllib.error.HTTPError as e: - msg = json.loads(e.read()).get('error', None) - raise RuntimeError('push: %s' % msg) from None + @AutoRetry('push', _RETRY_TIMES) + def _PushSingleFile(self, src, dst): + src_base = os.path.basename(src) + # Local file is a link + if os.path.islink(src): pbar = ProgressBar(src_base) - self._HTTPPostFile(url, src, pbar.SetProgress, - self._state.username, self._state.password) + link_path = os.readlink(src) + self.CheckOutput('mkdir -p %(dirname)s; ' + 'if [ -d "%(dst)s" ]; then ' + 'ln -sf "%(link_path)s" "%(dst)s/%(link_name)s"; ' + 'else ln -sf "%(link_path)s" "%(dst)s"; fi' % + dict(dirname=os.path.dirname(dst), + link_path=link_path, dst=dst, + link_name=src_base)) pbar.End() + return + + mode = '0%o' % (0x1FF & os.stat(src).st_mode) + url = ('%s:%d/api/agent/upload/%s?dest=%s&perm=%s' % + (self._state.host, self._state.port, + urllib.parse.quote(self._selected_mid), dst, mode)) + try: + UrlOpen(self._state, url + '&filename=%s' % src_base) + except urllib.error.HTTPError as e: + msg = json.loads(e.read()).get('error', None) + raise RuntimeError('push: %s' % msg) from None + + pbar = ProgressBar(src_base) + self._HTTPPostFile(url, src, pbar.SetProgress, + self._state.username, self._state.password) + pbar.End() + + @Command('push', 'push a file or directory to remote', [ + Arg('srcs', nargs='+', metavar='SOURCE'), + Arg('dst', metavar='DESTINATION')]) + def Push(self, args): + self.CheckClient() def _push_single_target(src, dst): if os.path.isdir(src): - dst_exists = ast.literal_eval(self.CheckOutput( - 'stat %s >/dev/null 2>&1 && echo True || echo False' % dst)) - for root, unused_x, files in os.walk(src): + src = os.path.abspath(src) + base_dir_name = os.path.basename(src) + dst_exists = self._RemoteDirExists(dst) + + if dst_exists and self._RemoteGetPathType(dst) != 'directory': + raise RuntimeError('push: %s: Not a directory' % dst) + + for subpath, unused_x, files in os.walk(src): # If destination directory does not exist, we should strip the first # layer of directory. For example: src_dir contains a single file 'A' # @@ -1236,16 +1249,16 @@ def _push_single_target(src, dst): # If dest_dir does not exist, the resulting directory structure should # be: # dest_dir/A - dst_root = root if dst_exists else root[len(src):].lstrip('/') + dst_root = base_dir_name if dst_exists else '' + relpath = os.path.relpath(subpath, src) for name in files: - _push(os.path.join(root, name), - os.path.join(dst, dst_root, name)) + self._PushSingleFile(os.path.join(subpath, name), + os.path.join(dst, dst_root, relpath, name)) else: - _push(src, dst) + self._PushSingleFile(src, dst) if len(args.srcs) > 1: - dst_type = self.CheckOutput('stat \'%s\' --printf \'%%F\' ' - '2>/dev/null' % args.dst).strip() + dst_type = self._RemoteGetPathType(args.dst) if not dst_type: raise RuntimeError('push: %s: No such file or directory' % args.dst) if dst_type != 'directory': @@ -1446,7 +1459,7 @@ def main(): handler.setFormatter(formatter) logger.addHandler(handler) - ovl = OverlordCLIClient() + ovl = OverlordCliClient() try: ovl.Main() except KeyboardInterrupt: diff --git a/scripts/ovl_unittest.py b/scripts/ovl_unittest.py new file mode 100755 index 0000000..a8a0571 --- /dev/null +++ b/scripts/ovl_unittest.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 + +import argparse +import os +import unittest + +from ovl import OverlordCliClient + + +class PushUnittest(unittest.TestCase): + """Test cases for push command.""" + def setUp(self): + self.cli = OverlordCliClient() + self.results = [] + self.git_root = os.path.normpath(os.path.join( + os.path.dirname(os.path.abspath(__file__)), '..')) + + self.cli.CheckClient = lambda: None + self.cli._PushSingleFile = self.PushSingleFile + + def PushSingleFile(self, src, dst): + """Mock function for _PushSingleFile.""" + self.results.append((src, dst)) + + def test_push_src_abs_dir_remote_exists_dir(self): + """Test push src dir to remote dir when remote dir exists.""" + + dst = '/home/aitjcize/some_dir' + self.cli._RemoteDirExists = lambda path: True + self.cli._RemoteGetPathType = lambda path: 'directory' + args = argparse.Namespace(srcs=[os.path.join(self.git_root, 'cmd')], dst=dst) + self.cli.Push(args) + + self.assertEqual(sorted(self.results), sorted([ + (os.path.join(self.git_root, 'cmd/ghost/main.go'), + os.path.join(dst, 'cmd/ghost/main.go')), + (os.path.join(self.git_root, 'cmd/overlordd/main.go'), + os.path.join(dst, 'cmd/overlordd/main.go')), + ])) + + def test_push_src_abs_dir_remote_exists_but_not_dir(self): + """Test push src dir to remote dir when remote path exists but not a + directory.""" + + dst = '/home/aitjcize/some_dir' + self.cli._RemoteDirExists = lambda path: True + self.cli._RemoteGetPathType = lambda path: 'file' + args = argparse.Namespace(srcs=[os.path.join(self.git_root, 'cmd')], dst=dst) + + self.assertRaises(RuntimeError, self.cli.Push, args) + + def test_push_src_abs_dir_remote_does_not_exist(self): + """Test push src dir to remote dir when remote dir does not exist.""" + + dst = '/home/aitjcize/some_dir' + self.cli._RemoteDirExists = lambda path: False + self.cli._RemoteGetPathType = lambda path: 'directory' + args = argparse.Namespace(srcs=[os.path.join(self.git_root, 'cmd')], dst=dst) + self.cli.Push(args) + + self.assertEqual(sorted(self.results), sorted([ + (os.path.join(self.git_root, 'cmd/ghost/main.go'), + os.path.join(dst, 'ghost/main.go')), + (os.path.join(self.git_root, 'cmd/overlordd/main.go'), + os.path.join(dst, 'overlordd/main.go')), + ])) + + def test_push_rel_dir_remote_rel_dir(self): + """Test push relative src dir to relative remote dir.""" + + os.chdir(self.git_root) + dst = 'some_dir' + self.cli._RemoteDirExists = lambda path: True + self.cli._RemoteGetPathType = lambda path: 'directory' + args = argparse.Namespace(srcs=['cmd'], dst=dst) + self.cli.Push(args) + + self.assertEqual(sorted(self.results), sorted([ + (os.path.join(self.git_root, 'cmd/ghost/main.go'), + os.path.join(dst, 'cmd/ghost/main.go')), + (os.path.join(self.git_root, 'cmd/overlordd/main.go'), + os.path.join(dst, 'cmd/overlordd/main.go')), + ])) + + def test_push_rel_dir_remote_rel_does_not_exist(self): + """Test push relative src dir to relative remote dir when remote dir does + not exist.""" + + os.chdir(self.git_root) + dst = 'some_dir' + self.cli._RemoteDirExists = lambda path: False + self.cli._RemoteGetPathType = lambda path: 'directory' + args = argparse.Namespace(srcs=['cmd'], dst=dst) + self.cli.Push(args) + + self.assertEqual(sorted(self.results), sorted([ + (os.path.join(self.git_root, 'cmd/ghost/main.go'), + os.path.join(dst, 'ghost/main.go')), + (os.path.join(self.git_root, 'cmd/overlordd/main.go'), + os.path.join(dst, 'overlordd/main.go')), + ])) + +if __name__ == '__main__': + unittest.main()