#!/usr/bin/env ruby # Encoding: utf-8 #-------------------------------------------------------------------- # Sifttter Redux # # A modification of Craig Eley's Sifttter that allows for smart # installation on a standalone *NIX device (such as a Raspberry Pi). # # Sifttter copyright Craig Eley 2014 # # Copyright (c) 2014 # Aaron Bach # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. #-------------------------------------------------------------------- require 'archive/zip' require 'cliutils' require 'gli' require 'sifttter-redux' require 'securerandom' include CLIUtils::Configuration include CLIUtils::Messaging include GLI::App # ====================================================== # App Info # ====================================================== program_desc(SifttterRedux::DESCRIPTION) version(SifttterRedux::VERSION) # ====================================================== # Global Flags and Switches # ====================================================== switch([:verbose], desc: 'Turns on verbose output') # ====================================================== # Pre, Post, and Error # ====================================================== pre do |global, command, options, args| # Load SifttterRedux configuration module. load_configuration(SifttterRedux::DEFAULT_SRD_CONFIG_FILEPATH) file_logger = Logger.new(SifttterRedux::DEFAULT_SRD_LOG_FILEPATH) file_logger.level = LOG_LEVELS[configuration.sifttter_redux[:log_level] || 'DEBUG'] messenger.attach(LOGFILE: file_logger) if File.exists?(SifttterRedux::DEFAULT_SRD_CONFIG_FILEPATH) # Set the current and last config versions in the Configurator. configuration.current_version = configuration.sifttter_redux[:version] configuration.last_version = SifttterRedux::NEWEST_CONFIG_VERSION # Compare the two versions and, if needed, update. configuration.compare_version do |c, l| messenger.debug("Upgrading from #{ c } to #{ l }") SifttterRedux.update_config_file exit!(0) end else # Force the user to init if they try to run any command other than `init` first. messenger.info('You need to initialize Sifttter Redux first!') SifttterRedux.init(true) exit!(0) end true end post do |global,command,options,args| # Post logic here # Use skips_post before a command to skip this # block on that command only end on_error do |exception| messenger.error(exception.to_s) exit!(1) true end # ====================================================== # Commands # ====================================================== # ------------------------------------------------------ # exec command # # Executes the app. # ------------------------------------------------------ desc 'Execute the app' command :exec do |c| c.flag([:d], desc: 'Run catch-up mode with a particular date') c.flag([:f], desc: 'Run catch-up mode with this start date') c.flag([:n], desc: 'Run catch-up mode for the last N days') c.flag([:t], desc: 'Run catch-up mode with this end date (must also have -f)') c.flag([:w], desc: 'Run catch-up mode for the last N weeks') c.switch([:c], desc: 'Run catch-up mode from the beginning of the week to yesterday') c.switch([:i], desc: "Include today's date in catch-up") c.switch([:verbose], desc: 'Turns on verbose output') c.switch([:y], desc: 'Run catch-up mode for yesterday') c.action do |global_options, options, args| SifttterRedux.verbose = global_options[:verbose] || options[:verbose] dates = SifttterRedux::get_dates_from_options(options) unless dates.nil? first_date = dates.first second_date = dates.reverse_each.first date_string = first_date.strftime('%B %d, %Y') date_string << " to #{ second_date.strftime('%B %d, %Y') }" if first_date != second_date messenger.info("Creating #{ first_date == second_date ? 'entry' : 'entries' }: #{ date_string }") # Download Sifttter files from Dropbox. dbu = SifttterRedux::DropboxUploader.new(configuration.db_uploader[:exe_filepath]) dbu.verbose = SifttterRedux.verbose dbu.local_target = configuration.sifttter_redux[:sifttter_local_filepath] dbu.remote_target = configuration.sifttter_redux[:sifttter_remote_filepath] dbu.message = 'Downloading Sifttter files...' messenger.info(dbu.message || dbu::DEFAULT_MESSAGE) dbu.download messenger.info('Done.') # Process a new Sifttter entry for each date. dates.each do |date| SifttterRedux::Sifttter.run(date) end # Upload any Day One entries to Dropbox (if there are any). unless Dir[configuration.sifttter_redux[:dayone_local_filepath] + '/*'].empty? dbu.local_target = "#{ configuration.sifttter_redux[:dayone_local_filepath] }/*" dbu.remote_target = configuration.sifttter_redux[:dayone_remote_filepath] dbu.message = 'Uploading Day One entries to Dropbox...' messenger.info(dbu.message || dbu::DEFAULT_MESSAGE) dbu.upload messenger.info('Done.') end # Remove any downloaded local files that we no longer need. SifttterRedux.cleanup_temp_files end end end # ------------------------------------------------------ # init command # # Initializes the app by asking the user for information # needed torun. # ------------------------------------------------------ desc 'Install and initialize dependencies' command :init do |c| c.switch([:s], desc: 'Run init from scratch (i.e., clear out all values from configuration)') c.action do |global_options, options, args| if options[:s] SifttterRedux::init(true) else long_message = "You've already initialized Sifttter Redux. Do it again?" SifttterRedux::init if messenger.prompt(long_message, 'N').downcase == 'y' end end end # ------------------------------------------------------ # upgrade command # # Upgrades existing Sifttter files to the format needed # by v 1.x.x. # ------------------------------------------------------ desc 'Upgrades Sifttter files to the new format' command :upgrade do |c| c.switch([:verbose], desc: 'Turns on verbose output') c.action do |global_options, options, args| SifttterRedux.verbose = global_options[:verbose] || options[:verbose] # Set the archive filepath and the files that will go into it. filename = "#{ ENV['HOME'] }/sifttter_backup_#{ Time.now.to_i }.zip" # Download Sifttter files from Dropbox. dbu = SifttterRedux::DropboxUploader.new(configuration.db_uploader[:exe_filepath]) dbu.verbose = SifttterRedux.verbose dbu.local_target = configuration.sifttter_redux[:sifttter_local_filepath] dbu.remote_target = configuration.sifttter_redux[:sifttter_remote_filepath] dbu.message = "Backing up Sifttter files to #{ filename }..." messenger.info(dbu.message || dbu::DEFAULT_MESSAGE) dbu.download messenger.info('Done.') # Archive the Sifttter files. Archive::Zip.archive(filename, configuration.sifttter_redux[:sifttter_local_filepath]) # Replace the old scheme with the new one. Dir.glob(configuration.sifttter_redux[:sifttter_local_filepath] + '/*.txt').each do |file| t = File.read(file) t.gsub!(/^- /, "@begin\n@date ") t.gsub!(/ - /, "\n- ") t.gsub!(/\s?@done/, '@end') messenger.debug("Replacing contents of file: #{ file }") File.open(file, 'w') { |f| f.write(t) } end # Upload the new Sifttter files back to Dropbox. dbu.local_target = "#{ configuration.sifttter_redux[:sifttter_local_filepath] }" dbu.remote_target = Pathname.new(configuration.sifttter_redux[:sifttter_remote_filepath]).dirname.to_s dbu.message = "Uploading revised Sifttter files to Dropbox..." messenger.info(dbu.message || dbu::DEFAULT_MESSAGE) dbu.upload messenger.info('Done.') # Remove any downloaded local files that we no longer need. SifttterRedux.cleanup_temp_files end end # ====================================================== # Run! # ====================================================== exit run(ARGV)