bitsa 0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/.rspec +3 -0
- data/COPYING +674 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +35 -0
- data/History.txt +4 -0
- data/README.md +117 -0
- data/Rakefile +10 -0
- data/bin/bitsa +35 -0
- data/bitsa.gemspec +28 -0
- data/lib/bitsa.rb +50 -0
- data/lib/bitsa/args_processor.rb +80 -0
- data/lib/bitsa/config_file.rb +39 -0
- data/lib/bitsa/contacts_cache.rb +100 -0
- data/lib/bitsa/gmail_contacts_loader.rb +80 -0
- data/lib/bitsa/settings.rb +50 -0
- data/lib/bitsa/version.rb +22 -0
- data/spec/args_processor_spec.rb +66 -0
- data/spec/confg_file_spec.rb +32 -0
- data/spec/contacts_cache_spec.rb +294 -0
- data/spec/data/bitsa_cache.yml +16 -0
- data/spec/data/config.yml +3 -0
- data/spec/gmail_contacts_loader_spec.rb +89 -0
- data/spec/helper.rb +11 -0
- data/spec/settings_spec.rb +34 -0
- data/tasks/create_tags.rake +7 -0
- data/tasks/retrieve_one_page.rake +24 -0
- data/tasks/spec.rake +3 -0
- metadata +177 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
bitsa (0.10.beta3)
|
5
|
+
gdata (= 1.1.1)
|
6
|
+
trollop (= 1.15)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
diff-lcs (1.1.2)
|
12
|
+
fakeweb (1.2.8)
|
13
|
+
gdata (1.1.1)
|
14
|
+
rspec (2.0.1)
|
15
|
+
rspec-core (~> 2.0.1)
|
16
|
+
rspec-expectations (~> 2.0.1)
|
17
|
+
rspec-mocks (~> 2.0.1)
|
18
|
+
rspec-core (2.0.1)
|
19
|
+
rspec-expectations (2.0.1)
|
20
|
+
diff-lcs (>= 1.1.2)
|
21
|
+
rspec-mocks (2.0.1)
|
22
|
+
rspec-core (~> 2.0.1)
|
23
|
+
rspec-expectations (~> 2.0.1)
|
24
|
+
trollop (1.15)
|
25
|
+
|
26
|
+
PLATFORMS
|
27
|
+
ruby
|
28
|
+
|
29
|
+
DEPENDENCIES
|
30
|
+
bitsa!
|
31
|
+
bundler (>= 1.0.0)
|
32
|
+
fakeweb (~> 1.2.8)
|
33
|
+
gdata (= 1.1.1)
|
34
|
+
rspec (~> 2.0.0.beta.22)
|
35
|
+
trollop (= 1.15)
|
data/History.txt
ADDED
data/README.md
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
# Bitsa
|
2
|
+
|
3
|
+
* <http://github.com/colbell/bitsa>
|
4
|
+
|
5
|
+
|
6
|
+
A command line tool to access your GMail/Google Apps contacts. Designed to be used
|
7
|
+
from Mutt but should be able to be used from any email client that
|
8
|
+
supports calling external programs.
|
9
|
+
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
gem install bitsa
|
14
|
+
|
15
|
+
|
16
|
+
## Configuration
|
17
|
+
|
18
|
+
Bitsa is configured through the configuration file
|
19
|
+
`~/.bitsa_config.yml`. Use your GMail (or Google Apps) email address
|
20
|
+
for the login.
|
21
|
+
|
22
|
+
---
|
23
|
+
:login: myself@gmail.com
|
24
|
+
:password: mypassword
|
25
|
+
:cache_file_path: ~/.bitsa_cache.yml
|
26
|
+
|
27
|
+
The configuration file is not mandatory, you can pass in your email address
|
28
|
+
and password on the command line, see [Usage](#usage).
|
29
|
+
|
30
|
+
If you have no configuration file or if `cache_file_path` is not specified in the
|
31
|
+
configuration file it will default to `~/.bitsa_cache.yml`
|
32
|
+
|
33
|
+
If you store your email password in the configuration file you should
|
34
|
+
ensue that it is only readable by you:
|
35
|
+
|
36
|
+
chmod 0600 .bitsa_config.yml
|
37
|
+
|
38
|
+
|
39
|
+
## <a name="usage">Usage</a>
|
40
|
+
|
41
|
+
Usage: bitsa [global-options] [subcommand] [command-opts]
|
42
|
+
|
43
|
+
Global options are:
|
44
|
+
--config-file, -c <s>: Configuration file (default: ~/.bitsa_config.yml)
|
45
|
+
--login, -l <s>: Login
|
46
|
+
--password, -p <s>: Password
|
47
|
+
|
48
|
+
bitsa sub-commands
|
49
|
+
update: get the latest changes from Gmail
|
50
|
+
reload: Clear all cached addresses and reload from Gmail
|
51
|
+
search: Search for the passed string
|
52
|
+
|
53
|
+
Information about this program
|
54
|
+
--version, -v: Print version and exit
|
55
|
+
--help, -h: Show this message
|
56
|
+
|
57
|
+
|
58
|
+
To search for all contacts that contain the string rob:
|
59
|
+
|
60
|
+
$ bitsa search rob
|
61
|
+
|
62
|
+
Rob_Smith@example.com.au Robert Smith
|
63
|
+
Rob_Smith@example.com Robert Smith
|
64
|
+
robert@example.com Robert Jones
|
65
|
+
jeff@example.net Robert Smith
|
66
|
+
bob@robertsystems Robert Brown
|
67
|
+
|
68
|
+
The first time you run Bitsa and then if it has been more than a day
|
69
|
+
since it was last updated it will get the latest changes from your
|
70
|
+
GMail contacts and copy them to a local cache (~/.bitsa_cache.yml).
|
71
|
+
|
72
|
+
You can update your cache with the latest changes at any time by using
|
73
|
+
the `update` sub-command:
|
74
|
+
|
75
|
+
$ bitsa update
|
76
|
+
|
77
|
+
If you want to clear your local cache and reload from GMail use the
|
78
|
+
`reload` sub-command:
|
79
|
+
|
80
|
+
$ bitsa reload
|
81
|
+
|
82
|
+
## Usage - Mutt
|
83
|
+
|
84
|
+
To use for address lookup (<ctrl> t) in Mutt put the following in your
|
85
|
+
`~/.muttrc` file:
|
86
|
+
|
87
|
+
set query_command = "bitsa search '%s'"
|
88
|
+
|
89
|
+
## Testing
|
90
|
+
|
91
|
+
To run the tests after cloning the repository you first need to
|
92
|
+
install the required libraries:
|
93
|
+
|
94
|
+
bundle install
|
95
|
+
|
96
|
+
And then you can run the tests:
|
97
|
+
|
98
|
+
rake spec
|
99
|
+
|
100
|
+
## License:
|
101
|
+
|
102
|
+
Copyright 2011 Colin Bell.
|
103
|
+
|
104
|
+
Bitsa is free software: you can redistribute it and/or modify
|
105
|
+
it under the terms of the GNU General Public License as published by
|
106
|
+
the Free Software Foundation, either version 3 of the License, or
|
107
|
+
(at your option) any later version.
|
108
|
+
|
109
|
+
This program is distributed in the hope that it will be useful,
|
110
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
111
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
112
|
+
GNU General Public License for more details.
|
113
|
+
|
114
|
+
You should have received a copy of the GNU General Public License
|
115
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
116
|
+
|
117
|
+
* * * * *
|
data/Rakefile
ADDED
data/bin/bitsa
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#
|
4
|
+
#
|
5
|
+
# Copyright 2011 Colin Noel Bell.
|
6
|
+
#
|
7
|
+
# This file is part of Bitsa.
|
8
|
+
#
|
9
|
+
# Bitsa is free software: you can redistribute it and/or modify
|
10
|
+
# it under the terms of the GNU General Public License as published by
|
11
|
+
# the Free Software Foundation, either version 3 of the License, or
|
12
|
+
# (at your option) any later version.
|
13
|
+
#
|
14
|
+
# This program is distributed in the hope that it will be useful,
|
15
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
+
# GNU General Public License for more details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the GNU General Public License
|
20
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
21
|
+
|
22
|
+
# begin
|
23
|
+
# require 'rubygems'
|
24
|
+
# rescue LoadError
|
25
|
+
# end
|
26
|
+
|
27
|
+
require "bitsa"
|
28
|
+
require "bitsa/args_processor"
|
29
|
+
|
30
|
+
args = Bitsa::ArgsProcessor.new
|
31
|
+
args.parse(ARGV)
|
32
|
+
|
33
|
+
app = Bitsa::BitsaApp.new
|
34
|
+
app.run(args.global_opts, args.cmd, args.search_data)
|
35
|
+
|
data/bitsa.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "bitsa/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "bitsa"
|
7
|
+
s.version = Bitsa::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Colin Noel Bell"]
|
10
|
+
s.email = ["col@baibell.org"]
|
11
|
+
s.homepage = "https://github.com/colbell/bitsa"
|
12
|
+
s.summary = %q{Command line GMail Contacts lookup tool.}
|
13
|
+
s.description = %q{Allows you to lookup GMail contacts and cache contacts locally from the command line.}
|
14
|
+
|
15
|
+
s.required_rubygems_version = ">= 1.3.6"
|
16
|
+
|
17
|
+
s.add_dependency "trollop", "1.15"
|
18
|
+
s.add_dependency "gdata", "1.1.1"
|
19
|
+
|
20
|
+
s.add_development_dependency "bundler", ">= 1.0.0"
|
21
|
+
s.add_development_dependency "rspec", "~> 2.0.0.beta.22"
|
22
|
+
s.add_development_dependency "fakeweb", "~> 1.2.8"
|
23
|
+
|
24
|
+
s.files = `git ls-files`.split("\n")
|
25
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
26
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
27
|
+
s.require_path = "lib"
|
28
|
+
end
|
data/lib/bitsa.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# Copyright 2011 Colin Bell.
|
2
|
+
#
|
3
|
+
# This file is part of Bitsa.
|
4
|
+
#
|
5
|
+
# Bitsa is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
|
15
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
16
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
17
|
+
|
18
|
+
require "bitsa/config_file"
|
19
|
+
require "bitsa/contacts_cache"
|
20
|
+
require "bitsa/gmail_contacts_loader"
|
21
|
+
require "bitsa/settings"
|
22
|
+
|
23
|
+
module Bitsa
|
24
|
+
|
25
|
+
# Application entry point.
|
26
|
+
class BitsaApp
|
27
|
+
|
28
|
+
# Run application.
|
29
|
+
def run(global_opts, cmd, search_data)
|
30
|
+
settings = Settings.new
|
31
|
+
settings.load(ConfigFile.new(global_opts[:config_file]), global_opts)
|
32
|
+
cache = ContactsCache.new(settings.cache_file_path, 1)
|
33
|
+
|
34
|
+
if cmd == "reload"
|
35
|
+
cache.clear!
|
36
|
+
end
|
37
|
+
|
38
|
+
if ["reload", "update"].include?(cmd) || cache.stale?
|
39
|
+
loader = GmailContactsLoader.new(settings.login, settings.password)
|
40
|
+
loader.update_cache(cache)
|
41
|
+
end
|
42
|
+
|
43
|
+
if cmd == "search"
|
44
|
+
puts "" # Force first entry to be displayed in mutt
|
45
|
+
cache.search(search_data).each {|k,v| puts "#{k}\t#{v}"}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# Command line arguments handler
|
2
|
+
#
|
3
|
+
# Copyright (C) 2011 Colin Noel Bell.
|
4
|
+
#
|
5
|
+
# This file is part of Bitsa.
|
6
|
+
#
|
7
|
+
# Bitsa is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
require "trollop"
|
21
|
+
|
22
|
+
require "bitsa/version"
|
23
|
+
|
24
|
+
module Bitsa #:nodoc:
|
25
|
+
|
26
|
+
# Arguments passed on the command line. Trollop http://trollop.rubyforge.org
|
27
|
+
# is used to handle the parsing.
|
28
|
+
class ArgsProcessor
|
29
|
+
# Valid commands.
|
30
|
+
SUB_COMMANDS = %w(update reload search)
|
31
|
+
|
32
|
+
# Global options passed on the command line.
|
33
|
+
attr_reader :global_opts
|
34
|
+
|
35
|
+
# The command to execute
|
36
|
+
attr_reader :cmd
|
37
|
+
|
38
|
+
# Data to search cached contacts for.
|
39
|
+
attr_reader :search_data
|
40
|
+
|
41
|
+
# Parse arguments and setup attributes. If invalid data is passed a
|
42
|
+
# Trollop exception is thrown and the program terminated.
|
43
|
+
#
|
44
|
+
# It also handles showing the Help and Version information.
|
45
|
+
def parse(args)
|
46
|
+
@global_opts = Trollop::options(args) do
|
47
|
+
version "bitsa v#{Bitsa::VERSION}"
|
48
|
+
banner <<EOS
|
49
|
+
Usage: bitsa [global-options] [subcommand] [command-opts]
|
50
|
+
|
51
|
+
Global options are:
|
52
|
+
EOS
|
53
|
+
opt :config_file, "Configuration file", :default => "~/.bitsa_config.yml"
|
54
|
+
opt :login, "Login", :type => String
|
55
|
+
opt :password, "Password", :type => String
|
56
|
+
|
57
|
+
stop_on SUB_COMMANDS
|
58
|
+
|
59
|
+
banner <<EOS
|
60
|
+
|
61
|
+
bitsa subcommands
|
62
|
+
update: get the latest changes from Gmail
|
63
|
+
reload: Clear all cached addresses and reload from Gmail
|
64
|
+
search: Search for the passed string
|
65
|
+
|
66
|
+
Information about this program
|
67
|
+
EOS
|
68
|
+
end
|
69
|
+
|
70
|
+
@cmd = args.shift || ''
|
71
|
+
@search_data = ''
|
72
|
+
|
73
|
+
if cmd == "search"
|
74
|
+
@search_data << args.shift unless args.empty?
|
75
|
+
elsif !["search", "update", "reload"].include?(cmd)
|
76
|
+
Trollop::die "unknown subcommand '#{cmd}'"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Loads configuration data from configuration file.
|
2
|
+
#
|
3
|
+
# Copyright (C) 2011 Colin Noel Bell.
|
4
|
+
#
|
5
|
+
# This file is part of Bitsa.
|
6
|
+
#
|
7
|
+
# Bitsa is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
require "yaml"
|
21
|
+
|
22
|
+
module Bitsa #:nodoc:
|
23
|
+
|
24
|
+
# Loads configuration data from a yaml file.
|
25
|
+
class ConfigFile
|
26
|
+
|
27
|
+
# Loaded configuration data as a Hash.
|
28
|
+
attr_reader :data
|
29
|
+
|
30
|
+
# Load data from passed file path.
|
31
|
+
def initialize(config_file_path_name)
|
32
|
+
c_f_n = File.expand_path(config_file_path_name)
|
33
|
+
if File.exist?(c_f_n)
|
34
|
+
@data = YAML.load_file(c_f_n)
|
35
|
+
end
|
36
|
+
@data = {} unless @data
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# Cache of Contacts.
|
2
|
+
#
|
3
|
+
# Copyright (C) 2011 Colin Noel Bell.
|
4
|
+
#
|
5
|
+
# This file is part of Bitsa.
|
6
|
+
#
|
7
|
+
# Bitsa is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
require "forwardable"
|
21
|
+
|
22
|
+
module Bitsa #:nodoc:
|
23
|
+
|
24
|
+
# Cache of Contacts.
|
25
|
+
class ContactsCache
|
26
|
+
extend Forwardable
|
27
|
+
|
28
|
+
# Number of entries in cache.
|
29
|
+
def_delegator :@addresses, :size
|
30
|
+
|
31
|
+
# True if cache is empty.
|
32
|
+
def_delegator :@addresses, :empty?
|
33
|
+
|
34
|
+
# Date/Time cache was last updated.
|
35
|
+
attr_accessor :source_last_modified
|
36
|
+
|
37
|
+
# Load cache from file system. After <tt>lifespan_days</tt> the cache is considered stale.
|
38
|
+
def initialize(cache_file_path, lifespan_days)
|
39
|
+
@cache_file_path = File.expand_path(cache_file_path || "~/.bitsa_cache.yml")
|
40
|
+
@lifespan_days = lifespan_days
|
41
|
+
@addresses = {}
|
42
|
+
@source_source_last_modified = nil
|
43
|
+
load_from_file_system
|
44
|
+
end
|
45
|
+
|
46
|
+
def stale?
|
47
|
+
(@source_last_modified.nil? ||
|
48
|
+
(DateTime.parse(@source_last_modified)+@lifespan_days) < DateTime.now)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Remove all entries from cache.
|
52
|
+
def clear!
|
53
|
+
@addresses.clear
|
54
|
+
@source_last_modified = nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def get(id)
|
58
|
+
@addresses[id]
|
59
|
+
end
|
60
|
+
|
61
|
+
def search(qry)
|
62
|
+
qry ||= ""
|
63
|
+
rg = Regexp.new(qry, Regexp::IGNORECASE)
|
64
|
+
|
65
|
+
# Flattens.each_slices to an array with [email1, name1, email2, name2] etc.
|
66
|
+
results = @addresses.values.flatten.each_slice(2).find_all do |e, n|
|
67
|
+
e.match(rg) || n.match(rg)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Sort by case-insensitive email address
|
71
|
+
results.sort{|a,b| a[0].downcase <=> b[0].downcase}
|
72
|
+
end
|
73
|
+
|
74
|
+
def update(id, name, addresses)
|
75
|
+
@addresses[id] = addresses.map { | a | [a, name]}
|
76
|
+
end
|
77
|
+
|
78
|
+
def delete(id)
|
79
|
+
@addresses.delete(id)
|
80
|
+
end
|
81
|
+
|
82
|
+
def save
|
83
|
+
File.open(@cache_file_path, "w") do |f|
|
84
|
+
f.write(YAML::dump([@source_last_modified, @addresses]))
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def load_from_file_system
|
91
|
+
if File.exist?(@cache_file_path)
|
92
|
+
@source_last_modified, @addresses = YAML::load_file(@cache_file_path)
|
93
|
+
unless @addresses
|
94
|
+
@addresses = {}
|
95
|
+
@source_last_modified = nil
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|