rufus-scheduler 3.0.8 → 3.1.0

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.
@@ -0,0 +1,95 @@
1
+ #--
2
+ # Copyright (c) 2006-2015, John Mettraux, jmettraux@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+ # Made in Japan.
23
+ #++
24
+
25
+ require 'fileutils'
26
+
27
+
28
+ class Rufus::Scheduler
29
+
30
+ #
31
+ # A lock that can always be acquired
32
+ #
33
+ class NullLock
34
+
35
+ # Locking is always successful.
36
+ #
37
+ def lock; true; end
38
+
39
+ def locked?; true; end
40
+ def unlock; true; end
41
+ end
42
+
43
+ #
44
+ # The standard flock mecha, with its own class thanks to @ecin
45
+ #
46
+ class FileLock
47
+
48
+ attr_reader :path
49
+
50
+ def initialize(path)
51
+
52
+ @path = path.to_s
53
+ end
54
+
55
+ # Locking is successful if this Ruby process can create and lock
56
+ # its lockfile (at the given path).
57
+ #
58
+ def lock
59
+
60
+ return true if locked?
61
+
62
+ @lockfile = nil
63
+
64
+ FileUtils.mkdir_p(::File.dirname(@path))
65
+
66
+ file = File.new(@path, File::RDWR | File::CREAT)
67
+ locked = file.flock(File::LOCK_NB | File::LOCK_EX)
68
+
69
+ return false unless locked
70
+
71
+ now = Time.now
72
+
73
+ file.print("pid: #{$$}, ")
74
+ file.print("scheduler.object_id: #{self.object_id}, ")
75
+ file.print("time: #{now}, ")
76
+ file.print("timestamp: #{now.to_f}")
77
+ file.flush
78
+
79
+ @lockfile = file
80
+
81
+ true
82
+ end
83
+
84
+ def unlock
85
+
86
+ !! (@lockfile && @lockfile.flock(File::LOCK_UN))
87
+ end
88
+
89
+ def locked?
90
+
91
+ !! (@lockfile && @lockfile.flock(File::LOCK_NB | File::LOCK_EX))
92
+ end
93
+ end
94
+ end
95
+
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2006-2014, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2006-2015, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -46,32 +46,9 @@ module Rufus
46
46
  o.is_a?(String) ? parse_duration(o, opts) : o
47
47
  end
48
48
 
49
- TZ_REGEX = /\b((?:[a-zA-Z][a-zA-z0-9\-+]+)(?:\/[a-zA-Z0-9\-+]+)?)\b/
50
-
51
49
  def self.parse_at(o, opts={})
52
50
 
53
- return o if o.is_a?(Time)
54
-
55
- # TODO: deal with tz if suffixed to Chronic string?
56
- return Chronic.parse(o, opts) if defined?(Chronic)
57
-
58
- tz = nil
59
- s =
60
- o.to_s.gsub(TZ_REGEX) { |m|
61
- t = TZInfo::Timezone.get(m) rescue nil
62
- tz ||= t
63
- t ? '' : m
64
- }
65
-
66
- begin
67
- DateTime.parse(o)
68
- rescue
69
- raise ArgumentError, "no time information in #{o.inspect}"
70
- end if RUBY_VERSION < '1.9.0'
71
-
72
- t = Time.parse(s)
73
-
74
- tz ? tz.local_to_utc(t) : t
51
+ Rufus::Scheduler::ZoTime.parse(o, opts).time
75
52
 
76
53
  rescue StandardError => se
77
54
 
@@ -0,0 +1,174 @@
1
+ #--
2
+ # Copyright (c) 2006-2015, John Mettraux, jmettraux@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+ # Made in Japan.
23
+ #++
24
+
25
+
26
+ class Rufus::Scheduler
27
+
28
+ TIMEZONES = %w[
29
+ GB NZ UCT EET CET PRC ROC WET GMT EST ROK UTC MST HST MET Zulu Cuba Iran W-SU
30
+ Eire GMT0 Libya Japan Egypt GMT+0 GMT-0 Israel Poland Navajo Turkey GB-Eire
31
+ Iceland PST8PDT Etc/UCT CST6CDT NZ-CHAT MST7MDT Jamaica EST5EDT Etc/GMT Etc/UTC
32
+ US/Samoa Etc/GMT0 Portugal Hongkong Etc/Zulu Singapore Asia/Baku Etc/GMT-9
33
+ Etc/GMT+1 Etc/GMT+0 Asia/Aden Etc/GMT+2 Etc/GMT+3 Etc/GMT+4 Etc/GMT+5 Etc/GMT+6
34
+ Etc/GMT+7 Etc/GMT+8 Etc/GMT+9 Etc/GMT-0 Etc/GMT-1 Universal Asia/Dili Greenwich
35
+ Asia/Gaza Etc/GMT-8 Etc/GMT-7 US/Alaska Asia/Oral Etc/GMT-6 Etc/GMT-5 Etc/GMT-4
36
+ Asia/Hovd Etc/GMT-3 US/Hawaii Etc/GMT-2 Kwajalein Asia/Omsk Asia/Macao
37
+ Etc/GMT-14 Asia/Kabul US/Central Etc/GMT-13 US/Arizona Asia/Macau Asia/Qatar
38
+ Asia/Seoul Asia/Tokyo Asia/Dubai US/Pacific Etc/GMT-12 Etc/GMT-11 Etc/GMT-10
39
+ Asia/Dhaka Asia/Dacca Asia/Chita Etc/GMT+12 Etc/GMT+10 Asia/Amman Asia/Aqtau
40
+ Etc/GMT+11 US/Eastern Asia/Thimbu Asia/Brunei Asia/Tehran Asia/Beirut
41
+ Europe/Rome Europe/Riga Brazil/Acre Brazil/East Europe/Oslo Brazil/West
42
+ Africa/Lome Asia/Taipei Asia/Saigon Asia/Riyadh Asia/Aqtobe Asia/Anadyr
43
+ Europe/Kiev Asia/Almaty Africa/Juba Pacific/Yap US/Aleutian Asia/Muscat
44
+ US/Mountain Asia/Harbin Asia/Hebron Asia/Manila Asia/Kuwait Asia/Urumqi
45
+ US/Michigan Indian/Mahe SystemV/EST5 Asia/Kashgar Indian/Cocos Asia/Jakarta
46
+ Asia/Kolkata Asia/Kuching America/Atka Asia/Irkutsk Pacific/Apia Asia/Magadan
47
+ Africa/Dakar America/Lima Pacific/Fiji Pacific/Guam Europe/Vaduz Pacific/Niue
48
+ Asia/Nicosia Africa/Ceuta Pacific/Truk America/Adak Pacific/Wake Africa/Tunis
49
+ Africa/Cairo Asia/Colombo SystemV/AST4 SystemV/CST6 Asia/Karachi Asia/Rangoon
50
+ SystemV/MST7 Asia/Baghdad Europe/Malta Africa/Lagos Europe/Minsk SystemV/PST8
51
+ Canada/Yukon Asia/Tbilisi America/Nome Asia/Bahrain Africa/Accra Europe/Paris
52
+ Asia/Bangkok Asia/Bishkek Asia/Thimphu SystemV/YST9 Asia/Yerevan Asia/Yakutsk
53
+ Europe/Sofia Asia/Ust-Nera Australia/ACT Australia/LHI Europe/Tirane
54
+ Asia/Tel_Aviv Australia/NSW Africa/Luanda Asia/Tashkent Africa/Lusaka
55
+ Asia/Shanghai Africa/Malabo Asia/Sakhalin Africa/Maputo Africa/Maseru
56
+ SystemV/HST10 Africa/Kigali Africa/Niamey Pacific/Samoa America/Sitka
57
+ Pacific/Palau Pacific/Nauru Pacific/Efate Asia/Makassar Pacific/Chuuk
58
+ Africa/Harare Africa/Douala America/Aruba America/Thule America/Bahia
59
+ America/Jujuy America/Belem Asia/Katmandu America/Boise Indian/Comoro
60
+ Indian/Chagos Asia/Jayapura Europe/Zurich Asia/Istanbul Europe/Zagreb
61
+ Etc/Greenwich Europe/Warsaw Europe/Vienna Etc/Universal Asia/Dushanbe
62
+ Europe/Athens Europe/Berlin Africa/Bissau Asia/Damascus Africa/Banjul
63
+ Europe/Dublin Africa/Bangui Africa/Bamako Europe/Jersey Africa/Asmera
64
+ Europe/Lisbon Africa/Asmara Europe/London Asia/Ashgabat Asia/Calcutta
65
+ Europe/Madrid Europe/Monaco Europe/Moscow Europe/Prague Europe/Samara
66
+ Europe/Skopje Asia/Khandyga Canada/Pacific Africa/Abidjan America/Manaus
67
+ Asia/Chongqing Asia/Chungking Africa/Algiers America/Maceio US/Pacific-New
68
+ Africa/Conakry America/La_Paz America/Juneau America/Nassau America/Inuvik
69
+ Europe/Andorra Africa/Kampala Asia/Ashkhabad Asia/Hong_Kong America/Havana
70
+ Canada/Eastern Europe/Belfast Canada/Central Australia/West Asia/Jerusalem
71
+ Africa/Mbabane Asia/Kamchatka America/Virgin America/Guyana Asia/Kathmandu
72
+ Mexico/General America/Panama Europe/Nicosia America/Denver Europe/Tallinn
73
+ Africa/Nairobi America/Dawson Europe/Vatican Europe/Vilnius America/Cuiaba
74
+ Africa/Tripoli Pacific/Wallis Atlantic/Faroe Pacific/Tarawa Pacific/Tahiti
75
+ Pacific/Saipan Pacific/Ponape America/Cayman America/Cancun Asia/Pontianak
76
+ Asia/Pyongyang Asia/Vientiane Asia/Qyzylorda Pacific/Noumea America/Bogota
77
+ Pacific/Midway Pacific/Majuro Asia/Samarkand Indian/Mayotte Pacific/Kosrae
78
+ Asia/Singapore Indian/Reunion America/Belize America/Regina America/Recife
79
+ Pacific/Easter Mexico/BajaSur America/Merida Pacific/Chatham Pacific/Fakaofo
80
+ Pacific/Gambier America/Rosario Asia/Ulan_Bator Indian/Maldives Pacific/Norfolk
81
+ America/Antigua Asia/Phnom_Penh America/Phoenix America/Caracas America/Cayenne
82
+ Atlantic/Azores Pacific/Pohnpei Atlantic/Canary America/Chicago Atlantic/Faeroe
83
+ Africa/Windhoek America/Cordoba America/Creston Africa/Timbuktu America/Curacao
84
+ Africa/Sao_Tome Africa/Ndjamena SystemV/AST4ADT Europe/Uzhgorod Europe/Tiraspol
85
+ SystemV/CST6CDT Africa/Monrovia America/Detroit Europe/Sarajevo Australia/Eucla
86
+ America/Tijuana America/Toronto America/Godthab America/Grenada Europe/Istanbul
87
+ America/Ojinaga America/Tortola Australia/Perth Europe/Helsinki Australia/South
88
+ Europe/Guernsey SystemV/EST5EDT Europe/Chisinau SystemV/MST7MDT Europe/Busingen
89
+ Europe/Budapest Europe/Brussels America/Halifax America/Mendoza America/Noronha
90
+ America/Nipigon Canada/Atlantic America/Yakutat SystemV/PST8PDT SystemV/YST9YDT
91
+ Canada/Mountain Africa/Kinshasa Africa/Khartoum Africa/Gaborone Africa/Freetown
92
+ America/Iqaluit America/Jamaica US/East-Indiana Africa/El_Aaiun America/Knox_IN
93
+ Africa/Djibouti Africa/Blantyre America/Moncton America/Managua Asia/Choibalsan
94
+ America/Marigot Australia/North Europe/Belgrade America/Resolute
95
+ America/Mazatlan Pacific/Funafuti Pacific/Auckland Pacific/Honolulu
96
+ Pacific/Johnston America/Miquelon America/Santarem Mexico/BajaNorte
97
+ America/Santiago Antarctica/Troll America/Asuncion America/Atikokan
98
+ America/Montreal America/Barbados Africa/Bujumbura Pacific/Pitcairn
99
+ Asia/Ulaanbaatar Indian/Mauritius America/New_York Antarctica/Syowa
100
+ America/Shiprock Indian/Kerguelen Asia/Novosibirsk America/Anguilla
101
+ Indian/Christmas Asia/Vladivostok Asia/Ho_Chi_Minh Antarctica/Davis
102
+ Atlantic/Bermuda Europe/Amsterdam Antarctica/Casey America/St_Johns
103
+ Atlantic/Madeira America/Winnipeg America/St_Kitts Europe/Volgograd
104
+ Brazil/DeNoronha Europe/Bucharest Africa/Mogadishu America/St_Lucia
105
+ Atlantic/Stanley Europe/Stockholm Australia/Currie Europe/Gibraltar
106
+ Australia/Sydney Asia/Krasnoyarsk Australia/Darwin America/Dominica
107
+ America/Edmonton America/Eirunepe Europe/Podgorica America/Ensenada
108
+ Europe/Ljubljana Australia/Hobart Europe/Mariehamn Africa/Lubumbashi
109
+ America/Goose_Bay Europe/Luxembourg America/Menominee America/Glace_Bay
110
+ America/Fortaleza Africa/Nouakchott America/Matamoros Pacific/Galapagos
111
+ America/Guatemala Pacific/Kwajalein Pacific/Marquesas America/Guayaquil
112
+ Asia/Kuala_Lumpur Europe/San_Marino America/Monterrey Europe/Simferopol
113
+ America/Araguaina Antarctica/Vostok Europe/Copenhagen America/Catamarca
114
+ Pacific/Pago_Pago America/Sao_Paulo America/Boa_Vista America/St_Thomas
115
+ Chile/Continental America/Vancouver Africa/Casablanca Europe/Bratislava
116
+ Pacific/Enderbury Pacific/Rarotonga Europe/Zaporozhye US/Indiana-Starke
117
+ Antarctica/Palmer Asia/Novokuznetsk Africa/Libreville America/Chihuahua
118
+ America/Anchorage Pacific/Tongatapu Antarctica/Mawson Africa/Porto-Novo
119
+ Asia/Yekaterinburg America/Paramaribo America/Hermosillo Atlantic/Jan_Mayen
120
+ Antarctica/McMurdo America/Costa_Rica Antarctica/Rothera America/Grand_Turk
121
+ Atlantic/Reykjavik Atlantic/St_Helena Australia/Victoria Chile/EasterIsland
122
+ Asia/Ujung_Pandang Australia/Adelaide America/Montserrat America/Porto_Acre
123
+ Africa/Brazzaville Australia/Brisbane America/Kralendijk America/Montevideo
124
+ America/St_Vincent America/Louisville Australia/Canberra Australia/Tasmania
125
+ Europe/Isle_of_Man Europe/Kaliningrad Africa/Ouagadougou America/Rio_Branco
126
+ Pacific/Kiritimati Africa/Addis_Ababa America/Metlakatla America/Martinique
127
+ Asia/Srednekolymsk America/Guadeloupe America/Fort_Wayne Australia/Lindeman
128
+ America/Whitehorse Arctic/Longyearbyen America/Pangnirtung America/Mexico_City
129
+ America/Los_Angeles America/Rainy_River Atlantic/Cape_Verde Pacific/Guadalcanal
130
+ Indian/Antananarivo America/El_Salvador Australia/Lord_Howe Africa/Johannesburg
131
+ America/Tegucigalpa Canada/Saskatchewan America/Thunder_Bay Canada/Newfoundland
132
+ America/Puerto_Rico America/Yellowknife Australia/Melbourne America/Porto_Velho
133
+ Australia/Queensland Australia/Yancowinna America/Santa_Isabel
134
+ America/Blanc-Sablon America/Scoresbysund America/Danmarkshavn
135
+ Pacific/Port_Moresby Antarctica/Macquarie America/Buenos_Aires
136
+ Africa/Dar_es_Salaam America/Campo_Grande America/Dawson_Creek
137
+ America/Indianapolis Pacific/Bougainville America/Rankin_Inlet
138
+ America/Indiana/Knox America/Lower_Princes America/Coral_Harbour
139
+ America/St_Barthelemy Australia/Broken_Hill America/Cambridge_Bay
140
+ America/Indiana/Vevay America/Swift_Current America/Port_of_Spain
141
+ Antarctica/South_Pole America/Santo_Domingo Atlantic/South_Georgia
142
+ America/Port-au-Prince America/Bahia_Banderas America/Indiana/Winamac
143
+ America/Indiana/Marengo America/Argentina/Jujuy America/Argentina/Salta
144
+ Canada/East-Saskatchewan America/Indiana/Vincennes America/Argentina/Tucuman
145
+ America/Argentina/Ushuaia Antarctica/DumontDUrville America/Indiana/Tell_City
146
+ America/Argentina/Mendoza America/Argentina/Cordoba America/Indiana/Petersburg
147
+ America/Argentina/San_Luis America/Argentina/San_Juan America/Argentina/La_Rioja
148
+ America/North_Dakota/Center America/Kentucky/Monticello
149
+ America/North_Dakota/Beulah America/Kentucky/Louisville
150
+ America/Argentina/Catamarca America/Indiana/Indianapolis
151
+ America/North_Dakota/New_Salem America/Argentina/Rio_Gallegos
152
+ America/Argentina/Buenos_Aires America/Argentina/ComodRivadavia
153
+ ]
154
+
155
+ ##
156
+ ## http://en.wikipedia.org/wiki/List_of_time_zone_abbreviations
157
+ #
158
+ #ABBREVIATIONS = %w[
159
+ #ACDT ACST ACT ADT AEDT AEST AFT AKDT AKST AMST AMST AMT AMT ART AST AST AWDT
160
+ #AWST AZOST AZT BDT BIOT BIT BOT BRT BST BST BTT CAT CCT CDT CDT CEDT CEST CET
161
+ #CHADT CHAST CHOT ChST CHUT CIST CIT CKT CLST CLT COST COT CST CST CST CST CST
162
+ #CT CVT CWST CXT DAVT DDUT DFT EASST EAST EAT ECT ECT EDT EEDT EEST EET EGST EGT
163
+ #EIT EST EST FET FJT FKST FKST FKT FNT GALT GAMT GET GFT GILT GIT GMT GST GST
164
+ #GYT HADT HAEC HAST HKT HMT HOVT HST ICT IDT IOT IRDT IRKT IRST IST IST IST JST
165
+ #KGT KOST KRAT KST LHST LHST LINT MAGT MART MAWT MDT MET MEST MHT MIST MIT MMT
166
+ #MSK MST MST MST MUT MVT MYT NCT NDT NFT NPT NST NT NUT NZDT NZST OMST ORAT PDT
167
+ #PET PETT PGT PHOT PKT PMDT PMST PONT PST PST PYST PYT RET ROTT SAKT SAMT SAST
168
+ #SBT SCT SGT SLST SRET SRT SST SST SYOT TAHT THA TFT TJT TKT TLT TMT TOT TVT UCT
169
+ #ULAT USZ1 UTC UYST UYT UZT VET VLAT VOLT VOST VUT WAKT WAST WAT WEDT WEST WET
170
+ #WIT WST YAKT YEKT Z
171
+ #].uniq
172
+
173
+ end
174
+
@@ -0,0 +1,154 @@
1
+ #--
2
+ # Copyright (c) 2006-2015, John Mettraux, jmettraux@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+ # Made in Japan.
23
+ #++
24
+
25
+ require 'rufus/scheduler/zones'
26
+
27
+
28
+ class Rufus::Scheduler
29
+
30
+ #
31
+ # Zon{ing|ed}Time, whatever.
32
+ #
33
+ class ZoTime
34
+
35
+ attr_accessor :seconds
36
+ attr_accessor :zone
37
+
38
+ def initialize(s, zone)
39
+
40
+ @seconds = s.to_f
41
+ @zone = zone
42
+ end
43
+
44
+ def time
45
+
46
+ in_zone do
47
+
48
+ t = Time.at(@seconds)
49
+
50
+ if t.isdst
51
+ t1 = Time.at(@seconds + 3600)
52
+ t = t1 if t.zone != t1.zone && t.hour == t1.hour && t.min == t1.min
53
+ # ambiguous TZ (getting out of DST)
54
+ else
55
+ t.hour # force t to compute itself
56
+ end
57
+
58
+ t
59
+ end
60
+ end
61
+
62
+ def utc
63
+
64
+ time.utc
65
+ end
66
+
67
+ def add(s)
68
+
69
+ @seconds += s.to_f
70
+ end
71
+
72
+ def substract(s)
73
+
74
+ @seconds -= s.to_f
75
+ end
76
+
77
+ def to_f
78
+
79
+ @seconds
80
+ end
81
+
82
+ #DELTA_TZ_REX = /^[+-][0-1][0-9]:?[0-5][0-9]$/
83
+
84
+ def self.envtzable?(s)
85
+
86
+ TIMEZONES.include?(s)
87
+ end
88
+
89
+ def self.parse(str, opts={})
90
+
91
+ if defined?(::Chronic) && t = ::Chronic.parse(str, opts)
92
+ return ZoTime.new(t, ENV['TZ'])
93
+ end
94
+
95
+ begin
96
+ DateTime.parse(str)
97
+ rescue
98
+ raise ArgumentError, "no time information in #{o.inspect}"
99
+ end if RUBY_VERSION < '1.9.0'
100
+
101
+ zone = nil
102
+
103
+ s =
104
+ str.gsub(/\S+/) { |m|
105
+ if envtzable?(m)
106
+ zone ||= m
107
+ ''
108
+ else
109
+ m
110
+ end
111
+ }
112
+
113
+ return nil unless zone.nil? || is_timezone?(zone)
114
+
115
+ zt = ZoTime.new(0, zone || ENV['TZ'])
116
+ zt.in_zone { zt.seconds = Time.parse(s).to_f }
117
+
118
+ zt.seconds == nil ? nil : zt
119
+ end
120
+
121
+ def self.is_timezone?(str)
122
+
123
+ return false if str == nil
124
+
125
+ return true if Time.zone_offset(str)
126
+ return true if str == 'Zulu'
127
+
128
+ return !! (::TZInfo::Timezone.get(str) rescue nil) if defined?(::TZInfo)
129
+
130
+ zt = ZoTime.new(0, str)
131
+ t = zt.time
132
+
133
+ return false if t.zone == ''
134
+ return false if str.match(/[a-z]/) && str.start_with?(t.zone)
135
+
136
+ return false if RUBY_PLATFORM.include?('java') && ! envtzable?(str)
137
+
138
+ true
139
+ end
140
+
141
+ def in_zone(&block)
142
+
143
+ current_timezone = ENV['TZ']
144
+ ENV['TZ'] = @zone
145
+
146
+ block.call
147
+
148
+ ensure
149
+
150
+ ENV['TZ'] = current_timezone
151
+ end
152
+ end
153
+ end
154
+
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2006-2014, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2006-2015, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -25,8 +25,7 @@
25
25
  require 'date' if RUBY_VERSION < '1.9.0'
