Class: Debci::Repository

Inherits:
Object
  • Object
show all
Defined in:
lib/debci/repository.rb

Overview

This class implements the backend access to the debci data files. Normally you should access the data through objects of the Debci::Package class, which you can obtain by calling this class' find_package method.

>> repository = Debci::Repository.new
>> package = repository.find_package('mypackage')

Defined Under Namespace

Classes: PackageNotFound

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path = nil) ⇒ Repository

:nodoc:



19
20
21
22
23
# File 'lib/debci/repository.rb', line 19

def initialize(path=nil) # :nodoc:
  path ||= Debci.config.data_basedir
  @path = path
  @data_dirs = Dir.glob(File.join(path, 'packages', '*', '*')).reject { |d| d =~ /\.old$/ }
end

Instance Attribute Details

#pathObject (readonly)

Returns the value of attribute path



17
18
19
# File 'lib/debci/repository.rb', line 17

def path
  @path
end

Instance Method Details

#all_status_for(package) ⇒ Object

Backend implementation for Debci::Package#all_status



150
151
152
153
154
155
156
157
# File 'lib/debci/repository.rb', line 150

def all_status_for(package)
  architectures.map do |arch|
    suites.map do |suite|
      status_file = File.join(data_dir(suite, arch, package), 'latest.json')
      load_status(status_file, suite, arch)
    end
  end
end

#architecturesObject

Returns an Array of architectures known to this debci instance



31
32
33
# File 'lib/debci/repository.rb', line 31

def architectures
  @architectures ||= @data_dirs.map { |d| File.basename(d) }.uniq.sort
end

#architectures_for(package) ⇒ Object

Returns an Array of architectures for which there is data for package.



92
93
94
95
# File 'lib/debci/repository.rb', line 92

def architectures_for(package)
  package = String(package)
  data_dirs_for(package).map { |d| File.basename(d) }.uniq
end

#blacklisted_status_for(package) ⇒ Object

Backend implementation for Debci::Package#blacklisted_status



165
166
167
# File 'lib/debci/repository.rb', line 165

def blacklisted_status_for(package)
  all_status_for(package).map { |r| r.select(&:blacklisted?) }
end

#each_packageObject

Iterates over all packages

For each package in the repostory, a Debci::Package object will be passed in to the block passed.

Example:

repository.each_package do |pkg| puts pkg end



123
124
125
126
127
128
# File 'lib/debci/repository.rb', line 123

def each_package
  packages.sort.each do |pkgname|
    pkg = Debci::Package.new(pkgname, self)
    yield pkg
  end
end

#failing_packagesObject

Returns a Set of packages known to this debci instance that are failing. If no packages are failing, nothing is returned



67
68
69
70
71
72
73
74
75
76
77
# File 'lib/debci/repository.rb', line 67

def failing_packages
  failing_packages = Set.new
  
  all_non_blacklisted_statuses.each do |status|
    if status.status == :fail
      failing_packages << status.package
    end
  end

  failing_packages.sort.map { |p| Debci::Package.new(p, self) }
end

#find_package(name) ⇒ Object

Returns a single package by its names.

Raises a Debci::PackageNotFound is there is no package with that name.



104
105
106
107
108
109
110
# File 'lib/debci/repository.rb', line 104

def find_package(name)
  if !packages.include?(name)
    raise PackageNotFound.new(name)
  end

  Debci::Package.new(name, self)
end

#global_news(limit = 10) ⇒ Object



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/debci/repository.rb', line 217

def global_news(limit = 10)
  latest = Dir[File.join(self.path, '*/*/*/*/*/latest.json')].sort_by do |f|
    File::Stat.new(f).mtime
  end

  news = []
  while !latest.empty?
    file = latest.pop
    dir = File.expand_path(File.dirname(file) + '/../..')
    suite = File.basename(File.dirname(dir))
    architecture = File.basename(dir)
    status = Debci::Status.from_file(file, suite, architecture)
    if status.newsworthy?
      news << status
    end
    if news.size >= limit
      break
    end
  end

  news
end

#history_for(package, suite, architecture) ⇒ Object

Backend implementation for Debci::Package#history



181
182
183
184
185
186
187
188
189
190
# File 'lib/debci/repository.rb', line 181

def history_for(package, suite, architecture)
  file = File.join(data_dir(suite, architecture, package), 'history.json')
  return [] unless File.exists?(file)

  entries = JSON.load(File.read(file))
  entries
    .map { |test| Debci::Status.from_data(test, suite, architecture) }
    .sort_by(&:date)
    .reverse
