apt-spy2 0.7.2 → 0.8.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 91d09bec4d6918e39405d38ee164b8215c6e04d778887c0e570bdab6cc39592e
4
- data.tar.gz: d2f69bf166ca8bf79fff732e30184270dfbc0422a41dbe616afc9ddd56b21641
3
+ metadata.gz: 456003f4c6ac4e210a1cd7ebe44888b8a58d3b9fac87d1b68f03e9b3d8c45bdf
4
+ data.tar.gz: 907656e6cf49fe081152826de58348ff75d3f2ff1014f5af854dfb24f86e421d
5
5
  SHA512:
6
- metadata.gz: 931ef089f949e870538b77887a7825a42647bcc8a4ef577118a12b51112bcba1b1a63c235d2bbe0e1fed348608d84954c6a44c7f16a578e42c29e198a4403619
7
- data.tar.gz: 956aa4b5d89409a4366549b84846a42b95c46f7013197182fdfd22956ba07e60fddccf5f210a5eb85d0c09f3e8ff15cc730642ea1afb66b9fee81703cb172da3
6
+ metadata.gz: 5a2c12f506751914dc44243f88ecef036e7a5ca41cab0f6595c70e4c61d7d68e3da6cc304f9879a8b4f8b36fd2daa96b664a8fd91cf5a5a9cf64a06c2723cd10
7
+ data.tar.gz: '0815dfcb1e3b857aac1a30a8d0cee549e3c4a8a95ee0213e227b6747bb88939813118fbbaffc3d44ed1de663963c2ab22d7a7f03f552d4cbcd2e744183461fcb'
@@ -0,0 +1,70 @@
1
+ # For most projects, this workflow file will not need changing; you simply need
2
+ # to commit it to your repository.
3
+ #
4
+ # You may wish to alter this file to override the set of languages analyzed,
5
+ # or to provide custom queries or build logic.
6
+ #
7
+ # ******** NOTE ********
8
+ # We have attempted to detect the languages in your repository. Please check
9
+ # the `language` matrix defined below to confirm you have the correct set of
10
+ # supported CodeQL languages.
11
+ #
12
+ name: "CodeQL"
13
+
14
+ on:
15
+ push:
16
+ branches: [ master ]
17
+ pull_request:
18
+ # The branches below must be a subset of the branches above
19
+ branches: [ master ]
20
+ schedule:
21
+ - cron: '43 11 * * 5'
22
+
23
+ jobs:
24
+ analyze:
25
+ name: Analyze
26
+ runs-on: ubuntu-latest
27
+ permissions:
28
+ actions: read
29
+ contents: read
30
+ security-events: write
31
+
32
+ strategy:
33
+ fail-fast: false
34
+ matrix:
35
+ language: [ 'ruby' ]
36
+ # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
37
+ # Learn more about CodeQL language support at https://git.io/codeql-language-support
38
+
39
+ steps:
40
+ - name: Checkout repository
41
+ uses: actions/checkout@v2
42
+
43
+ # Initializes the CodeQL tools for scanning.
44
+ - name: Initialize CodeQL
45
+ uses: github/codeql-action/init@v1
46
+ with:
47
+ languages: ${{ matrix.language }}
48
+ # If you wish to specify custom queries, you can do so here or in a config file.
49
+ # By default, queries listed here will override any specified in a config file.
50
+ # Prefix the list here with "+" to use these queries and those in the config file.
51
+ # queries: ./path/to/local/query, your-org/your-repo/queries@main
52
+
53
+ # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
54
+ # If this step fails, then you should remove it and run the build manually (see below)
55
+ - name: Autobuild
56
+ uses: github/codeql-action/autobuild@v1
57
+
58
+ # ℹ️ Command-line programs to run using the OS shell.
59
+ # 📚 https://git.io/JvXDl
60
+
61
+ # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
62
+ # and modify them (or add more) to build your code if your project
63
+ # uses a compiled language
64
+
65
+ #- run: |
66
+ # make bootstrap
67
+ # make release
68
+
69
+ - name: Perform CodeQL Analysis
70
+ uses: github/codeql-action/analyze@v1
@@ -11,11 +11,12 @@ jobs:
11
11
  strategy:
12
12
  matrix:
13
13
  ruby-version:
14
+ - '3.2'
15
+ - '3.1'
14
16
  - '3.0'
15
- - 2.7
16
- - 2.6
17
+ - '2.7'
17
18
  steps:
18
- - uses: actions/checkout@v2
19
+ - uses: actions/checkout@v3
19
20
  - uses: ruby/setup-ruby@v1
20
21
  with:
21
22
  ruby-version: ${{ matrix.ruby-version }}
@@ -24,9 +25,23 @@ jobs:
24
25
  - run: bundle exec rake build
25
26
  - run: ls -lah ./pkg/apt-spy2*
26
27
  - run: gem install pkg/apt-spy2*
27
- - run: apt-spy2
28
+ - run: apt-spy2 check
28
29
  - uses: coverallsapp/github-action@master
29
30
  with:
30
31
  github-token: ${{ secrets.GITHUB_TOKEN }}
31
32
 