26
26
  require 'time'
27
27
  require 'thread'
28
- require 'tzinfo'
29
- require 'fileutils'
28
+ #require 'tzinfo'
30
29
 
31
30
 
32
31
  module Rufus
@@ -34,11 +33,13 @@ module Rufus
34
33
  class Scheduler
35
34
 
36
35
  require 'rufus/scheduler/util'
36
+ require 'rufus/scheduler/zotime'
37
37
  require 'rufus/scheduler/jobs'
38
38
  require 'rufus/scheduler/cronline'
39
39
  require 'rufus/scheduler/job_array'
40
+ require 'rufus/scheduler/locks'
40
41
 
41
- VERSION = '3.0.8'
42
+ VERSION = '3.1.0'
42
43
 
43
44
  #
44
45
  # A common error class for rufus-scheduler
@@ -93,7 +94,17 @@ module Rufus
93
94
 
94
95
  @thread_key = "rufus_scheduler_#{self.object_id}"
95
96
 
96
- lock || return
97
+ @scheduler_lock =
98
+ if lockfile = opts[:lockfile]
99
+ Rufus::Scheduler::FileLock.new(lockfile)
100
+ else
101
+ opts[:scheduler_lock] || Rufus::Scheduler::NullLock.new
102
+ end
103
+
104
+ @trigger_lock = opts[:trigger_lock] || Rufus::Scheduler::NullLock.new
105
+
106
+ # If we can't grab the @scheduler_lock, don't run.
107
+ @scheduler_lock.lock || return
97
108
 
