Skip to content
This repository has been archived by the owner on Jul 11, 2024. It is now read-only.

Commit

Permalink
Merge pull request #30 from deadc0de6/fuse
Browse files Browse the repository at this point in the history
Fuse
  • Loading branch information
deadc0de6 authored Mar 12, 2023
2 parents 7590ad0 + ee2cf80 commit 511a32e
Show file tree
Hide file tree
Showing 26 changed files with 1,243 additions and 390 deletions.
7 changes: 7 additions & 0 deletions .github/workflows/testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ jobs:
python -m pip install --upgrade pip
pip install -r tests-requirements.txt
pip install -r requirements.txt
sudo apt-get -y install shellcheck jq
- name: Run tests
run: |
./tests.sh
- name: Coveralls
run: |
pip install coveralls
coveralls --service=github
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
*.pyc
.coverage
.coverage*
dist/
build/
*.egg-info/
*.catalog
.vscode/
.mypy_cache
.pytest_cache
__pycache__
27 changes: 25 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![Build Status](https://travis-ci.org/deadc0de6/catcli.svg?branch=master)](https://travis-ci.org/deadc0de6/catcli)
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0)
[![Coverage Status](https://coveralls.io/repos/github/deadc0de6/catcli/badge.svg?branch=master)](https://coveralls.io/github/deadc0de6/catcli?branch=master)
[![Coveralls](https://img.shields.io/coveralls/github/deadc0de6/catcli)](https://coveralls.io/github/deadc0de6/catcli?branch=master)

[![PyPI version](https://badge.fury.io/py/catcli.svg)](https://badge.fury.io/py/catcli)
[![AUR](https://img.shields.io/aur/version/catcli-git.svg)](https://aur.archlinux.org/packages/catcli-git)
Expand All @@ -24,6 +24,7 @@ Features:
* Index any directories in a catalog
* Ability to search for files by name in the catalog
* Ability to navigate through indexed data à la `ls`
* Support for fuse to mount the indexed data as a virtual filesystem
* Handle archive files (zip, tar, ...) and index their content
* Save catalog to json for easy versioning with git
* Command line interface FTW
Expand Down Expand Up @@ -73,6 +74,7 @@ See the [examples](#examples) for an overview of the available features.
* [Index archive files](#index-archive-files)
* [Walk indexed files with ls](#walk-indexed-files-with-ls)
* [Find files](#find-files)
* [Mount catalog](#mount-catalog)
* [Display entire hierarchy](#display-entire-hierarchy)
* [Catalog graph](#catalog-graph)
* [Edit storage](#edit-storage)
Expand Down Expand Up @@ -185,6 +187,27 @@ searching:

See the [examples](#examples) for more.

## Mount catalog

The catalog can be mounted with [fuse](https://www.kernel.org/doc/html/next/filesystems/fuse.html)
and navigate like any filesystem.

```bash
$ mkdir /tmp/mnt
$ catcli index -c github .github
$ catcli mount /tmp/mnt
$ ls -laR /tmp/mnt
drwxrwxrwx - user 8 Mar 22:08 github

mnt/github:
.rwxrwxrwx 17 user 19 Oct 2022 FUNDING.yml
drwxrwxrwx - user 2 Mar 10:15 workflows

mnt/github/workflows:
.rwxrwxrwx 691 user 19 Oct 2022 pypi-release.yml
.rwxrwxrwx 635 user 8 Mar 21:08 testing.yml
```

## Display entire hierarchy

The entire catalog can be shown using the `ls -r` command.
Expand Down Expand Up @@ -232,7 +255,7 @@ Each line contains the following fields:
* **indexed_at**: when this entry was indexed
* **maccess**: the entry modification date/time
* **md5**: the entry checksum (if any)
* **nbfiles**: the number of children (empty for not storage or directory nodes)
* **nbfiles**: the number of children (empty for nodes that are not storage or directory)
* **free_space**: free space (empty for not storage nodes)
* **total_space**: total space (empty for not storage nodes)
* **meta**: meta information (empty for not storage nodes)
Expand Down
2 changes: 1 addition & 1 deletion catcli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import sys


def main():
def main() -> None:
"""entry point"""
import catcli.catcli
if catcli.catcli.main():
Expand Down
62 changes: 27 additions & 35 deletions catcli/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,23 @@
"""

import os
import pickle
from anytree.exporter import JsonExporter
from anytree.importer import JsonImporter
from typing import Optional
from anytree.exporter import JsonExporter # type: ignore
from anytree.importer import JsonImporter # type: ignore

# local imports
from catcli import nodes
from catcli.nodes import NodeMeta, NodeTop
from catcli.utils import ask
from catcli.logger import Logger


class Catalog:
"""the catalog"""

def __init__(self, path, usepickle=False, debug=False, force=False):
def __init__(self, path: str,
debug: bool = False,
force: bool = False) -> None:
"""
@path: catalog path
@usepickle: use pickle
Expand All @@ -28,35 +32,33 @@ def __init__(self, path, usepickle=False, debug=False, force=False):
self.path = path
self.debug = debug
self.force = force
self.metanode = None
self.pickle = usepickle
self.metanode: Optional[NodeMeta] = None

def set_metanode(self, metanode):
def set_metanode(self, metanode: NodeMeta) -> None:
"""remove the metanode until tree is re-written"""
self.metanode = metanode
self.metanode.parent = None
if self.metanode:
self.metanode.parent = None

def exists(self):
def exists(self) -> bool:
"""does catalog exist"""
if not self.path:
return False
if os.path.exists(self.path):
return True
return False

def restore(self):
def restore(self) -> Optional[NodeTop]:
"""restore the catalog"""
if not self.path:
return None
if not os.path.exists(self.path):
return None
if self.pickle:
return self._restore_pickle()
with open(self.path, 'r', encoding='UTF-8') as file:
content = file.read()
return self._restore_json(content)

def save(self, node):
def save(self, node: NodeTop) -> bool:
"""save the catalog"""
if not self.path:
Logger.err('Path not defined')
Expand All @@ -73,41 +75,31 @@ def save(self, node):
return False
if self.metanode:
self.metanode.parent = node
if self.pickle:
return self._save_pickle(node)
return self._save_json(node)

def _debug(self, text):
def _debug(self, text: str) -> None:
if not self.debug:
return
Logger.debug(text)

def _save_pickle(self, node):
"""pickle the catalog"""
with open(self.path, 'wb') as file:
pickle.dump(node, file)
self._debug(f'Catalog saved to pickle \"{self.path}\"')
return True

def _restore_pickle(self):
"""restore the pickled tree"""
with open(self.path, 'rb') as file:
root = pickle.load(file)
msg = f'Catalog imported from pickle \"{self.path}\"'
self._debug(msg)
return root

def _save_json(self, node):
def _save_json(self, top: NodeTop) -> bool:
"""export the catalog in json"""
self._debug(f'saving {top} to json...')
exp = JsonExporter(indent=2, sort_keys=True)
with open(self.path, 'w', encoding='UTF-8') as file:
exp.write(node, file)
exp.write(top, file)
self._debug(f'Catalog saved to json \"{self.path}\"')
return True

def _restore_json(self, string):
def _restore_json(self, string: str) -> Optional[NodeTop]:
"""restore the tree from json"""
imp = JsonImporter()
self._debug(f'import from string: {string}')
root = imp.import_(string)
self._debug(f'Catalog imported from json \"{self.path}\"')
return root
self._debug(f'root imported: {root}')
if root.type != nodes.TYPE_TOP:
return None
top = NodeTop(root.name, children=root.children)
self._debug(f'top imported: {top}')
return top
Loading

0 comments on commit 511a32e

Please sign in to comment.