bitsa 0.10
Sign up to get free protection for your applications and to get access to all the features.
- 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
|