-
-
Notifications
You must be signed in to change notification settings - Fork 40
/
friends
executable file
·119 lines (94 loc) · 3.26 KB
/
friends
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/usr/bin/env ruby
# frozen_string_literal: true
if ENV["TRAVIS"] == "true" && ENV["CODE_COVERAGE"] == "true"
require "simplecov"
SimpleCov.print_error_status = false
SimpleCov.formatter = SimpleCov::Formatter::SimpleFormatter
SimpleCov.command_name Process.pid.to_s
SimpleCov.start
end
require "gli"
require "paint"
require "readline"
require "semverse"
require "friends/introvert"
require "friends/version"
include GLI::App # rubocop:disable Style/MixinUsage
program_desc "Spend time with the people you care about. Introvert-tested. "\
"Extrovert-approved."
version Friends::VERSION
subcommand_option_handling :normal
arguments :strict
class Tag
# @param str [String] of the form "tag" or "@tag"
# @return [String] the string, with whitespace stripped and a tag
# prepended if there isn't one already
# NOTE: This logic could be only in the accept block if GLI allowed type
# conversions for arguments.
# See: https://github.com/davetron5000/gli/issues/241
def self.convert_to_tag(str)
str = str.strip
!str.empty? && str[0] == "@" ? str : "@#{str}"
end
end
accept(Tag) do |value|
Tag.convert_to_tag(value)
end
class Stripped; end
accept(Stripped, &:strip)
class InputDate; end
accept(InputDate) do |value|
time = Chronic.parse(value)
time && time.to_date
end
switch [:quiet],
negatable: false,
desc: "Quiet output messages"
flag [:filename],
arg_name: "FILENAME",
default_value: "~/friends.md",
desc: "Set the location of the friends file"
switch [:debug],
negatable: false,
desc: "Debug error messages with a full backtrace"
switch [:colorless],
negatable: false,
desc: "Disable output colorization and other effects"
commands_from "friends/commands"
# Before each command, clean up all arguments and create the global Introvert.
pre do |global_options, cmd|
# If the --colorless flag is passed, don't do any fancy painting.
Paint.mode = 0 if global_options[:colorless]
@quiet_mode = global_options[:quiet]
@debug_mode = global_options[:debug]
# If we're updating the friends program we don't need to read the friends file
# but we don't skip this block entirely because we might still want to enable
# debug mode. If we're in a `friends edit` command we wait to initialize the
# @introvert until the command block when the system call has exited
# successfully.
unless [:update, :edit].include? cmd.name
@introvert = Friends::Introvert.new(filename: global_options[:filename])
end
true # Continue executing the command.
end
post do
# After each command, clean the file if we have modifications to make.
@introvert.clean(clean_command: @clean_command) if @dirty
if @introvert && !@quiet_mode
begin
IO.popen(ENV["FRIENDS_PAGER"] || "less -RFX", "w") { |pipe| pipe.puts @introvert.output }
rescue Errno::ENOENT
# If the pager is not installed, just print the output.
puts @introvert.output
rescue Errno::EPIPE # rubocop:disable Lint/HandleExceptions
# Occurs when quitting the pager.
end
end
end
# If an error is raised, print the message to STDERR and exit the program.
on_error do |error|
raise error if @debug_mode
abort "Error: #{error}"
end
# Run the program and return the exit code corresponding to its success.
exit run(ARGV)