├── tmp └── srd │ ├── .dropbox_uploader │ ├── .sifttter_redux │ └── .sifttter_redux_log ├── Gemfile ├── .gitignore ├── test ├── test_helper.rb └── date_range_maker_test.rb ├── .travis.yml ├── features ├── 1.ui.feature ├── step_definitions │ └── sifttter-redux_steps.rb ├── support │ └── env.rb └── 2.initialization.feature ├── res └── preference_prompts.yaml ├── LICENSE ├── lib ├── sifttter-redux │ ├── constants.rb │ ├── dropbox-uploader.rb │ ├── date-range-maker.rb │ └── sifttter.rb └── sifttter-redux.rb ├── Rakefile ├── sifttter-redux.gemspec ├── HISTORY.md ├── bin └── srd └── README.md /tmp/srd/.dropbox_uploader: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile.lock 2 | .bundle 3 | .DS_Store 4 | results.html 5 | *.gem 6 | features/3.execution.feature 7 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | require 'test/unit' 2 | 3 | # Add test libraries you want to use here, e.g. mocha 4 | 5 | class Test::Unit::TestCase 6 | 7 | # Add global extensions to the test case class here 8 | 9 | end 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.1.0 4 | - 2.0.0 5 | - 1.9.3 6 | - jruby-19mode 7 | env: 8 | - TEST_SUITE=1.ui.feature 9 | script: 10 | - bundle exec cucumber -f progress -r features features/$TEST_SUITE 11 | -------------------------------------------------------------------------------- /features/1.ui.feature: -------------------------------------------------------------------------------- 1 | Feature: UI 2 | As a user, when I ask for help, I should be presented 3 | with instructions on how to run the app. 4 | 5 | Scenario: Display help instructions 6 | When I get help for "srd" 7 | Then the exit status should be 0 -------------------------------------------------------------------------------- /features/step_definitions/sifttter-redux_steps.rb: -------------------------------------------------------------------------------- 1 | Given(/^a file located at "(.*?)"$/) do |filepath| 2 | expect(File).to exist(filepath) 3 | end 4 | 5 | Given(/^an empty file located at "(.*?)"$/) do |filepath| 6 | FileUtils.touch(File.expand_path(filepath)) 7 | end 8 | 9 | Given(/^a file located at "(.*?)" with the contents:$/) do |filepath, contents| 10 | File.open(filepath, 'w') { |f| f.write(contents) } 11 | end 12 | 13 | Given(/^no file located at "(.*?)"$/) do |filepath| 14 | step %(the file "#{ filepath }" should not exist) 15 | end 16 | 17 | When /^I get help for "([^"]*)"$/ do |app_name| 18 | step %(I run `#{app_name} --help`) 19 | end 20 | -------------------------------------------------------------------------------- /features/support/env.rb: -------------------------------------------------------------------------------- 1 | require 'aruba/cucumber' 2 | 3 | ENV['PATH'] = "#{File.expand_path(File.dirname(__FILE__) + '/../../bin')}#{File::PATH_SEPARATOR}#{ENV['PATH']}" 4 | LIB_DIR = File.join(File.expand_path(File.dirname(__FILE__)),'..','..','lib') 5 | 6 | Before do 7 | @aruba_timeout_seconds = 25 8 | @puts = true 9 | @original_rubylib = ENV['RUBYLIB'] 10 | ENV['RUBYLIB'] = LIB_DIR + File::PATH_SEPARATOR + ENV['RUBYLIB'].to_s 11 | @original_home = ENV['HOME'] 12 | ENV['HOME'] = "/tmp/srd" 13 | FileUtils.rm_rf "/tmp/srd" 14 | FileUtils.mkdir "/tmp/srd" 15 | end 16 | 17 | After do 18 | ENV['RUBYLIB'] = @original_rubylib 19 | ENV['HOME'] = @original_home 20 | end 21 | -------------------------------------------------------------------------------- /tmp/srd/.sifttter_redux: -------------------------------------------------------------------------------- 1 | --- 2 | :sifttter_redux: 3 | :config_location: "/Users/abach/Git/sifttter-redux/features/support/../../tmp/srd/.sifttter_redux" 4 | :log_level: WARN 5 | :version: 0.5.4 6 | :sifttter_local_filepath: "/Users/abach/Git/sifttter-redux/features/support/../../tmp/srd/sifttter_download" 7 | :sifttter_remote_filepath: "/Apps/ifttt/Sifttter" 8 | :dayone_local_filepath: "/Users/abach/Git/sifttter-redux/features/support/../../tmp/srd/day_one_download" 9 | :dayone_remote_filepath: "/Apps/Day\\ One/Journal.dayone/entries" 10 | :db_uploader: 11 | :base_filepath: "/usr/local/opt" 12 | :dbu_filepath: "/usr/local/opt/Dropbox-Uploader" 13 | :exe_filepath: "/usr/local/opt/Dropbox-Uploader/dropbox_uploader.sh" 14 | -------------------------------------------------------------------------------- /res/preference_prompts.yaml: -------------------------------------------------------------------------------- 1 | prompts: 2 | - prompt_text: Where do you want to download Sifttter files to (temporarily)? 3 | default: /tmp/sifttter 4 | config_key: sifttter_local_filepath 5 | config_section: sifttter_redux 6 | - prompt_text: Where are your Sifttter files located in Dropbox? 7 | default: /Apps/ifttt/sifttter 8 | config_key: sifttter_remote_filepath 9 | config_section: sifttter_redux 10 | - prompt_text: Where do you want to download Day One files to (temporarily)? 11 | default: /tmp/dayone 12 | config_key: dayone_local_filepath 13 | config_section: sifttter_redux 14 | - prompt_text: Where are your Day One files located in Dropbox? 15 | default: /Apps/Day\ One/Journal.dayone/entries 16 | config_key: dayone_remote_filepath 17 | config_section: sifttter_redux 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) Tom Preston-Werner 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /lib/sifttter-redux/constants.rb: -------------------------------------------------------------------------------- 1 | module SifttterRedux 2 | # The default configuration path for Dropbox Uploader 3 | DEFAULT_DBU_CONFIG_FILEPATH = File.join(ENV['HOME'], '.dropbox_uploader') 4 | 5 | # The default local filepath of the Dropbox-Uploader directory 6 | DEFAULT_DBU_LOCAL_FILEPATH = '/usr/local/opt' 7 | 8 | # The default message to display when Dropbox Uploader is running 9 | DEFAULT_DBU_MESSAGE = 'RUNNING DROPBOX UPLOADER' 10 | 11 | # The default local filepath of the Siftter Redux config file 12 | DEFAULT_SRD_CONFIG_FILEPATH = File.join(ENV['HOME'], '.sifttter_redux') 13 | 14 | # The default local filepath of the Siftter Redux log file 15 | DEFAULT_SRD_LOG_FILEPATH = File.join(ENV['HOME'], '.sifttter_redux_log') 16 | 17 | # The Gem's description 18 | DESCRIPTION = 'A customized IFTTT-to-Day One service that allows for smart installation and automated running on a standalone *NIX device (such as a Raspberry Pi).' 19 | 20 | # The last version to require a config update 21 | NEWEST_CONFIG_VERSION = '1.0.0' 22 | 23 | # Hash of preference files 24 | PREF_FILES = { 25 | 'INIT' => File.join(File.dirname(__FILE__), '..', '..', 'res/preference_prompts.yaml') 26 | } 27 | 28 | # The Gem's summary 29 | SUMMARY = 'Automated IFTTT to Day One engine.' 30 | 31 | # The Gem's version 32 | VERSION = '1.0.6' 33 | end 34 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake/clean' 2 | require 'rubygems' 3 | 4 | def version 5 | contents = File.read File.expand_path('../lib/sifttter-redux/constants.rb', __FILE__) 6 | contents[/\sVERSION = '([^']+)'/, 1] 7 | end 8 | 9 | spec = eval(File.read('sifttter-redux.gemspec')) 10 | 11 | require 'rake/testtask' 12 | desc 'Run unit tests' 13 | Rake::TestTask.new do |t| 14 | t.libs << "test" 15 | t.test_files = FileList['test/*_test.rb'] 16 | end 17 | 18 | require 'cucumber' 19 | require 'cucumber/rake/task' 20 | CUKE_RESULTS = 'results.html' 21 | CLEAN << CUKE_RESULTS 22 | desc 'Run Cucumber features' 23 | Cucumber::Rake::Task.new(:features) do |t| 24 | opts = "features --format html -o #{CUKE_RESULTS} --format progress -x" 25 | opts += " --tags #{ENV['TAGS']}" if ENV['TAGS'] 26 | t.cucumber_opts = opts 27 | t.fork = false 28 | end 29 | 30 | desc "Release Sifttter Redux version #{ version }" 31 | task :release => :build do 32 | unless `git branch` =~ /^\* master$/ 33 | puts "You must be on the master branch to release!" 34 | exit! 35 | end 36 | 37 | sh "git commit --allow-empty -a -m 'Release #{ version }'" 38 | sh "git tag v#{ version }" 39 | sh "git push origin master" 40 | sh "git push origin v#{ version }" 41 | sh "gem push pkg/sifttter-redux-#{ version }.gem" 42 | end 43 | 44 | desc "Build the gem" 45 | task :build do 46 | FileUtils.mkdir_p "pkg" 47 | sh "gem build sifttter-redux.gemspec" 48 | FileUtils.mv("./sifttter-redux-#{ version }.gem", "pkg") 49 | end 50 | 51 | task :default => [:test, :features] 52 | -------------------------------------------------------------------------------- /sifttter-redux.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'sifttter-redux/constants' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = 'sifttter-redux' 8 | spec.version = SifttterRedux::VERSION 9 | spec.authors = ['Aaron Bach'] 10 | spec.email = ['bachya1208@googlemail.com'] 11 | spec.summary = SifttterRedux::SUMMARY 12 | spec.description = SifttterRedux::DESCRIPTION 13 | spec.homepage = 'https://github.com/bachya/sifttter-redux' 14 | spec.license = 'MIT' 15 | spec.platform = Gem::Platform::RUBY 16 | 17 | spec.require_paths = ["lib"] 18 | spec.files = `git ls-files`.split("\n") 19 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 20 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 21 | 22 | spec.license = 'MIT' 23 | spec.rdoc_options = ['--charset=UTF-8'] 24 | spec.extra_rdoc_files = %w[README.md HISTORY.md LICENSE] 25 | 26 | spec.add_development_dependency('rake', '10.1.1') 27 | spec.add_development_dependency('rdoc', '4.1.1') 28 | spec.add_development_dependency('aruba', '0.5.4') 29 | spec.add_runtime_dependency('archive-zip', '0.6.0') 30 | spec.add_runtime_dependency('chronic', '0.10.2') 31 | spec.add_runtime_dependency('cliutils', '~> 2') 32 | spec.add_runtime_dependency('gli','2.9.0') 33 | spec.add_runtime_dependency('htmlentities','4.3.1') 34 | end 35 | -------------------------------------------------------------------------------- /tmp/srd/.sifttter_redux_log: -------------------------------------------------------------------------------- 1 | # Logfile created on 2014-03-22 08:12:43 -0600 by logger.rb/44203 2 | D, [2014-03-22T08:12:43.563366 #13209] DEBUG -- : CONFIGURING DROPBOX UPLOADER... 3 | D, [2014-03-22T08:12:43.563826 #13209] DEBUG -- : Answer to "Location for Dropbox-Uploader": /usr/local/opt 4 | W, [2014-03-22T08:12:43.563882 #13209] WARN -- : Using pre-existing Dropbox Uploader at /usr/local/opt/Dropbox-Uploader... 5 | D, [2014-03-22T08:12:43.563920 #13209] DEBUG -- : COLLECTING PREFERENCES... 6 | D, [2014-03-22T08:12:43.564297 #13209] DEBUG -- : Answer to "Temporary path to download Sifttter files to": ~/sifttter_download 7 | D, [2014-03-22T08:12:43.564661 #13209] DEBUG -- : Answer to "Path to Sifttter files in Dropbox": /Apps/ifttt/Sifttter 8 | D, [2014-03-22T08:12:43.564995 #13209] DEBUG -- : Answer to "Temporary path to download Day One files to": ~/day_one_download 9 | D, [2014-03-22T08:12:43.565542 #13209] DEBUG -- : Answer to "Path to Day One files in Dropbox": /Apps/Day\ One/Journal.dayone/entries 10 | D, [2014-03-22T08:12:43.565605 #13209] DEBUG -- : Configuration values: {:sifttter_redux=>{:config_location=>"/Users/abach/Git/sifttter-redux/features/support/../../tmp/srd/.sifttter_redux", :log_level=>"WARN", :version=>"0.5.4", :sifttter_local_filepath=>"/Users/abach/Git/sifttter-redux/features/support/../../tmp/srd/sifttter_download", :sifttter_remote_filepath=>"/Apps/ifttt/Sifttter", :dayone_local_filepath=>"/Users/abach/Git/sifttter-redux/features/support/../../tmp/srd/day_one_download", :dayone_remote_filepath=>"/Apps/Day\\ One/Journal.dayone/entries"}, :db_uploader=>{:base_filepath=>"/usr/local/opt", :dbu_filepath=>"/usr/local/opt/Dropbox-Uploader", :exe_filepath=>"/usr/local/opt/Dropbox-Uploader/dropbox_uploader.sh"}} 11 | -------------------------------------------------------------------------------- /lib/sifttter-redux/dropbox-uploader.rb: -------------------------------------------------------------------------------- 1 | module SifttterRedux 2 | # DropboxUploader Class 3 | # Wrapper class for the Dropbox Uploader project 4 | class DropboxUploader 5 | # Stores the local filepath. 6 | # @return [String] 7 | attr_accessor :local_target 8 | 9 | # Stores the remote filepath. 10 | # @return [String] 11 | attr_accessor :remote_target 12 | 13 | # Stores the message to display. 14 | # @return [String] 15 | attr_accessor :message 16 | 17 | # Stores the verbosity level. 18 | # @return [Boolean] 19 | attr_accessor :verbose 20 | 21 | # Loads the location of dropbox_uploader.sh. 22 | # @param [String] dbu_path The local filepath to the script 23 | # @param [Logger] A Logger to use 24 | # @return [void] 25 | def initialize(dbu_path, logger = nil) 26 | @dbu = dbu_path 27 | @logger = logger 28 | end 29 | 30 | # Downloads files from Dropbox (assumes that both 31 | # local_target and remote_target have been set). 32 | # @return [void] 33 | def download 34 | if !@local_target.nil? && !@remote_target.nil? 35 | if @verbose 36 | system "#{ @dbu } download #{ @remote_target } #{ @local_target }" 37 | else 38 | exec = `#{ @dbu } download #{ @remote_target } #{ @local_target }` 39 | end 40 | else 41 | error_msg = 'Local and remote targets cannot be nil' 42 | @logger.error(error_msg) if @logger 43 | fail StandardError, error_msg 44 | end 45 | end 46 | 47 | # Uploads files tro Dropbox (assumes that both 48 | # local_target and remote_target have been set). 49 | # @return [void] 50 | def upload 51 | if !@local_target.nil? && !@remote_target.nil? 52 | if @verbose 53 | system "#{ @dbu } upload #{ @local_target } #{ @remote_target }" 54 | else 55 | exec = `#{ @dbu } upload #{ @local_target } #{ @remote_target }` 56 | end 57 | else 58 | error_msg = 'Local and remote targets cannot be nil' 59 | @logger.error(error_msg) if @logger 60 | fail StandardError, error_msg 61 | end 62 | end 63 | end 64 | end -------------------------------------------------------------------------------- /test/date_range_maker_test.rb: -------------------------------------------------------------------------------- 1 | require 'date' 2 | require 'test_helper' 3 | require File.join(File.dirname(__FILE__), '..', 'lib/sifttter-redux/date-range-maker.rb') 4 | 5 | class DateRangeMakerTest < Test::Unit::TestCase 6 | def test_today 7 | assert_equal(SifttterRedux::DateRangeMaker.today, (Date.today..Date.today)) 8 | end 9 | 10 | def test_yesterday 11 | assert_equal(SifttterRedux::DateRangeMaker.yesterday, (Date.today - 1..Date.today - 1)) 12 | end 13 | 14 | def test_last_5_days 15 | assert_equal(SifttterRedux::DateRangeMaker.last_n_days(5), (Date.today - 5...Date.today)) 16 | end 17 | 18 | def test_last_5_days_include_today 19 | assert_equal(SifttterRedux::DateRangeMaker.last_n_days(5, true), (Date.today - 5..Date.today)) 20 | end 21 | 22 | def test_last_12_days 23 | assert_equal(SifttterRedux::DateRangeMaker.last_n_days(12), (Date.today - 12...Date.today)) 24 | end 25 | 26 | def test_last_12_days_include_today 27 | assert_equal(SifttterRedux::DateRangeMaker.last_n_days(12, true), (Date.today - 12..Date.today)) 28 | end 29 | 30 | def test_current_week 31 | end_date = Date.today - Date.today.wday + 7 32 | if end_date > Date.today 33 | end_date = Date.today 34 | end 35 | 36 | assert_equal(SifttterRedux::DateRangeMaker.last_n_weeks, (Date.today - Date.today.wday + 1...end_date)) 37 | end 38 | 39 | def test_current_week_include_today 40 | end_date = Date.today - Date.today.wday + 7 41 | if end_date > Date.today 42 | end_date = Date.today 43 | end 44 | 45 | assert_equal(SifttterRedux::DateRangeMaker.last_n_weeks(0, true), (Date.today - Date.today.wday + 1..end_date)) 46 | end 47 | 48 | def test_last_2_weeks 49 | end_date = Date.today - Date.today.wday + 7 50 | if end_date > Date.today 51 | end_date = Date.today 52 | end 53 | 54 | assert_equal(SifttterRedux::DateRangeMaker.last_n_weeks(2), (Date.today - Date.today.wday - 13...end_date)) 55 | end 56 | 57 | def test_last_2_weeks_include_today 58 | end_date = Date.today - Date.today.wday + 7 59 | if end_date > Date.today 60 | end_date = Date.today 61 | end 62 | 63 | assert_equal(SifttterRedux::DateRangeMaker.last_n_weeks(2, true), (Date.today - Date.today.wday - 13..end_date)) 64 | end 65 | 66 | def test_range_only_start_date 67 | assert_equal(SifttterRedux::DateRangeMaker.range("2014-02-01", nil), (Date.parse("2014-02-01")...Date.today)) 68 | end 69 | 70 | def test_range_only_start_date_include_today 71 | assert_equal(SifttterRedux::DateRangeMaker.range("2014-02-01", nil, true), (Date.parse("2014-02-01")..Date.today)) 72 | end 73 | 74 | def test_range_start_date_and_end_date 75 | assert_equal(SifttterRedux::DateRangeMaker.range("2014-02-01", "2014-02-05"), (Date.parse("2014-02-01")..Date.parse("2014-02-05"))) 76 | end 77 | 78 | def test_range_bad_dates 79 | assert_raise ArgumentError do 80 | SifttterRedux::DateRangeMaker.range("Bad Start Date", "Bad End Date") 81 | end 82 | end 83 | 84 | def test_range_end_date_with_no_start_date 85 | assert_raise ArgumentError do 86 | SifttterRedux::DateRangeMaker.range(nil, Date.today) 87 | end 88 | end 89 | 90 | def test_range_end_date_before_start_date 91 | assert_raise ArgumentError do 92 | SifttterRedux::DateRangeMaker.range(Date.today, Date.today - 1) 93 | end 94 | end 95 | 96 | def test_range_negative_look_back 97 | assert_raise ArgumentError do 98 | SifttterRedux::DateRangeMaker.last_n_days(-5) 99 | end 100 | end 101 | end 102 | -------------------------------------------------------------------------------- /lib/sifttter-redux/date-range-maker.rb: -------------------------------------------------------------------------------- 1 | require 'chronic' 2 | 3 | module SifttterRedux 4 | # DateRangeMaker Module 5 | # Returns a Range of dates based on supplied parameters 6 | module DateRangeMaker 7 | # Returns a date range for the last N days (including 8 | # today's date if specified). 9 | # @param [Integer} num_days The number of days to look back 10 | # @param [Boolean] include_today Should today be included? 11 | # @return [Range] 12 | def self.last_n_days(num_days, include_today = false) 13 | if num_days < 0 14 | error = 'Cannot specify a negative number of days' 15 | fail ArgumentError, error 16 | end 17 | 18 | if include_today 19 | (Date.today - num_days..Date.today) 20 | else 21 | (Date.today - num_days...Date.today) 22 | end 23 | end 24 | 25 | # Returns a date range for the last N weeks (including 26 | # today's date if specified). 27 | # @param [Integer] num_days The number of weeks to look back 28 | # @param [Boolean] include_today Should today be included? 29 | # @return [Range] 30 | def self.last_n_weeks(num_weeks = 0, include_today = false) 31 | if num_weeks < 0 32 | error = 'Cannot specify a negative number of weeks' 33 | fail ArgumentError, error 34 | end 35 | 36 | beginning_date = Date.today - Date.today.wday + 1 37 | end_date = Date.today - Date.today.wday + 7 38 | 39 | # We coerce the end date to be today if a date 40 | # greater than today has been specified. 41 | end_date = Date.today if end_date > Date.today 42 | 43 | if include_today 44 | (beginning_date - num_weeks * 7..end_date) 45 | else 46 | (beginning_date - num_weeks * 7...end_date) 47 | end 48 | end 49 | 50 | # Returns a date range for specified start dates and 51 | # end dates. Note that specifying an end date greater 52 | # than today's date will force today to be the end date. 53 | # @param [Start] start_date The start date 54 | # @param [Date] end_date The end date 55 | # @param [Hash] options Miscellaneous options 56 | # @return [Range] 57 | def self.range(start_date, end_date, include_today = false) 58 | if start_date.nil? && !end_date.nil? 59 | error = "You can't specify -t without specifying -f" 60 | fail ArgumentError, error 61 | end 62 | 63 | begin 64 | chronic_start_date = Chronic.parse(start_date).to_date 65 | rescue 66 | unless start_date.nil? 67 | error = "Invalid date provided to Chronic: #{ start_date }" 68 | fail ArgumentError, error 69 | end 70 | nil 71 | end 72 | 73 | begin 74 | chronic_end_date = Chronic.parse(end_date).to_date 75 | rescue 76 | unless end_date.nil? 77 | error = "Invalid date provided to Chronic: #{ end_date }" 78 | fail ArgumentError, error 79 | end 80 | nil 81 | end 82 | 83 | if chronic_end_date && chronic_start_date > chronic_end_date 84 | error = 'The start date must be before or equal to the end date' 85 | fail ArgumentError, error 86 | end 87 | 88 | unless chronic_start_date.nil? 89 | if chronic_end_date.nil? 90 | if include_today 91 | (chronic_start_date..Date.today) 92 | else 93 | (chronic_start_date...Date.today) 94 | end 95 | else 96 | (chronic_start_date..chronic_end_date) 97 | end 98 | end 99 | end 100 | 101 | # Returns a date range for today 102 | # @return [Range] 103 | def self.today 104 | (Date.today..Date.today) 105 | end 106 | 107 | # Returns a date range for yesterday 108 | # @return [Range] 109 | def self.yesterday 110 | (Date.today - 1..Date.today - 1) 111 | end 112 | end 113 | end 114 | -------------------------------------------------------------------------------- /lib/sifttter-redux/sifttter.rb: -------------------------------------------------------------------------------- 1 | require 'htmlentities' 2 | 3 | module SifttterRedux 4 | # Sifttter Module 5 | # Used to examine Sifttter data and create 6 | # Day One entries as necessary. 7 | module Sifttter 8 | extend self 9 | 10 | class << self 11 | # Stores the collection of entries to create. 12 | # @return [Hash] 13 | attr_accessor :entries 14 | end 15 | 16 | # Generates an ERB template for a Day One entry 17 | # @param [String] datestamp The ISO8601 datestamp 18 | # @param [String] entrytext The text of the entry 19 | # @param [Boolean] starred Whether the entry should be starred 20 | # @param [String] uuid The UUID of the entry 21 | def generate_template(datestamp, entrytext, starred, uuid) 22 | ERB.new <<-XMLTEMPLATE 23 | 24 | 25 | 26 | 27 | Creation Date 28 | <%= datestamp %> 29 | Entry Text 30 | <%= entrytext %> 31 | Starred 32 | <<%= starred %>/> 33 | Tags 34 | 35 | daily logs 36 | 37 | UUID 38 | <%= uuid %> 39 | 40 | 41 | XMLTEMPLATE 42 | end 43 | 44 | # Opens a filepath and parses it for Sifttter 45 | # data for the passed date. 46 | # @param [String] file The filepath to parse 47 | # @param [Date] date The date to search for 48 | # @return [void] 49 | def parse_sifttter_file(filepath, date) 50 | title = File.basename(filepath).gsub(/^.*?\/([^\/]+)$/, "\\1") + "\n" 51 | 52 | date_regex = /(?:#{ date.strftime("%B") } 0?#{ date.strftime("%-d") }, #{ date.strftime("%Y") })/ 53 | time_regex = /(?:\d{1,2}:\d{1,2}\s?[AaPpMm]{2})/ 54 | entry_regex = /@begin\n@date\s#{ date_regex }(?: at (#{ time_regex }?)\n)?(.*?)\n@end/m 55 | 56 | contents = File.read(filepath) 57 | cur_entries = contents.scan(entry_regex) 58 | unless cur_entries.empty? 59 | @entries.merge!(title => []) unless @entries.key?(title) 60 | cur_entries.each { |e| @entries[title] << [e[0], e[1].strip] } 61 | end 62 | end 63 | 64 | # Finds Siftter data for the passed date and 65 | # creates corresponding Day One entries. 66 | # @param [Date] date The date to search for 67 | # @return [void] 68 | def self.run(date) 69 | @entries = {} 70 | uuid = SecureRandom.uuid.upcase.gsub(/-/, '').strip 71 | date_for_title = date.strftime('%B %d, %Y') 72 | datestamp = date.to_time.utc.iso8601 73 | starred = false 74 | 75 | output_dir = configuration.sifttter_redux[:dayone_local_filepath] 76 | Dir.mkdir(output_dir) unless Dir.exists?(output_dir) 77 | 78 | files = `find #{ configuration.sifttter_redux[:sifttter_local_filepath] } -type f -name "*.txt" | grep -v -i daily | sort` 79 | if files.empty? 80 | messenger.error('No Sifttter files to parse...') 81 | messenger.error('Is Dropbox Uploader configured correctly?') 82 | messenger.error("Is #{ configuration.sifttter_redux[:sifttter_remote_filepath] } the correct remote filepath?") 83 | exit!(1) 84 | end 85 | 86 | files.split("\n").each do |file| 87 | file.strip! 88 | if File.exists?(file) 89 | parse_sifttter_file(file, date) 90 | end 91 | end 92 | 93 | if @entries.length > 0 94 | 95 | entrytext = "# Things done on #{ date_for_title }\n" 96 | @entries.each do |key, value| 97 | coder = HTMLEntities.new 98 | entrytext += '### ' + key.gsub(/.txt/, '').gsub(/_/, ' ').upcase + "\n\n" 99 | value.each { |v| entrytext += "#{ coder.encode(v[1].gsub(/%time%/, v[0])) }\n" } 100 | entrytext += "\n" 101 | end 102 | 103 | template = generate_template(datestamp, entrytext, starred, uuid) 104 | fh = File.new(File.expand_path("#{ output_dir }/#{ uuid }.doentry"), 'w+') 105 | fh.puts template.result(binding) 106 | fh.close 107 | messenger.success("Entry logged for #{ date_for_title }...") 108 | else 109 | messenger.warn("No entries found for #{ date_for_title }...") 110 | end 111 | end 112 | end 113 | end 114 | -------------------------------------------------------------------------------- /features/2.initialization.feature: -------------------------------------------------------------------------------- 1 | Feature: Initialization 2 | As a user, when I initialize Sifttter Redux, 3 | I should be guided through the process as 4 | necessary. 5 | 6 | Scenario: Basic Initialization 7 | Given no file located at "/tmp/srd/.sifttter_redux" 8 | And an empty file located at "/tmp/srd/.dropbox_uploader" 9 | When I run `srd init` interactively 10 | And I type "" 11 | And I type "/tmp/srd/sifttter_download" 12 | And I type "/Apps/ifttt/Sifttter" 13 | And I type "/tmp/srd/day_one_download" 14 | And I type "/Apps/Day\ One/Journal.dayone/entries" 15 | Then the exit status should be 0 16 | And the file "/tmp/srd/.sifttter_redux" should contain: 17 | """ 18 | --- 19 | sifttter_redux: 20 | config_location: "/tmp/srd/.sifttter_redux" 21 | log_level: WARN 22 | """ 23 | And the file "/tmp/srd/.sifttter_redux" should contain: 24 | """ 25 | sifttter_local_filepath: "/tmp/srd/sifttter_download" 26 | sifttter_remote_filepath: "/Apps/ifttt/Sifttter" 27 | dayone_local_filepath: "/tmp/srd/day_one_download" 28 | dayone_remote_filepath: "/Apps/Day\\ One/Journal.dayone/entries" 29 | db_uploader: 30 | base_filepath: "/usr/local/opt" 31 | dbu_filepath: "/usr/local/opt/Dropbox-Uploader" 32 | exe_filepath: "/usr/local/opt/Dropbox-Uploader/dropbox_uploader.sh" 33 | """ 34 | 35 | Scenario: Reinitialization (refuse) 36 | Given a file located at "/tmp/srd/.sifttter_redux" with the contents: 37 | """ 38 | --- 39 | sifttter_redux: 40 | config_location: "/tmp/srd/.sifttter_redux" 41 | log_level: WARN 42 | version: 10.0 43 | sifttter_local_filepath: "/tmp/srd/sifttter_download" 44 | sifttter_remote_filepath: "/Apps/ifttt/Sifttter" 45 | dayone_local_filepath: "/tmp/srd/day_one_download" 46 | dayone_remote_filepath: "/Apps/Day\\ One/Journal.dayone/entries" 47 | db_uploader: 48 | base_filepath: "/usr/local/opt" 49 | dbu_filepath: "/usr/local/opt/Dropbox-Uploader" 50 | exe_filepath: "/usr/local/opt/Dropbox-Uploader/dropbox_uploader.sh" 51 | """ 52 | And an empty file located at "/tmp/srd/.dropbox_uploader" 53 | When I run `srd init` interactively 54 | And I type "" 55 | Then the exit status should be 0 56 | 57 | Scenario: Reinitialization (accept) 58 | Given a file located at "/tmp/srd/.sifttter_redux" with the contents: 59 | """ 60 | --- 61 | sifttter_redux: 62 | config_location: "/tmp/srd/.sifttter_redux" 63 | log_level: WARN 64 | version: 10.0 65 | sifttter_local_filepath: "/tmp/srd/sifttter_download" 66 | sifttter_remote_filepath: "/Apps/ifttt/Sifttter" 67 | dayone_local_filepath: "/tmp/srd/day_one_download" 68 | dayone_remote_filepath: "/Apps/Day\\ One/Journal.dayone/entries" 69 | db_uploader: 70 | base_filepath: "/usr/local/opt" 71 | dbu_filepath: "/usr/local/opt/Dropbox-Uploader" 72 | exe_filepath: "/usr/local/opt/Dropbox-Uploader/dropbox_uploader.sh" 73 | """ 74 | And an empty file located at "/tmp/srd/.dropbox_uploader" 75 | When I run `srd init` interactively 76 | And I type "y" 77 | And I type "" 78 | And I type "/tmp/srd/sifttter_download2" 79 | And I type "/Apps/ifttt/Sifttter2" 80 | And I type "/tmp/srd/day_one_download2" 81 | And I type "/Apps/Day\ One/Journal.dayone/entries2" 82 | Then the exit status should be 0 83 | And the file "/tmp/srd/.sifttter_redux" should contain: 84 | """ 85 | --- 86 | sifttter_redux: 87 | config_location: "/tmp/srd/.sifttter_redux" 88 | log_level: WARN 89 | """ 90 | And the file "/tmp/srd/.sifttter_redux" should contain: 91 | """ 92 | sifttter_local_filepath: "/tmp/srd/sifttter_download2" 93 | sifttter_remote_filepath: "/Apps/ifttt/Sifttter2" 94 | dayone_local_filepath: "/tmp/srd/day_one_download2" 95 | dayone_remote_filepath: "/Apps/Day\\ One/Journal.dayone/entries2" 96 | db_uploader: 97 | base_filepath: "/usr/local/opt" 98 | dbu_filepath: "/usr/local/opt/Dropbox-Uploader" 99 | exe_filepath: "/usr/local/opt/Dropbox-Uploader/dropbox_uploader.sh" 100 | """ 101 | 102 | Scenario: Reinitialization (from scratch) 103 | Given no file located at "/tmp/srd/.sifttter_redux" 104 | And an empty file located at "/tmp/srd/.dropbox_uploader" 105 | When I run `srd init -s` interactively 106 | And I type "" 107 | And I type "/tmp/srd/sifttter_download" 108 | And I type "/Apps/ifttt/Sifttter" 109 | And I type "/tmp/srd/day_one_download" 110 | And I type "/Apps/Day\ One/Journal.dayone/entries" 111 | Then the exit status should be 0 112 | And the file "/tmp/srd/.sifttter_redux" should contain: 113 | """ 114 | --- 115 | sifttter_redux: 116 | config_location: "/tmp/srd/.sifttter_redux" 117 | log_level: WARN 118 | """ 119 | And the file "/tmp/srd/.sifttter_redux" should contain: 120 | """ 121 | sifttter_local_filepath: "/tmp/srd/sifttter_download" 122 | sifttter_remote_filepath: "/Apps/ifttt/Sifttter" 123 | dayone_local_filepath: "/tmp/srd/day_one_download" 124 | dayone_remote_filepath: "/Apps/Day\\ One/Journal.dayone/entries" 125 | db_uploader: 126 | base_filepath: "/usr/local/opt" 127 | dbu_filepath: "/usr/local/opt/Dropbox-Uploader" 128 | exe_filepath: "/usr/local/opt/Dropbox-Uploader/dropbox_uploader.sh" 129 | """ 130 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | # 1.0.5 (2014-05-19) 2 | 3 | * Small addition to show date of unfound entries 4 | 5 | # 1.0.4 (2014-05-06) 6 | 7 | * Fixed a bug where date range without and end date would incorrectly include today's date 8 | 9 | # 1.0.3 (2014-05-05) 10 | 11 | * Fixed a bug in which HTML entities from IFTTT could cause srd to fail 12 | * Bumped CLIUtils version to 2.2.3 13 | 14 | # 1.0.2 (2014-04-22) 15 | 16 | * Added `-d` flag to catch up a specific date 17 | * Added an error message for instances where Dropbox Uploader might be misconfigured 18 | * Small bugfixes 19 | 20 | # 1.0.1 (2014-04-22) 21 | 22 | * Fixed a bug in which entry titles were not being cased properly 23 | 24 | # 1.0.0 (2014-04-21) 25 | 26 | * Added new Sifttter file format (which allows for any Markdown) 27 | * Added `srd upgrade` to upgrade to new format 28 | * Lots of bugfixes 29 | 30 | # 0.6.4 (2014-04-13) 31 | 32 | * Now using Configurator's `compare_version` 33 | 34 | # 0.6.3 (2014-04-12) 35 | 36 | * Updated to CLIUtils 1.3.1 37 | * Fixed namespacing error 38 | * Fixed a bug in preference prompts 39 | 40 | # 0.6.2 (2014-04-03) 41 | 42 | * Updated to CLIUtils 1.2.1 43 | 44 | # 0.6.1 (2014-04-02) 45 | 46 | * Fixed Aruba tests 47 | 48 | # 0.6.0 (2014-04-01) 49 | 50 | * Migrated to CLIUtils 51 | 52 | # 0.5.4 (2014-03-19) 53 | 54 | * Fixed several bugs related to configuration management 55 | 56 | # 0.5.3 (2014-03-18) 57 | 58 | * Fixed regression with gemspec 59 | 60 | # 0.5.2 (2014-03-18) 61 | 62 | * New Configuration management system 63 | 64 | # 0.5.1 (2014-03-18) 65 | 66 | * Fixed a bug regarding missing Methadone references 67 | 68 | # 0.5.0 (2014-03-16) 69 | 70 | * Fixed a bug where Dropbox Uploader would fail when not in "verbose mode" 71 | 72 | # 0.4.9 (2014-03-15) 73 | 74 | * Fixed a bug with importing Logger into CLIMessage 75 | 76 | # 0.4.8 (2014-03-15) 77 | 78 | * Fixed a bug in which Sifttter Redux would ignore log level specified in config file 79 | * Made all prompt entry readline-based (for easier completion options) 80 | 81 | # 0.4.7 (2014-03-14) 82 | 83 | * Reworked logging to not require Methadone 84 | * Logging more verbose and configurable in ~/.sifttter_redux 85 | * Dropbox Uploader updates 86 | * Added support for path completion when prompting user to enter a filepath 87 | * Cleaned up error handling to be displayed to user at single point 88 | 89 | # 0.4.6 (2014-03-13) 90 | 91 | * Added new error messaaging if Sifttter remote path is invalid 92 | * Removed dependencies on exernal UUID library 93 | * Removed OS module (not needed anymore) 94 | 95 | # 0.4.5 (2014-03-01) 96 | 97 | * Added Methadone logging for prompts 98 | 99 | # 0.4.4 (2014-02-28) 100 | 101 | * Fixed a prompt error when providing Dropbox-Uploader with a bad path 102 | 103 | # 0.4.3 (2014-02-26) 104 | 105 | * Fixed regression with Dropbox-Uploader 106 | 107 | # 0.4.2 (2014-02-26) 108 | 109 | * Fixed regression with Dropbox-Uploader 110 | 111 | # 0.4.1 (2014-02-26) 112 | 113 | * Added `-s` flag to `init` command for initialization from scratch 114 | * Added gem version to config file (for reference going forward) 115 | * Added message to prompt users to re-init on upgrade 116 | 117 | # 0.4.0 (2014-02-26) 118 | 119 | * Removed some hardcoded values 120 | 121 | # 0.3.9 (2014-02-25) 122 | 123 | * Smarter checking for initialization before execution 124 | * Fixed a bug in which the config file wouldn't be properly written to 125 | 126 | # 0.3.8 (2014-02-25) 127 | 128 | * Upgraded to Methadone 1.3.2 in gemspec 129 | * Redirected all Methadone logging to file 130 | * Fixed a bug in which initailization would fail under certain circumstances 131 | * Fixed a bug in which Dropbox Uploader would fail to initialize properly 132 | 133 | # 0.3.7 (2014-02-25) 134 | 135 | * Fixed a bug in which Sifttter-Redux would fail on Ruby 2.0.0 (and potentially others) 136 | 137 | # 0.3.6 (2014-02-21) 138 | 139 | * Added logging via Methadone (key interactions logged to ~/.sifttter\_redux\_log) 140 | 141 | # 0.3.5 (2014-02-21) 142 | 143 | * Updated documentation and usage message 144 | 145 | # 0.3.4 (2014-02-21) 146 | 147 | * Automatically configure Dropbox Uploader during init (if needed) 148 | * Fixed several small bugs 149 | * Added more test cases 150 | 151 | # 0.3.3 (2014-02-20) 152 | 153 | * Fixed a bug in which the SifttterRedux module wouldn't load 154 | 155 | # 0.3.2 (2014-02-20) 156 | 157 | * Added verbose flag 158 | * Big refactorings = much nicer, more modular code 159 | * Removed dependency on colored gem 160 | 161 | # 0.3.1 162 | 163 | * Removed reliance on Rails methods for first-and-last-day-of-week calculations 164 | * Fixed a bug with the gemspec 165 | 166 | # 0.3.0 167 | 168 | * Added ability to create entries for the past N days (not just 7) 169 | * Added ability to create entries for the past N weeks 170 | * Refactorings of existing DateRangeMaker class 171 | * Additional documentation 172 | * Fixed a bug with using Chronic's language parsing using `-f` 173 | 174 | # 0.2.5 175 | 176 | * Fixed a bug where execution could prematurely halt if no Day One entries were found 177 | * Fixed a bug where re-initialization could continue, even if user declines 178 | * Updated some more help documentation 179 | * Changed messaging for initialization completion 180 | 181 | # 0.2.4 (originally 0.2.3) 182 | 183 | * Updated some help documentation 184 | * Changed message re: no entries found to a warning state 185 | 186 | # 0.2.2 187 | 188 | * Fixed a bug caused by caching of old configuration results 189 | 190 | # 0.2.1 191 | 192 | * Fixed a bug where the config manager would fail on certain platforms 193 | * Fixed a bug where the path to Dropbox Uploader became malformed 194 | 195 | # 0.2.0 196 | 197 | * Implemented catch-up mode 198 | 199 | # 0.1.0 200 | 201 | * Initial release of Sifttter Redux 202 | -------------------------------------------------------------------------------- /lib/sifttter-redux.rb: -------------------------------------------------------------------------------- 1 | require 'sifttter-redux/constants' 2 | require 'sifttter-redux/date-range-maker' 3 | require 'sifttter-redux/dropbox-uploader' 4 | require 'sifttter-redux/sifttter' 5 | 6 | # The SifttterRedux module, which wraps everything 7 | # in this gem. 8 | module SifttterRedux 9 | class << self 10 | # Stores whether initalization has completed. 11 | # @return [Boolean] 12 | attr_reader :initialized 13 | 14 | # Stores whether verbose output is turned on. 15 | # @return [Boolean] 16 | attr_accessor :verbose 17 | end 18 | 19 | # Removes temporary directories and their contents 20 | # @return [void] 21 | def self.cleanup_temp_files 22 | dirs = [ 23 | configuration.sifttter_redux[:dayone_local_filepath], 24 | configuration.sifttter_redux[:sifttter_local_filepath] 25 | ] 26 | 27 | messenger.info('Removing temporary local files...') 28 | dirs.each do |d| 29 | FileUtils.rm_rf(d) 30 | messenger.debug("Removed directory: #{ d }") 31 | end 32 | end 33 | 34 | # Runs a wizard that installs Dropbox Uploader on the 35 | # local filesystem. 36 | # @param [Boolean] from_scratch 37 | # @return [void] 38 | def self.dbu_install_wizard(from_scratch = false) 39 | valid_path_chosen = false 40 | 41 | until valid_path_chosen 42 | # Prompt the user for a location to save Dropbox Uploader. 43 | if from_scratch && !configuration.db_uploader[:base_filepath].nil? 44 | default = configuration.db_uploader[:base_filepath] 45 | else 46 | default = DEFAULT_DBU_LOCAL_FILEPATH 47 | end 48 | path = messenger.prompt('Location for Dropbox-Uploader', default) 49 | path = default if path.empty? 50 | path.chop! if path.end_with?('/') 51 | 52 | # If the entered directory exists, clone the repository. 53 | if Dir.exists?(File.expand_path(path)) 54 | valid_path_chosen = true 55 | 56 | dbu_path = File.join(path, 'Dropbox-Uploader') 57 | executable_path = File.join(dbu_path, 'dropbox_uploader.sh') 58 | 59 | if File.directory?(dbu_path) 60 | messenger.warn("Using pre-existing Dropbox Uploader at #{ dbu_path }...") 61 | else 62 | messenger.info("Downloading Dropbox Uploader to #{ dbu_path }...") 63 | system "git clone https://github.com/andreafabrizi/Dropbox-Uploader.git #{ dbu_path }" 64 | messenger.info('Done.') 65 | end 66 | 67 | # If the user has never configured Dropbox Uploader, have them do it here. 68 | unless File.exists?(DEFAULT_DBU_CONFIG_FILEPATH) 69 | messenger.info('Initializing Dropbox Uploader...') 70 | system "#{ executable_path }" 71 | end 72 | 73 | configuration.add_section(:db_uploader) unless configuration.data.key?(:db_uploader) 74 | configuration.db_uploader.merge!({ 75 | base_filepath: path, 76 | dbu_filepath: dbu_path, 77 | exe_filepath: executable_path 78 | }) 79 | else 80 | messenger.error("Sorry, but #{ path } isn't a valid directory.") 81 | end 82 | end 83 | end 84 | 85 | # Creates a date range from the supplied command line 86 | # options. 87 | # @param [Hash] options GLI command line options 88 | # @return [Range] 89 | def self.get_dates_from_options(options) 90 | if options[:c] || options[:n] || options[:w] || 91 | options[:y] || options[:f] || options[:t] || 92 | options[:d] 93 | # Yesterday 94 | r = DateRangeMaker.yesterday if options[:y] 95 | 96 | # Specific date 97 | r = DateRangeMaker.range(options[:d], options[:d]) if options[:d] 98 | 99 | # Current Week 100 | r = DateRangeMaker.last_n_weeks(0, options[:i]) if options[:c] 101 | 102 | # Last N Days 103 | r = DateRangeMaker.last_n_days(options[:n].to_i, options[:i]) if options[:n] 104 | 105 | # Last N Weeks 106 | r = DateRangeMaker.last_n_weeks(options[:w].to_i, options[:i]) if options[:w] 107 | 108 | # Custom Range 109 | if (options[:f] || options[:t]) 110 | _dates = DateRangeMaker.range(options[:f], options[:t], options[:i]) 111 | 112 | if _dates.last > Date.today 113 | messenger.warn("Ignoring overextended end date and using today's date (#{ Date.today })...") 114 | r = (_dates.first..Date.today) 115 | else 116 | r = _dates 117 | end 118 | end 119 | else 120 | r = DateRangeMaker.today 121 | end 122 | 123 | messenger.debug("Date range: #{ r }") 124 | r 125 | end 126 | 127 | # Initializes Sifttter Redux by downloading and 128 | # collecting all necessary items and info. 129 | # @param [Boolean] from_scratch 130 | # @return [void] 131 | def self.init(from_scratch = false) 132 | messenger.section('INITIALIZING...') 133 | 134 | if from_scratch 135 | configuration.reset 136 | configuration.add_section(:sifttter_redux) 137 | end 138 | 139 | configuration.sifttter_redux.merge!({ 140 | config_location: configuration.config_path, 141 | log_level: 'WARN', 142 | version: SifttterRedux::VERSION, 143 | }) 144 | 145 | # Run the wizard to download Dropbox Uploader. 146 | dbu_install_wizard(from_scratch = from_scratch) 147 | 148 | pm = CLIUtils::Prefs.new(SifttterRedux::PREF_FILES['INIT'], configuration) 149 | pm.ask 150 | configuration.ingest_prefs(pm) 151 | 152 | messenger.debug("Collected configuration values: #{ configuration.data }") 153 | configuration.save 154 | @initialized = true 155 | end 156 | 157 | # Notifies the user that the config file needs to be 158 | # re-done and does it. 159 | # @return [void] 160 | def self.update_config_file 161 | m = "This version needs to make some config changes. Don't worry; " \ 162 | "when prompted, your current values for existing config options " \ 163 | "will be presented (so it'll be easier to fly through the upgrade)." 164 | messenger.info(m) 165 | messenger.prompt('Press enter to continue') 166 | SifttterRedux.init(true) 167 | end 168 | end 169 | -------------------------------------------------------------------------------- /bin/srd: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # Encoding: utf-8 3 | #-------------------------------------------------------------------- 4 | # Sifttter Redux 5 | # 6 | # A modification of Craig Eley's Sifttter that allows for smart 7 | # installation on a standalone *NIX device (such as a Raspberry Pi). 8 | # 9 | # Sifttter copyright Craig Eley 2014 10 | # 11 | # Copyright (c) 2014 12 | # Aaron Bach 13 | # 14 | # Permission is hereby granted, free of charge, to any person 15 | # obtaining a copy of this software and associated documentation 16 | # files (the "Software"), to deal in the Software without 17 | # restriction, including without limitation the rights to use, 18 | # copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | # copies of the Software, and to permit persons to whom the 20 | # Software is furnished to do so, subject to the following 21 | # conditions: 22 | # 23 | # The above copyright notice and this permission notice shall be 24 | # included in all copies or substantial portions of the Software. 25 | # 26 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 28 | # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 30 | # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 31 | # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 32 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 33 | # OTHER DEALINGS IN THE SOFTWARE. 34 | #-------------------------------------------------------------------- 35 | require 'archive/zip' 36 | require 'cliutils' 37 | require 'gli' 38 | require 'sifttter-redux' 39 | require 'securerandom' 40 | 41 | include CLIUtils::Configuration 42 | include CLIUtils::Messaging 43 | include GLI::App 44 | 45 | # ====================================================== 46 | # App Info 47 | # ====================================================== 48 | program_desc(SifttterRedux::DESCRIPTION) 49 | version(SifttterRedux::VERSION) 50 | 51 | # ====================================================== 52 | # Global Flags and Switches 53 | # ====================================================== 54 | switch([:verbose], desc: 'Turns on verbose output') 55 | 56 | # ====================================================== 57 | # Pre, Post, and Error 58 | # ====================================================== 59 | pre do |global, command, options, args| 60 | # Load SifttterRedux configuration module. 61 | load_configuration(SifttterRedux::DEFAULT_SRD_CONFIG_FILEPATH) 62 | file_logger = Logger.new(SifttterRedux::DEFAULT_SRD_LOG_FILEPATH) 63 | file_logger.level = LOG_LEVELS[configuration.sifttter_redux[:log_level] || 'DEBUG'] 64 | messenger.attach(LOGFILE: file_logger) 65 | 66 | if File.exists?(SifttterRedux::DEFAULT_SRD_CONFIG_FILEPATH) 67 | # Set the current and last config versions in the Configurator. 68 | configuration.current_version = configuration.sifttter_redux[:version] 69 | configuration.last_version = SifttterRedux::NEWEST_CONFIG_VERSION 70 | 71 | # Compare the two versions and, if needed, update. 72 | configuration.compare_version do |c, l| 73 | messenger.debug("Upgrading from #{ c } to #{ l }") 74 | SifttterRedux.update_config_file 75 | exit!(0) 76 | end 77 | else 78 | # Force the user to init if they try to run any command other than `init` first. 79 | messenger.info('You need to initialize Sifttter Redux first!') 80 | SifttterRedux.init(true) 81 | exit!(0) 82 | end 83 | true 84 | end 85 | 86 | post do |global,command,options,args| 87 | # Post logic here 88 | # Use skips_post before a command to skip this 89 | # block on that command only 90 | end 91 | 92 | on_error do |exception| 93 | messenger.error(exception.to_s) 94 | exit!(1) 95 | true 96 | end 97 | 98 | # ====================================================== 99 | # Commands 100 | # ====================================================== 101 | # ------------------------------------------------------ 102 | # exec command 103 | # 104 | # Executes the app. 105 | # ------------------------------------------------------ 106 | desc 'Execute the app' 107 | command :exec do |c| 108 | c.flag([:d], desc: 'Run catch-up mode with a particular date') 109 | c.flag([:f], desc: 'Run catch-up mode with this start date') 110 | c.flag([:n], desc: 'Run catch-up mode for the last N days') 111 | c.flag([:t], desc: 'Run catch-up mode with this end date (must also have -f)') 112 | c.flag([:w], desc: 'Run catch-up mode for the last N weeks') 113 | 114 | c.switch([:c], desc: 'Run catch-up mode from the beginning of the week to yesterday') 115 | c.switch([:i], desc: "Include today's date in catch-up") 116 | c.switch([:verbose], desc: 'Turns on verbose output') 117 | c.switch([:y], desc: 'Run catch-up mode for yesterday') 118 | 119 | c.action do |global_options, options, args| 120 | SifttterRedux.verbose = global_options[:verbose] || options[:verbose] 121 | 122 | dates = SifttterRedux::get_dates_from_options(options) 123 | unless dates.nil? 124 | first_date = dates.first 125 | second_date = dates.reverse_each.first 126 | 127 | date_string = first_date.strftime('%B %d, %Y') 128 | date_string << " to #{ second_date.strftime('%B %d, %Y') }" if first_date != second_date 129 | messenger.info("Creating #{ first_date == second_date ? 'entry' : 'entries' }: #{ date_string }") 130 | 131 | # Download Sifttter files from Dropbox. 132 | dbu = SifttterRedux::DropboxUploader.new(configuration.db_uploader[:exe_filepath]) 133 | dbu.verbose = SifttterRedux.verbose 134 | dbu.local_target = configuration.sifttter_redux[:sifttter_local_filepath] 135 | dbu.remote_target = configuration.sifttter_redux[:sifttter_remote_filepath] 136 | dbu.message = 'Downloading Sifttter files...' 137 | 138 | messenger.info(dbu.message || dbu::DEFAULT_MESSAGE) 139 | dbu.download 140 | messenger.info('Done.') 141 | 142 | # Process a new Sifttter entry for each date. 143 | dates.each do |date| 144 | SifttterRedux::Sifttter.run(date) 145 | end 146 | 147 | # Upload any Day One entries to Dropbox (if there are any). 148 | unless Dir[configuration.sifttter_redux[:dayone_local_filepath] + '/*'].empty? 149 | dbu.local_target = "#{ configuration.sifttter_redux[:dayone_local_filepath] }/*" 150 | dbu.remote_target = configuration.sifttter_redux[:dayone_remote_filepath] 151 | dbu.message = 'Uploading Day One entries to Dropbox...' 152 | 153 | messenger.info(dbu.message || dbu::DEFAULT_MESSAGE) 154 | dbu.upload 155 | messenger.info('Done.') 156 | end 157 | 158 | # Remove any downloaded local files that we no longer need. 159 | SifttterRedux.cleanup_temp_files 160 | end 161 | end 162 | 163 | end 164 | 165 | # ------------------------------------------------------ 166 | # init command 167 | # 168 | # Initializes the app by asking the user for information 169 | # needed torun. 170 | # ------------------------------------------------------ 171 | desc 'Install and initialize dependencies' 172 | command :init do |c| 173 | c.switch([:s], desc: 'Run init from scratch (i.e., clear out all values from configuration)') 174 | c.action do |global_options, options, args| 175 | if options[:s] 176 | SifttterRedux::init(true) 177 | else 178 | long_message = "You've already initialized Sifttter Redux. Do it again?" 179 | SifttterRedux::init if messenger.prompt(long_message, 'N').downcase == 'y' 180 | end 181 | end 182 | end 183 | 184 | # ------------------------------------------------------ 185 | # upgrade command 186 | # 187 | # Upgrades existing Sifttter files to the format needed 188 | # by v 1.x.x. 189 | # ------------------------------------------------------ 190 | desc 'Upgrades Sifttter files to the new format' 191 | command :upgrade do |c| 192 | c.switch([:verbose], desc: 'Turns on verbose output') 193 | c.action do |global_options, options, args| 194 | SifttterRedux.verbose = global_options[:verbose] || options[:verbose] 195 | 196 | # Set the archive filepath and the files that will go into it. 197 | filename = "#{ ENV['HOME'] }/sifttter_backup_#{ Time.now.to_i }.zip" 198 | 199 | # Download Sifttter files from Dropbox. 200 | dbu = SifttterRedux::DropboxUploader.new(configuration.db_uploader[:exe_filepath]) 201 | dbu.verbose = SifttterRedux.verbose 202 | dbu.local_target = configuration.sifttter_redux[:sifttter_local_filepath] 203 | dbu.remote_target = configuration.sifttter_redux[:sifttter_remote_filepath] 204 | dbu.message = "Backing up Sifttter files to #{ filename }..." 205 | 206 | messenger.info(dbu.message || dbu::DEFAULT_MESSAGE) 207 | dbu.download 208 | messenger.info('Done.') 209 | 210 | # Archive the Sifttter files. 211 | Archive::Zip.archive(filename, configuration.sifttter_redux[:sifttter_local_filepath]) 212 | 213 | # Replace the old scheme with the new one. 214 | Dir.glob(configuration.sifttter_redux[:sifttter_local_filepath] + '/*.txt').each do |file| 215 | t = File.read(file) 216 | t.gsub!(/^- /, "@begin\n@date ") 217 | t.gsub!(/ - /, "\n- ") 218 | t.gsub!(/\s?@done/, '@end') 219 | messenger.debug("Replacing contents of file: #{ file }") 220 | File.open(file, 'w') { |f| f.write(t) } 221 | end 222 | 223 | # Upload the new Sifttter files back to Dropbox. 224 | dbu.local_target = "#{ configuration.sifttter_redux[:sifttter_local_filepath] }" 225 | dbu.remote_target = Pathname.new(configuration.sifttter_redux[:sifttter_remote_filepath]).dirname.to_s 226 | dbu.message = "Uploading revised Sifttter files to Dropbox..." 227 | 228 | messenger.info(dbu.message || dbu::DEFAULT_MESSAGE) 229 | dbu.upload 230 | messenger.info('Done.') 231 | 232 | # Remove any downloaded local files that we no longer need. 233 | SifttterRedux.cleanup_temp_files 234 | end 235 | end 236 | 237 | # ====================================================== 238 | # Run! 239 | # ====================================================== 240 | exit run(ARGV) 241 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Sifttter Redux 2 | ============== 3 | [![Build Status](https://travis-ci.org/bachya/Sifttter-Redux.svg?branch=master)](https://travis-ci.org/bachya/Sifttter-Redux) 4 | [![Gem Version](https://badge.fury.io/rb/sifttter-redux.svg)](http://badge.fury.io/rb/sifttter-redux) 5 | 6 | # Upgrading From 0.x.x to 1.0.0? 7 | 8 | Make sure you read the [IFTTT Template](#ifttt-template) section. 9 | 10 | # Intro 11 | 12 | Siftter Redux is a modification of Craig Eley's 13 | [Sifttter](http://craigeley.com/post/72565974459/sifttter-an-ifttt-to-day-one-logger "Sifttter"), 14 | a script to collect information from [IFTTT](http://www.ifttt.com "IFTTT") and 15 | place it in a [Day One](http://dayoneapp.com, "Day One") journal. 16 | 17 | Siftter Redux has several fundamental differences: 18 | 19 | * Interactive logging of today's events or events in the past 20 | * "Catch Up" mode for logging several days' events at once 21 | * Packaged as a command line app, complete with documentation and help 22 | * Easy installation on cron for automated running 23 | 24 | # Prerequisites 25 | 26 | In addition to Git (which, given you being on this site, I'll assume you have), 27 | Ruby (v. 1.9.3 or greater) is needed. 28 | 29 | # Installation 30 | 31 | ``` 32 | gem install sifttter-redux 33 | ``` 34 | 35 | # Usage 36 | 37 | Syntax and usage can be accessed by running `srd help`: 38 | 39 | ``` 40 | $ srd help 41 | NAME 42 | srd - Sifttter Redux 43 | 44 | A customized IFTTT-to-Day One service that allows for 45 | smart installation and automated running on a standalone 46 | *NIX device (such as a Raspberry Pi). 47 | 48 | SYNOPSIS 49 | srd [global options] command [command options] [arguments...] 50 | 51 | VERSION 52 | 1.0.6 53 | 54 | GLOBAL OPTIONS 55 | --help - Show this message 56 | --[no-]verbose - Turns on verbose output 57 | --version - Display the program version 58 | 59 | COMMANDS 60 | exec - Execute the script 61 | help - Shows a list of commands or help for one command 62 | init - Install and initialize dependencies 63 | ``` 64 | 65 | Note that each command's options can be revealed by adding the `--help` switch 66 | after the command. For example: 67 | 68 | ``` 69 | $ srd exec --help 70 | NAME 71 | exec - Execute the script 72 | 73 | SYNOPSIS 74 | srd [global options] exec [command options] 75 | 76 | COMMAND OPTIONS 77 | -c - Run catch-up mode from the beginning of the week to yesterday 78 | -f arg - Run catch-up mode with this start date (default: none) 79 | -i - Include today's date in catch-up 80 | -n arg - Run catch-up mode for the last N days (default: none) 81 | -t arg - Run catch-up mode with this end date (must also have -f) (default: none) 82 | --[no-]verbose - Turns on verbose output 83 | -w arg - Run catch-up mode for the last N weeks (default: none) 84 | -y - Run catch-up mode for yesterday 85 | ``` 86 | 87 | ## IFTTT Template 88 | 89 | Version 1.0.0+ uses a new schema that allows for any type of Markdown. Thus, Sifttter 90 | files from IFTTT need to follow this format: 91 | 92 | ``` 93 | @begin 94 | @date April 21, 2014 at 12:34PM 95 | **Any** sort of *Markdown* goes here... 96 | @end 97 | ``` 98 | 99 | Whereas the previous Sifttter Redux only allowed output of bulleted lists, this new 100 | template style allows you to include *any* Markdown, making output like tables possibe. 101 | 102 | ### Upgrade Command 103 | 104 | Note that a new command has been introduced that attempts to upgrade to this 105 | new format. **Although the command backs up your current Sifttter files, you 106 | are strongly encouraged to make a separate, manual backup.** 107 | 108 | ```Bash 109 | $ srd upgrade 110 | ``` 111 | 112 | ### Template Tokens 113 | 114 | IFTTT templates can make use of the following tokens: 115 | 116 | * `%time%`: the time the entry was created 117 | 118 | As an example, to include the entry time in a template: 119 | 120 | ``` 121 | @begin 122 | @date April 21, 2014 at 12:34PM 123 | - %time%: My text goes here... 124 | @end 125 | ``` 126 | 127 | ## Initialization 128 | 129 | ``` 130 | $ srd init 131 | ``` 132 | 133 | Initialization will perform the following steps: 134 | 135 | 1. Download [Dropbox Uploader](https://github.com/andreafabrizi/Dropbox-Uploader "Dropbox-Uploder") 136 | to a location of your choice. 137 | 2. Automatically configure Dropbox Uploader. 138 | 3. Collect some user paths (note that you can use tab completion here!): 139 | * The location on your filesystem where Sifttter files will be temporarily stored 140 | * The location of your Sifttter files in Dropbox 141 | * The location on your filesystem where Day One files will be temporarily stored 142 | * The location of your Day One files in Dropbox 143 | 144 | ## Pathing 145 | 146 | Note that when Sifttter Redux asks you for paths, it will ask for "local" and 147 | "remote" filepaths. It's important to understand the difference. 148 | 149 | ### Local Filepaths 150 | 151 | Local filepaths are, as you'd expect, filepaths on your local machine. Some 152 | examples might be: 153 | 154 | * `/tmp/my_data` 155 | * `/home/bob/ifttt/sifttter_data` 156 | * `~/sifttter` 157 | 158 | ### Remote Filepaths 159 | 160 | Remote filepaths, on the other hand, are absolute filepaths in your Dropbox 161 | folder (*as Dropbox Uploader would see them*). For instance, 162 | `/home/bob/Dropbox/apps/sifttter` is *not* a valid remote filepath; rather, 163 | `/apps/sifttter` would be correct. 164 | 165 | ## Basic Execution 166 | 167 | ``` 168 | $ srd exec 169 | #### EXECUTING... 170 | ---> INFO: Creating entry for February 15, 2014... 171 | ---> INFO: Downloading Sifttter files...DONE. 172 | ---> SUCCESS: Entry logged for February 15, 2014... 173 | ---> INFO: Uploading Day One entries to Dropbox...DONE. 174 | ---> INFO: Removing downloaded Day One files...DONE. 175 | ---> INFO: Removing downloaded Sifttter files...DONE. 176 | #### EXECUTION COMPLETE! 177 | ``` 178 | 179 | ## "Catch-up" Mode 180 | 181 | Sometimes, events occur that prevent Sifttter Redux from running (power loss to 182 | your device, a bad Cron job, etc.). In this case, Sifttter Redux's "catch-up" 183 | mode can be used to collect any valid journal on or before today's date. 184 | 185 | There are many ways to use this mode (note that "today" in these examples is 186 | **February 15, 2014**): 187 | 188 | ### Yesterday Catch-up 189 | 190 | To create an entry for yesterday: 191 | 192 | ``` 193 | $ srd exec -y 194 | #### EXECUTING... 195 | ---> INFO: Creating entry for February 14, 2014... 196 | ---> INFO: Downloading Sifttter files...DONE. 197 | ---> SUCCESS: Entry logged for February 14, 2014... 198 | ---> INFO: Uploading Day One entries to Dropbox...DONE. 199 | ---> INFO: Removing downloaded Day One files...DONE. 200 | ---> INFO: Removing downloaded Sifttter files...DONE. 201 | #### EXECUTION COMPLETE! 202 | ``` 203 | 204 | ### Catch-up for a Specific Date 205 | 206 | To create an entry for specific date: 207 | 208 | ``` 209 | $ srd exec -d 2014-02-14 210 | #### EXECUTING... 211 | ---> INFO: Creating entry for February 14, 2014... 212 | ---> INFO: Downloading Sifttter files...DONE. 213 | ---> SUCCESS: Entry logged for February 14, 2014... 214 | ---> INFO: Uploading Day One entries to Dropbox...DONE. 215 | ---> INFO: Removing downloaded Day One files...DONE. 216 | ---> INFO: Removing downloaded Sifttter files...DONE. 217 | #### EXECUTION COMPLETE! 218 | ``` 219 | 220 | ### Last "N" Days Catch-up 221 | 222 | Sifttter Redux allows you to specify the number of days back it should look for 223 | new entries: 224 | 225 | ``` 226 | $ srd exec -n 3 227 | #### EXECUTING... 228 | ---> INFO: Creating entries for dates from February 12, 2014 to February 14, 2014... 229 | ---> INFO: Downloading Sifttter files...DONE. 230 | ---> SUCCESS: Entry logged for February 12, 2014... 231 | ---> SUCCESS: Entry logged for February 13, 2014... 232 | ---> SUCCESS: Entry logged for February 14, 2014... 233 | ---> INFO: Uploading Day One entries to Dropbox...DONE. 234 | ---> INFO: Removing downloaded Day One files...DONE. 235 | ---> INFO: Removing downloaded Sifttter files...DONE. 236 | #### EXECUTION COMPLETE! 237 | 238 | $ srd exec -n 12 239 | #### EXECUTING... 240 | ---> INFO: Creating entries for dates from February 03, 2014 to February 14, 2014... 241 | ---> INFO: Downloading Sifttter files...DONE. 242 | ---> SUCCESS: February 03, 2014... 243 | ---> SUCCESS: February 04, 2014... 244 | ---> SUCCESS: February 05, 2014... 245 | ---> SUCCESS: February 06, 2014... 246 | ---> SUCCESS: February 07, 2014... 247 | ---> SUCCESS: February 08, 2014... 248 | ---> SUCCESS: February 09, 2014... 249 | ---> SUCCESS: February 10, 2014... 250 | ---> SUCCESS: February 11, 2014... 251 | ---> SUCCESS: February 12, 2014... 252 | ---> SUCCESS: February 13, 2014... 253 | ---> SUCCESS: February 14, 2014... 254 | ---> INFO: Uploading Day One entries to Dropbox...DONE. 255 | ---> INFO: Removing downloaded Day One files...DONE. 256 | ---> INFO: Removing downloaded Sifttter files...DONE. 257 | #### EXECUTION COMPLETE! 258 | ``` 259 | 260 | Note that this option goes until yesterday ("yesterday" because you might not be 261 | ready to have today's entries scanned). If you'd rather include today's date, you 262 | can always add the `-i` switch: 263 | 264 | ``` 265 | $ srd exec -i -n 3 266 | #### EXECUTING... 267 | ---> INFO: Creating entries for dates from February 12, 2014 to February 15, 2014... 268 | ---> INFO: Downloading Sifttter files...DONE. 269 | ---> SUCCESS: Entry logged for February 12, 2014... 270 | ---> SUCCESS: Entry logged for February 13, 2014... 271 | ---> SUCCESS: Entry logged for February 14, 2014... 272 | ---> SUCCESS: Entry logged for February 15, 2014... 273 | ---> INFO: Uploading Day One entries to Dropbox...DONE. 274 | ---> INFO: Removing downloaded Day One files...DONE. 275 | ---> INFO: Removing downloaded Sifttter files...DONE. 276 | #### EXECUTION COMPLETE! 277 | ``` 278 | 279 | ### Last "N" Weeks Catch-up 280 | 281 | Sifttter Redux also allows you to specify a number of weeks back that should be 282 | scanned for new entries: 283 | 284 | ``` 285 | $ srd exec -w 1 286 | #### EXECUTING... 287 | ---> INFO: Creating entries for dates from February 03, 2014 to February 14, 2014... 288 | ---> INFO: Downloading Sifttter files...DONE. 289 | ---> SUCCESS: Entry logged for February 03, 2014... 290 | ---> SUCCESS: Entry logged for February 04, 2014... 291 | ---> SUCCESS: Entry logged for February 05, 2014... 292 | ---> SUCCESS: Entry logged for February 06, 2014... 293 | ---> SUCCESS: Entry logged for February 07, 2014... 294 | ---> SUCCESS: Entry logged for February 08, 2014... 295 | ---> SUCCESS: Entry logged for February 09, 2014... 296 | ---> SUCCESS: Entry logged for February 10, 2014... 297 | ---> SUCCESS: Entry logged for February 11, 2014... 298 | ---> SUCCESS: Entry logged for February 12, 2014... 299 | ---> SUCCESS: Entry logged for February 13, 2014... 300 | ---> SUCCESS: Entry logged for February 14, 2014... 301 | ---> INFO: Uploading Day One entries to Dropbox...DONE. 302 | ---> INFO: Removing downloaded Day One files...DONE. 303 | ---> INFO: Removing downloaded Sifttter files...DONE. 304 | #### EXECUTION COMPLETE! 305 | 306 | $ srd exec -w 3 307 | #### EXECUTING... 308 | ---> INFO: Creating entries for dates from January 20, 2014 to February 14, 2014... 309 | ---> INFO: Downloading Sifttter files...DONE. 310 | ---> SUCCESS: Entry logged for January 20, 2014... 311 | ---> SUCCESS: Entry logged for January 21, 2014... 312 | ---> SUCCESS: Entry logged for January 22, 2014... 313 | ---> SUCCESS: Entry logged for January 23, 2014... 314 | ---> SUCCESS: Entry logged for January 24, 2014... 315 | ---> SUCCESS: Entry logged for January 25, 2014... 316 | ---> SUCCESS: Entry logged for January 26, 2014... 317 | ---> SUCCESS: Entry logged for January 27, 2014... 318 | ---> SUCCESS: Entry logged for January 28, 2014... 319 | ---> SUCCESS: Entry logged for January 29, 2014... 320 | ---> SUCCESS: Entry logged for January 30, 2014... 321 | ---> SUCCESS: Entry logged for January 31, 2014... 322 | ---> SUCCESS: Entry logged for February 01, 2014... 323 | ---> SUCCESS: Entry logged for February 02, 2014... 324 | ---> SUCCESS: Entry logged for February 03, 2014... 325 | ---> SUCCESS: Entry logged for February 04, 2014... 326 | ---> SUCCESS: Entry logged for February 05, 2014... 327 | ---> SUCCESS: Entry logged for February 06, 2014... 328 | ---> SUCCESS: Entry logged for February 07, 2014... 329 | ---> SUCCESS: Entry logged for February 08, 2014... 330 | ---> SUCCESS: Entry logged for February 09, 2014... 331 | ---> SUCCESS: Entry logged for February 10, 2014... 332 | ---> SUCCESS: Entry logged for February 11, 2014... 333 | ---> SUCCESS: Entry logged for February 12, 2014... 334 | ---> SUCCESS: Entry logged for February 13, 2014... 335 | ---> SUCCESS: Entry logged for February 14, 2014... 336 | ---> INFO: Uploading Day One entries to Dropbox...DONE. 337 | ---> INFO: Removing downloaded Day One files...DONE. 338 | ---> INFO: Removing downloaded Sifttter files...DONE. 339 | #### EXECUTION COMPLETE! 340 | ``` 341 | 342 | As you'd expect, you can always add the `-i` switch: 343 | 344 | ``` 345 | $ srd exec -i -w 1 346 | #### EXECUTING... 347 | ---> INFO: Creating entries for dates from February 03, 2014 to February 15, 2014... 348 | ---> INFO: Downloading Sifttter files...DONE. 349 | ---> SUCCESS: Entry logged for February 03, 2014... 350 | ---> SUCCESS: Entry logged for February 04, 2014... 351 | ---> SUCCESS: Entry logged for February 05, 2014... 352 | ---> SUCCESS: Entry logged for February 06, 2014... 353 | ---> SUCCESS: Entry logged for February 07, 2014... 354 | ---> SUCCESS: Entry logged for February 08, 2014... 355 | ---> SUCCESS: Entry logged for February 09, 2014... 356 | ---> SUCCESS: Entry logged for February 10, 2014... 357 | ---> SUCCESS: Entry logged for February 11, 2014... 358 | ---> SUCCESS: Entry logged for February 12, 2014... 359 | ---> SUCCESS: Entry logged for February 13, 2014... 360 | ---> SUCCESS: Entry logged for February 14, 2014... 361 | ---> SUCCESS: Entry logged for February 15, 2014... 362 | ---> INFO: Uploading Day One entries to Dropbox...DONE. 363 | ---> INFO: Removing downloaded Day One files...DONE. 364 | ---> INFO: Removing downloaded Sifttter files...DONE. 365 | #### EXECUTION COMPLETE! 366 | ``` 367 | 368 | ### Date Range Catch-up 369 | 370 | To create entries for a range of dates: 371 | 372 | ``` 373 | $ srd exec -f 2014-02-01 -t 2014-02-12 374 | #### EXECUTING... 375 | ---> INFO: Creating entries for dates from February 01, 2014 to February 12, 2014... 376 | ---> INFO: Downloading Sifttter files...DONE. 377 | ---> SUCCESS: Entry logged for February 01, 2014... 378 | ---> SUCCESS: Entry logged for February 02, 2014... 379 | ---> SUCCESS: Entry logged for February 03, 2014... 380 | ---> SUCCESS: Entry logged for February 04, 2014... 381 | ---> SUCCESS: Entry logged for February 05, 2014... 382 | ---> SUCCESS: Entry logged for February 06, 2014... 383 | ---> SUCCESS: Entry logged for February 07, 2014... 384 | ---> SUCCESS: Entry logged for February 08, 2014... 385 | ---> SUCCESS: Entry logged for February 09, 2014... 386 | ---> SUCCESS: Entry logged for February 10, 2014... 387 | ---> SUCCESS: Entry logged for February 11, 2014... 388 | ---> SUCCESS: Entry logged for February 12, 2014... 389 | ---> INFO: Uploading Day One entries to Dropbox...DONE. 390 | ---> INFO: Removing downloaded Day One files...DONE. 391 | ---> INFO: Removing downloaded Sifttter files...DONE. 392 | #### EXECUTION COMPLETE! 393 | ``` 394 | 395 | Even more simply, to create entries from a specific point until yesterday 396 | ("yesterday" because you might not be ready to have today's entries scanned): 397 | 398 | ``` 399 | $ srd exec -f 2014-02-01 400 | #### EXECUTING... 401 | ---> INFO: Creating entries for dates from February 01, 2014 to February 12, 2014... 402 | ---> INFO: Downloading Sifttter files...DONE. 403 | ---> SUCCESS: Entry logged for February 01, 2014... 404 | ---> SUCCESS: Entry logged for February 02, 2014... 405 | ---> SUCCESS: Entry logged for February 03, 2014... 406 | ---> SUCCESS: Entry logged for February 04, 2014... 407 | ---> SUCCESS: Entry logged for February 05, 2014... 408 | ---> SUCCESS: Entry logged for February 06, 2014... 409 | ---> SUCCESS: Entry logged for February 07, 2014... 410 | ---> SUCCESS: Entry logged for February 08, 2014... 411 | ---> SUCCESS: Entry logged for February 09, 2014... 412 | ---> SUCCESS: Entry logged for February 10, 2014... 413 | ---> SUCCESS: Entry logged for February 11, 2014... 414 | ---> SUCCESS: Entry logged for February 12, 2014... 415 | ---> INFO: Uploading Day One entries to Dropbox...DONE. 416 | ---> INFO: Removing downloaded Day One files...DONE. 417 | ---> INFO: Removing downloaded Sifttter files...DONE. 418 | #### EXECUTION COMPLETE! 419 | ``` 420 | 421 | In this case, once more, you can use the trusty `-i` switch if you want: 422 | 423 | ``` 424 | $ srd exec -i -f 2014-02-01 425 | #### EXECUTING... 426 | ---> INFO: Creating entries for dates from February 01, 2014 to February 15, 2014... 427 | ---> INFO: Downloading Sifttter files...DONE. 428 | ---> SUCCESS: Entry logged for February 01, 2014... 429 | ---> SUCCESS: Entry logged for February 02, 2014... 430 | ---> SUCCESS: Entry logged for February 03, 2014... 431 | ---> SUCCESS: Entry logged for February 04, 2014... 432 | ---> SUCCESS: Entry logged for February 05, 2014... 433 | ---> SUCCESS: Entry logged for February 06, 2014... 434 | ---> SUCCESS: Entry logged for February 07, 2014... 435 | ---> SUCCESS: Entry logged for February 08, 2014... 436 | ---> SUCCESS: Entry logged for February 09, 2014... 437 | ---> SUCCESS: Entry logged for February 10, 2014... 438 | ---> SUCCESS: Entry logged for February 11, 2014... 439 | ---> SUCCESS: Entry logged for February 12, 2014... 440 | ---> SUCCESS: Entry logged for February 13, 2014... 441 | ---> SUCCESS: Entry logged for February 14, 2014... 442 | ---> SUCCESS: Entry logged for February 15, 2014... 443 | ---> INFO: Uploading Day One entries to Dropbox...DONE. 444 | ---> INFO: Removing downloaded Day One files...DONE. 445 | ---> INFO: Removing downloaded Sifttter files...DONE. 446 | #### EXECUTION COMPLETE! 447 | ``` 448 | 449 | Two notes to be aware of: 450 | 451 | * `-f` and `-t` are *inclusive* parameters, meaning that when specified, those 452 | dates will be included when searching for Siftter data. 453 | * Although you can specify `-f` by itself, you cannot specify `-t` by itself. 454 | 455 | Sifttter Redux makes use of the excellent 456 | [Chronic gem](https://github.com/mojombo/chronic "Chronic"), which provides 457 | natural language parsing for dates and times. This means that you can run 458 | commands with more "human" dates: 459 | 460 | ``` 461 | $ srd exec -f "last monday" -t "yesterday" 462 | #### EXECUTING... 463 | ---> INFO: Creating entries for dates from February 10, 2014 to February 14, 2014... 464 | ---> INFO: Downloading Sifttter files...DONE. 465 | ---> SUCCESS: Entry logged for February 10, 2014... 466 | ---> SUCCESS: Entry logged for February 11, 2014... 467 | ---> SUCCESS: Entry logged for February 12, 2014... 468 | ---> SUCCESS: Entry logged for February 13, 2014... 469 | ---> SUCCESS: Entry logged for February 14, 2014... 470 | ---> INFO: Uploading Day One entries to Dropbox...DONE. 471 | ---> INFO: Removing downloaded Day One files...DONE. 472 | ---> INFO: Removing downloaded Sifttter files...DONE. 473 | #### EXECUTION COMPLETE! 474 | ``` 475 | 476 | See [Chronic's Examples section](https://github.com/mojombo/chronic#examples "Chronic Examples") 477 | for more examples. 478 | 479 | # Cron Job 480 | 481 | By installing an entry to a `crontab`, Sifttter Redux can be run automatically 482 | on a schedule. The aim of this project was to use a Raspberry Pi; as such, the 483 | instructions below are specifically catered to that platform. That said, it 484 | should be possible to install and configure on any *NIX platform. 485 | 486 | One issue that arises is the loading of the bundled gems; because cron runs in a 487 | limited environment, it does not automatically know where to find installed gems. 488 | 489 | ## Using RVM 490 | 491 | If your Raspberry Pi uses RVM, this `crontab` entry will do: 492 | 493 | ``` 494 | 55 23 * * * /bin/bash -l -c 'source "$HOME/.rvm/scripts/rvm" && srd exec' 495 | ``` 496 | 497 | ## Globally Installing Bundled Gems 498 | 499 | Another option is to install the bundled gems to the global gemset: 500 | 501 | ``` 502 | $ bundle install --global 503 | ``` 504 | 505 | # Logging 506 | 507 | Sifttter Redux logs a lot of good info to `~/.sifttter_redux_log`. It makes use 508 | of Ruby's standard log levels: 509 | 510 | * DEBUG 511 | * INFO 512 | * WARN 513 | * ERROR 514 | * FATAL 515 | * UNKNOWN 516 | 517 | If you want to see more or less in your log files, simply change the `log_level` 518 | value in `~/.sifttter_redux` to your desired level. 519 | 520 | # Bugs and Feature Requests 521 | 522 | My current roadmap can be found on my 523 | [Trello board](https://trello.com/b/z4vl3YxC/sifttter-redux "Sifttter Redux Trello Board"). 524 | 525 | To report bugs with or suggest features/changes for Sifttter Redux, please use 526 | the [Issues Page](http://github.com/bachya/sifttter-redux/issues). 527 | 528 | Contributions are welcome and encouraged. To contribute: 529 | 530 | * [Fork Sifttter Redux](http://github.com/bachya/sifttter-redux/fork). 531 | * Create a branch for your contribution (`git checkout -b new-feature`). 532 | * Commit your changes (`git commit -am 'Added this new feature'`). 533 | * Push to the branch (`git push origin new-feature`). 534 | * Create a new [Pull Request](http://github.com/bachya/sifttter-redux/compare/). 535 | 536 | # License 537 | 538 | (The MIT License) 539 | 540 | Copyright © 2014 Aaron Bach 541 | 542 | Permission is hereby granted, free of charge, to any person obtaining a copy of 543 | this software and associated documentation files (the 'Software'), to deal in the 544 | Software without restriction, including without limitation the rights to use, 545 | copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 546 | Software, and to permit persons to whom the Software is furnished to do so, 547 | subject to the following conditions: 548 | 549 | The above copyright notice and this permission notice shall be included in all 550 | copies or substantial portions of the Software. 551 | 552 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 553 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 554 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 555 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 556 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 557 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 558 | 559 | # Credits 560 | 561 | * Craig Eley for [Sifttter](http://craigeley.com/post/72565974459/sifttter-an-ifttt-to-day-one-logger "Sifttter") 562 | and for giving me the idea for Sifttter Redux 563 | * Dave Copeland for [GLI](https://github.com/davetron5000/gli "GLI") 564 | * Andrea Fabrizi for [Dropbox Uploader](https://github.com/andreafabrizi/Dropbox-Uploader "Dropbox Uploader") 565 | * ~~Tom Preston-Werner~~ (sorry: can't 566 | support [harrassment](http://www.businessinsider.com/github-co-founder-suspended-2014-3 "GitHub Founder Tom Preston-Werner Suspended After Harassment Allegations")) 567 | ~~and~~ Lee Jarvis for [Chronic](https://github.com/mojombo/chronic "Chronic") 568 | --------------------------------------------------------------------------------