slack-utils 0.5.3 → 0.6.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.
data/README.rdoc CHANGED
@@ -38,7 +38,7 @@ TODO:
38
38
  == Installation
39
39
 
40
40
  To install the gem
41
- sudo gem install pkg/slack-utils-0.5.3.gem
41
+ sudo gem install pkg/slack-utils-0.6.0.gem
42
42
 
43
43
  == Quick Start
44
44
 
File without changes
data/examples/repo.rb CHANGED
File without changes
File without changes
data/lib/slackware.rb CHANGED
@@ -2,4 +2,5 @@
2
2
  require 'slackware/version'
3
3
  require 'slackware/package'
4
4
  require 'slackware/system'
5
+ require 'slackware/changelog'
5
6
  require 'slackware/repo'
@@ -0,0 +1,238 @@
1
+
2
+ require 'slackware/package'
3
+ require 'date'
4
+ require 'time'
5
+
6
+ module Slackware
7
+ # The class for parsing a Slackware standard ChangeLog.txt
8
+ class ChangeLog
9
+
10
+ # yanked from +Date+
11
+ ABBR_DAYNAMES = %w(Sun Mon Tue Wed Thu Fri Sat)
12
+ ABBR_MONTHNAMES = %w(Jan Feb Mar Apr May Jun
13
+ Jul Aug Sep Oct Nov Dec)
14
+
15
+ # Compiling a fat regex to find the date entries
16
+ re_daynames = Regexp.new(ABBR_DAYNAMES.join('|'))
17
+ re_monthnames = Regexp.new(ABBR_MONTHNAMES.join('|'))
18
+ RE_DATE = Regexp.new(/^(#{re_daynames}\s+#{re_monthnames}\s+\d+\s+\d{2}:\d{2}:\d{2}\s\w+\s+\d+)$/)
19
+
20
+ # This break has been the same as long as I can find
21
+ RE_CHANGELOG_BREAK = Regexp.new(/^\+--------------------------\+$/)
22
+
23
+ # The regular entry, accounting for usb-and-pxe-installers directory,
24
+ # and notes after the action
25
+ re_package_entry0 = Regexp.new(/^(([\w+-]+).*\/.*):\s+(\w+).*\.?$/)
26
+ # Some didn't have an action after the name
27
+ re_package_entry1 = Regexp.new(/^(([\w+-]+).*\/.*):/)
28
+ # and some didn't have the ':' or an action
29
+ re_package_entry2 = Regexp.new(/^(([\w+-]+).*\/.*\.t[gbx]z)/)
30
+ # combine them
31
+ RE_PACKAGE_ENTRY = Regexp.union(re_package_entry0, re_package_entry1, re_package_entry2)
32
+
33
+ # (* Security fix *)
34
+ RE_SECURITY_FIX = Regexp.new(/\(\*\s+security\s+fix\s+\*\)/i)
35
+
36
+ # for hacks sake, make these usbable elsewhere
37
+ def self::re_date ; RE_DATE ; end
38
+ def self::re_changelog_break ; RE_CHANGELOG_BREAK ; end
39
+ def self::re_package_entry ; RE_PACKAGE_ENTRY ; end
40
+ def self::re_security_fix ; RE_SECURITY_FIX ; end
41
+
42
+ # A changeset, which should consist of entries of changes and/or notes
43
+ # regarding the updates
44
+ class Update
45
+ # FIXME this class needs more proper value setting
46
+ def initialize(date = nil, notes = "", entries = Array.new)
47
+ @date = date
48
+ @notes = notes
49
+ @entries = entries
50
+ end
51
+ def date; @date; end
52
+ def notes; @notes; end
53
+ def entries; @entries; end
54
+
55
+ def date=(timestamp)
56
+ if (timestamp.is_a?(Time))
57
+ @date = timestamp
58
+ elsif (timestamp.is_a?(Date))
59
+ @date = timestamp.to_time
60
+ else
61
+ @date = Time.parse(timestamp)
62
+ end
63
+ end
64
+ def notes=(text); @notes = text; end
65
+ end
66
+
67
+ # The class for each item in a change set
68
+ class Entry
69
+ def initialize(package = nil, section = nil, action = nil, notes = "", security = false)
70
+ @package = package
71
+ @section = section
72
+ @action = action
73
+ notes.is_a?(String) ? @notes = notes : @notes = ""
74
+ security == true ? @security = security : @security = false
75
+ end
76
+
77
+ def package; @package; end
78
+ def section; @section; end
79
+ def action; @action; end
80
+ def notes; @notes; end
81
+ def security; @security; end
82
+
83
+ def package=(package_name); @package = package_name ; end
84
+ def section=(section_name); @section = section_name ; end
85
+ def action=(action_name); @action = action_name ; end
86
+ def notes=(notes_txt)
87
+ notes_txt.is_a?(String) ? @notes = notes_txt : @notes = ""
88
+ end
89
+ def security=(bool)
90
+ bool == true ? @security = bool : @security = false
91
+ end
92
+ end
93
+
94
+ # +file+ can be a path to a file, or a +File+ object
95
+ # +opts+ can include
96
+ # * :arch - basically '64' or '32'
97
+ # * :version - 13.1, 13.2, current, etc.
98
+ # * :url - the URL web link to the ChangeLog.txt
99
+ def initialize(file = nil, opts = {})
100
+ @file = file
101
+ @opts = opts
102
+ @updates = Array.new
103
+ end
104
+
105
+ def file; @file; end
106
+ def opts; @opts; end
107
+ def updates; @updates; end
108
+ def entries
109
+ @updates.map {|update| update.entries.map {|entry| {:date => update.date, :entry => entry } } }.flatten
110
+ end
111
+ def security
112
+ @updates.map {|u| u.entries.map {|e| {:date => u.date, :entry => e } if e.security } }.flatten.compact
113
+ end
114
+ def opts=(hash)
115
+ if hash.is_a?(Hash)
116
+ @opts = hash
117
+ end
118
+ end
119
+
120
+ def parse
121
+ unless @file.nil?
122
+ @updates = parse_this_file(@file).updates
123
+ end
124
+ return self
125
+ end
126
+
127
+ # Class method
128
+ def self::parse(file)
129
+ return parse_this_file(file)
130
+ end
131
+
132
+ def self::open(file)
133
+ return parse_this_file(file)
134
+ end
135
+
136
+ def inspect
137
+ "#<%s:0x%x @file=%s, %d @updates, %d @entries>" % [self.class.name, self.object_id.abs, self.file || '""', self.updates.count || 0, self.entries.count || 0]
138
+ end
139
+
140
+ private
141
+ # Parse order is something like:
142
+ # * if its' a date match, store the date
143
+ # * take change notes until
144
+ # * package match on name and action
145
+ # * set @security if present
146
+ # * take packge notes until
147
+ # * next package or entry separator
148
+ # * separator creates next change entry
149
+ def parse_this_file(file)
150
+ f_handle = ""
151
+ if file.is_a?(File)
152
+ f_handle = file
153
+ elsif file.is_a?(String)
154
+ if File.exist?(File.expand_path(file))
155
+ f_handle = File.open(File.expand_path(file))
156
+ else
157
+ raise StandardError.new("file not found\n")
158
+ end
159
+ else
160
+ raise StandardError.new("file not found\n")
161
+ end
162
+
163
+ # Start our changelog
164
+ changelog = ChangeLog.new(f_handle)
165
+ f_handle.each do |line|
166
+ if (line =~ RE_DATE)
167
+ u = Update.new(Time.parse($1))
168
+ while true
169
+ if (f_handle.eof?)
170
+ break
171
+ end
172
+
173
+ # take the next line
174
+ u_line = f_handle.readline
175
+ if (u_line =~ RE_CHANGELOG_BREAK)
176
+ break
177
+ end
178
+
179
+ # the intimate iteration
180
+ # +Match+ is more expensive than =~,
181
+ # but ruby-1.8.x is lossing the matched values down below
182
+ # so this works on both ...
183
+ if (match = RE_PACKAGE_ENTRY.match(u_line))
184
+ u_entry = Entry.new()
185
+ # This silly iteration catches the different cases of
186
+ # which package line, matches which Regexp. WIN
187
+ if match[1].nil?
188
+ if match[4].nil?
189
+ u_entry.package = match[6] unless match[6].nil?
190
+ else
191
+ u_entry.package = match[4]
192
+ end
193
+ else
194
+ u_entry.package = match[1]
195
+ end
196
+ if u_entry.package.include?("/")
197
+ u_entry.package = u_entry.package.split("/")[-1]
198
+ end
199
+ if match[2].nil?
200
+ if match[5].nil?
201
+ u_entry.section = match[7] unless match[7].nil?
202
+ else
203
+ u_entry.section = match[5]
204
+ end
205
+ else
206
+ u_entry.section = match[2]
207
+ end
208
+ # set the action for the item, if it's present
209
+ u_entry.action = match[3] unless match[3].nil?
210
+
211
+ # Add this entry to the stack
212
+ u.entries << u_entry
213
+ else
214
+ # if u.entries is empty, then this text is notes
215
+ # for the upate, else it is notes, for the entry
216
+ if (u.entries.empty?)
217
+ u.notes = u.notes + u_line
218
+ else
219
+ # if this line of the entry security fix, toggle the bool
220
+ if (u_line =~ RE_SECURITY_FIX)
221
+ u.entries[-1].security = true
222
+ end
223
+ u.entries[-1].notes = u.entries[-1].notes + u_line
224
+ end
225
+ end
226
+ end
227
+
228
+ # Add this update to the stack
229
+ changelog.updates << u
230
+ end
231
+ end
232
+
233
+ # Give them their change set
234
+ return changelog
235
+ end
236
+
237
+ end
238
+ end
@@ -0,0 +1,87 @@
1
+ require 'rss/maker'
2
+ require 'slackware/changelog'
3
+
4
+ module Slackware
5
+ class ChangeLog
6
+ def to_rss
7
+ version = "2.0" # ["0.9", "1.0", "2.0"]
8
+ content = RSS::Maker.make(version) do |m|
9
+ added_title = ""
10
+ if @opts[:arch]
11
+ added_title = added_title + "slackware#{@opts[:arch]}"
12
+ end
13
+ if @opts[:version]
14
+ added_title = added_title + "-#{@opts[:version]}"
15
+ end
16
+
17
+ if added_title.empty?
18
+ m.channel.title = "Slackware ChangeLog.txt feed"
19
+ else
20
+ m.channel.title = "Slackware ChangeLog.txt feed for #{added_title}"
21
+ end
22
+ if @opts[:url]
23
+ m.channel.link = "%s#slackagg" % [@opts[:url]]
24
+ else
25
+ m.channel.link = "http://www.slackware.com/#slackagg"
26
+ end
27
+ #m.channel.logo = "http://connie.slackware.com/~msimons/slackware/grfx/shared/bluepiSW.jpg"
28
+ m.channel.logo = "http://connie.slackware.com/~msimons/slackware/grfx/shared/dobbslack1.jpg"
29
+ m.channel.description = "a parsed ChangeLog.txt, is an extendable ChangeLog.txt"
30
+ m.items.do_sort = true # sort items by date
31
+
32
+ @updates.each {|update|
33
+ i = m.items.new_item
34
+ # Add a plug to the title of the update, if it includes a security fix
35
+ # set this here, so we don't have to .map again down below
36
+ security = update.entries.map {|e| 1 if e.security }.compact.count
37
+ if (security > 0)
38
+ i.title = "%s (* Security fix *)" % [update.date.utc.to_s]
39
+ else
40
+ i.title = update.date.utc.to_s
41
+ end
42
+ if @opts[:url]
43
+ i.link = "%s#%s" % [@opts[:url], update.date.to_i]
44
+ else
45
+ i.link = "http://slackware.com/#slackagg#%s" % [update.date.to_i]
46
+ end
47
+ i.date = update.date
48
+
49
+ i.description = ""
50
+ if (update.entries.count > 0)
51
+ if (security > 0)
52
+ i.description = "%d new update(s), %d security update(s)\n\n" % [update.entries.count, security]
53
+ else
54
+ i.description = "%d new update(s)\n\n" % [update.entries.count]
55
+ end
56
+ end
57
+ i.description = i.description + "<pre><blockquote>\n"
58
+ unless (update.notes.empty?)
59
+ i.description = i.description + update.notes + "\n\n"
60
+ end
61
+ if (update.entries.count > 0)
62
+ update.entries.each {|entry|
63
+ if (entry.notes.empty?)
64
+ i.description = i.description + sprintf("%s/%s:\s%s\n",
65
+ entry.section,
66
+ entry.package,
67
+ entry.action)
68
+ else
69
+ i.description = i.description + sprintf("%s/%s:\s%s\n\s\s%s\n",
70
+ entry.section,
71
+ entry.package,
72
+ entry.action,
73
+ entry.notes)
74
+ end
75
+ }
76
+ end
77
+ i.description = i.description + "</blockquote></pre>\n"
78
+ i.description.gsub!(/\n/, "<br/>\n")
79
+ }
80
+ end
81
+ return content
82
+ end
83
+ end
84
+ end
85
+
86
+
87
+
@@ -18,8 +18,8 @@ module Slackware
18
18
  name = $1
19
19
  self.upgrade_time = Time.strptime($2 + ' ' + $3, fmt='%F %H:%M:%S')
20
20
  end
21
- arr = name.split('-').reverse
22
- build = arr.shift
21
+ arr = name.split('-')
22
+ build = arr.pop
23
23
  if (build.include?("_"))
24
24
  self.tag_sep = "_"
25
25
  self.build = build.split(self.tag_sep)[0]
@@ -29,10 +29,11 @@ module Slackware
29
29
  self.tag = $2
30
30
  else
31
31
  self.build = build
32
+ self.tag = ""
32
33
  end
33
- self.arch = arr.shift
34
- self.version = arr.shift
35
- self.name = arr.reverse.join('-')
34
+ self.arch = arr.pop
35
+ self.version = arr.pop
36
+ self.name = arr.join('-')
36
37
  end
37
38
 
38
39
  # Package.parse class method
@@ -54,8 +55,8 @@ module Slackware
54
55
 
55
56
  # Accessor for the PACKAGE DESCRIPTION from the package file
56
57
  def package_description
57
- if not(self.package_description.nil?)
58
- return self.package_description
58
+ if not(@package_description.nil?)
59
+ return @package_description
59
60
  end
60
61
 
61
62
  f = File.open(self.path + '/' + self.fullname)
@@ -69,13 +70,13 @@ module Slackware
69
70
 
70
71
  # Setter for the PACKAGE DESCRIPTION, in the event you are parsing a repo file
71
72
  def package_description=(desc)
72
- self.package_description = desc
73
+ @package_description = desc
73
74
  end
74
75
 
75
76
  # Accessor for the PACKAGE LOCATION from the package file
76
77
  def package_location
77
- if not(self.package_location.nil?)
78
- return self.package_location
78
+ if not(@package_location.nil?)
79
+ return @package_location
79
80
  end
80
81
 
81
82
  f = File.open(self.path + '/' + self.fullname)
@@ -88,13 +89,13 @@ module Slackware
88
89
 
89
90
  # Setter for the PACKAGE LOCATION, in the event you are parsing a repo file
90
91
  def package_location=(path)
91
- self.package_location = path
92
+ @package_location = path
92
93
  end
93
94
 
94
95
  # Accessor for the UNCOMPRESSED PACKAGE SIZE from the package file
95
96
  def uncompressed_size
96
- if not(self.uncompressed_size.nil?)
97
- return self.uncompressed_size
97
+ if not(@uncompressed_size.nil?)
98
+ return @uncompressed_size
98
99
  end
99
100
 
100
101
  f = File.open(self.path + '/' + self.fullname)
@@ -107,13 +108,13 @@ module Slackware
107
108
 
108
109
  # Setter for the UNCOMPRESSED PACKAGE SIZE, in the event you are parsing a repo file
109
110
  def uncompressed_size=(size)
110
- self.uncompressed_size = size
111
+ @uncompressed_size = size
111
112
  end
112
113
 
113
114
  # Accessor for the COMPRESSED PACKAGE SIZE from the package file
114
115
  def compressed_size
115
- if not(self.compressed_size.nil?)
116
- return self.compressed_size
116
+ if not(@compressed_size.nil?)
117
+ return @compressed_size
117
118
  end
118
119
 
119
120
  f = File.open(self.path + '/' + self.fullname)
@@ -126,14 +127,14 @@ module Slackware
126
127
 
127
128
  # Setter for the COMPRESSED PACKAGE SIZE, in the event you are parsing a repo file
128
129
  def compressed_size=(size)
129
- self.compressed_size = size
130
+ @compressed_size = size
130
131
  end
131
132
 
132
133
  # Accessor for the FILE LIST from the package file
133
134
  # unless the :owned_files symbol is populated
134
135
  def get_owned_files
135
- if not(self.owned_files.nil?)
136
- return self.owned_files
136
+ if not(@owned_files.nil?)
137
+ return @owned_files
137
138
  else
138
139
  f = File.open(self.path + '/' + self.fullname)
139
140
  files = f.drop_while {|l| not( l =~ /^FILE LIST:/) }[2..-1].map {|l| l.chomp }
@@ -144,8 +145,8 @@ module Slackware
144
145
 
145
146
  # Set the file list in the package object in memory
146
147
  def set_owned_files
147
- if self.owned_files.nil?
148
- self.owned_files = self.get_owned_files
148
+ if @owned_files.nil?
149
+ @owned_files = @get_owned_files
149
150
  return true
150
151
  else
151
152
  return false
@@ -158,7 +159,7 @@ module Slackware
158
159
  if (File.exist?(self.path + "/" + self.fullname))
159
160
  self.time = File.mtime(self.path + "/" + self.fullname)
160
161
  end
161
- elsif (self.time.nil? && not(self.path))
162
+ elsif (not(self.path) && (self.time.nil?))
162
163
  if (File.exist?(DIR_INSTALLED_PACKAGES + "/" + self.fullname))
163
164
  self.time = File.mtime(DIR_INSTALLED_PACKAGES + "/" + self.fullname)
164
165
  end
@@ -174,6 +175,18 @@ module Slackware
174
175
  end
175
176
  end
176
177
 
178
+ def inspect
179
+ "#<%s:0x%x name=%s version=%s arch=%s build=%s tag=%s>" % [
180
+ self.class.name,
181
+ self.object_id,
182
+ self.name,
183
+ self.version,
184
+ self.arch,
185
+ self.build,
186
+ self.tag
187
+ ]
188
+ end
189
+
177
190
  end
178
191
 
179
192
  class Script < Package
@@ -1,5 +1,6 @@
1
1
 
2
2
  require 'slackware/package'
3
+ require 'slackware/changelog'
3
4
  require 'slackware/system'
4
5
  require 'net/http'
5
6
  require 'net/ftp'
@@ -38,15 +39,17 @@ module Slackware
38
39
  end
39
40
  a
40
41
  end
42
+ else
43
+ ## do some hot parsing of repo
41
44
  end
42
45
  end
43
46
 
44
47
  def fetch(file = nil)
45
- if file.nil?
46
- url = URI.parse(self.proto + self.mirror + self.path)
47
- else
48
- url = URI.parse(self.proto + self.mirror + self.path + file)
49
- end
48
+ #if file.nil?
49
+ #url = URI.parse(self.proto + self.mirror + self.path)
50
+ #else
51
+ #url = URI.parse(self.proto + self.mirror + self.path + file)
52
+ #end
50
53
  if self.proto =~ /ftp/
51
54
  ftp = Net::FTP.open(self.mirror)
52
55
  ftp.login
@@ -63,6 +66,12 @@ module Slackware
63
66
  req = Net::HTTP::Get.new(url.path)
64
67
  res = Net::HTTP.start(url.host, url.port) {|http| http.request(req) }
65
68
  return res
69
+ elsif self.proto =~ /file/
70
+ if (file.nil?)
71
+ return Dir.glob(self.path + "slackware" + self.arch + "-" + self.version + "/*")
72
+ else
73
+ return File.read(self.path + "slackware" + self.arch + "-" + self.version + "/" + file)
74
+ end
66
75
  else
67
76
  return nil
68
77
  end
@@ -81,8 +90,22 @@ module Slackware
81
90
  actions = %w{removed added upgraded rebuilt}
82
91
  actions.each {|action|
83
92
  changelog[:"#{action}"] = changelog_date.map {|line|
84
- if line =~ /^\w+\/(.*)\.t[gx]z:\s+#{action}\.?$/i
85
- Slackware::Package.parse($1)
93
+ if line =~ /^(\w+)\/(.*)\.t[gx]z:\s+#{action}\.?$/i
94
+ s = Slackware::Package.parse($2)
95
+ s.path = $1
96
+ if (self.mirror.nil?)
97
+ base_path= self.path
98
+ else
99
+ base_path= self.mirror + self.path
100
+ end
101
+ s.package_location = self.proto +
102
+ base_path +
103
+ "slackware" +
104
+ self.arch +
105
+ "-" +
106
+ self.version +
107
+ "/"
108
+ s
86
109
  end
87
110
  }.compact
88
111
  }
@@ -33,7 +33,15 @@ module Slackware
33
33
  end
34
34
 
35
35
  def self::tags_used
36
- return installed_packages.map {|p| p.tag }.uniq.compact
36
+ pkgs = installed_packages
37
+ set = []
38
+ pkgs.map {|p| p.tag }.uniq.each {|tag|
39
+ m_set = {}
40
+ m_set[:tag] = tag
41
+ m_set[:count] = pkgs.map {|p| p if p.tag == tag }.compact.count
42
+ set << m_set
43
+ }
44
+ return set
37
45
  end
38
46
 
39
47
  def self::with_tag(tag)
@@ -142,7 +142,11 @@ def find_orphaned_config_files
142
142
  # build a list of config files currently installed
143
143
  installed_config_files = Slackware::System.installed_packages.map {|pkg|
144
144
  pkg.get_owned_files.map {|file|
145
- file if (file =~ /^etc\// && not(file =~ /\/$/))
145
+ if not(file =~ /\/$/)
146
+ if (file =~ /^etc\//)
147
+ file
148
+ end
149
+ end
146
150
  }
147
151
  }.flatten.compact
148
152
 
@@ -155,8 +159,10 @@ def find_orphaned_config_files
155
159
  if (config.count > 0)
156
160
  # remove config files that are owned by a currently installed package
157
161
  config = config.map {|file|
158
- if (not(installed_config_files.include?(file)) && not(installed_config_files.include?(file + ".new")))
159
- file
162
+ if not(installed_config_files.include?(file))
163
+ if not(installed_config_files.include?(file + ".new"))
164
+ file
165
+ end
160
166
  end
161
167
  }.compact
162
168
  # check again, and continue if there are no config files left
@@ -7,6 +7,6 @@ module Slackware
7
7
  rescue
8
8
  nil
9
9
  end
10
- UTILS_VERSION = "0.5.3"
10
+ UTILS_VERSION = "0.6.0"
11
11
  end
12
12
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slack-utils
3
3
  version: !ruby/object:Gem::Version
4
- hash: 13
4
+ hash: 7
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 5
9
- - 3
10
- version: 0.5.3
8
+ - 6
9
+ - 0
10
+ version: 0.6.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Vincent Batts
@@ -48,6 +48,8 @@ files:
48
48
  - examples/repo.rb
49
49
  - lib/slackware.rb
50
50
  - lib/slackware/utils.rb
51
+ - lib/slackware/changelog.rb
52
+ - lib/slackware/changelog/rss.rb
51
53
  - lib/slackware/package.rb
52
54
  - lib/slackware/repo.rb
53
55
  - lib/slackware/version.rb
@@ -61,7 +63,7 @@ rdoc_options:
61
63
  - --main=README.rdoc
62
64
  - --line-numbers
63
65
  - --inline-source
64
- - --title=Slackware utils (slack-utils) 0.5.3 Documentation
66
+ - --title=Slackware utils (slack-utils) 0.6.0 Documentation
65
67
  require_paths:
66
68
  - lib
67
69
  required_ruby_version: !ruby/object:Gem::Requirement