98
109
  start
99
110
  end
@@ -324,6 +335,49 @@ module Rufus
324
335
  @jobs[job_id]
325
336
  end
326
337
 
338
+ # Returns true if the scheduler has acquired the [exclusive] lock and
339
+ # thus may run.
340
+ #
341
+ # Most of the time, a scheduler is run alone and this method should
342
+ # return true. It is useful in cases where among a group of applications
343
+ # only one of them should run the scheduler. For schedulers that should
344
+ # not run, the method should return false.
345
+ #
346
+ # Out of the box, rufus-scheduler proposes the
347
+ # :lockfile => 'path/to/lock/file' scheduler start option. It makes
348
+ # it easy for schedulers on the same machine to determine which should
349
+ # run (the first to write the lockfile and lock it). It uses "man 2 flock"
350
+ # so it probably won't work reliably on distributed file systems.
351
+ #
352
+ # If one needs to use a special/different locking mechanism, the scheduler
353
+ # accepts :scheduler_lock => lock_object. lock_object only needs to respond
354
+ # to #lock
355
+ # and #unlock, and both of these methods should be idempotent.
356
+ #
357
+ # Look at rufus/scheduler/locks.rb for an example.
358
+ #
359
+ def lock
360
+
361
+ @scheduler_lock.lock
362
+ end
363
+
364
+ # Sister method to #lock, is called when the scheduler shuts down.
365
+ #
366
+ def unlock
367
+
368
+ @trigger_lock.unlock
369
+ @scheduler_lock.unlock
370
+ end
371
+
372
+ # Callback called when a job is triggered. If the lock cannot be acquired,
373
+ # the job won't run (though it'll still be scheduled to run again if
374
+ # necessary).
375
+ #
376
+ def confirm_lock
377
+
378
+ @trigger_lock.lock
379
+ end
380
+
327
381
  # Returns true if this job is currently scheduled.
