Created
October 12, 2010 15:26
-
-
Save konnov/622362 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# | |
# Convenient script to store scientific papers in a local repository | |
# and set various links, i.e. tags, on them. | |
# | |
# Igor Konnov <konnov at cs.msu.su>, 2009-2010 | |
# | |
# USAGE: | |
# | |
# For instance, if the repository is set as ~/sci and one wishes | |
# to add the paper 2020doe_ufo.pdf tagged by words 'ufo', 'astronomy' | |
# do just the following: | |
# | |
# ./sciit --add 2020doe_ufo.pdf ufo astronomy | |
# | |
# It results in moving 2020doe_ufo.pdf into ~/sci/.stor/ and then | |
# sets symbolic link ~/sci/ufo/2020doe_ufo.pdf -> ~/sci/.stor/2020doe_ufo.pdf | |
# as well as ~/sci/astronomy/2020doe_ufo.pdf -> ~/sci/.stor/2020doe_ufo.pdf | |
# | |
# CONFIGURATION | |
# | |
# Create a file ~/.sciitrc and write the following: | |
# | |
# [default] | |
# repo-path = <path-to-your-repository> | |
import ConfigParser | |
import exceptions | |
import getopt | |
import os | |
import re | |
import shutil | |
import sys | |
class ConfigReader: | |
def __init__(self): | |
self.config = ConfigParser.ConfigParser() | |
self.config.read(os.path.expanduser("~/.sciitrc")) | |
def repo_path(self): | |
return self.config.get("default", "repo-path") | |
class FileNotFoundException(exceptions.Exception): | |
def __init__(self, value): | |
self.value = value | |
def __str__(self): | |
return str(self.value) | |
class ConventionsViolatedException(exceptions.Exception): | |
def __init__(self, value): | |
self.value = value | |
def __str__(self): | |
return str(self.value) | |
class Command: | |
def run(self, **kwargs): | |
print "Nothing to do" | |
class AddCommand: | |
def __init__(self, cfg_reader): | |
self._cfg_reader = cfg_reader | |
def run(self, filename, tags): | |
if not os.path.exists(filename): | |
raise FileNotFoundException("File %s not found" % filename) | |
stor_path = os.path.expanduser(self._cfg_reader.repo_path()) | |
if not os.path.exists(stor_path): | |
raise FileNotFoundException("Storage home %s not found" % stor_path) | |
basename = os.path.basename(filename) | |
self._check_conventions(basename) | |
target = os.path.join(stor_path, ".stor", basename) | |
print "%s -> %s" % (filename, target) | |
if not os.path.isfile(filename): | |
print "%s is not a file. Refusing to continue" % filename | |
try: | |
os.rename(filename, target) | |
except OSError, e: | |
# probably, filename and target reside on different volumes | |
shutil.copy2(filename, target) | |
os.remove(filename) | |
for tag in tags: | |
tag_dir = os.path.join(stor_path, tag) | |
if not os.path.exists(tag_dir): | |
os.makedirs(tag_dir) | |
tag_link = os.path.join(tag_dir, basename) | |
print "symlink %s to %s" % (tag_link, target) | |
os.symlink(target, tag_link) | |
def _check_conventions(self, basename): | |
m = re.match("^[0-9]{4,4}[a-z]+_[0-9a-z]+(\.[a-z]+)+$", basename) | |
if not m: | |
raise ConventionsViolatedException("Conventions violated for %s" \ | |
% basename) | |
class TagCommand: | |
def __init__(self, cfg_reader): | |
self._cfg_reader = cfg_reader | |
def run(self, filename, tags): | |
stor_path = os.path.expanduser(self._cfg_reader.repo_path()) | |
basename = os.path.basename(filename) | |
source = os.path.join(stor_path, ".stor", basename) | |
if not os.path.exists(source): | |
raise FileNotFoundException("File %s not found" % source) | |
for tag in tags: | |
tag_dir = os.path.join(stor_path, tag) | |
if not os.path.exists(tag_dir): | |
os.makedirs(tag_dir) | |
tag_link = os.path.join(tag_dir, basename) | |
print "symlink %s to %s" % (tag_link, source) | |
if not os.path.exists(tag_link): | |
os.symlink(source, tag_link) | |
class UntagCommand: | |
def __init__(self, cfg_reader): | |
self._cfg_reader = cfg_reader | |
def run(self, filename, tags): | |
stor_path = os.path.expanduser(self._cfg_reader.repo_path()) | |
basename = os.path.basename(filename) | |
source = os.path.join(stor_path, ".stor", basename) | |
if not os.path.exists(source): | |
raise FileNotFoundException("File %s not found" % source) | |
for tag in tags: | |
tag_dir = os.path.join(stor_path, tag) | |
if not os.path.exists(tag_dir): | |
os.makedirs(tag_dir) | |
tag_link = os.path.join(tag_dir, basename) | |
print "unlink %s" % tag_link | |
if os.path.exists(tag_link): | |
os.unlink(tag_link) | |
def usage(): | |
print "Use: sciit command file tag1 ... tagN" | |
print " where command is one of the following:" | |
print " --add add file to repository and set the tags given" | |
print " --tag add tags to the file in repository" | |
print " --untag remove tags of the file in repository" | |
if __name__ == "__main__": | |
try: | |
opts, args = getopt.getopt(sys.argv[1:], "h", | |
["help", "add=", "tag=", "untag="]) | |
except getopt.GetoptError, err: | |
# print help information and exit: | |
print str(err) # will print something like "option -a not recognized" | |
usage() | |
sys.exit(2) | |
cfg_reader = ConfigReader() | |
cmd = None | |
cmd_args = [] | |
for o, a in opts: | |
if o in ("-h", "--help"): | |
usage() | |
sys.exit() | |
elif o in ("--add"): | |
cmd = AddCommand(cfg_reader) | |
cmd_args = { "filename" : a, "tags" : args } | |
elif o in ("--tag"): | |
cmd = TagCommand(cfg_reader) | |
cmd_args = { "filename" : a, "tags" : args } | |
elif o in ("--untag"): | |
cmd = UntagCommand(cfg_reader) | |
cmd_args = { "filename" : a, "tags" : args } | |
else: | |
assert False, "unhandled option" | |
if cmd: | |
try: | |
cmd.run(**cmd_args) | |
except FileNotFoundException, e: | |
print str(e) | |
except ConventionsViolatedException, e: | |
print str(e) | |
else: | |
usage() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment