ical2gcal 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +17 -0
- data/LICENSE.txt +29 -0
- data/README.rdoc +54 -0
- data/Rakefile +57 -0
- data/VERSION +1 -0
- data/bin/ical2gcal +5 -0
- data/ical2gcal.gemspec +92 -0
- data/lib/google_calendar.rb +110 -0
- data/lib/ical2gcal.rb +62 -0
- data/lib/ics.rb +5 -0
- data/lib/ics/events.rb +39 -0
- data/lib/ics/list.rb +30 -0
- data/spec/ics/events_spec.rb +27 -0
- data/spec/ics/list_spec.rb +60 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/support/ics_list.txt +1 -0
- data/spec/support/japanese_holidays.ics +728 -0
- metadata +233 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
gem 'ri_cal'
|
9
|
+
gem 'gcal4ruby'
|
10
|
+
gem 'pit'
|
11
|
+
|
12
|
+
group :development do
|
13
|
+
gem "rspec", "~> 2.3.0"
|
14
|
+
gem "bundler", "~> 1.0.0"
|
15
|
+
gem "jeweler", "~> 1.5.2"
|
16
|
+
gem "rcov", ">= 0"
|
17
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
Copyright (c) 2011 wtnabe. All rights reserved.
|
2
|
+
|
3
|
+
Redistribution and use in source and binary forms, with or without
|
4
|
+
modification, are permitted provided that the following conditions are
|
5
|
+
met:
|
6
|
+
|
7
|
+
1. Redistributions of source code must retain the above copyright
|
8
|
+
notice, this list of conditions and the following disclaimer.
|
9
|
+
|
10
|
+
2. Redistributions in binary form must reproduce the above
|
11
|
+
copyright notice, this list of conditions and the following
|
12
|
+
disclaimer in the documentation and/or other materials provided
|
13
|
+
with the distribution.
|
14
|
+
|
15
|
+
THIS SOFTWARE IS PROVIDED BY wtnabe ``AS IS'' AND ANY EXPRESS OR
|
16
|
+
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
17
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
18
|
+
DISCLAIMED. IN NO EVENT SHALL wtnabe OR CONTRIBUTORS BE LIABLE FOR ANY
|
19
|
+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
20
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
21
|
+
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
22
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
23
|
+
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
24
|
+
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
25
|
+
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
26
|
+
|
27
|
+
The views and conclusions contained in the software and documentation
|
28
|
+
are those of the authors and should not be interpreted as representing
|
29
|
+
official policies, either expressed or implied, of wtnabe.
|
data/README.rdoc
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
= ical2gcal
|
2
|
+
|
3
|
+
sync ics(es) to google calendar
|
4
|
+
|
5
|
+
== Benefits
|
6
|
+
|
7
|
+
* Solve the PROBLEM that Android's calendar program cannot reference webcal !
|
8
|
+
* Complete sync calendar from .ics to google calendar ( also deleting )
|
9
|
+
|
10
|
+
== Requirements
|
11
|
+
|
12
|
+
* PC :-)
|
13
|
+
* Ruby ( tested with CRuby 1.8.7 )
|
14
|
+
* RiCal
|
15
|
+
* GCal4ruby
|
16
|
+
* Pit
|
17
|
+
* Googlecl ( made with Python )
|
18
|
+
|
19
|
+
== How to use
|
20
|
+
|
21
|
+
1. Install Ruby and gems.
|
22
|
+
2. Install Googlecl from http://code.google.com/p/googlecl/
|
23
|
+
3. Setup Your Google account info using Pit
|
24
|
+
4. Prepare calendar that you like to import to
|
25
|
+
5. Here we go !
|
26
|
+
|
27
|
+
== How to config pit
|
28
|
+
|
29
|
+
1. SET ENVIRONMENT VARIABLE **EDITOR**
|
30
|
+
2. type
|
31
|
+
|
32
|
+
pit set google
|
33
|
+
|
34
|
+
ex)
|
35
|
+
|
36
|
+
username: `google account'
|
37
|
+
password: PASSWORD
|
38
|
+
calendar:
|
39
|
+
name: `calendar name above'
|
40
|
+
|
41
|
+
== Contributing to ical2gcal
|
42
|
+
|
43
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
44
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
45
|
+
* Fork the project
|
46
|
+
* Start a feature/bugfix branch
|
47
|
+
* Commit and push until you are happy with your contribution
|
48
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
49
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
50
|
+
|
51
|
+
== Copyright
|
52
|
+
|
53
|
+
Copyright (c) 2011 wtnabe. See LICENSE.txt for
|
54
|
+
further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "ical2gcal"
|
18
|
+
gem.homepage = "http://github.com/wtnabe/ical2gcal"
|
19
|
+
gem.license = "two-clause BSD"
|
20
|
+
gem.summary = %Q{sync ics(es) to google calendar}
|
21
|
+
gem.description = %Q{You can sync local and remote ics file(s) to google calendar}
|
22
|
+
gem.email = "wtnabe@gmail.com"
|
23
|
+
gem.authors = ["wtnabe"]
|
24
|
+
gem.executables = %w( ical2gcal )
|
25
|
+
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
26
|
+
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
27
|
+
|
28
|
+
gem.add_runtime_dependency 'ri_cal'
|
29
|
+
gem.add_runtime_dependency 'gcal4ruby'
|
30
|
+
gem.add_runtime_dependency 'pit'
|
31
|
+
|
32
|
+
# gem.add_development_dependency 'rspec', '> 1.2.3'
|
33
|
+
end
|
34
|
+
Jeweler::RubygemsDotOrgTasks.new
|
35
|
+
|
36
|
+
require 'rspec/core'
|
37
|
+
require 'rspec/core/rake_task'
|
38
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
39
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
40
|
+
end
|
41
|
+
|
42
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
43
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
44
|
+
spec.rcov = true
|
45
|
+
end
|
46
|
+
|
47
|
+
task :default => :spec
|
48
|
+
|
49
|
+
require 'rake/rdoctask'
|
50
|
+
Rake::RDocTask.new do |rdoc|
|
51
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
52
|
+
|
53
|
+
rdoc.rdoc_dir = 'rdoc'
|
54
|
+
rdoc.title = "ical2gcal #{version}"
|
55
|
+
rdoc.rdoc_files.include('README*')
|
56
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
57
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.1
|
data/bin/ical2gcal
ADDED
data/ical2gcal.gemspec
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{ical2gcal}
|
8
|
+
s.version = "0.2.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["wtnabe"]
|
12
|
+
s.date = %q{2011-04-27}
|
13
|
+
s.default_executable = %q{ical2gcal}
|
14
|
+
s.description = %q{You can sync local and remote ics file(s) to google calendar}
|
15
|
+
s.email = %q{wtnabe@gmail.com}
|
16
|
+
s.executables = ["ical2gcal"]
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"LICENSE.txt",
|
19
|
+
"README.rdoc"
|
20
|
+
]
|
21
|
+
s.files = [
|
22
|
+
".document",
|
23
|
+
".rspec",
|
24
|
+
"Gemfile",
|
25
|
+
"LICENSE.txt",
|
26
|
+
"README.rdoc",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"bin/ical2gcal",
|
30
|
+
"ical2gcal.gemspec",
|
31
|
+
"lib/google_calendar.rb",
|
32
|
+
"lib/ical2gcal.rb",
|
33
|
+
"lib/ics.rb",
|
34
|
+
"lib/ics/events.rb",
|
35
|
+
"lib/ics/list.rb",
|
36
|
+
"spec/ics/events_spec.rb",
|
37
|
+
"spec/ics/list_spec.rb",
|
38
|
+
"spec/spec_helper.rb",
|
39
|
+
"spec/support/ics_list.txt",
|
40
|
+
"spec/support/japanese_holidays.ics"
|
41
|
+
]
|
42
|
+
s.homepage = %q{http://github.com/wtnabe/ical2gcal}
|
43
|
+
s.licenses = ["two-clause BSD"]
|
44
|
+
s.require_paths = ["lib"]
|
45
|
+
s.rubygems_version = %q{1.5.0}
|
46
|
+
s.summary = %q{sync ics(es) to google calendar}
|
47
|
+
s.test_files = [
|
48
|
+
"spec/ics/events_spec.rb",
|
49
|
+
"spec/ics/list_spec.rb",
|
50
|
+
"spec/spec_helper.rb"
|
51
|
+
]
|
52
|
+
|
53
|
+
if s.respond_to? :specification_version then
|
54
|
+
s.specification_version = 3
|
55
|
+
|
56
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
57
|
+
s.add_runtime_dependency(%q<ri_cal>, [">= 0"])
|
58
|
+
s.add_runtime_dependency(%q<gcal4ruby>, [">= 0"])
|
59
|
+
s.add_runtime_dependency(%q<pit>, [">= 0"])
|
60
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
|
61
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
62
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
|
63
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
64
|
+
s.add_runtime_dependency(%q<ri_cal>, [">= 0"])
|
65
|
+
s.add_runtime_dependency(%q<gcal4ruby>, [">= 0"])
|
66
|
+
s.add_runtime_dependency(%q<pit>, [">= 0"])
|
67
|
+
else
|
68
|
+
s.add_dependency(%q<ri_cal>, [">= 0"])
|
69
|
+
s.add_dependency(%q<gcal4ruby>, [">= 0"])
|
70
|
+
s.add_dependency(%q<pit>, [">= 0"])
|
71
|
+
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
72
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
73
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
74
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
75
|
+
s.add_dependency(%q<ri_cal>, [">= 0"])
|
76
|
+
s.add_dependency(%q<gcal4ruby>, [">= 0"])
|
77
|
+
s.add_dependency(%q<pit>, [">= 0"])
|
78
|
+
end
|
79
|
+
else
|
80
|
+
s.add_dependency(%q<ri_cal>, [">= 0"])
|
81
|
+
s.add_dependency(%q<gcal4ruby>, [">= 0"])
|
82
|
+
s.add_dependency(%q<pit>, [">= 0"])
|
83
|
+
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
84
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
85
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
86
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
87
|
+
s.add_dependency(%q<ri_cal>, [">= 0"])
|
88
|
+
s.add_dependency(%q<gcal4ruby>, [">= 0"])
|
89
|
+
s.add_dependency(%q<pit>, [">= 0"])
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# -*- mode: ruby; coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'pty'
|
4
|
+
require 'expect'
|
5
|
+
require 'gcal4ruby'
|
6
|
+
|
7
|
+
module Ical2gcal
|
8
|
+
class GoogleCalendar
|
9
|
+
include GCal4Ruby
|
10
|
+
|
11
|
+
class GoogleclNotAuthenticated < StandardError; end
|
12
|
+
|
13
|
+
def initialize( opts )
|
14
|
+
@service = nil
|
15
|
+
@opts = {
|
16
|
+
'username' => nil,
|
17
|
+
'password' => nil,
|
18
|
+
'calendar' => nil
|
19
|
+
}.merge( opts )
|
20
|
+
@calendar = nil
|
21
|
+
@events = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def service
|
25
|
+
if ( !@service and @opts )
|
26
|
+
@service = Service.new
|
27
|
+
@service.authenticate( @opts['username'], @opts['password'] )
|
28
|
+
end
|
29
|
+
|
30
|
+
@service
|
31
|
+
end
|
32
|
+
|
33
|
+
def calendar
|
34
|
+
if ( !@calendar )
|
35
|
+
@calendar = Calendar.find( service, :title => calendar_name ).first
|
36
|
+
end
|
37
|
+
|
38
|
+
@calendar
|
39
|
+
end
|
40
|
+
|
41
|
+
def calendar_name
|
42
|
+
@opts['calendar']['name']
|
43
|
+
end
|
44
|
+
|
45
|
+
def create_event( event )
|
46
|
+
begin
|
47
|
+
e = Event.new( service )
|
48
|
+
e.calendar = calendar
|
49
|
+
e.title = event.summary
|
50
|
+
e.start_time = Time.iso8601(event.start_time.to_s)
|
51
|
+
e.all_day = event.all?
|
52
|
+
e.end_time = if event.respond_to? :end_time
|
53
|
+
Time.iso8601(event.end_time.to_s)
|
54
|
+
else
|
55
|
+
Time.iso8601(event.start_time.to_s)
|
56
|
+
end
|
57
|
+
e.save
|
58
|
+
rescue
|
59
|
+
;
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def remove_all_events
|
64
|
+
if ( events.size )
|
65
|
+
PTY.spawn( "google calendar delete --cal '#{calendar_name}' --title '.*'" ) { |r, w|
|
66
|
+
w.sync = true
|
67
|
+
|
68
|
+
events.each { |e|
|
69
|
+
r.expect( /Are you SURE.*\?.*\(y\/N\)/iu, 5 ) {
|
70
|
+
w.puts 'y'
|
71
|
+
}
|
72
|
+
}
|
73
|
+
}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def events
|
78
|
+
if ( !@events )
|
79
|
+
@events = []
|
80
|
+
list_below = false
|
81
|
+
|
82
|
+
`google calendar list --cal '#{calendar_name}' --title '.*'`.lines.each { |line|
|
83
|
+
if ( line.chomp == "[#{calendar_name}]" )
|
84
|
+
list_below = true
|
85
|
+
next
|
86
|
+
end
|
87
|
+
if ( list_below )
|
88
|
+
@events << line.chomp
|
89
|
+
end
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
93
|
+
@events
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.authenticated?
|
97
|
+
begin
|
98
|
+
PTY.spawn( 'google calendar list' ) { |r, w|
|
99
|
+
r.expect( /(?:user|pass)/, 3 ) { |s|
|
100
|
+
raise GoogleclNotAuthenticated if ( s[0] =~ /(?:user|pass)/ )
|
101
|
+
}
|
102
|
+
}
|
103
|
+
rescue GoogleclNotAuthenticated
|
104
|
+
false
|
105
|
+
else
|
106
|
+
true
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/lib/ical2gcal.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'rubygems' unless defined? ::Gem
|
2
|
+
require File.dirname( __FILE__ ) + '/ics'
|
3
|
+
require File.dirname( __FILE__ ) + '/google_calendar'
|
4
|
+
|
5
|
+
require 'optparse'
|
6
|
+
require 'pit'
|
7
|
+
|
8
|
+
module Ical2gcal
|
9
|
+
class App
|
10
|
+
def initialize
|
11
|
+
@ics = nil
|
12
|
+
@list = nil
|
13
|
+
@calendars = nil
|
14
|
+
@target = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
opts.parse( ARGV )
|
19
|
+
|
20
|
+
opts = ::Pit.get('google')
|
21
|
+
opts.merge!( {'calendar' => {'name' => @target}} ) if @target
|
22
|
+
if ( Ical2gcal::GoogleCalendar.authenticated? )
|
23
|
+
g = Ical2gcal::GoogleCalendar.new( opts )
|
24
|
+
g.remove_all_events
|
25
|
+
calendars.each { |c|
|
26
|
+
Ical2gcal::Ics::Events.new( c ).each { |e|
|
27
|
+
g.create_event( e )
|
28
|
+
}
|
29
|
+
}
|
30
|
+
else
|
31
|
+
puts "Your `google' command is not authorized. Please type `google calendar list' and get auth."
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def calendars
|
36
|
+
if ( @ics )
|
37
|
+
@calendars = @ics
|
38
|
+
end
|
39
|
+
if ( @list )
|
40
|
+
l = Ical2gcal::Ics::List.new( @list ).import
|
41
|
+
@calendars = l.list
|
42
|
+
end
|
43
|
+
|
44
|
+
@calendars
|
45
|
+
end
|
46
|
+
|
47
|
+
def opts
|
48
|
+
OptionParser.new do |opt|
|
49
|
+
opt.on( '-c', '--calendar-name NAME' ) { |c|
|
50
|
+
@target = c
|
51
|
+
}
|
52
|
+
opt.on( '-i', '--ics URI' ) { |i|
|
53
|
+
@ics = i
|
54
|
+
}
|
55
|
+
opt.on( '-l', '--calendar-list' ) { |l|
|
56
|
+
@list = l
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|