328
382
  #
329
383
  # Takes extra care to answer true if the job is a repeat job
@@ -423,7 +477,8 @@ module Rufus
423
477
  stderr.puts(" #{pre} opts:")
424
478
  stderr.puts(" #{pre} #{@opts.inspect}")
425
479
  stderr.puts(" #{pre} frequency: #{self.frequency}")
426
- stderr.puts(" #{pre} lockfile: #{@lockfile.inspect}")
480
+ stderr.puts(" #{pre} scheduler_lock: #{@scheduler_lock.inspect}")
481
+ stderr.puts(" #{pre} trigger_lock: #{@trigger_lock.inspect}")
427
482
  stderr.puts(" #{pre} uptime: #{uptime} (#{uptime_s})")
428
483
  stderr.puts(" #{pre} down?: #{down?}")
429
484
  stderr.puts(" #{pre} threads: #{self.threads.size}")
@@ -468,61 +523,6 @@ module Rufus
468
523
  end
469
524
  end
470
525
 
471
- # Returns true if the scheduler has acquired the [exclusive] lock and
472
- # thus may run.
473
- #
474
- # Most of the time, a scheduler is run alone and this method should
475
- # return true. It is useful in cases where among a group of applications
476
- # only one of them should run the scheduler. For schedulers that should
477
- # not run, the method should return false.
478
- #
479
- # Out of the box, rufus-scheduler proposes the
480
- # :lockfile => 'path/to/lock/file' scheduler start option. It makes
481
- # it easy for schedulers on the same machine to determine which should
482
- # run (to first to write the lockfile and lock it). It uses "man 2 flock"
483
- # so it probably won't work reliably on distributed file systems.
484
- #
485
- # If one needs to use a special/different locking mechanism, providing
486
- # overriding implementation for this #lock and the #unlock complement is
487
- # easy.
488
- #
489
- def lock
490
-
491
- @lockfile = nil
492
-
493
- return true unless f = @opts[:lockfile]
494
-
495
- raise ArgumentError.new(
496
- ":lockfile argument must be a string, not a #{f.class}"
497
- ) unless f.is_a?(String)
498
-
499
- FileUtils.mkdir_p(File.dirname(f))
500
-
501
- f = File.new(f, File::RDWR | File::CREAT)
502
- locked = f.flock(File::LOCK_NB | File::LOCK_EX)
503
-
504
- return false unless locked
505
-
506
- now = Time.now
507
-
508
- f.print("pid: #{$$}, ")
509
- f.print("scheduler.object_id: #{self.object_id}, ")
510
- f.print("time: #{now}, ")
511
- f.print("timestamp: #{now.to_f}")
512
- f.flush
513
-
514
- @lockfile = f
515
-
516
- true
517
- end
518
-
519
- # Sister method to #lock, is called when the scheduler shuts down.
520
- #
521
- def unlock
522
-
523
- @lockfile.flock(File::LOCK_UN) if @lockfile
524
- end
525
-
526
526
  def terminate_all_jobs
