You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

238 lines
7.6 KiB

import os
import shutil
import glob
import files
from paper import PaperInRepo, NoDocumentFile
from color import colored
import configs
ALPHABET = 'abcdefghijklmopqrstuvwxyz'
BASE_FILE = 'papers.yaml'
BIB_DIR = 'bibdata'
META_DIR = 'meta'
DOC_DIR = 'doc'
class CiteKeyAlreadyExists(Exception):
pass
class Repository(object):
def __init__(self, config=None):
self.papersdir = None
self.citekeys = []
if config is None:
config = configs.CONFIG
self.config = config
def has_paper(self, citekey):
return citekey in self.citekeys
def paper_from_citekey(self, citekey):
"""Load a paper by its citekey from disk, if necessary."""
return PaperInRepo.load(
self, self.path_to_paper_file(citekey, 'bib'),
metapath=self.path_to_paper_file(citekey, 'meta'))
def citekey_from_ref(self, ref, fatal=True):
"""Tries to get citekey from given ref.
Ref can be a citekey or a number.
"""
if ref in self.citekeys:
return ref
else:
try:
return self.citekeys[int(ref)]
except (IndexError, ValueError):
if fatal:
print(colored('error', 'error')
+ ': no paper with reference {}'.format(
colored(ref, 'citekey')))
exit(-1)
raise(IOError('file not found'))
def paper_from_ref(self, ref, fatal=True):
key = self.citekey_from_ref(ref, fatal=fatal)
return self.paper_from_citekey(key)
# creating new papers
def add_paper(self, p):
if p.citekey is None: # TODO also test if citekey is valid
raise(ValueError("Invalid citekey: %s." % p.citekey))
elif self.has_paper(p.citekey):
raise(ValueError("Citekey already exists in repository: %s"
% p.citekey))
self.citekeys.append(p.citekey)
# write paper files
self.save_paper(p)
# update repository files
self.save()
# TODO change to logging system (17/12/2012)
print "Added: %s" % p.citekey
def add_or_update(self, paper):
if not self.has_paper(paper.citekey):
self.add_paper(paper)
else:
self.save_paper(paper)
def update(self, paper, old_citekey=None, overwrite=False):
"""Updates a paper, eventually changing its citekey.
The paper should be in repository. If the citekey changes,
the new citekey should be free except if the overwrite argument
is set to True.
"""
if old_citekey is None:
old_citekey = paper.citekey
if old_citekey not in self.citekeys:
raise(ValueError, 'Paper not in repository. Add first')
else:
if paper.citekey == old_citekey:
self.save_paper(paper)
else:
if self.has_paper(paper.citekey):
if not overwrite:
raise(CiteKeyAlreadyExists,
"There is already a paper with citekey: %s."
% paper.citekey)
else:
self.save_paper(paper)
else:
self.add_paper(paper)
# Eventually move document file
paper = PaperInRepo.from_paper(paper, self)
try:
path = self.find_document(old_citekey)
self.import_document(paper.citekey, path)
except NoDocumentFile:
pass
self.remove(old_citekey)
def remove(self, citekey):
paper = self.paper_from_citekey(citekey)
self.citekeys.remove(citekey)
self.save()
for f in ('bib', 'meta'):
os.remove(self.path_to_paper_file(citekey, f))
# Eventually remove associated document
try:
path = paper.get_document_path_in_repo()
os.remove(path)
except NoDocumentFile:
pass
def save_paper(self, paper):
if not self.has_paper(paper.citekey):
raise(ValueError('Paper not in repository, first add it.'))
paper.save_to_disc(self.path_to_paper_file(paper.citekey, 'bib'),
self.path_to_paper_file(paper.citekey, 'meta'))
def get_free_citekey(self, paper, citekey=None):
"""Create a unique citekey for the given paper.
"""
if citekey is None:
citekey = paper.generate_citekey()
num = []
while citekey + _to_suffix(num) in self.citekeys:
_str_incr(num)
return citekey + _to_suffix(num)
def base_file_path(self):
return os.path.join(self.papersdir, 'papers.yaml')
def size(self):
return len(self.citekeys)
def save(self):
papers_config = {'citekeys': self.citekeys}
files.write_yamlfile(self.base_file_path(), papers_config)
def load(self):
papers_config = files.read_yamlfile(self.base_file_path())
self.citekeys = papers_config['citekeys']
def init(self, papersdir):
self.papersdir = papersdir
os.makedirs(os.path.join(self.papersdir, BIB_DIR))
os.makedirs(os.path.join(self.papersdir, META_DIR))
doc_dir = self.get_document_directory()
if not os.path.exists(doc_dir):
os.makedirs(doc_dir)
self.save()
def path_to_paper_file(self, citekey, file_):
if file_ == 'bib':
return os.path.join(self.papersdir, BIB_DIR, citekey + '.bibyaml')
elif file_ == 'meta':
return os.path.join(self.papersdir, META_DIR, citekey + '.meta')
else:
raise(ValueError("%s is not a valid paper file." % file_))
def get_document_directory(self):
if self.config.has_option('papers', 'document-directory'):
doc_dir = self.config.get('papers', 'document-directory')
else:
doc_dir = os.path.join(self.papersdir, DOC_DIR)
return files.clean_path(doc_dir)
def find_document(self, citekey):
doc_dir = self.get_document_directory()
found = glob.glob(doc_dir + "/%s.*" % citekey)
if found:
return found[0]
else:
raise NoDocumentFile
def all_papers(self):
for key in self.citekeys:
yield self.paper_from_citekey(key)
def import_document(self, citekey, doc_file):
if citekey not in self.citekeys:
raise(ValueError, "Unknown citekey: %s." % citekey)
else:
doc_path = self.get_document_directory()
if not (os.path.exists(doc_path) and os.path.isdir(doc_path)):
raise(NoDocumentFile,
"Document directory %s, does not exist." % doc_path)
ext = os.path.splitext(doc_file)[1]
new_doc_file = os.path.join(doc_path, citekey + ext)
shutil.copy(doc_file, new_doc_file)
@classmethod
def from_directory(cls, config, papersdir=None):
repo = cls(config=config)
if papersdir is None:
papersdir = config.get('papers', 'papers-directory')
repo.papersdir = files.clean_path(papersdir)
repo.load()
return repo
def _char_incr(c):
return chr(ord(c) + 1)
def _str_incr(l):
"""Increment a number in a list string representation.
Numbers are represented in base 26 with letters as digits.
"""
pos = 0
while pos < len(l):
if l[pos] == 'z':
l[pos] = 'a'
pos += 1
else:
l[pos] = _char_incr(l[pos])
return
l.append('a')
def _to_suffix(l):
return ''.join(l[::-1])