bmc/backend/commands.py

276 lines
8.5 KiB
Python
Raw Normal View History

2016-03-30 19:14:18 +02:00
import libbmc
import os
import subprocess
import tempfile
2016-03-30 19:14:18 +02:00
from backend import config
from backend import tools
2016-03-30 19:14:18 +02:00
from libbmc import bibtex
from libbmc import fetcher
2016-03-30 19:14:18 +02:00
from libbmc.repositories import arxiv
from libbmc.papers import identifiers
from libbmc.papers import tearpages
2016-03-30 19:14:18 +02:00
def get_entry_from_index(item, file_or_id=None):
"""
Fetch an entry from the global index.
:param item: An identifier or filename.
:param file_or_id: Whether it is a file or an entry identifier. If \
``None``, will try to match both.
:returns: TODO.
"""
entry = None
# If explictly an identifier
if file_or_id == "id":
entry = bibtex.get_entry(config.get("index"), item)
# If explicitely a filename
elif file_or_id == "file":
entry = bibtex.get_entry_by_filter(config.get("index"),
lambda x: x.file == item) # TODO
# Else, get by id or file
else:
entry = bibtex.get_entry_by_filter(config.get("index"),
lambda x: (
x.id == item or
x.file == item)) # TODO
return entry
def download(url, manual, autoconfirm, tag):
"""
Download a given URL and add it to the library.
:param url: URL to download.
:param manual: Whether BibTeX should be fetched automatically.
:param autoconfirm: Whether import should be made silent or not.
:param tag: A tag for this file.
:returns: The name of the downloaded file once imported, \
or ``None`` in case of error.
"""
# Download the paper
print("Downloading %s" % (url,))
dl, contenttype = fetcher.download(url)
if dl is not None:
print("Download finished.")
# Store it to a temporary file
try:
tmp = tempfile.NamedTemporaryFile(suffix='.%s' % (contenttype,))
with open(tmp.name, 'wb+') as fh:
fh.write(dl)
# And add it as a normal paper from now on
2016-03-30 19:14:18 +02:00
new_name = import_file(tmp.name, manual,
autoconfirm, tag)
if new_name is None:
return None
else:
return new_name
finally:
tmp.close()
else:
tools.warning("Could not fetch %s." % (url,))
return None
2016-03-30 19:14:18 +02:00
def import_file(src, manual=False, autoconfirm=False,
tag='', rename=True):
"""
Add a file to the library.
:param src: The path of the file to import.
2016-03-30 19:14:18 +02:00
:param manual: Whether BibTeX should be fetched automatically. \
Default to ``False``.
:param autoconfirm: Whether import should be made silent or not. \
Default to ``False``.
:param tag: A tag for this file. \
Default to no tag.
:param rename: Whether or not the file should be renamed according to the \
mask in the config.
:returns: The name of the imported file, or ``None`` in case of error.
"""
2016-03-30 19:14:18 +02:00
if not manual:
type, identifier = identifiers.find_identifiers(src)
if type is None:
tools.warning("Could not find an identifier for %s. \
Switching to manual entry." % (src))
# Fetch available identifiers types from libbmc
# Append "manual" for manual entry of BibTeX and "skip" to skip the
# file.
available_types_list = (libbmc.__valid_identifiers__ +
["manual", "skip"])
available_types = " / ".joint(available_types_list)
# Query for the type to use
while type not in available_types_list:
type = input("%s? " % (available_types)).lower()
if type == "skip":
# If "skip" is chosen, skip this file
return None
elif type == "manual":
identifier = None
else:
# Query for the identifier if required
identifier = input("Value? ")
else:
print("%s found for %s: %s." % (type, src, identifier))
# Fetch BibTeX automatically if we have an identifier
bibtex = None
if identifier is not None:
# If an identifier was provided, try to automatically fetch the bibtex
bibtex = identifiers.get_bibtex((type, identifier))
# TODO: Check bibtex
# Handle tag
if not autoconfirm:
# If autoconfirm is not enabled, query for a tag
user_tag = input("Tag for this paper [%s]? " % tag)
if user_tag != "":
tag = user_tag
bibtex["tag"] = tag
# TODO: Handle renaming
new_name = src
if rename:
pass
bibtex['file'] = os.path.abspath(new_name)
# Tear some pages if needed
should_tear_pages = True
if not autoconfirm:
# Ask for confirmation
pages_to_tear = tearpages.tearpage_needed(bibtex)
user_tear_pages = input("Found some pages to tear: %s. \
Confirm? [Y/n]" % (pages_to_tear)).lower()
if user_tear_pages == "n":
should_tear_pages = False
if should_tear_pages:
tearpages.tearpage(new_name, bibtex=bibtex)
# TODO: Append to global bibtex index
return new_name
def delete(item, keep=False, file_or_id=None):
"""
Delete an entry in the main BibTeX file, and the associated documents.
:param item: An entry or filename to delete from the database.
:param keep: Whether or not the document should be kept on the disk. \
If True, will simply delete the entry in the main BibTeX index.
:param file_or_id: Whether it is a file or an entry identifier. If \
``None``, will try to match both.
:returns: Nothing.
"""
entry = get_entry_from_index(item, file_or_id)
# Delete the entry from the bibtex index
bibtex.delete(config.get("index"), entry.id) # TODO
# If file should not be kept
if not keep:
# Delete it
os.unlink(entry.file) # TODO
def edit(item, file_or_id):
"""
Edit an entry in the main BibTeX file.
:param item: An entry or filename to edit in the database.
:param file_or_id: Whether it is a file or an entry identifier. If \
``None``, will try to match both.
:returns: Nothing.
"""
# TODO
pass
2016-03-30 19:14:18 +02:00
def list_entries():
"""
List all the available entries and their associated files.
:returns: A dict with entry identifiers as keys and associated files as \
values.
"""
# Get the list of entries from the BibTeX index
entries_list = bibtex.get(config.get("index"))
return {entry.id: entry.file for entry in entries_list} # TODO
def open(id):
"""
Open the file associated with the provided entry identifier.
:param id: An entry identifier in the main BibTeX file.
:returns: ``False`` if an error occured. ``True`` otherwise.
"""
# Fetch the entry from the BibTeX index
entry = bibtex.get_entry(config.get("index"), id)
if entry is None:
return False
else:
# Run xdg-open on the associated file to open it
subprocess.Popen(['xdg-open', entry.filename]) # TODO
return True
def export(item, file_or_id=None):
"""
Export the BibTeX entries associated to some items.
:param item: An entry or filename to export as BibTeX.
:param file_or_id: Whether it is a file or an entry identifier. If \
``None``, will try to match both.
:returns: TODO.
"""
# Fetch the entry from the BibTeX index
entry = get_entry_from_index(item, file_or_id)
if entry is not None:
return bibtex.dict2BibTeX(entry) # TODO
def resync():
"""
Compute the diff between the main BibTeX index and the files on the disk,
and try to resync them.
:returns: Nothing.
"""
# TODO
pass
def update(item, file_or_id=None):
"""
Update an entry, trying to fetch a more recent version (on arXiv for \
instance.)
:param item: An entry or filename to fetch update from.
:param file_or_id: Whether it is a file or an entry identifier. If \
``None``, will try to match both.
:returns: TODO.
"""
entry = get_entry_from_index(item, file_or_id)
# Fetch latest version
latest_version = arxiv.get_latest_version(entry.eprint) # TODO
if latest_version != entry.eprint: # TODO
print("New version found for %s: %s" % (entry, latest_version))
confirm = input("Download it? [Y/n] ")
if confirm.lower() == 'n':
return
# Download the updated version
# TODO
# Delete previous version if needed
# TODO