527
527
 
528
528
  jobs.each { |j| j.unschedule }
@@ -26,38 +26,13 @@ job scheduler for Ruby (at, cron, in and every jobs).
26
26
  '*.gemspec', '*.txt', '*.rdoc', '*.md'
27
27
  ]
28
28
 
29
- s.add_runtime_dependency 'tzinfo'
29
+ #s.add_runtime_dependency 'tzinfo'
30
30
 
31
31
  s.add_development_dependency 'rake'
32
32
  s.add_development_dependency 'rspec', '>= 2.13.0'
33
33
  s.add_development_dependency 'chronic'
34
+ s.add_development_dependency 'tzinfo'
34
35
 
35
36
  s.require_path = 'lib'
36
-
37
- s.post_install_message =
38
- %{
39
- ***
40
-
41
- Thanks for installing rufus-scheduler #{s.version}
42
-
43
- It might not be 100% compatible with rufus-scheduler 2.x.
44
-
45
- If you encounter issues with this new rufus-scheduler, especially
46
- if your app worked fine with previous versions of it, you can
47
-
48
- A) Forget it and peg your Gemfile to rufus-scheduler 2.0.24
49
-
50
- and / or
51
-
52
- B) Take some time to carefully report the issue at
53
- https://github.com/jmettraux/rufus-scheduler/issues
54
-
55
- For general help about rufus-scheduler, ask via:
56
- http://stackoverflow.com/questions/ask?tags=rufus-scheduler+ruby
57
-
58
- Cheers.
59
-
60
- ***
61
- }
62
37
  end
63
38