apt-spy2 0.4.0 → 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
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