gsm-sources-manager 1.0.0.alpha3

Sign up to get free protection for your applications and to get access to all the features.
Binary file
@@ -0,0 +1,97 @@
1
+ ---
2
+ permalink: index.html
3
+ layout: default
4
+ ---
5
+ <div id="intro">
6
+ <div id="intro-logo">
7
+ <img src="/gsm/image/gsm.png">
8
+ </div>
9
+ <div id="intro-text">
10
+ GSM is a simple sources manager for RubyGems.
11
+ </div>
12
+ <div id="intro-desc">
13
+ In Ruby development, we always need alternative RubyGems source in special networks. e.g. In China Mainland, you know. GSM helps get your gem sources managed.
14
+ </div>
15
+ <div id="intro-button">
16
+ <div class="install-item install-gsm">
17
+ <a href="#install">Install GSM</a>
18
+ </div>
19
+ <div class="install-item install-user-guide">
20
+ <a href="#guide">User Guide</a>
21
+ </div>
22
+ </div>
23
+ <div id="intro-version">
24
+ <span>Version <a href="#changelog">{{ site.data.changelog[0].version }}</a> ·</span>
25
+ <span>Created by <a href="https://crispgm.com">David Zhang</a></span>
26
+ </div>
27
+ </div>
28
+ <div id="social">
29
+ <a class="github-button" href="https://github.com/crispgm/gsm" data-icon="octicon-star" data-count-href="/crispgm/gsm/stargazers" data-count-api="/repos/crispgm/gsm#stargazers_count" data-count-aria-label="# stargazers on GitHub" aria-label="Star crispgm/gsm on GitHub">Star</a>
30
+ <a class="github-button" href="https://github.com/crispgm/gsm/fork" data-icon="octicon-repo-forked" data-count-href="/crispgm/gsm/network" data-count-api="/repos/crispgm/gsm#forks_count" data-count-aria-label="# forks on GitHub" aria-label="Fork crispgm/gsm on GitHub">Fork</a>
31
+ </div>
32
+ <div id="install" class="content">
33
+ <div class="content-title">
34
+ Installation
35
+ </div>
36
+ <div>
37
+ {{ site.data.index.install | markdownify }}
38
+ </div>
39
+ <div class="back-top">
40
+ <a href="#topbar">Back to top</a>
41
+ </div>
42
+ </div>
43
+ <div id="guide" class="content">
44
+ <div class="content-title">
45
+ User Guide
46
+ </div>
47
+ {{ site.data.index.guide | markdownify }}
48
+ <div class="back-top">
49
+ <a href="#topbar">Back to top</a>
50
+ </div>
51
+ </div>
52
+ <div id="changelog" class="content">
53
+ <div class="content-title">
54
+ Changelog
55
+ </div>
56
+ {% for change in site.data.changelog %}
57
+ <h3>Version {{ change.version }}</h3>
58
+ <ul>
59
+ {% for log in change.changes %}
60
+ <li>
61
+ {{ log.text }}
62
+ {% if log.issue != nil %}
63
+ <a href="https://github.com/crispgm/gsm/issues/{{ log.issue }}">#{{ log.issue }}</a></li>
64
+ {% endif %}
65
+ </li>
66
+ {% endfor %}
67
+ </ul>
68
+ {% endfor %}
69
+ <div class="back-top">
70
+ <a href="#topbar">Back to top</a>
71
+ </div>
72
+ </div>
73
+ <div id="contributing" class="content">
74
+ <div class="content-title">
75
+ Contributing
76
+ </div>
77
+ {{ site.data.index.contrib | markdownify }}
78
+ <div class="back-top">
79
+ <a href="#topbar">Back to top</a>
80
+ </div>
81
+ </div>
82
+ <div id="disqus" class="content">
83
+ <div id="disqus_thread"></div>
84
+ <script>
85
+ var disqus_config = function () {
86
+ this.page.url = 'https://crispgm.github.io/gsm/';
87
+ this.page.identifier = 'Home | GSM Sources Manager';
88
+ };
89
+ (function() { // DON'T EDIT BELOW THIS LINE
90
+ var d = document, s = d.createElement('script');
91
+ s.src = '//crispgm-github-io.disqus.com/embed.js';
92
+ s.setAttribute('data-timestamp', +new Date());
93
+ (d.head || d.body).appendChild(s);
94
+ })();
95
+ </script>
96
+ <noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
97
+ </div>
data/exe/gsm ADDED
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), *%w(.. lib)))
4
+
5
+ require "gsm"
6
+ require "mercenary"
7
+
8
+ Mercenary.program(:gsm) do |p|
9
+ p.version Gsm::VERSION
10
+ p.description "GSM Sources Manager"
11
+ p.syntax "gsm <subcommand> [options]"
12
+
13
+ conf_path = ""
14
+ user_path = Dir.home()
15
+ Dir.chdir(user_path) do
16
+ if !Dir.exist?(".gsm")
17
+ Dir.mkdir(".gsm")
18
+ end
19
+ end
20
+
21
+ conf_path = "#{user_path}/.gsm/sources.yml"
22
+
23
+ gem = Gsm::Gem.new("#{user_path}/sources.yml")
24
+
25
+ p.command(:list) do |c|
26
+ c.syntax "list"
27
+ c.description "List all sources"
28
+
29
+ c.action do |_, _|
30
+ gem.sources.each do |name, url|
31
+ use_mark = ""
32
+ if gem.get == name
33
+ use_mark = "(*)"
34
+ end
35
+ puts "#{name}: #{url} #{use_mark}"
36
+ end
37
+ end
38
+ end
39
+
40
+ p.command(:use) do |c|
41
+ c.syntax "use [source]"
42
+ c.description "Use source"
43
+
44
+ c.action do |args, _|
45
+ name = args[0]
46
+ use = gem.use(name)
47
+ if use
48
+ puts "GSM: Source `#{use}` has been applied."
49
+ else
50
+ puts "GSM Error: Illegal source `#{name}`."
51
+ end
52
+ end
53
+ end
54
+
55
+ p.command(:add) do |c|
56
+ c.syntax "add [name] [url]"
57
+ c.description "Add source"
58
+
59
+ c.option "use", "--use", "Add and use source"
60
+
61
+ c.action do |args, opts|
62
+ name = args[0]
63
+ url = args[1]
64
+ is_use = opts["use"]
65
+
66
+ if gem.add(name, url)
67
+ if is_use
68
+ if !gem.use(name)
69
+ puts "GSM Error: Illegal source `#{name}`."
70
+ end
71
+ end
72
+ else
73
+ puts "GSM Error: Illegal name/url."
74
+ end
75
+ end
76
+ end
77
+
78
+ p.command(:del) do |c|
79
+ c.syntax "del [source]"
80
+ c.description "Delete source"
81
+
82
+ c.action do |args, _|
83
+ name = args[0]
84
+ ret = gem.del(name)
85
+ if ret == false
86
+ puts "GSM Error: Source is in use. Please switch to other source in advance."
87
+ return
88
+ elsif ret == nil
89
+ puts "GSM Error: No source name with `#{name}`."
90
+ return
91
+ end
92
+ end
93
+ end
94
+
95
+ p.command(:reset) do |c|
96
+ c.syntax "reset"
97
+ c.description "Reset all sources"
98
+
99
+ c.action do |_, _|
100
+ gem.reset
101
+ end
102
+ end
103
+
104
+ p.command(:mirror) do |c|
105
+ c.syntax "mirror [source]"
106
+ c.description "Mirror source for Bundler"
107
+
108
+ c.option "reset", "--reset", "Reset bundler mirror"
109
+
110
+ c.action do |args, opts|
111
+ if opts["reset"]
112
+ Gsm::Bundle.reset
113
+ return
114
+ end
115
+
116
+ if args.size == 0
117
+ name = gem.get
118
+ if name.empty?
119
+ puts "GSM Error: no default source for mirror."
120
+ return
121
+ end
122
+ else
123
+ name = args[0]
124
+ end
125
+ Gsm::Bundle.mirror(gem.sources[name])
126
+ end
127
+ end
128
+
129
+ p.command(:help) do |c|
130
+ c.syntax "help"
131
+ c.description "Show usage"
132
+
133
+ c.action do |_, _|
134
+ puts p
135
+ end
136
+ end
137
+
138
+ p.default_command(:help)
139
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'gsm/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "gsm-sources-manager"
8
+ spec.version = Gsm::VERSION
9
+ spec.authors = ["David Zhang"]
10
+ spec.email = ["crispgm@gmail.com"]
11
+ spec.summary = "GSM Sources Manager"
12
+ spec.description = "GSM is a simple sources manager for RubyGems."
13
+ spec.homepage = "https://github.com/crispgm/gsm"
14
+ spec.license = "MIT"
15
+
16
+ spec.required_ruby_version = '>= 2.3.0'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0")
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency "minitest"
25
+ spec.add_development_dependency "shoulda-context"
26
+ spec.add_development_dependency "codeclimate-test-reporter"
27
+
28
+ spec.add_dependency "mercenary", "~> 0.3.6"
29
+ end
@@ -0,0 +1,6 @@
1
+ module Gsm
2
+ require "gsm/bundle"
3
+ require "gsm/gem"
4
+ require "gsm/util"
5
+ require "gsm/version"
6
+ end
@@ -0,0 +1,14 @@
1
+ module Gsm
2
+ class Bundle
3
+
4
+ RUBY_GEM_URL = "https://rubygems.org/".freeze
5
+
6
+ def self.mirror(dst_url, src_url = RUBY_GEM_URL)
7
+ `bundle config mirror.#{src_url} #{dst_url}`
8
+ end
9
+
10
+ def self.reset
11
+ self.mirror(RUBY_GEM_URL)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,178 @@
1
+ module Gsm
2
+ class Gem
3
+ require "yaml"
4
+
5
+ attr_reader :conf_path, :name_pivot
6
+ attr_reader :sources
7
+ attr_reader :use_name
8
+
9
+ MAX_GENERATED_NAMES = 11
10
+ GEMSTONE_NAMES = [
11
+ "Amethyst",
12
+ "Emerald",
13
+ "Chrysocolla",
14
+ "Hematite",
15
+ "Jasper",
16
+ "Malachite",
17
+ "Quartz",
18
+ "Ruby",
19
+ "Sapphire",
20
+ "Sugilite",
21
+ "Turquoise"
22
+ ].freeze
23
+
24
+ def initialize(conf_path)
25
+ @sources = Hash.new
26
+ @use_name = ""
27
+ @name_pivot = 0
28
+ @conf_path = conf_path
29
+
30
+ if !load_from_yaml?
31
+ # load from `gem sources`
32
+ load
33
+ end
34
+ save
35
+ end
36
+
37
+ def load(mock = nil)
38
+ if mock != nil
39
+ outputs = mock
40
+ else
41
+ outputs = `gem sources -l`
42
+ end
43
+ outputs.split("\n").each do |line|
44
+ line.strip!
45
+ if validate_url?(line)
46
+ if @sources.length >= MAX_GENERATED_NAMES
47
+ return false
48
+ end
49
+ name = generate_name
50
+ @sources[name] = line
51
+ end
52
+ end
53
+ end
54
+
55
+ def add(name, url)
56
+ return false if validate_name?(name)
57
+
58
+ # validate url
59
+ if !validate_url?(url)
60
+ return false
61
+ end
62
+
63
+ @sources[name] = url
64
+ save
65
+
66
+ name
67
+ end
68
+
69
+ def del(name)
70
+ return false if @use_name.eql?(name)
71
+ return nil if !@sources.has_key?(name)
72
+
73
+ @sources.delete(name)
74
+ save
75
+
76
+ name
77
+ end
78
+
79
+ def get
80
+ @use_name
81
+ end
82
+
83
+ def reset
84
+ @use_name.clear
85
+ @sources.clear
86
+ save
87
+ end
88
+
89
+ def use(name)
90
+ return false if !@sources.has_key?(name)
91
+ return @use_name if @use_name.eql?(name)
92
+
93
+ if !apply_source(name)
94
+ return false
95
+ end
96
+
97
+ @use_name = name
98
+ save
99
+
100
+ @use_name
101
+ end
102
+
103
+ def save
104
+ data = {
105
+ :use => @use_name,
106
+ :sources => @sources
107
+ }
108
+ # write to file
109
+ f = File.new(@conf_path, "w")
110
+ f.syswrite(data.to_yaml)
111
+ f.close
112
+ end
113
+
114
+ def to_s
115
+ return @sources[@use_name] if @sources.has_key?(@use_name)
116
+ end
117
+
118
+ private
119
+ def apply_source(name)
120
+ outputs = `gem sources -l`
121
+ outputs.split("\n").each do |line|
122
+ line.strip!
123
+ if validate_url?(line)
124
+ `gem sources --remove #{line}`
125
+ end
126
+ end
127
+
128
+ url = @sources[name]
129
+ output = `gem sources --add #{url}`
130
+ output.include?("#{url} added to sources")
131
+ end
132
+
133
+ private
134
+ def validate_name?(name)
135
+ return false if %r{[a-zA-Z]{1,32}*} =~ name
136
+ return false if @sources.has_key?(name)
137
+ true
138
+ end
139
+
140
+ private
141
+ def validate_url?(url)
142
+ url.start_with?("http://") || url.start_with?("https://") ? true : false
143
+ end
144
+
145
+ private
146
+ def load_from_yaml?
147
+ # read yaml
148
+ if File.exist?(@conf_path)
149
+ data = YAML.load_file(@conf_path)
150
+ @use_name = data[:use] if data.has_key?(:use)
151
+ @sources = data[:sources] if data.has_key?(:sources)
152
+ true
153
+ else
154
+ f = File.new(@conf_path, "w")
155
+ f.close
156
+ false
157
+ end
158
+ end
159
+
160
+ private
161
+ def generate_name
162
+ gen_name = ""
163
+
164
+ while @name_pivot < MAX_GENERATED_NAMES
165
+ gen_name = GEMSTONE_NAMES[@name_pivot].to_s
166
+
167
+ @name_pivot = @name_pivot + 1
168
+
169
+ if !@sources.has_key?(gen_name)
170
+ return gen_name
171
+ end
172
+ end
173
+
174
+ return false
175
+ end
176
+
177
+ end
178
+ end