apt-spy2 0.4.0 → 0.7.2

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 91d09bec4d6918e39405d38ee164b8215c6e04d778887c0e570bdab6cc39592e
4
+ data.tar.gz: d2f69bf166ca8bf79fff732e30184270dfbc0422a41dbe616afc9ddd56b21641
5
+ SHA512:
6
+ metadata.gz: 931ef089f949e870538b77887a7825a42647bcc8a4ef577118a12b51112bcba1b1a63c235d2bbe0e1fed348608d84954c6a44c7f16a578e42c29e198a4403619
7
+ data.tar.gz: 956aa4b5d89409a4366549b84846a42b95c46f7013197182fdfd22956ba07e60fddccf5f210a5eb85d0c09f3e8ff15cc730642ea1afb66b9fee81703cb172da3
data/.dockerignore ADDED
@@ -0,0 +1 @@
1
+ vendor/bundle
@@ -0,0 +1,9 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: "/"
5
+ schedule:
6
+ interval: daily
7
+ open-pull-requests-limit: 10
8
+ assignees:
9
+ - till
@@ -0,0 +1,32 @@
1
+ ---
2
+ name: pr
3
+
4
+ on:
5
+ pull_request
6
+
7
+ jobs:
8
+ test:
9
+ name: "test-${{ matrix.ruby-version }}"
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ ruby-version:
14
+ - '3.0'
15
+ - 2.7
16
+ - 2.6
17
+ steps:
18
+ - uses: actions/checkout@v2
19
+ - uses: ruby/setup-ruby@v1
20
+ with:
21
+ ruby-version: ${{ matrix.ruby-version }}
22
+ - run: bundle install
23
+ - run: bundle exec rake test
24
+ - run: bundle exec rake build
25
+ - run: ls -lah ./pkg/apt-spy2*
26
+ - run: gem install pkg/apt-spy2*
27
+ - run: apt-spy2
28
+ - uses: coverallsapp/github-action@master
29
+ with:
30
+ github-token: ${{ secrets.GITHUB_TOKEN }}
31
+
32
+
data/.gitignore CHANGED
@@ -1,2 +1,5 @@
1
1
  .vagrant
2
2
  pkg
3
+ vendor
4
+ coverage
5
+ .bundle
data/.ruby_version ADDED
@@ -0,0 +1 @@
1
+ 2.6.3-p62
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,22 @@
1
+ # Contribute!
2
+
3
+ First off: all contributions are welcome and thanks for taking the time!
4
+
5
+ ## Setup
6
+
7
+ Clone the repository and install the dependencies:
8
+
9
+ ```
10
+ gem install bundler
11
+ bundle install --dev
12
+ ```
13
+
14
+ ## Submit
15
+
16
+ 1. Make a feature branch (`topics/foo` or `bugfix/foo`).
17
+ 2. Run `bundle exec rake test`.
18
+ 3. Send a pull-request.
19
+
20
+ ## Testing
21
+
22
+ If applicable, please add a new test. :)
data/Dockerfile ADDED
@@ -0,0 +1,11 @@
1
+ FROM ubuntu:18.04
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
7
+
8
+ WORKDIR /work
9
+ COPY . /work
10
+
11
+ CMD ["ruby", "-v"]
data/Gemfile.lock CHANGED
@@ -1,23 +1,42 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- apt-spy2 (0.4.0)
4
+ apt-spy2 (0.7.2)
5
5
  colored (>= 1.2)
6
6
  json
7
+ nokogiri (>= 1.6, < 1.13)
7
8
  thor (>= 0.18.1)
8
9
 
9
10
  GEM
10
11
  remote: https://rubygems.org/
11
12
  specs:
12
13
  colored (1.2)
13
- json (1.8.0)
14
- rake (10.1.0)
15
- thor (0.18.1)
14
+ docile (1.4.0)
15
+ json (2.6.1)
16
+ minitest (5.15.0)
17
+ nokogiri (1.12.5-x86_64-darwin)
18
+ racc (~> 1.4)
19
+ racc (1.5.2)
20
+ rake (13.0.6)
21
+ simplecov (0.21.2)
22
+ docile (~> 1.1)
23
+ simplecov-html (~> 0.11)
24
+ simplecov_json_formatter (~> 0.1)
25
+ simplecov-html (0.12.3)
26
+ simplecov-lcov (0.8.0)
27
+ simplecov_json_formatter (0.1.3)
28
+ thor (1.1.0)
16
29
 
