Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 4fac669c66
Fetching contributors…

Cannot retrieve contributors at this time

executable file 272 lines (257 sloc) 8.862 kb
#!/usr/bin/env ruby
require 'yaml'
require 'rubygems'
require 'digest/sha1'
require 'cloudlib' # cloudlib gem
require 'optparse'
require 'highline/import' # highline gem
PROGNAME = "cloudlib"
NUMITEMS = 10
options = {}
opts = OptionParser.new do |opts|
opts.program_name = "#{PROGNAME} (c) 2008 John MacFarlane"
opts.banner = "cloudlib -- a library of books and articles in the AWS `cloud'\n" +
"Usage: #{PROGNAME} - start interactive menu\n" +
" #{PROGNAME} add FILE - upload FILE to library, prompting for metadata\n" +
" #{PROGNAME} new-library - initialize new library\n" +
" #{PROGNAME} delete-library - delete library and all its entries\n" +
" #{PROGNAME} dump [PATH] - create a local backup of library in PATH\n" +
" #{PROGNAME} restore [PATH] - restore library from local backup in PATH\n" +
" #{PROGNAME} list - list entries in library and print statistics\n" +
"Options:"
end
opts.on("-h", "--help", "Show usage message") do
puts opts.help
exit 0
end
begin
opts.parse!
rescue OptionParser::ParseError => e
puts e.message
puts opts.help
exit 1
end
# check that required environment variables are set, and prompt if they aren't
envvars = ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "CLOUDLIB_LIBRARY_NAME"]
envvars.each do |var|
unless ENV[var]
ENV[var] = ask("#{var}: ", String) { |q| q.echo = if var == "AWS_SECRET_ACCESS_KEY" then "*" else true end }
end
end
Cloudlib::Entry.connect(ENV['CLOUDLIB_LIBRARY_NAME'], ENV['AWS_ACCESS_KEY_ID'], ENV['AWS_SECRET_ACCESS_KEY'])
class Cloudlib::Entry
# Prompts for metadata for the entry, using existing metadata as defaults.
def ask_attributes
default_type = if self.show_attribute('entry_type').empty?
"article"
else
self.show_attribute('entry_type')
end
entry_types = ['article','book','chapter','incollection','unpublished']
type = ask("Type (#{entry_types.join(', ')})? ", entry_types) {|q| q.default = default_type; q.case = :downcase; q.readline = true }
self.attributes['entry_type'] = [type]
self.fields.each { |field| self.ask_attribute(field.to_s) }
return self
end
# Prompts for metadata for a particular field.
def ask_attribute(attribute)
default = self.show_attribute(attribute)
ans = ask(attribute.capitalize +
if attribute == 'editors' || attribute == 'authors' then " (name [and name...]) " else " " end, String) { |q| q.readline = true; q.default = default }
set_attribute(attribute, ans)
end
end
def show_items(items, more=false)
items.each_index do |i|
say "<%= color('[#{i}]', BOLD) %> #{items[i].to_s}\n"
end
if more
say "<%= color('Enter', BOLD)%> for more...\n"
end
end
def html_version(entries)
"<html>\n" +
"<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\" />\n" +
"<body>\n" +
"<ol>\n" +
entries.map do |entry|
"<li><a href=\"" + CGI.escape(entry.name) + "\">" +
CGI.escapeHTML(entry.to_s) + "</a></li>"
end.join("\n") +
"</ol>\n" +
"</body>\n" +
"</html>"
end
def menu(items)
token = query = ""
while true
commands = ["find KEYWORDS", "quit"]
if items.length > 0
then commands = ["bib NUM", "get NUM", "del NUM", "mod NUM", "url NUM"] + commands
end
choices = commands.join(' | ')
ans = ask("#{choices} ? ", String) { |q| q.readline = true; q.case = :downcase }
if ans == ""
if token.empty?
items = []
else
token, items = Cloudlib::Entry.query(query, NUMITEMS, token)
end
show_items(items, more=(not token.empty?))
elsif ans =~ /^quit|q$/
exit 0
elsif ans =~ /^find *(.+)$/
query = $1
token, items = Cloudlib::Entry.query(query, NUMITEMS)
show_items(items, more=(not token.empty?))
elsif ans =~ /^(get|del|mod|bib|url) *(\d+)$/
num = $2.to_i
if (num < 0) || (num >= items.length)
next
else
item = items[num]
case $1
when "get":
destpath = ask("Save as: ", String) { |q| q.default = item.friendly_filename; q.readline = true }
item.download(destpath)
puts "Downloaded #{destpath}"
when "mod":
item.ask_attributes
item.save
when "del":
item.delete
when "bib":
puts item.to_bibtex
when "url":
validminutes = ask("How long (in minutes) should the link be valid? ", Integer) { |q| q.default = 10; q.readline = true; }
puts item.url(validminutes)
else
raise "Unknown command."
end
end
else
puts "Unknown command"
end
end
end
if ARGV.length >= 1
if ARGV[0] == "new-library"
print "Create new library `#{ENV['CLOUDLIB_LIBRARY_NAME']}' (y/n)? "
ans = STDIN.gets
if ans =~ /^[Yy]/
begin
Cloudlib::Entry.create_library
rescue AWS::S3::BucketAlreadyExists
STDERR.puts "The library name `#{ENV['CLOUDLIB_LIBRARY_NAME']}' is already taken by another user."
STDERR.puts "Please set CLOUDLIB_LIBRARY_NAME to something else and try again."
exit 1
end
end
exit 0
end
if ARGV[0] == "delete-library"
print "Delete `#{ENV['CLOUDLIB_LIBRARY_NAME']}' and ALL OF ITS CONTENTS (y/n)? "
ans = STDIN.gets
if ans =~ /^[Yy]/
Cloudlib::Entry.delete_library
end
exit 0
end
if ARGV[0] == "backup"
print "Delete `#{ENV['CLOUDLIB_LIBRARY_NAME']}' and ALL OF ITS CONTENTS (y/n)? "
ans = STDIN.gets
if ans =~ /^[Yy]/
Cloudlib::Entry.delete_library
end
exit 0
end
if ARGV[0] == "add"
ARGV[1..(ARGV.length - 1)].each do |target|
unless File.exists?(target)
puts "File not found: #{target}"
exit 1
end
item = Cloudlib::Entry.from_file(target)
puts "Please enter metadata for `#{target}':"
item.ask_attributes
item.save
puts "Uploaded #{target}"
end
exit 0
end
if ARGV[0] == "list"
STDERR.puts "Generating list of entries (this may take a while)..."
token, entries = Cloudlib::Entry.query("",100)
while not (token.empty?)
token, next_entries = Cloudlib::Entry.query("", 100, token)
entries += next_entries
end
total_size = entries.inject(0) do |accum, e|
size = e.attributes['size'][0].to_i / (1024.0 * 1024.0)
printf "%7.2f MB %s\n", size, e.to_s
accum + size
end
rate_gb_month = 0.15
printf("\n%7.2f MB TOTAL (%d entries). ", total_size, entries.length)
printf("This will cost $%.2f to store for a year at $%.2f/GB/month.\n", (total_size / 1024.0) * rate_gb_month * 12, rate_gb_month)
exit 0
end
if ARGV[0] == "dump"
path = ARGV[1] || ask("Dump to which directory? ", String) { |q| q.default = "."; q.echo = true }
new_entries = 0
token, entries = Cloudlib::Entry.query("",100)
while not (token.empty?)
token, next_entries = Cloudlib::Entry.query("", 100, token)
entries += next_entries
end
total_size = entries.inject(0) {|accum, e| accum + e.attributes['size'][0].to_i}
printf("Total size is %.2f megabytes.\n", (total_size / (1024.0 * 1024.0)))
open("#{path}/#{ENV['CLOUDLIB_LIBRARY_NAME']}.db", 'w') do |file|
STDERR.puts "Backing up metadata..."
file.write(YAML.dump(entries))
end
open("#{path}/index.html", 'w') do |file|
STDERR.puts "Writing HTML index..."
file.write(html_version(entries))
end
STDERR.puts "Backing up files:"
bibtex = []
entries.each do |entry|
if not File.exists?("#{path}/#{entry.name}")
entry.download("#{path}/#{entry.name}")
new_entries += 1
STDERR.puts entry.to_s
end
bibtex << entry.to_bibtex
end
open("#{path}/references.bib", 'w') do |file|
STDERR.puts "Writing bibtex bibliography..."
file.write(bibtex.join("\n\n"))
end
STDERR.puts "Backed up metadata and #{new_entries} new files."
exit 0
end
if ARGV[0] == "restore"
path = ARGV[1] || "."
entries = open("#{path}/#{ENV['CLOUDLIB_LIBRARY_NAME']}.db", 'r') { |file| YAML.load(file) }
entries.each do |entry|
filename = "#{path}/#{entry.name}"
Cloudlib::Entry.from_file(filename)
entry.save
STDERR.puts entry.to_s
end
STDERR.puts "Restored #{entries.length} entries."
exit 0
end
STDERR.puts "Unknown command #{ARGV[0]}."
puts opts.help
exit 1
else
begin
menu([])
rescue AwsSdb::NoSuchDomainError
STDERR.puts "The library `#{ENV['CLOUDLIB_LIBRARY_NAME']}' does not exist."
STDERR.puts "Use `#{PROGNAME} new-library' to create it."
exit 1
end
end
Jump to Line
Something went wrong with that request. Please try again.