33
+ test_strict:
34
+ runs-on: ubuntu-latest
35
+ steps:
36
+ - uses: actions/checkout@v3
37
+ - uses: ruby/setup-ruby@v1
38
+ with:
39
+ ruby-version: 3.2
40
+ - run: bundle install
41
+ - run: bundle exec rake test
42
+ - run: bundle exec rake build
43
+ - run: ls -lah ./pkg/apt-spy2*
44
+ - run: gem install pkg/apt-spy2*
45
+ - run: apt-spy2 check --strict
46
+
32
47
 
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: release
3
+
4
+ on:
5
+ push:
6
+ tags:
7
+ - 'v*'
8
+
9
+ jobs:
10
+ publish:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v2
14
+ - uses: ruby/setup-ruby@v1
15
+ with:
16
+ ruby-version: 3.0
17
+ - run: bundle install
18
+ - uses: cadwallion/publish-rubygems-action@master
19
+ env:
20
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
21
+ RUBYGEMS_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
22
+ RELEASE_COMMAND: bundle exec rake release
data/Dockerfile CHANGED
@@ -1,9 +1,13 @@
1
- FROM ubuntu:18.04
1
+ FROM ubuntu:22.10
2
2
 
3
- RUN apt-get update -y \
4
- && apt-get install -y ruby ruby-dev git gcc g++ make zlib1g-dev lsb-release \
5
- && gem install bundler \
6
- && mkdir -p /work
3
+ RUN apt update -y \
4
+ && apt install -y \
5
+ ruby3.0 \
6
+ ruby-dev \
7
+ ruby-bundler \
8
+ git \
9
+ lsb-release \
10
+ build-essential
7
11
 
8
12
  WORKDIR /work
9
13
  COPY . /work
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  gemspec
data/Gemfile.lock CHANGED
@@ -1,23 +1,45 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- apt-spy2 (0.7.2)
4
+ apt-spy2 (0.8.0)
5
5
  colored (>= 1.2)
6
6
  json
7
- nokogiri (>= 1.6, < 1.13)
7
+ nokogiri (~> 1.14.1)
8
8
  thor (>= 0.18.1)
9
9
 
10
10
  GEM
11
11
  remote: https://rubygems.org/
12
12
  specs:
13
+ ast (2.4.2)
13
14
  colored (1.2)
14
15
  docile (1.4.0)
15
- json (2.6.1)
16
+ json (2.6.3)
17
+ mini_portile2 (2.8.1)
16
18
  minitest (5.15.0)
17
- nokogiri (1.12.5-x86_64-darwin)
19
+ nokogiri (1.14.1)
20
+ mini_portile2 (~> 2.8.0)
18
21
  racc (~> 1.4)
19
- racc (1.5.2)
22
+ parallel (1.22.1)
23
+ parser (3.2.1.0)
24
+ ast (~> 2.4.1)
25
+ racc (1.6.2)
26
+ rainbow (3.1.1)
20
27
  rake (13.0.6)
28
+ regexp_parser (2.7.0)
29
+ rexml (3.2.5)
30
+ rubocop (1.45.1)
31
+ json (~> 2.3)
32
+ parallel (~> 1.10)
33
+ parser (>= 3.2.0.0)
34
+ rainbow (>= 2.2.2, < 4.0)
35
+ regexp_parser (>= 1.8, < 3.0)
36
+ rexml (>= 3.2.5, < 4.0)
37
+ rubocop-ast (>= 1.24.1, < 2.0)
38
+ ruby-progressbar (~> 1.7)
39
+ unicode-display_width (>= 2.4.0, < 3.0)
40
+ rubocop-ast (1.24.1)
41
+ parser (>= 3.1.1.0)
42
+ ruby-progressbar (1.11.0)
21
43
  simplecov (0.21.2)
22
44
  docile (~> 1.1)
23
45
  simplecov-html (~> 0.11)
@@ -25,7 +47,8 @@ GEM
25
47
  simplecov-html (0.12.3)
26
48
  simplecov-lcov (0.8.0)
27
49
  simplecov_json_formatter (0.1.3)
28
- thor (1.1.0)
50
+ thor (1.2.1)
51
+ unicode-display_width (2.4.2)
29
52
 
30
53
  PLATFORMS
31
54
  ruby
@@ -35,6 +58,7 @@ DEPENDENCIES
35
58
  bundler (~> 2.0)
36
59
  minitest (~> 5.15.0)
37
60
  rake
61
+ rubocop
38
62
  simplecov (~> 0.18)
39
63
  simplecov-lcov (~> 0.8.0)
40
64
 
data/Makefile CHANGED
@@ -1,11 +1,29 @@
1
+ .PHONY: clean install release docker-build docker-run
2
+
3
+ IMAGE?=lagged/apt-spy2:dev
4
+
5
+ container:=apt-spy2
6
+
7
+ clean:
8
+ docker rm -f $(container) || true
9
+
1
10
  install:
2
11
  bundle install --path ./vendor/bundle
3
12
 
4
13
  release:
5
14
  bundle exec rake release
6
15
 
16
+ lint:
17
+ bundle exec rubocop .
18
+
19
+ test: install
20
+ bundle exec rake test
21
+
7
22
  docker-build:
8
- docker build -t lagged/apt-spy2:dev .
23
+ docker build -t $(IMAGE) .
9
24
 
10
- docker-run: docker-build
11
- docker run -it lagged/apt-spy2:dev bash
25
+ docker-run: clean docker-build
26
+ docker run --rm -it \
27
+ --name $(container) \
28
+ -v $(CURDIR):/work \
29
+ $(IMAGE) bash
data/README.md CHANGED
@@ -44,13 +44,14 @@ $ apt-spy2 list --launchpad --country=Germany
44
44
 