end

#news_for(package, n = 10) ⇒ Object

Backend implementation for Debci::Package#news



193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/debci/repository.rb', line 193

def news_for(package, n=10)
  history = []
  suites.each do |suite|
    architectures.each do |arch|
      history += history_for(package, suite, arch)
    end
  end
  history.sort_by! { |e| -e.run_id.to_i }

  news = []

  while !history.empty?
    status = history.shift
    if status.newsworthy?
      news << status
    end
    if news.size >= n
      break
    end
  end

  news
end

#non_blacklisted_packagesObject

Returns a Set of packages known to this debci instance which are not blacklisted



41
42
43
# File 'lib/debci/repository.rb', line 41

def non_blacklisted_packages
  @non_blacklisted_packages ||= packages - Debci.blacklist.packages
end

#packagesObject

Returns a Set of packages known to this debci instance



36
37
38
# File 'lib/debci/repository.rb', line 36

def packages
  @packages ||= (@data_dirs.map { |d| Dir.glob(File.join(d, '*/*')) }.flatten.map { |d| File.basename(d) } + Debci.blacklist.packages).to_set.sort
end

#platform_specific_issuesObject



169
170
171
172
173
174
175
176
177
178
# File 'lib/debci/repository.rb', line 169

def platform_specific_issues
  result = {}
  non_blacklisted_packages.each do |package|
    statuses = status_for(package).flatten
    if statuses.map(&:status).reject { |s| [:no_test_data, :tmpfail].include?(s) }.uniq.size > 1
      result[package] = statuses
    end
  end
  result
end

#prefixesObject

Returns an Array of package prefixes known to this debci instance



46
47
48
# File 'lib/debci/repository.rb', line 46

def prefixes
  @prefixes ||= @data_dirs.map { |d| Dir.glob(File.join(d, '*/')) }.flatten.map { |d| File.basename(d) }.uniq.sort
end

#search(query) ⇒ Object

Searches packages by name.

Returns a sorted Array of Debci::Package objects. On an exact match, it will return an Array with a single element. Otherwise all packages that match the query (which is converted into a regular expression) are returned.



136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/debci/repository.rb', line 136

def search(query)
  # first try exact match
  match = packages.select { |p| p == query }

  # then try regexp match
  if match.empty?
    re = Regexp.new(query)
    match = packages.select { |p| p =~ re }
  end

  match.sort.map { |p| Debci::Package.new(p, self) }
end

#slow_packagesObject



79
80
81
82
83
# File 'lib/debci/repository.rb', line 79

def slow_packages
  all_non_blacklisted_statuses.select do |status|
    status.duration_seconds && status.duration_seconds > 60 * 60 # 1h
  end.sort_by(&:duration_seconds)
end

#status_for(package) ⇒ Object

Backend implementation for Debci::Package#status



160
161
162
# File 'lib/debci/repository.rb', line 160

def status_for(package)
  all_status_for(package).map { |r| r.reject(&:blacklisted?) }
end

#status_history(suite, architecture) ⇒ Object

Returns the status history for this debci instance



241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/debci/repository.rb', line 241

def status_history(suite, architecture)
  return unless File.exists?(file = File.join(status_dir(suite, architecture), 'history.json'))

  data = nil

  begin
    File.open(file, 'r') do |f|
      data = JSON.load(f)
    end
  rescue JSON::ParserError
    true
  end

  data
end

#suitesObject

Returns an Array of suites known to this debci instance



26
27
28
# File 'lib/debci/repository.rb', line 26

def suites
  @suites ||= Dir.glob(File.join(@path, 'packages', '*')).reject { |d| d =~ /\.old$/ }.map { |d| File.basename(d) }.sort
end

#suites_for(package) ⇒ Object

Returns an Array of suites for which there is data for package.



86
87
88
89
# File 'lib/debci/repository.rb', line 86

def suites_for(package)
  package = String(package)
  data_dirs_for(package).map { |d| File.basename(File.dirname(d)) }.uniq
end

#tmpfail_packagesObject

Returns a Set of packages known to this debci instance that are temporarily failing. If no packages are temporarily failing, nothing is returned.



53
54
55
56
57
58
59
60
61
62
63
# File 'lib/debci/repository.rb', line 53

def tmpfail_packages
  tmpfail_packages = Set.new

  all_non_blacklisted_statuses.each do |status|
    if status.status == :tmpfail
      tmpfail_packages << status.package
    end
  end

  tmpfail_packages.sort.map { |p| Debci::Package.new(p, self) }
end