17
30
  PLATFORMS
18
31
  ruby
19
32
 
20
33
  DEPENDENCIES
21
34
  apt-spy2!
22
- bundler (~> 1.3)
35
+ bundler (~> 2.0)
36
+ minitest (~> 5.15.0)
23
37
  rake
38
+ simplecov (~> 0.18)
39
+ simplecov-lcov (~> 0.8.0)
40
+
41
+ BUNDLED WITH
42
+ 2.2.32
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ BSD 2-Clause License
2
+
3
+ Copyright (c) 2013-2019, Till Klampaeckel
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/Makefile ADDED
@@ -0,0 +1,11 @@
1
+ install:
2
+ bundle install --path ./vendor/bundle
3
+
4
+ release:
5
+ bundle exec rake release
6
+
7
+ docker-build:
8
+ docker build -t lagged/apt-spy2:dev .
9
+
10
+ docker-run: docker-build
11
+ docker run -it lagged/apt-spy2:dev bash
data/README.md CHANGED
@@ -1,23 +1,20 @@
1
- # apt-spy2 or, "apt-spy for ubuntu"
2
-
3
- [![Gem Version](https://badge.fury.io/rb/apt-spy2.png)](http://badge.fury.io/rb/apt-spy2)
4
- [![Code Climate](https://codeclimate.com/github/lagged/apt-spy2.png)](https://codeclimate.com/github/lagged/apt-spy2)
1
+ # apt-spy2
5
2
 
3
+ … or: "apt-spy for Ubuntu"
6
4
 
7
- ## setup
5
+ [![pr](https://github.com/lagged/apt-spy2/actions/workflows/pr.yml/badge.svg)](https://github.com/lagged/apt-spy2/actions/workflows/pr.yml)
6
+ [![Gem Version](https://badge.fury.io/rb/apt-spy2.svg)](https://badge.fury.io/rb/apt-spy2)
7
+ [![Code Climate](https://codeclimate.com/github/lagged/apt-spy2.png)](https://codeclimate.com/github/lagged/apt-spy2)
8
+ [![Coverage Status](https://coveralls.io/repos/lagged/apt-spy2/badge.png)](https://coveralls.io/r/lagged/apt-spy2)
8
9
 
9
- ```
10
- gem install bundler
11
- bundle install --dev
12
- ```
13
10
 
14
- or:
11
+ ## Installation
15
12
 
16
13
  ```
17
14
  gem install apt-spy2
18
15
  ```
19
16
 
20
- ## usage
17
+ ## Usage
21
18
 
22
19
  ```
23
20
  $ apt-spy2 [21:03:52]
@@ -28,25 +25,48 @@ apt-spy2 commands:
28
25
  apt-spy2 list # List the currently available mirrors
29
26
  ```
30
27
 
31
- ### list
28
+ ### list command
32
29
 
33
30
  Displays a list of currently available mirrors. These mirrors are automatically selected via
34
31
  [ubuntu-mirrors](http://mirrors.ubuntu.com) using your IP's location.
35
32
 
36
- ### check
33
+ ```
34
+ $ apt-spy2 list
35
+ ...
36
+ ```
37
+
38
+ Since `mirrors.ubuntu.com` is frequently down, you can the list on [Launchpad](launchpad.net/ubuntu/+archivemirrors):
39
+
40
+ ```
41
+ $ apt-spy2 list --launchpad --country=Germany
42
+ ...
43
+ ```
44
+
45
+ ### check command
46
+
47
+ `check` works like `list`, but also determines if the servers returned are working. It supports Launchpad as well.
37
48
 
38
- `check` works like `list`, but also determines if the servers returned are working.
49
+ ```
50
+ $ apt-spy2 check
51
+ ...
52
+ $ apt-spy2 list --launchpad --country=US
53
+ ...
54
+ ```
39
55
 
40
- ### fix
56
+ ### fix command
41
57
 
42
58
  `fix` applies the result of `check` and updates `/etc/apt/sources.list`.
43
59
 
44
- Please note: Depending on the context, it may require sudo.
60
+ Once the fix is applied, please run `apt-get update`.
61
+
62
+ **Please note:** Depending on the context, it may require sudo.
45
63
 
46
64
  ### options/switches
47
65
 
48
66
  See `apt-spy2 help list|check|fix` for available options.
49
67
 
68
+ **Please note:** `--launchpad` always requires you pass `--country=FOO` as well.
69
+
50
70
  ### exit codes
51
71
 
52
72
  * 0 - all went well
@@ -56,13 +76,8 @@ See `apt-spy2 help list|check|fix` for available options.
56
76
 
57
77
  See `apt-spy2 help COMMAND` for more information.
58
78
 
59
- Generally, this piece of code plays especially nice in a non-interactive environment and won't ask for anything.
79
+ Generally, `apt-spy2` plays especially nice in a non-interactive environment and won't ask for anything without setting environment variables or using the usual `-y`.
60
80
 
61
81
  ## License
62
82
 
63
83
  [New BSD License](http://opensource.org/licenses/BSD-2-Clause)
64
-
65
- ## Contributions
66
-
67
- Contributions are welcome!
68
-
data/Rakefile CHANGED
@@ -1 +1,24 @@
1
1
  require "bundler/gem_tasks"
2
+ require "minitest/autorun"
3
+ require "simplecov"
4
+ require "simplecov-lcov"
5
+
6
+ Encoding.default_external = Encoding::UTF_8
7
+ Encoding.default_internal = Encoding::UTF_8
8
+
9
+ task :test do
10
+ ENV['COVERAGE'] = 'true'
11
+
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
24
+ end
data/apt-spy2.gemspec CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
11
11
  spec.description = "Keep your /etc/apt/sources.list up to date"
12
12
  spec.summary = "apt-spy2, or apt-spy for ubuntu"
13
13
  spec.homepage = "https://github.com/lagged/apt-spy2"
14
- spec.license = "BSD"
14
+ spec.license = 'BSD-2-Clause'
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
@@ -21,7 +21,11 @@ Gem::Specification.new do |spec|
21
21
  spec.add_dependency 'thor', '>= 0.18.1'
22
22
  spec.add_dependency 'colored', '>= 1.2'
23
23
  spec.add_dependency 'json'
24
+ spec.add_dependency 'nokogiri', '>= 1.6', '< 1.13'
24
25
 
25
- spec.add_development_dependency "bundler", "~> 1.3"
26
+ spec.add_development_dependency "bundler", "~> 2.0"
26
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"
27
31
  end
data/bin/apt-spy2 CHANGED
@@ -3,6 +3,9 @@
3
3
  require 'apt/spy2'
4
4
  require 'colored'
5
5
 
6
+ Encoding.default_external = Encoding::UTF_8
7
+ Encoding.default_internal = Encoding::UTF_8
8
+
6
9
  begin
7
10
  AptSpy2.start
8
11
  rescue => the_error
@@ -0,0 +1,33 @@
1
+ module Apt
2
+ module Spy2
3
+ class Country
4
+
5
+ def initialize(country_database)
6
+ @database = country_database
7
+ end
8
+
9
+ def to_country_name(code)
10
+ code = code.upcase
11
+ return capitalize(code) unless code.length == 2
12
+
13
+ File.open(@database).each do |line|
14
+ country, tld = line.split(';', 2)
15
+ tld.gsub!(/\n/, '')
16
+
17
+ if code == tld
18
+ return capitalize(country)
19
+ end
20
+
21
+ end
22
+
23
+ raise "Could not look up: #{code}"
24
+ end
25
+
26
+ private
27
+ def capitalize(str)
28
+ return str.split(" ").map(&:capitalize).join(" ")
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,30 @@
1
+ require 'open-uri'
2
+
3
+ module Apt
4
+ module Spy2
5
+ class Downloader
6
+
7
+ def initialize(url = nil)
8
+ @url = url if !url.nil?
9
+ end
10
+
11
+ def do_download(url = nil)
12
+ @url = url if !url.nil?
13
+
14
+ raise "Please supply a url." if url.nil?
15
+
16
+ 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
25
+ end
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,36 @@
1
+ require 'nokogiri'
2
+
3
+ module Apt
4
+ module Spy2
5
+ class Launchpad
6
+
7
+ def initialize(download)
8
+ @launchpad = download
9
+ end
10
+
11
+ def get_mirrors(country)
12
+
13
+ mirrors = []
14
+
15
+ document = Nokogiri::HTML(@launchpad)
16
+ table_rows = document.xpath("//tr/th[text()='#{country}']/../following-sibling::*")
17
+ raise "Couldn't find a mirror for #{country}." if table_rows.empty?
18
+
19
+ table_rows.each do |node|
20
+ break if node['class'] == 'head' # this is the next country heading
21
+
22
+ next if node.xpath(".//span[@class='distromirrorstatusUP']").empty? # this mirror is broken, behind, etc.
23
+
24
+ # return all mirrors: .//a[not(starts-with(@href, '/'))] - we'll just get http(s):// for now
25
+ node.xpath(".//a[starts-with(@href, 'http')]").each do |child|
26
+ mirrors << child['href']
27
+ end
28
+ end
29
+
30
+ return mirrors
31
+
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+ module Apt
2
+ module Spy2
3
+ class UbuntuMirrors
4
+
5
+ def initialize(download)
6
+ @ubuntu_mirrors = download
7
+ end
8
+
9
+ def get_mirrors(country)
10
+
11
+ mirrors = @ubuntu_mirrors
12
+ mirrors = mirrors.split(/\n/)
13
+ return mirrors
14
+
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -1,5 +1,5 @@
1
1
  module Apt
2
2
  module Spy2
3
- VERSION = "0.4.0"
3
+ VERSION = "0.7.2"
4
4
  end
5
5
  end
data/lib/apt/spy2.rb CHANGED
@@ -3,7 +3,10 @@ require 'open-uri'
3
3
  require 'colored'
4
4
  require 'fileutils'
5
5
  require 'apt/spy2/writer'
6
- require 'json'
6
+ require 'apt/spy2/country'
7
+ require 'apt/spy2/downloader'
8
+ require 'apt/spy2/ubuntu_mirrors'
9
+ require 'apt/spy2/launchpad'
7
10
 
8
11
  class AptSpy2 < Thor
9
12
  package_name "apt-spy2"
@@ -11,10 +14,11 @@ class AptSpy2 < Thor
11
14
  desc "fix", "Set the closest/fastest mirror"
12
15
  option :country, :default => "mirrors"
13
16
  option :commit, :type => :boolean
17
+ option :launchpad, :type => :boolean, :banner => "Use launchpad's mirror list"
14
18
  def fix
15
- working = filter(retrieve(), false)
19
+ working = filter(retrieve(options[:country], use_launchpad?(options)), false)
16
20
  print "The closest mirror is: "
17
- puts "#{working[0]}".white_on_green
21
+ puts "#{working[0]}".bold.magenta
18
22
  if !options[:commit]
19
23
  puts "Run with --commit to adjust /etc/apt/sources.list".yellow
20
24
  else
@@ -27,11 +31,12 @@ class AptSpy2 < Thor
27
31
  option :country, :default => "mirrors"
28
32
  option :output, :type => :boolean, :default => true
29
33
  option :format, :default => "shell"
34
+ option :launchpad, :type => :boolean, :banner => "Use launchpad's mirror list"
30
35
  def check
31
36
 
32
37
  @writer = Apt::Spy2::Writer.new(options[:format])
33
38
 
34
- mirrors = retrieve(options[:country])
39
+ mirrors = retrieve(options[:country], use_launchpad?(options))
35
40
  filter(mirrors, options[:output])
36
41
 
37
42
  puts @writer.to_json if @writer.json?
@@ -40,9 +45,10 @@ class AptSpy2 < Thor
40
45
  desc "list", "List the currently available mirrors"
41
46
  option :country, :default => "mirrors"
42
47
  option :format, :default => "shell"
48
+ option :launchpad, :type => :boolean, :banner => "Use launchpad's mirror list"
43
49
  def list
50
+ mirrors = retrieve(options[:country], use_launchpad?(options))
44
51
 
45
- mirrors = retrieve(options[:country])
46
52
  @writer = Apt::Spy2::Writer.new(options[:format])
47
53
 
48
54
  @writer.set_complete(mirrors)
@@ -51,24 +57,32 @@ class AptSpy2 < Thor
51
57
  puts mirrors if !@writer.json?
52
58
  end
53
59
 
60
+ desc "version", "Show which version of apt-spy2 is installed"
61
+ def version
62
+ puts Apt::Spy2::VERSION
63
+ exit
64
+ end
65
+
54
66
  private
55
- def retrieve(country = "mirrors")
56
- begin
57
- country.upcase! if country.length == 2
58
- mirrors = open("http://mirrors.ubuntu.com/#{country}.txt") do |list|
59
- list.read
60
- end
61
- rescue OpenURI::HTTPError => the_error
62
- case the_error.io.status[0]
63
- when "404"
64
- raise "The country code '#{country}' is incorrect."
65
- else
66
- raise "Status: #{the_error.io.status[0]}"
67
- end
67
+ def retrieve(country = "mirrors", launchpad = false)
68
+
69
+ downloader = Apt::Spy2::Downloader.new
70
+
71
+ if launchpad === true
72
+ csv_path = File.expand_path(File.dirname(__FILE__) + "/../../var/country-names.txt")
73
+ country = Apt::Spy2::Country.new(csv_path)
74
+ name = country.to_country_name(options[:country])
75
+
76
+ launchpad = Apt::Spy2::Launchpad.new(downloader.do_download('https://launchpad.net/ubuntu/+archivemirrors'))
77
+ return launchpad.get_mirrors(name)
68
78
  end
69
79
 
70
- mirrors = mirrors.split(/\n/)
80
+ country.upcase! if country.length == 2
81
+
82
+ ubuntu_mirrors = Apt::Spy2::UbuntuMirrors.new(downloader.do_download("http://mirrors.ubuntu.com/#{country}.txt"))
83
+ mirrors = ubuntu_mirrors.get_mirrors(country)
71
84
  return mirrors
85
+
72
86
  end
73
87
 
74
88
  private
@@ -80,12 +94,13 @@ class AptSpy2 < Thor
80
94
  mirrors.each do |mirror|
81
95
  data = {"mirror" => mirror }
82
96
  begin
83
- mirror_status = open(mirror)
97
+ open(mirror)
84
98
  data["status"] = "up"
85
99
  working_mirrors << mirror
86
- rescue OpenURI::HTTPError => the_error
100
+ rescue OpenURI::HTTPError
87
101
  data["status"] = "broken"
88
- rescue Errno::ECONNREFUSED
102
+ rescue
103
+ # this is a catch-all for everything else
89
104
  data["status"] = "down"
90
105
  end
91
106
 
@@ -121,6 +136,19 @@ class AptSpy2 < Thor
121
136
  end
122
137
 
123
138
  puts "Updated '#{apt_sources}' with #{mirror}".green
124
- puts "Run `apt-get update` to update".red_on_yellow
139
+ puts "Run `apt-get update` to update".black_on_yellow
140
+ end
141
+
142
+ private
143
+ def use_launchpad?(options)
144
+ if !options[:launchpad]
145
+ return false
146
+ end
147
+
148
+ if options[:country] && options[:country] == 'mirrors'
149
+ raise "Please supply a `--country=foo`. Launchpad cannot guess!"
150
+ end
151
+
152
+ return true
125
153
  end
126
154
  end
@@ -0,0 +1,27 @@
1
+ require 'apt/spy2/country'
2
+
3
+ class CountryTest < Minitest::Test
4
+ def setup
5
+ @country_list = File.expand_path(File.dirname(__FILE__) + "/../var/country-names.txt")
6
+ end
7
+
8
+ def test_tld_to_name()
9
+
10
+ # fixtures for people who don't want to read about rails
11
+ data = {
12
+ 'de' => 'Germany',
13
+ 'fr' => 'France',
14
+ 'IE' => 'Ireland',
15
+ 'US' => 'United States',
16
+ 'United Kingdom' => 'United Kingdom',
17
+ 'germany' => 'Germany'
18
+ }
19
+
20
+ c = Apt::Spy2::Country.new(@country_list)
21
+
22
+ data.each_pair do |code, expected|
23
+ assert_equal(expected, c.to_country_name(code))
24
+ end
25
+
26
+ end
27
+ end