def ls(self, path: Text, max_depth: int = 1) -> List[jobs_pb2.StatEntry]: """Lists contents of a given VFS directory. Args: path: A path to the directory to list the contents of. max_depth: Max depth of subdirectories to explore. If max_depth is >1, then the results will also include the contents of subdirectories (and sub-subdirectories and so on). Returns: A sequence of stat entries. """ if max_depth < 1: return representer.StatEntryList([]) try: f = self._get_file(path).Get() except api_errors.AccessForbiddenError as e: raise errors.ApprovalMissingError(self._client.client_id, e) if not f.is_directory: raise errors.NotDirectoryError(self._client.client_id, path) try: stat_entries = [_.data.stat for _ in f.ListFiles()] except api_errors.AccessForbiddenError as e: raise errors.ApprovalMissingError(self._client.client_id, e) inner_entries = [] for entry in stat_entries: try: inner_entries += self.ls(entry.pathspec.path, max_depth - 1) except errors.NotDirectoryError: inner_entries += [] return representer.StatEntryList(stat_entries + inner_entries)
def testCommonExplicitRoot(self): entry1 = jobs_pb2.StatEntry() entry1.pathspec.path = '/foo/bar' entry1.st_size = 42 entry1.st_mode = 16877 entry2 = jobs_pb2.StatEntry() entry2.pathspec.path = '/foo/bar/baz' entry2.st_size = 42 entry2.st_mode = 33188 entry3 = jobs_pb2.StatEntry() entry3.pathspec.path = '/foo/bar/quux' entry3.st_size = 42 entry3.st_mode = 33188 sts = representer.StatEntryList([entry1, entry2, entry3]) out = io.StringIO() sts._repr_pretty_(pretty.PrettyPrinter(out), cycle=False) expected = """ /foo 📂 bar (drwxr-xr-x /foo/bar, {size}) 📄 baz (-rw-r--r-- /foo/bar/baz, {size}) 📄 quux (-rw-r--r-- /foo/bar/quux, {size}) """ expected = expected.format(size=humanize.naturalsize(42)) self.assertEqual(out.getvalue(), expected)
def ls(self, path, max_depth = 1): """Lists contents of a given directory. Args: path: A path to the directory to list the contents of. max_depth: Max depth of subdirectories to explore. If max_depth is >1, then the results will also include the contents of subdirectories (and sub-subdirectories and so on). Returns: A sequence of stat entries. """ if max_depth > 1: args = flows_pb2.RecursiveListDirectoryArgs() args.pathspec.path = path args.pathspec.pathtype = self._path_type args.max_depth = max_depth try: ls = self._client.CreateFlow(name='RecursiveListDirectory', args=args) except api_errors.AccessForbiddenError as e: raise errors.ApprovalMissingError(self.id, e) else: args = flows_pb2.ListDirectoryArgs() args.pathspec.path = path args.pathspec.pathtype = self._path_type try: ls = self._client.CreateFlow(name='ListDirectory', args=args) except api_errors.AccessForbiddenError as e: raise errors.ApprovalMissingError(self.id, e) _timeout.await_flow(ls) return representer.StatEntryList([_.payload for _ in ls.ListResults()])
def testDifferentRoots(self): entry1 = jobs_pb2.StatEntry() entry1.pathspec.path = '/foo1/bar' entry1.st_size = 42 entry1.st_mode = 33188 entry2 = jobs_pb2.StatEntry() entry2.pathspec.path = '/foo2/baz' entry2.st_size = 43 entry2.st_mode = 16877 sts = representer.StatEntryList([entry1, entry2]) out = io.StringIO() sts._repr_pretty_(pretty.PrettyPrinter(out), cycle=False) expected = """ /foo1 📄 bar (-rw-r--r-- /foo1/bar, {}) /foo2 📂 baz (drwxr-xr-x /foo2/baz, {}) """ expected = expected.format(humanize.naturalsize(42), humanize.naturalsize(43)) self.assertEqual(out.getvalue(), expected)
def testSlice(self): entry1 = jobs_pb2.StatEntry() entry2 = jobs_pb2.StatEntry() sts = representer.StatEntryList([entry1, entry2]) sts = sts[:1] self.assertLen(sts, 1) self.assertIsInstance(sts, representer.StatEntryList)
def testSingleFile(self): entry = jobs_pb2.StatEntry() entry.pathspec.path = '/foo/bar' entry.st_size = 42 entry.st_mode = 33188 sts = representer.StatEntryList([entry]) out = io.StringIO() sts._repr_pretty_(pretty.PrettyPrinter(out), cycle=False) expected = """ /foo 📄 bar (-rw-r--r-- /foo/bar, {}) """ expected = expected.format(humanize.naturalsize(42)) self.assertEqual(out.getvalue(), expected)
def glob(self, path): """Globs for files on the given client. Args: path: A glob expression (that may include `*` and `**`). Returns: A sequence of stat entries to the found files. """ args = flows_pb2.GlobArgs() args.paths.append(path) args.pathtype = self._path_type try: glob = self._client.CreateFlow(name='Glob', args=args) except api_errors.AccessForbiddenError as e: raise errors.ApprovalMissingError(self.id, e) _timeout.await_flow(glob) return representer.StatEntryList([_.payload for _ in glob.ListResults()])
def testCycle(self): sts = representer.StatEntryList([]) out = io.StringIO() with self.assertRaises(AssertionError): sts._repr_pretty_(pretty.PrettyPrinter(out), cycle=True)
def testEmptyResults(self): sts = representer.StatEntryList([]) out = io.StringIO() sts._repr_pretty_(pretty.PrettyPrinter(out), cycle=False) self.assertEqual(out.getvalue(), 'No results.')