papers-cli 2.13__tar.gz → 2.14__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- papers_cli-2.14/.github/FUNDING.yml +2 -0
- {papers_cli-2.13 → papers_cli-2.14}/PKG-INFO +11 -9
- {papers_cli-2.13 → papers_cli-2.14}/README.md +10 -8
- {papers_cli-2.13 → papers_cli-2.14}/papers/__main__.py +54 -17
- {papers_cli-2.13 → papers_cli-2.14}/papers/_version.py +9 -4
- {papers_cli-2.13 → papers_cli-2.14}/papers/bib.py +71 -8
- {papers_cli-2.13 → papers_cli-2.14}/papers/config.py +1 -1
- {papers_cli-2.13 → papers_cli-2.14}/papers/encoding.py +0 -1
- {papers_cli-2.13 → papers_cli-2.14}/papers_cli.egg-info/PKG-INFO +11 -9
- {papers_cli-2.13 → papers_cli-2.14}/papers_cli.egg-info/SOURCES.txt +1 -0
- {papers_cli-2.13 → papers_cli-2.14}/.gitattributes +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/.github/workflows/pypi.yml +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/.github/workflows/tests.yml +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/.gitignore +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/LICENSE +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/papers/__init__.py +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/papers/duplicate.py +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/papers/extract.py +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/papers/filename.py +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/papers/latexenc.py +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/papers/utils.py +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/papers_cli.egg-info/dependency_links.txt +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/papers_cli.egg-info/entry_points.txt +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/papers_cli.egg-info/requires.txt +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/papers_cli.egg-info/top_level.txt +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/pyproject.toml +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/requirements.txt +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/setup.cfg +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/setup.py +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/tests/__init__.py +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/tests/common.py +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/tests/config.py +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/tests/download.py +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/tests/downloadedpapers/.gitignore +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/tests/downloadedpapers/bg-8-515-2011.txt +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/tests/test_add.py +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/tests/test_biblio.py +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/tests/test_duplicates.py +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/tests/test_encoding.py +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/tests/test_extract.py +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/tests/test_filecheck.py +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/tests/test_install.py +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/tests/test_list.py +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/tests/test_misc.py +0 -0
- {papers_cli-2.13 → papers_cli-2.14}/tests/test_undo.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: papers-cli
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.14
|
|
4
4
|
Summary: utilities to keep your PDF library organized
|
|
5
5
|
Author-email: Mahé Perrette <mahe.perrette@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -17,7 +17,7 @@ Requires-Dist: scholarly
|
|
|
17
17
|
Requires-Dist: rapidfuzz
|
|
18
18
|
Requires-Dist: normality
|
|
19
19
|
|
|
20
|
-
[](https://github.com/perrette/papers/actions)
|
|
21
21
|
[]()
|
|
22
22
|
[]()
|
|
23
23
|
[]()
|
|
@@ -306,6 +306,14 @@ That command is also convenient to check on what's actually tracked and what is
|
|
|
306
306
|
# ...
|
|
307
307
|
papers filecheck --rename --filesdir files
|
|
308
308
|
|
|
309
|
+
There is also a command specifically designed to clean up the zombie files and folders:
|
|
310
|
+
|
|
311
|
+
papers filecheck --clean-filesdir
|
|
312
|
+
|
|
313
|
+
That command will ask before removig anything, unless `--force` is passed. Currently
|
|
314
|
+
it ignores hidden files and folders, and will only consider folder that have a `.{folder}.bib` file inside,
|
|
315
|
+
which is the convention `papers` follows to store multiple attachments. That command works best
|
|
316
|
+
when the files are in their own folder, and not mixed up with other things, obviously.
|
|
309
317
|
|
|
310
318
|
### Setup git-tracked library (optional)
|
|
311
319
|
|
|
@@ -321,14 +329,8 @@ If `--git-lfs` is passed, the files will be backed-up along with the bibtex.
|
|
|
321
329
|
Under the hood, bibtex and files (if applicable) are copied (hard-linked) to a back-up directory.
|
|
322
330
|
Details are described in [issue 51](https://github.com/perrette/papers/issues/51).
|
|
323
331
|
|
|
324
|
-
|
|
325
|
-
Type `papers status -v` to find out.
|
|
326
|
-
|
|
332
|
+
Backup occurs in a subfolder of `~/.local/.share/papers` regardless of the type of installation. Type `papers status -v` to find out.
|
|
327
333
|
For local install that are already git-tracked, the feature remains useful as it is the basis for `papers undo` and `papers redo`.
|
|
328
|
-
You might want to add `.papers` to your .gitignore to avoid messing up with your larger project.
|
|
329
|
-
|
|
330
|
-
This feature is experimental.
|
|
331
|
-
|
|
332
334
|
|
|
333
335
|
### undo / redo
|
|
334
336
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[](https://github.com/perrette/papers/actions)
|
|
2
2
|
[]()
|
|
3
3
|
[]()
|
|
4
4
|
[]()
|
|
@@ -287,6 +287,14 @@ That command is also convenient to check on what's actually tracked and what is
|
|
|
287
287
|
# ...
|
|
288
288
|
papers filecheck --rename --filesdir files
|
|
289
289
|
|
|
290
|
+
There is also a command specifically designed to clean up the zombie files and folders:
|
|
291
|
+
|
|
292
|
+
papers filecheck --clean-filesdir
|
|
293
|
+
|
|
294
|
+
That command will ask before removig anything, unless `--force` is passed. Currently
|
|
295
|
+
it ignores hidden files and folders, and will only consider folder that have a `.{folder}.bib` file inside,
|
|
296
|
+
which is the convention `papers` follows to store multiple attachments. That command works best
|
|
297
|
+
when the files are in their own folder, and not mixed up with other things, obviously.
|
|
290
298
|
|
|
291
299
|
### Setup git-tracked library (optional)
|
|
292
300
|
|
|
@@ -302,14 +310,8 @@ If `--git-lfs` is passed, the files will be backed-up along with the bibtex.
|
|
|
302
310
|
Under the hood, bibtex and files (if applicable) are copied (hard-linked) to a back-up directory.
|
|
303
311
|
Details are described in [issue 51](https://github.com/perrette/papers/issues/51).
|
|
304
312
|
|
|
305
|
-
|
|
306
|
-
Type `papers status -v` to find out.
|
|
307
|
-
|
|
313
|
+
Backup occurs in a subfolder of `~/.local/.share/papers` regardless of the type of installation. Type `papers status -v` to find out.
|
|
308
314
|
For local install that are already git-tracked, the feature remains useful as it is the basis for `papers undo` and `papers redo`.
|
|
309
|
-
You might want to add `.papers` to your .gitignore to avoid messing up with your larger project.
|
|
310
|
-
|
|
311
|
-
This feature is experimental.
|
|
312
|
-
|
|
313
315
|
|
|
314
316
|
### undo / redo
|
|
315
317
|
|
|
@@ -9,8 +9,6 @@ import subprocess as sp
|
|
|
9
9
|
import shutil
|
|
10
10
|
import itertools
|
|
11
11
|
import fnmatch # unix-like match
|
|
12
|
-
import hashlib
|
|
13
|
-
import time
|
|
14
12
|
|
|
15
13
|
import papers
|
|
16
14
|
from papers import logger
|
|
@@ -19,7 +17,8 @@ from papers.extract import fetch_bibtex_by_doi, fetch_bibtex_by_fulltext_crossre
|
|
|
19
17
|
from papers.encoding import parse_file, format_file, family_names, format_entries, standard_name, format_entry, parse_keywords, format_key
|
|
20
18
|
from papers.config import bcolors, Config, search_config, CONFIG_FILE, CONFIG_FILE_LOCAL, DATA_DIR, CONFIG_FILE_LEGACY, BACKUP_DIR
|
|
21
19
|
from papers.duplicate import list_duplicates, list_uniques, edit_entries
|
|
22
|
-
from papers.bib import Biblio, FUZZY_RATIO, DEFAULT_SIMILARITY, entry_filecheck,
|
|
20
|
+
from papers.bib import (Biblio, FUZZY_RATIO, DEFAULT_SIMILARITY, entry_filecheck,
|
|
21
|
+
backupfile as backupfile_func, isvalidkey, DuplicateKeyError, clean_filesdir)
|
|
23
22
|
from papers.utils import move, checksum, view_pdf, open_folder
|
|
24
23
|
from papers import __version__
|
|
25
24
|
|
|
@@ -89,6 +88,9 @@ def _backup_bib(biblio, config, message=None):
|
|
|
89
88
|
biblio.rename_entries_files(copy=True, relative_to=backupdir, hardlink=True)
|
|
90
89
|
biblio.save(config.backupfile_clean)
|
|
91
90
|
config.gitcmd(f"add {config.backupfile_clean.name}")
|
|
91
|
+
|
|
92
|
+
# Remove unlink files
|
|
93
|
+
clean_filesdir(biblio, interactive=False, ignore_files=[config.backupfile, config.backupfile_clean])
|
|
92
94
|
config.gitcmd(f"add files")
|
|
93
95
|
|
|
94
96
|
else:
|
|
@@ -288,19 +290,41 @@ def installcmd(parser, o, config):
|
|
|
288
290
|
"""
|
|
289
291
|
prompt = o.prompt and not o.edit
|
|
290
292
|
# installed = config.file is not None
|
|
293
|
+
# WARNING if pre-existing config file
|
|
291
294
|
if config.file is not None and prompt:
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
295
|
+
if ((o.local and config.local) or ((not o.local and not config.local))):
|
|
296
|
+
while True:
|
|
297
|
+
ans = input(f'An existing {"local" if config.local else "global"} install was found: {config.file}. Overwrite (O) or Edit (E) ? [o / e]')
|
|
298
|
+
if ans.lower() in ('o', 'e'):
|
|
299
|
+
break
|
|
300
|
+
else:
|
|
301
|
+
print('Use the --edit option to selectively edit existing configuration, or --force to ignore pre-existing configuration.')
|
|
302
|
+
o.edit = ans.lower() == 'e'
|
|
303
|
+
|
|
304
|
+
elif not o.local and config.local:
|
|
305
|
+
print(f"A local configuration file was found that will have precedence over the global install: {config.file}. Delete (D) or Ignore (any other key) ?")
|
|
306
|
+
ans = input()
|
|
307
|
+
if ans.lower() == "d":
|
|
308
|
+
logger.info(f"Removing pre-existing local configuration file {config.file}")
|
|
309
|
+
os.remove(config.file)
|
|
310
|
+
config = Config()
|
|
311
|
+
|
|
312
|
+
elif o.local and not config.local:
|
|
313
|
+
logger.warning(f"A global configuration file was found, but the local install will have precedence: {config.file}. Delete the global configuration file (D) or Ignore (any other key) ?")
|
|
314
|
+
ans = input()
|
|
315
|
+
if ans.lower() == "d":
|
|
316
|
+
logger.info(f"Removing pre-existing global configuration file {config.file}")
|
|
317
|
+
os.remove(config.file)
|
|
318
|
+
config = Config()
|
|
319
|
+
|
|
320
|
+
else:
|
|
321
|
+
raise PapersExit("Unexpected configuration state")
|
|
322
|
+
|
|
299
323
|
|
|
300
324
|
if not o.edit:
|
|
301
|
-
if config.
|
|
325
|
+
if config.file and os.path.exists(config.file) and ((o.local and config.local) or ((not o.local and not config.local))):
|
|
302
326
|
# if we don't do that the local install will take precedence over global install
|
|
303
|
-
logger.warning(f"remove pre-existing
|
|
327
|
+
logger.warning(f"remove pre-existing configuration file: {config.file}")
|
|
304
328
|
os.remove(config.file)
|
|
305
329
|
config = Config()
|
|
306
330
|
|
|
@@ -673,6 +697,10 @@ def filecheckcmd(parser, o, config):
|
|
|
673
697
|
if o.rename:
|
|
674
698
|
biblio.rename_entries_files(o.copy)
|
|
675
699
|
|
|
700
|
+
if o.clean_filesdir:
|
|
701
|
+
print("Check files directory for unlinked files")
|
|
702
|
+
clean_filesdir(biblio, interactive=not o.force, ignore_files=[config.bibtex])
|
|
703
|
+
|
|
676
704
|
savebib(biblio, config)
|
|
677
705
|
|
|
678
706
|
def redocmd(parser, o, config):
|
|
@@ -1116,6 +1144,9 @@ def get_parser(config=None):
|
|
|
1116
1144
|
filecheckp.add_argument('-d', '--delete-broken', action='store_true',
|
|
1117
1145
|
help='remove file entry if the file link is broken')
|
|
1118
1146
|
|
|
1147
|
+
filecheckp.add_argument('--clean-filesdir', action='store_true',
|
|
1148
|
+
help='remove files in filesdir if not referred to in any entry')
|
|
1149
|
+
|
|
1119
1150
|
filecheckp.add_argument('--fix-mendeley', action='store_true',
|
|
1120
1151
|
help='fix a Mendeley bug where the leading "/" is omitted.')
|
|
1121
1152
|
|
|
@@ -1187,13 +1218,13 @@ def get_parser(config=None):
|
|
|
1187
1218
|
|
|
1188
1219
|
# doi
|
|
1189
1220
|
# ===
|
|
1190
|
-
doip = subparsers.add_parser('doi', description='parse DOI from PDF')
|
|
1221
|
+
doip = subparsers.add_parser('doi', description='parse DOI from PDF', parents=[loggingp])
|
|
1191
1222
|
doip.add_argument('pdf')
|
|
1192
1223
|
doip.add_argument('--image', action='store_true', help='convert to image and use tesseract instead of pdftotext')
|
|
1193
1224
|
|
|
1194
1225
|
# fetch
|
|
1195
1226
|
# =====
|
|
1196
|
-
fetchp = subparsers.add_parser('fetch', description='fetch bibtex from DOI or full-text')
|
|
1227
|
+
fetchp = subparsers.add_parser('fetch', description='fetch bibtex from DOI or full-text', parents=[loggingp])
|
|
1197
1228
|
fetchp.add_argument('doi_or_text', nargs='+', help='DOI or full text.')
|
|
1198
1229
|
fetchp.add_argument('--scholar', action='store_true', help='use google scholar instead of default crossref for fulltext search')
|
|
1199
1230
|
|
|
@@ -1232,6 +1263,13 @@ def get_parser(config=None):
|
|
|
1232
1263
|
# Main script
|
|
1233
1264
|
#############
|
|
1234
1265
|
|
|
1266
|
+
def handle_logging(o):
|
|
1267
|
+
# verbosity
|
|
1268
|
+
if getattr(o,'logging_level',None):
|
|
1269
|
+
logger.setLevel(o.logging_level)
|
|
1270
|
+
logger.debug("LOGGER LEVEL: "+logging.getLevelName(logger.getEffectiveLevel()))
|
|
1271
|
+
|
|
1272
|
+
|
|
1235
1273
|
def main(args=None):
|
|
1236
1274
|
papers.config.DRYRUN = False # reset in case main() if called directly
|
|
1237
1275
|
if args is not None:
|
|
@@ -1255,9 +1293,8 @@ def main(args=None):
|
|
|
1255
1293
|
print(__version__)
|
|
1256
1294
|
return
|
|
1257
1295
|
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
logger.setLevel(o.logging_level)
|
|
1296
|
+
handle_logging(o)
|
|
1297
|
+
|
|
1261
1298
|
# modify disk state?
|
|
1262
1299
|
if hasattr(o,'dry_run'):
|
|
1263
1300
|
papers.config.DRYRUN = o.dry_run
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
# file generated by
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
2
|
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
|
|
5
|
+
|
|
3
6
|
TYPE_CHECKING = False
|
|
4
7
|
if TYPE_CHECKING:
|
|
5
|
-
from typing import Tuple
|
|
8
|
+
from typing import Tuple
|
|
9
|
+
from typing import Union
|
|
10
|
+
|
|
6
11
|
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
7
12
|
else:
|
|
8
13
|
VERSION_TUPLE = object
|
|
@@ -12,5 +17,5 @@ __version__: str
|
|
|
12
17
|
__version_tuple__: VERSION_TUPLE
|
|
13
18
|
version_tuple: VERSION_TUPLE
|
|
14
19
|
|
|
15
|
-
__version__ = version = '2.
|
|
16
|
-
__version_tuple__ = version_tuple = (2,
|
|
20
|
+
__version__ = version = '2.14'
|
|
21
|
+
__version_tuple__ = version_tuple = (2, 14)
|
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
import logging
|
|
4
|
-
# logger.basicConfig(level=logger.INFO)
|
|
5
|
-
import argparse
|
|
6
|
-
import subprocess as sp
|
|
7
3
|
import shutil
|
|
8
4
|
import bisect
|
|
9
|
-
import
|
|
10
|
-
import fnmatch # unix-like match
|
|
5
|
+
from unidecode import unidecode as unicode_to_ascii
|
|
11
6
|
import bibtexparser
|
|
12
7
|
from bibtexparser.customization import convert_to_unicode
|
|
13
8
|
|
|
@@ -18,8 +13,8 @@ from papers.extract import extract_pdf_doi, isvaliddoi, parse_doi
|
|
|
18
13
|
from papers.extract import extract_pdf_metadata
|
|
19
14
|
from papers.extract import fetch_bibtex_by_fulltext_crossref, fetch_bibtex_by_doi
|
|
20
15
|
|
|
21
|
-
from papers.encoding import unicode_to_latex, unicode_to_ascii
|
|
22
16
|
from papers.encoding import parse_file, format_file, standard_name, family_names, format_entries, update_file_path, format_entry
|
|
17
|
+
from papers.latexenc import unicode_to_latex, latex_to_unicode
|
|
23
18
|
|
|
24
19
|
from papers.filename import NAMEFORMAT, KEYFORMAT
|
|
25
20
|
from papers.utils import bcolors, checksum, move as _move
|
|
@@ -309,7 +304,7 @@ class Biblio:
|
|
|
309
304
|
else:
|
|
310
305
|
print(format_entry(self, entry, prefix="New entry"))
|
|
311
306
|
print(format_entry(self, self.entries[i], prefix="Conflicts with"))
|
|
312
|
-
raise DuplicateKeyError('Key conflict. Try update_key is True
|
|
307
|
+
raise DuplicateKeyError('Key conflict. Try update_key is True or specify --key KEY explicitly')
|
|
313
308
|
|
|
314
309
|
else:
|
|
315
310
|
logger.info('new entry: '+self.key(entry))
|
|
@@ -821,3 +816,71 @@ def entry_filecheck(e, delete_broken=False, fix_mendeley=False,
|
|
|
821
816
|
newfiles.append(file)
|
|
822
817
|
|
|
823
818
|
e['file'] = format_file(newfiles, relative_to=relative_to)
|
|
819
|
+
|
|
820
|
+
|
|
821
|
+
def clean_filesdir(biblio, interactive=True, ignore_files=None, ignore_folders=None):
|
|
822
|
+
if biblio.filesdir is None:
|
|
823
|
+
raise ValueError('filesdir is not defined, cannot clean')
|
|
824
|
+
removed_files = []
|
|
825
|
+
|
|
826
|
+
allfiles = set(os.path.abspath(file) for e in biblio.entries for file in biblio.get_files(e))
|
|
827
|
+
if ignore_files:
|
|
828
|
+
for f in ignore_files:
|
|
829
|
+
allfiles.add(os.path.abspath(f))
|
|
830
|
+
allfolders = set(os.path.abspath(folder) for e in biblio.entries for folder in {os.path.dirname(file) for file in biblio.get_files(e)})
|
|
831
|
+
|
|
832
|
+
if ignore_folders is None:
|
|
833
|
+
ignore_folders = []
|
|
834
|
+
|
|
835
|
+
for root, direcs, files in os.walk(biblio.filesdir):
|
|
836
|
+
|
|
837
|
+
ANS = None # Y(es) or N(o) for all files in this folder (reset at each pass)
|
|
838
|
+
if root in ignore_folders:
|
|
839
|
+
continue
|
|
840
|
+
if '.git' in root.split(os.path.sep):
|
|
841
|
+
continue
|
|
842
|
+
for file in files:
|
|
843
|
+
path = os.path.abspath(os.path.join(root, file))
|
|
844
|
+
if file.startswith('.') or file.endswith('.bib'):
|
|
845
|
+
continue
|
|
846
|
+
if path not in allfiles:
|
|
847
|
+
if interactive:
|
|
848
|
+
if ANS is None:
|
|
849
|
+
ans = input(f"File: {os.path.relpath(path, biblio.filesdir)} not in library. Remove ? [Y/n/Y/N] ")
|
|
850
|
+
else:
|
|
851
|
+
ans = ANS
|
|
852
|
+
if ans in ['Y', 'N']:
|
|
853
|
+
ans = ANS = ans.lower() # same reply for all files in this folder
|
|
854
|
+
if ans.lower() == 'y':
|
|
855
|
+
os.remove(path)
|
|
856
|
+
removed_files.append(path)
|
|
857
|
+
else:
|
|
858
|
+
logger.info(f"Remove unlinked file {os.path.relpath(path, biblio.filesdir)}.")
|
|
859
|
+
os.remove(path)
|
|
860
|
+
removed_files.append(path)
|
|
861
|
+
|
|
862
|
+
for direc in direcs:
|
|
863
|
+
if direc.startswith('.'):
|
|
864
|
+
continue
|
|
865
|
+
if direc in ignore_folders:
|
|
866
|
+
continue
|
|
867
|
+
|
|
868
|
+
# Check multifile entries
|
|
869
|
+
bibtex = os.path.join(root, direc, '.'+direc+'.bib')
|
|
870
|
+
if not os.path.exists(bibtex):
|
|
871
|
+
continue
|
|
872
|
+
|
|
873
|
+
direcpath = os.path.abspath(os.path.join(root, direc))
|
|
874
|
+
|
|
875
|
+
if direcpath not in allfolders:
|
|
876
|
+
if interactive:
|
|
877
|
+
ans = input(f"Folder: {os.path.relpath(direcpath, root)} not in library. Remove ? [Y/n] ")
|
|
878
|
+
if ans.lower() == 'y':
|
|
879
|
+
shutil.rmtree(os.path.join(root, direcpath))
|
|
880
|
+
else:
|
|
881
|
+
logger.info(f"Remove folder {direc}.")
|
|
882
|
+
shutil.rmtree(os.path.join(root, direcpath))
|
|
883
|
+
|
|
884
|
+
break
|
|
885
|
+
|
|
886
|
+
return removed_files
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: papers-cli
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.14
|
|
4
4
|
Summary: utilities to keep your PDF library organized
|
|
5
5
|
Author-email: Mahé Perrette <mahe.perrette@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -17,7 +17,7 @@ Requires-Dist: scholarly
|
|
|
17
17
|
Requires-Dist: rapidfuzz
|
|
18
18
|
Requires-Dist: normality
|
|
19
19
|
|
|
20
|
-
[](https://github.com/perrette/papers/actions)
|
|
21
21
|
[]()
|
|
22
22
|
[]()
|
|
23
23
|
[]()
|
|
@@ -306,6 +306,14 @@ That command is also convenient to check on what's actually tracked and what is
|
|
|
306
306
|
# ...
|
|
307
307
|
papers filecheck --rename --filesdir files
|
|
308
308
|
|
|
309
|
+
There is also a command specifically designed to clean up the zombie files and folders:
|
|
310
|
+
|
|
311
|
+
papers filecheck --clean-filesdir
|
|
312
|
+
|
|
313
|
+
That command will ask before removig anything, unless `--force` is passed. Currently
|
|
314
|
+
it ignores hidden files and folders, and will only consider folder that have a `.{folder}.bib` file inside,
|
|
315
|
+
which is the convention `papers` follows to store multiple attachments. That command works best
|
|
316
|
+
when the files are in their own folder, and not mixed up with other things, obviously.
|
|
309
317
|
|
|
310
318
|
### Setup git-tracked library (optional)
|
|
311
319
|
|
|
@@ -321,14 +329,8 @@ If `--git-lfs` is passed, the files will be backed-up along with the bibtex.
|
|
|
321
329
|
Under the hood, bibtex and files (if applicable) are copied (hard-linked) to a back-up directory.
|
|
322
330
|
Details are described in [issue 51](https://github.com/perrette/papers/issues/51).
|
|
323
331
|
|
|
324
|
-
|
|
325
|
-
Type `papers status -v` to find out.
|
|
326
|
-
|
|
332
|
+
Backup occurs in a subfolder of `~/.local/.share/papers` regardless of the type of installation. Type `papers status -v` to find out.
|
|
327
333
|
For local install that are already git-tracked, the feature remains useful as it is the basis for `papers undo` and `papers redo`.
|
|
328
|
-
You might want to add `.papers` to your .gitignore to avoid messing up with your larger project.
|
|
329
|
-
|
|
330
|
-
This feature is experimental.
|
|
331
|
-
|
|
332
334
|
|
|
333
335
|
### undo / redo
|
|
334
336
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|