45
45
  ### check command
46
46
 
47
- `check` works like `list`, but also determines if the servers returned are working. It supports Launchpad as well.
47
+ `check` works like `list`, but also determines if the servers returned are working. It supports the flag `--launchpad` as well and additionally a flag `--strict` which checks if a mirror carries a certain release and distribution.
48
48
 
49
49
  ```
50
50
  $ apt-spy2 check
51
51
  ...
52
- $ apt-spy2 list --launchpad --country=US
52
+ $ apt-spy2 check --launchpad --country=US
53
53
  ...
54
+ $ apt-spy2 check --strict
54
55
  ```
55
56
 
56
57
  ### fix command
@@ -81,3 +82,9 @@ Generally, `apt-spy2` plays especially nice in a non-interactive environment and
81
82
  ## License
82
83
 
83
84
  [New BSD License](http://opensource.org/licenses/BSD-2-Clause)
85
+
86
+ ### Release (procedure)
87
+
88
+ - update version in `lib/apt/spy2/version.rb`
89
+ - `bundle install`
90
+ - `git commit -a -m 'New release' && git tag -a vVERSION && git push --tags`
data/Rakefile CHANGED
@@ -1,24 +1,17 @@
1
- require "bundler/gem_tasks"
2
- require "minitest/autorun"
3
- require "simplecov"
4
- require "simplecov-lcov"
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
5
 
6
6
  Encoding.default_external = Encoding::UTF_8
7
7
  Encoding.default_internal = Encoding::UTF_8
8
8
 
9
- task :test do
9
+ Rake::TestTask.new do |t|
10
10
  ENV['COVERAGE'] = 'true'
11
+ t.pattern = 'tests/*_test.rb'
11
12
 
12
- SimpleCov.formatter = SimpleCov::Formatter::LcovFormatter
13
- SimpleCov::Formatter::LcovFormatter.config do |c|
14
- c.output_directory = './coverage'
15
- c.report_with_single_file = true
16
- c.single_report_path = './coverage/lcov.info'
17
- end
18
- SimpleCov.start
19
-
20
- $LOAD_PATH.unshift('lib', 'tests')
21
- Dir.glob('./tests/*_test.rb') do |f|
22
- require f
23
- end
13
+ # $LOAD_PATH.unshift('lib', 'tests')
14
+ # Dir.glob('./tests/*_test.rb').sort.each do |f|
15
+ # require f
16
+ # end
24
17
  end
data/apt-spy2.gemspec CHANGED
@@ -1,31 +1,36 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ # require 'English'
4
+ lib = File.expand_path('lib', __dir__)
3
5
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
6
  require 'apt/spy2/version'
5
7
 
6
8
  Gem::Specification.new do |spec|
7
- spec.name = "apt-spy2"
9
+ spec.name = 'apt-spy2'
8
10
  spec.version = Apt::Spy2::VERSION
9
- spec.authors = ["till"]
10
- spec.email = ["till@php.net"]
11
- spec.description = "Keep your /etc/apt/sources.list up to date"
12
- spec.summary = "apt-spy2, or apt-spy for ubuntu"
13
- spec.homepage = "https://github.com/lagged/apt-spy2"
11
+ spec.authors = ['till']
12
+ spec.email = ['till@php.net']
13
+ spec.description = 'Keep your /etc/apt/sources.list up to date'
14
+ spec.summary = 'apt-spy2, or apt-spy for ubuntu'
15
+ spec.homepage = 'https://github.com/lagged/apt-spy2'
14
16
  spec.license = 'BSD-2-Clause'
15
17
 
16
- spec.files = `git ls-files`.split($/)
18
+ spec.required_ruby_version = '>= 2.7', '< 3.3'
19
+
20
+ spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
17
21
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
22
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
23
+ spec.require_paths = ['lib']
20
24
 
21
- spec.add_dependency 'thor', '>= 0.18.1'
22
25
  spec.add_dependency 'colored', '>= 1.2'
23
26
  spec.add_dependency 'json'
24
- spec.add_dependency 'nokogiri', '>= 1.6', '< 1.13'
27
+ spec.add_dependency 'nokogiri', '~> 1.14.1'
28
+ spec.add_dependency 'thor', '>= 0.18.1'
25
29
 
26
- spec.add_development_dependency "bundler", "~> 2.0"
27
- spec.add_development_dependency "rake"
28
- spec.add_development_dependency "minitest", "~> 5.15.0"
29
- spec.add_development_dependency "simplecov", "~> 0.18"
30
- spec.add_development_dependency "simplecov-lcov", "~> 0.8.0"
30
+ spec.add_development_dependency 'bundler', '~> 2.0'
31
+ spec.add_development_dependency 'minitest', '~> 5.15.0'
32
+ spec.add_development_dependency 'rake'
33
+ spec.add_development_dependency 'rubocop'
34
+ spec.add_development_dependency 'simplecov', '~> 0.18'
35
+ spec.add_development_dependency 'simplecov-lcov', '~> 0.8.0'
31
36
  end
data/bin/apt-spy2 CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'apt/spy2'
4
5
  require 'colored'
@@ -8,7 +9,7 @@ Encoding.default_internal = Encoding::UTF_8
8
9
 
9
10
  begin
10
11
  AptSpy2.start
11
- rescue => the_error
12
- puts the_error.to_s.white_on_red
12
+ rescue StandardError => e
13
+ puts e.to_s.white_on_red
13
14
  exit 1
14
15
  end
@@ -1,33 +1,32 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Apt
2
4
  module Spy2
5
+ # lookup a country based on code
3
6
  class Country
4
-
5
7
  def initialize(country_database)
6
8
  @database = country_database
7
9
  end
8
10
 
9
11
  def to_country_name(code)
10
12
  code = code.upcase
11
- return capitalize(code) unless code.length == 2
13
+ return capitalize!(code) unless code.length == 2
12
14
 
13
15
  File.open(@database).each do |line|
14
16
  country, tld = line.split(';', 2)
15
17
  tld.gsub!(/\n/, '')
16
18
 
17
- if code == tld
18
- return capitalize(country)
19
- end
20
-
19
+ return capitalize!(country) if code == tld
21
20
  end
22
21
 
23
22
  raise "Could not look up: #{code}"
24
23
  end
25
24
 
26
25
  private
27
- def capitalize(str)
28
- return str.split(" ").map(&:capitalize).join(" ")
29
- end
30
26
 
27
+ def capitalize!(str)
28
+ str.split(' ').map(&:capitalize).join(' ')
29
+ end
31
30
  end
32
31
  end
33
32
  end
@@ -1,30 +1,27 @@
1
- require 'open-uri'
1
+ # frozen_string_literal: true
2
+
3
+ require 'apt/spy2/request'
2
4
 
3
5
  module Apt
4
6
  module Spy2
7
+ # download url (e.g. mirror list or launchpad page)
5
8
  class Downloader
6
-
7
- def initialize(url = nil)
8
- @url = url if !url.nil?
9
- end
10
-
11
9
  def do_download(url = nil)
12
- @url = url if !url.nil?
10
+ raise 'Please supply a url.' if url.nil?
13
11
 
14
- raise "Please supply a url." if url.nil?
12
+ req = Apt::Spy2::Request.new(url)
15
13
 
16
14
  begin
17
- return open(@url).read
18
- rescue OpenURI::HTTPError => the_error
19
- case the_error.io.status[0]
20
- when "404"
21
- raise "The URL #{@url} does not exist."
22
- else
23
- raise "Status: #{the_error.io.status[0]}"
24
- end
15
+ response = req.get
16
+ return response.body if response.code == '200'
17
+
18
+ raise "The URL #{@url} does not exist." if response.code == '404'
19
+
20
+ raise "Status code: #{response.code}"
21
+ rescue StandardError => e
22
+ raise e
25
23
  end
26
24
  end
27
-
28
25
  end
29
26
  end
30
27
  end
@@ -1,15 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'nokogiri'
2
4
 
3
5
  module Apt
4
6
  module Spy2
7
+ # parse launchpad output
5
8
  class Launchpad
6
-
7
9
  def initialize(download)
8
10
  @launchpad = download
9
11
  end
10
12
 
11
- def get_mirrors(country)
12
-
13
+ def mirrors(country)
13
14
  mirrors = []
14
15
 
15
16
  document = Nokogiri::HTML(@launchpad)
@@ -27,10 +28,8 @@ module Apt
27
28
  end
28
29
  end
29
30
 
30
- return mirrors
31
-
31
+ mirrors
32
32
  end
33
-
34
33
  end
35
34
  end
36
35
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'net/https'
5
+ require 'uri'
6
+
7
+ module Apt
8
+ module Spy2
9
+ # make requests
10
+ class Request
11
+ def initialize(url)
12
+ uri = URI(url)
13
+
14
+ http = Net::HTTP.new(uri.host, uri.port)
15
+ http.use_ssl = true if uri.scheme == 'https'
16
+
17
+ @http = http
18
+ @request_uri = uri.request_uri
19
+ end
20
+
21
+ def get
22
+ @http.request(Net::HTTP::Get.new(@request_uri))
23
+ end
24
+
25
+ def head
26
+ @http.request(Net::HTTP::Head.new(@request_uri))
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,19 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Apt
2
4
  module Spy2
5
+ # wraps around the \n delimited list of mirrors
3
6
  class UbuntuMirrors
4
-
5
7
  def initialize(download)
6
8
  @ubuntu_mirrors = download
7
9
  end
8
10
 
9
- def get_mirrors(country)
10
-
11
+ def mirrors(_country)
11
12
  mirrors = @ubuntu_mirrors
12
- mirrors = mirrors.split(/\n/)
13
- return mirrors
14
-
13
+ mirrors.split(/\n/)
15
14
  end
16
-
17
15
  end
18
16
  end
19
17
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Apt
4
+ module Spy2
5
+ # build mirror url
6
+ class Url
7
+ def initialize(strict)
8
+ @strict = strict
9
+ end
10
+
11
+ def adjust!(mirror)
12
+ return mirror unless @strict
13
+
14
+ "#{mirror}dists/#{release}/Contents-#{arch}.gz"
15
+ end
16
+
17
+ private
18
+
19
+ def arch
20
+ `dpkg --print-architecture`.strip
21
+ end
22
+
23
+ def release
24
+ `lsb_release -c`.split(' ')[1].strip
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Apt
2
4
  module Spy2
3
- VERSION = "0.7.2"
5
+ VERSION = '0.8.0'
4
6
  end
5
7
  end
@@ -1,20 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'colored'
2
4
  require 'json'
3
5
 
4
6
  module Apt
5
7
  module Spy2
8
+ # abstracted puts or json
6
9
  class Writer
7
10
  def initialize(format)
8
-
9
- if !["json", "shell"].include?(format)
10
- raise "Unknown format: #{format}"
11
- end
11
+ raise "Unknown format: #{format}" unless %w[json shell].include?(format)
12
12
 
13
13
  @format = format
14
14
  @complete = []
15
15
  end
16
16
 
17
- def set_complete(complete)
17
+ def complete(complete)
18
18
  @complete = complete
19
19
  end
20
20
 
@@ -24,32 +24,29 @@ module Apt
24
24
  return
25
25
  end
26
26
 
27
- print "Mirror: #{data["mirror"]} - "
27
+ print "Mirror: #{data['mirror']} - "
28
28
 
29
- case data["status"]
30
- when "up"
31
- puts data["status"].upcase.green
32
- when "down"
33
- puts data["status"].upcase.red
34
- when "broken"
35
- puts data["status"].upcase.yellow
29
+ case data['status']
30
+ when 'up'
31
+ puts data['status'].upcase.green
32
+ when 'down'
33
+ puts data['status'].upcase.red
34
+ when 'broken'
35
+ puts data['status'].upcase.yellow
36
36
  else
37
- puts "Unknown status: #{data["status"]}".white_on_red
37
+ puts "Unknown status: #{data['status']}".white_on_red
38
38
  end
39
39
  end
40
40
 
41
41
  def json?
42
- if @format == 'json'
43
- return true
44
- end
42
+ return true if @format == 'json'
45
43
 
46
- return false
44
+ false
47
45
  end
48
46
 
49
- def to_json
47
+ def to_json(*_args)
50
48
  JSON.generate(@complete)
51
49
  end
52
-
53
50
  end
54
51
  end
55
52
  end
data/lib/apt/spy2.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'thor'
2
4
  require 'open-uri'
3
5
  require 'colored'
@@ -7,116 +9,126 @@ require 'apt/spy2/country'
7
9
  require 'apt/spy2/downloader'
8
10
  require 'apt/spy2/ubuntu_mirrors'
9
11
  require 'apt/spy2/launchpad'
12
+ require 'apt/spy2/request'
13
+ require 'apt/spy2/url'
10
14
 
15
+ # apt-spy2 command interface
11
16
  class AptSpy2 < Thor
12
- package_name "apt-spy2"
17
+ package_name 'apt-spy2'
18
+ class_option :country, default: 'mirrors'
19
+ class_option :launchpad, type: :boolean, banner: "Use launchpad's mirror list"
13
20
 
14
- desc "fix", "Set the closest/fastest mirror"
15
- option :country, :default => "mirrors"
16
- option :commit, :type => :boolean
17
- option :launchpad, :type => :boolean, :banner => "Use launchpad's mirror list"
21
+ desc 'fix', 'Set the closest/fastest mirror'
22
+ option :commit, type: :boolean
23
+ option :strict, type: :boolean
18
24
  def fix
19
- working = filter(retrieve(options[:country], use_launchpad?(options)), false)
20
- print "The closest mirror is: "
21
- puts "#{working[0]}".bold.magenta
22
- if !options[:commit]
23
- puts "Run with --commit to adjust /etc/apt/sources.list".yellow
24
- else
25
- puts "Updating /etc/apt/sources.list".yellow
26
- update(working[0])
25
+ mirrors = retrieve(options[:country], use_launchpad?(options))
26
+ working = filter(mirrors, options[:strict], false)
27
+ print 'The closest mirror is: '
28
+ puts (working[0]).to_s.bold.magenta
29
+ unless options[:commit]
30
+ puts 'Run with --commit to adjust /etc/apt/sources.list'.yellow
31
+ return
27
32
  end
33
+
34
+ puts 'Updating /etc/apt/sources.list'.yellow
35
+ update(working[0])
28
36
  end
29
37
 
30
- desc "check", "Evaluate mirrors"
31
- option :country, :default => "mirrors"
32
- option :output, :type => :boolean, :default => true
33
- option :format, :default => "shell"
34
- option :launchpad, :type => :boolean, :banner => "Use launchpad's mirror list"
38
+ desc 'check', 'Evaluate mirrors'
39
+ option :output, type: :boolean, default: true
40
+ option :format, default: 'shell'
41
+ option :strict, type: :boolean
35
42
  def check
36
-
37
43
  @writer = Apt::Spy2::Writer.new(options[:format])
38
44
 
39
45
  mirrors = retrieve(options[:country], use_launchpad?(options))
40
- filter(mirrors, options[:output])
46
+ filter(mirrors, options[:strict], options[:output])
41
47
 
42
48
  puts @writer.to_json if @writer.json?
43
49
  end
44
50
 
45
- desc "list", "List the currently available mirrors"
46
- option :country, :default => "mirrors"
47
- option :format, :default => "shell"
48
- option :launchpad, :type => :boolean, :banner => "Use launchpad's mirror list"
51
+ desc 'list', 'List the currently available mirrors'
52
+ option :format, default: 'shell'
49
53
  def list
50
54
  mirrors = retrieve(options[:country], use_launchpad?(options))
51
55
 
52
56
  @writer = Apt::Spy2::Writer.new(options[:format])
53
57
 
54
- @writer.set_complete(mirrors)
58
+ @writer.complete(mirrors)
55
59
 
56
60
  puts @writer.to_json if @writer.json?
57
- puts mirrors if !@writer.json?
61
+ puts mirrors unless @writer.json?
58
62
  end
59
63
 
60
- desc "version", "Show which version of apt-spy2 is installed"
64
+ desc 'version', 'Show which version of apt-spy2 is installed'
61
65
  def version
62
66
  puts Apt::Spy2::VERSION
63
67
  exit
64
68
  end
65
69
 
66
70
  private
67
- def retrieve(country = "mirrors", launchpad = false)
68
71
 
72
+ def retrieve(country = 'mirrors', launchpad = false)
69
73
  downloader = Apt::Spy2::Downloader.new
70
74
 
71
- if launchpad === true
72
- csv_path = File.expand_path(File.dirname(__FILE__) + "/../../var/country-names.txt")
75
+ if launchpad
76
+ csv_path = File.expand_path("#{File.dirname(__FILE__)}/../../var/country-names.txt")
73
77
  country = Apt::Spy2::Country.new(csv_path)
74
78
  name = country.to_country_name(options[:country])
75
79
 
76
80
  launchpad = Apt::Spy2::Launchpad.new(downloader.do_download('https://launchpad.net/ubuntu/+archivemirrors'))
77
- return launchpad.get_mirrors(name)
81
+ return launchpad.mirrors(name)
78
82
  end
79
83
 
80
84
  country.upcase! if country.length == 2
81
85
 
82
86
  ubuntu_mirrors = Apt::Spy2::UbuntuMirrors.new(downloader.do_download("http://mirrors.ubuntu.com/#{country}.txt"))
83
- mirrors = ubuntu_mirrors.get_mirrors(country)
84
- return mirrors
85
-
87
+ ubuntu_mirrors.mirrors(country)
86
88
  end
87
89
 
88
- private
89
- def filter(mirrors, output = true)
90
+ def filter(mirrors, strict = false, output = true)
90
91
  # f me :)
91
92
 
92
93
  working_mirrors = []
93
94
 
95
+ url = Apt::Spy2::Url.new(strict)
96
+
94
97
  mirrors.each do |mirror|
95
- data = {"mirror" => mirror }
96
- begin
97
- open(mirror)
98
- data["status"] = "up"
99
- working_mirrors << mirror
100
- rescue OpenURI::HTTPError
101
- data["status"] = "broken"
102
- rescue
103
- # this is a catch-all for everything else
104
- data["status"] = "down"
105
- end
98
+ data = { 'mirror' => mirror }
99
+
100
+ check = url.adjust!(mirror)
101
+
102
+ status = broken?(check)
103
+
104
+ data['status'] = status
105
+
106
+ working_mirrors << mirror if status == 'up'
106
107
 
107
108
  @writer.echo(data) if output
108
109
  end
109
110
 
110
- return working_mirrors
111
+ working_mirrors
112
+ end
113
+
114
+ def broken?(url)
115
+ begin
116
+ req = Apt::Spy2::Request.new(url)
117
+ response = req.head
118
+ return 'up' if response.code == '200'
119
+
120
+ return 'broken' if response.code == '404'
121
+ rescue StandardError
122
+ # connection errors, ssl errors, etc.
123
+ end
111
124
 
125
+ 'down'
112
126
  end
113
127
 
114
- private
115
128
  def update(mirror)
116
-
117
129
  t = Time.now
118
- r = `lsb_release -c`.split(" ")[1]
119
- sources = "## Updated on #{t.to_s} by apt-spy2\n"
130
+ r = `lsb_release -c`.split(' ')[1]
131
+ sources = "## Updated on #{t} by apt-spy2\n"
120
132
  sources << "deb #{mirror} #{r} main restricted universe multiverse\n"
121
133
  sources << "deb #{mirror} #{r}-updates main restricted universe multiverse\n"
122
134
  sources << "deb #{mirror} #{r}-backports main restricted universe multiverse\n"
@@ -129,26 +141,23 @@ class AptSpy2 < Thor
129
141
  File.open(apt_sources, 'w') do |f|
130
142
  f.write(sources)
131
143
  end
132
- rescue
144
+ rescue StandardError
133
145
  msg = "Failed updating #{apt_sources}!"
134
- msg << "You probably need sudo!"
146
+ msg << 'You probably need sudo!'
135
147
  raise msg
136
148
  end
137
149
 
138
150
  puts "Updated '#{apt_sources}' with #{mirror}".green
139
- puts "Run `apt-get update` to update".black_on_yellow
151
+ puts 'Run `apt-get update` to update'.black_on_yellow
140
152
  end
141
153
 
142
- private
143
154
  def use_launchpad?(options)
144
- if !options[:launchpad]
145
- return false
146
- end
155
+ return false unless options[:launchpad]
147
156
 
148
157
  if options[:country] && options[:country] == 'mirrors'
149
- raise "Please supply a `--country=foo`. Launchpad cannot guess!"
158
+ raise 'Please supply a `--country=foo`. Launchpad cannot guess!'
150
159
  end
151
160
 
152
- return true
161
+ true
153
162
  end
154
163
  end
data/test_helper.rb ADDED
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'simplecov'
4
+ require 'simplecov-lcov'
5
+
6
+ if ENV['CI']
7
+ SimpleCov.formatter = SimpleCov::Formatter::LcovFormatter
8
+ SimpleCov::Formatter::LcovFormatter.config do |c|
9
+ c.output_directory = './coverage'
10
+ c.report_with_single_file = true
11
+ c.single_report_path = './coverage/lcov.info'
12
+ end
13
+ else
14
+ SimpleCov.formatter SimpleCov::Formatter::MultiFormatter.new([
15
+ SimpleCov::Formatter::SimpleFormatter,
16
+ SimpleCov::Formatter::HTMLFormatter
17
+ ])
18
+ end
19
+
20
+ SimpleCov.profiles.define 'apt-spy2' do
21
+ add_filter '/tests/'
22
+ add_filter '/pkg/'
23
+ add_filter '/vendor/'
24
+ add_filter '/var'
25
+
26
+ add_group 'lib', 'lib/apt'
27
+ add_group 'bin', 'bin'
28
+ end
29
+ SimpleCov.start 'apt-spy2'
30
+ require 'minitest/autorun'
@@ -1,12 +1,15 @@
1
- require 'apt/spy2/country'
1
+ # frozen_string_literal: true
2
2
 
3
+ require_relative '../test_helper'
4
+ require_relative '../lib/apt/spy2/country'
5
+
6
+ # test the name resolution
3
7
  class CountryTest < Minitest::Test
4
8
  def setup
5
- @country_list = File.expand_path(File.dirname(__FILE__) + "/../var/country-names.txt")
9
+ @country_list = File.expand_path("#{File.dirname(__FILE__)}/../var/country-names.txt")
6
10
  end
7
11
 
8
- def test_tld_to_name()
9
-
12
+ def test_tld_to_name
10
13
  # fixtures for people who don't want to read about rails
11
14
  data = {
12
15
  'de' => 'Germany',
@@ -22,6 +25,5 @@ class CountryTest < Minitest::Test
22
25
  data.each_pair do |code, expected|
23
26
  assert_equal(expected, c.to_country_name(code))
24
27
  end
25
-
26
28
  end
27
29
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../test_helper'
4
+ require_relative '../lib/apt/spy2/downloader'
5
+
6
+ # this is an integration test (needs interwebs)
7
+ class DownloaderTest < Minitest::Test
8
+ def test_do
9
+ downloader = Apt::Spy2::Downloader.new
10
+ data = downloader.do_download('http://mirrors.ubuntu.com/DE.txt')
11
+ assert(!data.empty?, 'There should have been a response, unless the mirrors are down.')
12
+ end
13
+
14
+ def test_do_wrong_countrys
15
+ downloader = Apt::Spy2::Downloader.new
16
+ assert_raises(RuntimeError) { downloader.do_download('http://mirrors.ubuntu.com/de.txt') }
17
+ end
18
+ end
@@ -1,13 +1,17 @@
1
- require 'apt/spy2/launchpad'
1
+ # frozen_string_literal: true
2
2
 
3
+ require_relative '../test_helper'
4
+ require_relative '../lib/apt/spy2/launchpad'
5
+
6
+ # test to confirm launchpad format (HTML) is parsed
3
7
  class LaunchpadTest < Minitest::Test
4
8
  def setup
5
- @download_fixture = File.read(File.expand_path(File.dirname(__FILE__) + "/fixtures/launchpad.html"))
9
+ @download_fixture = File.read(File.expand_path("#{File.dirname(__FILE__)}/fixtures/launchpad.html"))
6
10
  end
7
11
 
8
12
  def test_german_mirrors
9
13
  lp = Apt::Spy2::Launchpad.new(@download_fixture)
10
- mirrors = lp.get_mirrors('Germany')
14
+ mirrors = lp.mirrors('Germany')
11
15
  assert_equal(false, mirrors.empty?)
12
16
  end
13
17
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../test_helper'
4
+ require_relative '../lib/apt/spy2/ubuntu_mirrors'
5
+
6
+ # test to confirm launchpad format (HTML) is parsed
7
+ class UbuntuMirrorsTest < Minitest::Test
8
+ def test_mirrors
9
+ expected = ['http://example.org', 'http://example.de']
10
+ fixture = expected.join("\n")
11
+
12
+ m = Apt::Spy2::UbuntuMirrors.new(fixture)
13
+ assert_equal(expected, m.mirrors('country'))
14
+ end
15
+ end
data/tests/url_test.rb ADDED
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../test_helper'
4
+ require_relative '../lib/apt/spy2/url'
5
+
6
+ # test to check request lib
7
+ class UrlTest < Minitest::Test
8
+ def test_non_strict
9
+ expected = 'http://example.org'
10
+
11
+ url = Apt::Spy2::Url.new(false)
12
+ assert_equal(expected, url.adjust!(expected))
13
+ end
14
+
15
+ # def strict
16
+ # skip "Test only runs on ubuntu" if OS.unix? and not OS.mac?
17
+
18
+ # expected = 'http://example.org'
19
+
20
+ # url = Apt::Spy2::Url.new(true)
21
+ # assert_not_equal(expected, url.mirror)
22
+ # end
23
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../test_helper'
4
+ require_relative '../lib/apt/spy2/writer'
5
+ require 'json'
6
+
7
+ # test to check request lib
8
+ class WriterTest < Minitest::Test
9
+ def test_json
10
+ fixture = { 'mirror': 'http://example.org', 'status': 'up' }
11
+
12
+ w = Apt::Spy2::Writer.new('json')
13
+ w.echo(fixture)
14
+
15
+ # json string
16
+ j = w.to_json
17
+
18
+ assert_equal(true, w.json?)
19
+ assert_equal(true, j.is_a?(String))
20
+ assert_equal(true, JSON.parse(j).is_a?(Array))
21
+ end
22
+
23
+ def test_no_json
24
+ w = Apt::Spy2::Writer.new('shell')
25
+ assert_equal(false, w.json?)
26
+ end
27
+ end
metadata CHANGED
@@ -1,77 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apt-spy2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - till
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-22 00:00:00.000000000 Z
11
+ date: 2023-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: thor
14
+ name: colored
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.18.1
19
+ version: '1.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 0.18.1
26
+ version: '1.2'
27
27
  - !ruby/object:Gem::Dependency
28
- name: colored
28
+ name: json
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '1.2'
33
+ version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '1.2'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: json
42
+ name: nokogiri
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 1.14.1
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: 1.14.1
55
55
  - !ruby/object:Gem::Dependency
56
- name: nokogiri
56
+ name: thor
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '1.6'
62
- - - "<"
63
- - !ruby/object:Gem::Version
64
- version: '1.13'
61
+ version: 0.18.1
65
62
  type: :runtime
66
63
  prerelease: false
67
64
  version_requirements: !ruby/object:Gem::Requirement
68
65
  requirements:
69
66
  - - ">="
70
67
  - !ruby/object:Gem::Version
71
- version: '1.6'
72
- - - "<"
73
- - !ruby/object:Gem::Version
74
- version: '1.13'
68
+ version: 0.18.1
75
69
  - !ruby/object:Gem::Dependency
76
70
  name: bundler
77
71
  requirement: !ruby/object:Gem::Requirement
@@ -86,6 +80,20 @@ dependencies:
86
80
  - - "~>"
87
81
  - !ruby/object:Gem::Version
88
82
  version: '2.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: minitest
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 5.15.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 5.15.0
89
97
  - !ruby/object:Gem::Dependency
90
98
  name: rake
91
99
  requirement: !ruby/object:Gem::Requirement
@@ -101,19 +109,19 @@ dependencies:
101
109
  - !ruby/object:Gem::Version
102
110
  version: '0'
103
111
  - !ruby/object:Gem::Dependency
104
- name: minitest
112
+ name: rubocop
105
113
  requirement: !ruby/object:Gem::Requirement
106
114
  requirements:
107
- - - "~>"
115
+ - - ">="
108
116
  - !ruby/object:Gem::Version
109
- version: 5.15.0
117
+ version: '0'
110
118
  type: :development
111
119
  prerelease: false
112
120
  version_requirements: !ruby/object:Gem::Requirement
113
121
  requirements:
114
- - - "~>"
122
+ - - ">="
115
123
  - !ruby/object:Gem::Version
116
- version: 5.15.0
124
+ version: '0'
117
125
  - !ruby/object:Gem::Dependency
118
126
  name: simplecov
119
127
  requirement: !ruby/object:Gem::Requirement
@@ -152,7 +160,9 @@ extra_rdoc_files: []
152
160
  files:
153
161
  - ".dockerignore"
154
162
  - ".github/dependabot.yml"
163
+ - ".github/workflows/codeql-analysis.yml"
155
164
  - ".github/workflows/pr.yml"
165
+ - ".github/workflows/release.yml"
156
166
  - ".gitignore"
157
167
  - ".ruby_version"
158
168
  - CONTRIBUTING.md
@@ -169,12 +179,19 @@ files:
169
179
  - lib/apt/spy2/country.rb
170
180
  - lib/apt/spy2/downloader.rb
171
181
  - lib/apt/spy2/launchpad.rb
182
+ - lib/apt/spy2/request.rb
172
183
  - lib/apt/spy2/ubuntu_mirrors.rb
184
+ - lib/apt/spy2/url.rb
173
185
  - lib/apt/spy2/version.rb
174
186
  - lib/apt/spy2/writer.rb
187
+ - test_helper.rb
175
188
  - tests/country_test.rb
189
+ - tests/downloader_test.rb
176
190
  - tests/fixtures/launchpad.html
177
191
  - tests/launchpad_test.rb
192
+ - tests/ubuntu_mirrors_test.rb
193
+ - tests/url_test.rb
194
+ - tests/writer_test.rb
178
195
  - var/country-names.txt
179
196
  homepage: https://github.com/lagged/apt-spy2
180
197
  licenses:
@@ -188,14 +205,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
188
205
  requirements:
189
206
  - - ">="
190
207
  - !ruby/object:Gem::Version
191
- version: '0'
208
+ version: '2.7'
209
+ - - "<"
210
+ - !ruby/object:Gem::Version
211
+ version: '3.3'
192
212
  required_rubygems_version: !ruby/object:Gem::Requirement
193
213
  requirements:
194
214
  - - ">="
195
215
  - !ruby/object:Gem::Version
196
216
  version: '0'
197
217
  requirements: []
198
- rubygems_version: 3.2.32
218
+ rubygems_version: 3.4.2
199
219
  signing_key:
200
220
  specification_version: 4
201
221
  summary: apt-spy2, or apt-spy for ubuntu