vps_cli 0.1.4
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 +7 -0
- data/.gitignore +14 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +62 -0
- data/LICENSE.txt +21 -0
- data/README.md +72 -0
- data/Rakefile +20 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/bin/vps-cli +6 -0
- data/example_credentials.yaml +39 -0
- data/exe/vps-cli +6 -0
- data/lib/vps_cli/access.rb +176 -0
- data/lib/vps_cli/cli.rb +99 -0
- data/lib/vps_cli/configuration.rb +78 -0
- data/lib/vps_cli/configurations/default_configuration.rb +44 -0
- data/lib/vps_cli/configurations/testing_configuration.rb +25 -0
- data/lib/vps_cli/copy.rb +146 -0
- data/lib/vps_cli/helpers/access_helper.rb +132 -0
- data/lib/vps_cli/helpers/file_helper.rb +146 -0
- data/lib/vps_cli/helpers/github_http.rb +107 -0
- data/lib/vps_cli/install.rb +137 -0
- data/lib/vps_cli/packages.rb +22 -0
- data/lib/vps_cli/pull.rb +110 -0
- data/lib/vps_cli/setup.rb +105 -0
- data/lib/vps_cli/version.rb +3 -0
- data/lib/vps_cli.rb +90 -0
- data/sops_testing_key.asc +125 -0
- data/unencrypted_example_credentials.yaml +19 -0
- data/vps_cli.gemspec +46 -0
- metadata +176 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'vps_cli'
|
4
|
+
|
5
|
+
VpsCli.configure do |config|
|
6
|
+
# Where items will be copied to
|
7
|
+
# For example, the local dir is where you would your dotfiles
|
8
|
+
# saved to
|
9
|
+
config.local_dir = Dir.home
|
10
|
+
config.backup_dir = File.join(Dir.home, 'backup_files')
|
11
|
+
config.local_sshd_config = File.join('/etc', 'ssh', 'sshd_config')
|
12
|
+
|
13
|
+
# You must set these values yourself
|
14
|
+
|
15
|
+
# Location of your config files
|
16
|
+
# config.config_files = File.join(Dir.home, 'config_files')
|
17
|
+
# This is just used for easier git pulling and git pushing
|
18
|
+
|
19
|
+
config.config_files = File.join(Dir.home, 'vps_setup')
|
20
|
+
|
21
|
+
# Location of your dotfiles
|
22
|
+
# config.dotfiles = File.join(Dir.home, 'vps_setup', 'dotfiles')
|
23
|
+
config.dotfiles = File.join(config.config_files, 'dotfiles')
|
24
|
+
|
25
|
+
# Location of your dotfiles
|
26
|
+
# config.dotfiles = File.join(Dir.home, 'config_files', 'dotfiles')
|
27
|
+
config.misc_files = File.join(config.config_files, 'misc_files')
|
28
|
+
|
29
|
+
# credentials.yaml file, wherever its located, for me I have it in the home dir
|
30
|
+
config.credentials = File.join(Dir.home, '.credentials.yaml')
|
31
|
+
|
32
|
+
# location of your .netrc file, usually ~/.netrc
|
33
|
+
config.netrc = File.join(Dir.home, '.netrc')
|
34
|
+
|
35
|
+
config.verbose = false
|
36
|
+
|
37
|
+
# Change to false if you dont want to be prompted
|
38
|
+
# about file creations / overwrites
|
39
|
+
config.interactive = true
|
40
|
+
|
41
|
+
# this is merely for testing purposes, dont worry about this
|
42
|
+
config.testing = false
|
43
|
+
end
|
44
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'vps_cli'
|
4
|
+
|
5
|
+
test_dir = File.expand_path('../../../test', __dir__)
|
6
|
+
|
7
|
+
VpsCli.configure do |config|
|
8
|
+
config.local_dir = File.join(test_dir, 'local_dir')
|
9
|
+
config.backup_dir = File.join(test_dir, 'backup_dir')
|
10
|
+
config.local_sshd_config = File.join(config.local_dir, 'sshd_config')
|
11
|
+
config.sshd_backup = File.join(config.backup_dir, 'sshd_config.orig')
|
12
|
+
|
13
|
+
config.config_files = File.join(test_dir, 'config_files')
|
14
|
+
config.misc_files = File.join(config.config_files, 'miscfiles')
|
15
|
+
config.dotfiles = File.join(config.config_files, 'dotfiles')
|
16
|
+
config.credentials = File.join(File.expand_path('../../../', __dir__), 'example_credentials.yaml')
|
17
|
+
config.netrc = File.join(test_dir, 'access_dir', 'netrc')
|
18
|
+
|
19
|
+
|
20
|
+
config.verbose = true
|
21
|
+
config.interactive = false
|
22
|
+
config.testing = true
|
23
|
+
end
|
24
|
+
|
25
|
+
# puts VpsCli.configuration.local_dir
|
data/lib/vps_cli/copy.rb
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rake'
|
4
|
+
|
5
|
+
require 'vps_cli/helpers/file_helper'
|
6
|
+
|
7
|
+
module VpsCli
|
8
|
+
# Copies config from /vps_cli/config_files/dotfiles
|
9
|
+
# & vps_cli/config_files/miscfiles to your home dir
|
10
|
+
class Copy
|
11
|
+
extend FileHelper
|
12
|
+
|
13
|
+
# Top level method for copying all files
|
14
|
+
# Will use the configurations set by VpsCli.configuration
|
15
|
+
# unless passed a different config
|
16
|
+
# @raise [RuntimeError]
|
17
|
+
# Will raise this error if you run this method as root or sudo
|
18
|
+
def self.all(config = VpsCli.configuration)
|
19
|
+
# raises an error if the script is run as root
|
20
|
+
return unless root? == false
|
21
|
+
|
22
|
+
# fills in options that are not explicitly filled in
|
23
|
+
FileHelper.mkdirs(config.local_dir, config.backup_dir)
|
24
|
+
|
25
|
+
# copies dotfiles
|
26
|
+
dotfiles(config)
|
27
|
+
|
28
|
+
# copies gnome_settings
|
29
|
+
gnome_settings(config)
|
30
|
+
|
31
|
+
# copies sshd_config
|
32
|
+
sshd_config(config)
|
33
|
+
|
34
|
+
puts "dotfiles copied to #{config.local_dir}"
|
35
|
+
puts "backups created @ #{config.backup_dir}"
|
36
|
+
end
|
37
|
+
|
38
|
+
# Copy files from 'config_files/dotfiles' directory via the copy_all method
|
39
|
+
# Defaults are provided in the VpsCli.create_options method
|
40
|
+
# @see VpsCli::Configuration
|
41
|
+
def self.dotfiles(config = VpsCli.configuration)
|
42
|
+
Dir.each_child(config.dotfiles) do |file|
|
43
|
+
config_file = File.join(config.dotfiles, file)
|
44
|
+
local = File.join(config.local_dir, ".#{file}")
|
45
|
+
backup = File.join(config.backup_dir, "#{file}.orig")
|
46
|
+
|
47
|
+
files_and_dirs(config_file: config_file,
|
48
|
+
local_file: local,
|
49
|
+
backup_file: backup,
|
50
|
+
verbose: config.verbose,
|
51
|
+
interactive: config.interactive)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Checks that sshd_config is able to be copied
|
56
|
+
# @param sshd_config [File] File containing your original sshd_config
|
57
|
+
# Defaults to /etc/ssh/sshd_config
|
58
|
+
# @return [Boolean] Returns true if the sshd_config exists
|
59
|
+
def self.sshd_copyable?(sshd_config = nil)
|
60
|
+
sshd_config ||= '/etc/ssh/sshd_config'
|
61
|
+
|
62
|
+
no_sshd_config = 'No sshd_config found. sshd_config not copied'
|
63
|
+
|
64
|
+
return true if File.exist?(sshd_config)
|
65
|
+
|
66
|
+
VpsCli.errors << Exception.new(no_sshd_config)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Copies sshd_config to the VpsCli.configuration.local_sshd_config
|
70
|
+
# location
|
71
|
+
# Defaults to [/etc/ssh/sshd_config] if not set
|
72
|
+
# This is slightly different from other copy methods in this file
|
73
|
+
# It uses Rake.sh("sudo cp")
|
74
|
+
# Due to copying to /etc/ssh/sshd_config requiring root permissions
|
75
|
+
def self.sshd_config(config = VpsCli.configuration)
|
76
|
+
|
77
|
+
config.local_sshd_config ||= File.join('/etc', 'ssh', 'sshd_config')
|
78
|
+
return unless sshd_copyable?(config.local_sshd_config)
|
79
|
+
|
80
|
+
config.sshd_backup ||= File.join(config.backup_dir, 'sshd_config.orig')
|
81
|
+
|
82
|
+
misc_sshd_path = File.join(config.misc_files, 'sshd_config')
|
83
|
+
|
84
|
+
if File.exist?(config.local_sshd_config) && !File.exist?(config.sshd_backup)
|
85
|
+
Rake.cp(config.local_sshd_config, config.sshd_backup)
|
86
|
+
else
|
87
|
+
puts "#{config.sshd_backup} already exists. no backup created"
|
88
|
+
end
|
89
|
+
|
90
|
+
return Rake.cp(misc_sshd_path, config.local_sshd_config) if config.testing
|
91
|
+
|
92
|
+
# This method must be run this way due to it requiring root privileges
|
93
|
+
unless FileHelper.overwrite?(config.local_sshd_config, config.interactive)
|
94
|
+
return
|
95
|
+
end
|
96
|
+
|
97
|
+
Rake.sh("sudo cp #{misc_sshd_path} #{config.local_sshd_config}")
|
98
|
+
end
|
99
|
+
|
100
|
+
# Deciphers between files & directories
|
101
|
+
# Also utilizes the settings from your configuration to properly
|
102
|
+
# copy things
|
103
|
+
# @see VpsCli::FileHelper#copy_dirs
|
104
|
+
# @see VpsCli::FileHelper#copy_files
|
105
|
+
def self.files_and_dirs(opts = {})
|
106
|
+
if File.directory?(opts[:config_file])
|
107
|
+
FileHelper.copy_dirs(opts)
|
108
|
+
else
|
109
|
+
FileHelper.copy_files(opts)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Copies gnome terminal via dconf
|
114
|
+
# @see https://wiki.gnome.org/Projects/dconf dconf wiki
|
115
|
+
# @param config [VpsCli::Configuration] Where to save the current gnome terminal settings
|
116
|
+
# @note This method will raise an error if dconf errors out
|
117
|
+
# The error will be saved to VpsCli.errors
|
118
|
+
def self.gnome_settings(config = VpsCli.configuration)
|
119
|
+
backup = "#{config.backup_dir}/gnome_terminal_settings.orig"
|
120
|
+
|
121
|
+
# This is the ONLY spot for gnome terminal
|
122
|
+
gnome_path = '/org/gnome/terminal/'
|
123
|
+
gnome_file = File.join(config.misc_files, 'gnome_terminal_settings')
|
124
|
+
|
125
|
+
raise RuntimeError if config.testing
|
126
|
+
raise RuntimeError unless File.exists?(gnome_file)
|
127
|
+
|
128
|
+
overwrite = proc { |file| FileHelper.overwrite?(file, config.interactive) }
|
129
|
+
Rake.sh("dconf dump #{gnome_path} > #{backup}") if overwrite.call(backup)
|
130
|
+
|
131
|
+
dconf_load = "dconf load #{gnome_path} < #{config.misc_files}/gnome_terminal_settings"
|
132
|
+
Rake.sh(dconf_load) if overwrite.call(gnome_path)
|
133
|
+
rescue RuntimeError => error
|
134
|
+
puts 'something went wrong with gnome, continuing on' if config.verbose
|
135
|
+
VpsCli.errors << error
|
136
|
+
end
|
137
|
+
|
138
|
+
def self.root?
|
139
|
+
root = (Process.uid.zero? || Dir.home == '/root')
|
140
|
+
root_msg = 'Do not run this as root or sudo. Run as a normal user'
|
141
|
+
raise root_msg if root == true
|
142
|
+
|
143
|
+
false
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @see https://ruby-doc.org/stdlib-2.6.0.preview2/libdoc/open3/rdoc/Open3.html
|
4
|
+
require 'open3'
|
5
|
+
require 'json'
|
6
|
+
require 'net/http'
|
7
|
+
|
8
|
+
# Helper methods to be used within Access to help reduce the file size
|
9
|
+
module AccessHelper
|
10
|
+
# retrieves the values of .netrc for heroku and creates a writable string
|
11
|
+
# @return [String] Returns the string to be written to netrc
|
12
|
+
def heroku_api_string(yaml_file:)
|
13
|
+
# initial tree traversal in the .yaml file
|
14
|
+
heroku_api = %i[heroku api]
|
15
|
+
heroku_api_keys = %i[machine login password]
|
16
|
+
|
17
|
+
make_string(base: heroku_api, keys: heroku_api_keys) do |path|
|
18
|
+
decrypt(yaml_file: yaml_file, path: path)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# retries the git values for heroku in your .yaml file
|
23
|
+
# @return [String] Returns the string to be written to your netrc file
|
24
|
+
def heroku_git_string(yaml_file:)
|
25
|
+
heroku_git = %i[heroku git]
|
26
|
+
heroku_git_keys = %i[machine login password]
|
27
|
+
|
28
|
+
make_string(base: heroku_git, keys: heroku_git_keys) do |path|
|
29
|
+
decrypt(yaml_file: yaml_file, path: path)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# my version of Enumerable#inject intended to return a string
|
34
|
+
# provides a count to know what # object youre on
|
35
|
+
# @param array [Array<#to_s>]
|
36
|
+
# For each element in the array, yield to the block given.
|
37
|
+
# @yieldparam accum [String]
|
38
|
+
# The value that will persist throughout the block
|
39
|
+
# @yieldparam element [String] The current element in the array
|
40
|
+
# @yield param count [Integer]
|
41
|
+
# @return [String] Returns the string returned by the block passed to it
|
42
|
+
def my_inject_with_count(array)
|
43
|
+
value = nil
|
44
|
+
count = 0
|
45
|
+
array.inject('') do |accum, element|
|
46
|
+
value = yield(accum, element, count)
|
47
|
+
count += 1
|
48
|
+
value # if not here, returns the value of count
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Creates a string to be used to write to .netrc
|
53
|
+
# @param base [String] Provides the base string from which to add to
|
54
|
+
# @param keys [Array<String>] An array of strings to append to base
|
55
|
+
# @return [String] Returns the string after concatenating them
|
56
|
+
def make_string(base:, keys:)
|
57
|
+
# iterates through the keys to provide a path to each array
|
58
|
+
# essentialy is the equivalent of Hash.dig(:heroku, :api, :key)
|
59
|
+
my_inject_with_count(keys) do |string, key, count|
|
60
|
+
path = dig_for_path(base, key)
|
61
|
+
|
62
|
+
value = yield(path)
|
63
|
+
value << "\n " if count < keys.length - 1
|
64
|
+
string + value
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Writes the value of string to netrc
|
69
|
+
# @param netrc_file [File] ($HOME/.netrc)
|
70
|
+
# The location of your .netrc file to be read by heroku
|
71
|
+
# @param string [String] The String to write to the netrc file
|
72
|
+
# @return void
|
73
|
+
def write_to_netrc(netrc_file: nil, string:)
|
74
|
+
netrc_file ||= File.join(Dir.home, '.netrc')
|
75
|
+
Rake.mkdir_p(File.dirname(netrc_file))
|
76
|
+
Rake.touch(netrc_file) unless File.exist?(netrc_file)
|
77
|
+
|
78
|
+
begin
|
79
|
+
File.write(netrc_file, string)
|
80
|
+
rescue Errno::EACCES => e
|
81
|
+
netrc_error(netrc_file: netrc_file, error: e)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Adds the error to VpsCli#errors array
|
86
|
+
# @param [File] Location of netrc_file
|
87
|
+
# @param [Exception] The error to write to the array
|
88
|
+
# @return void
|
89
|
+
def netrc_error(netrc_file:, error:)
|
90
|
+
error_msg = "Unable to write to your #{netrc_file}."
|
91
|
+
VpsCli.errors << error.exception(error_msg)
|
92
|
+
end
|
93
|
+
|
94
|
+
# uses an access file via SOPS
|
95
|
+
# SOPS is an encryption tool
|
96
|
+
# @see https://github.com/mozilla/sops
|
97
|
+
# It will decrypt the file, please use a .yaml file
|
98
|
+
# @param file [File]
|
99
|
+
# The .yaml file encrypted with sops used to login to various accounts
|
100
|
+
# @path [String] JSON formatted string to traverse
|
101
|
+
# a yaml file tree
|
102
|
+
# Example: "[\"github\"][\"username\"]"
|
103
|
+
# @return [String] The value of key given in the .yaml file
|
104
|
+
def decrypt(yaml_file:, path:)
|
105
|
+
# puts all keys into a ["key"] within the array
|
106
|
+
sops_cmd = "sops -d --extract '#{path}' #{yaml_file}"
|
107
|
+
|
108
|
+
# this allows you to enter your passphrase
|
109
|
+
export_tty
|
110
|
+
# this will return in the string form the value you were looking for
|
111
|
+
stdout, _stderr, _status = Open3.capture3(sops_cmd)
|
112
|
+
|
113
|
+
stdout
|
114
|
+
end
|
115
|
+
|
116
|
+
# @param [#to_s, Array<#to_s>] The ordered path to traverse
|
117
|
+
# @return [String] Returns a path string to be able to traverse a yaml file
|
118
|
+
# @see VpsCli::Access#decrypt
|
119
|
+
def dig_for_path(*path)
|
120
|
+
path.flatten.inject('') do |final_path, node|
|
121
|
+
final_path + "[#{node.to_s.to_json}]"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# I noticed needing to export $(tty) while troubleshooting
|
126
|
+
# issues with gpg keys. It is here just in case its not in
|
127
|
+
# your zshrc / bashrc file
|
128
|
+
# @return void
|
129
|
+
def export_tty
|
130
|
+
Rake.sh('GPG_TTY=$(tty) && export GPG_TTY')
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rake'
|
4
|
+
|
5
|
+
# Used for copying files, making directories, copying directories etc
|
6
|
+
module FileHelper
|
7
|
+
# Helper method for making multiple directories
|
8
|
+
# @param [Dir, Array<Dir>] Creates either one, or multiple directories
|
9
|
+
def self.mkdirs(*dirs)
|
10
|
+
dirs.flatten.each { |dir| Rake.mkdir_p(dir) unless Dir.exist?(dir) }
|
11
|
+
end
|
12
|
+
|
13
|
+
# Copies files, called by copy_all
|
14
|
+
# @see VpsCli::Copy#all
|
15
|
+
# @param [Hash] opts The options to copy with
|
16
|
+
# @option opts [File] :config_file The file from the repo to be copied locally
|
17
|
+
# @option opts [File] :local_file The file that is currently present locally
|
18
|
+
# @option opts [File] :backup_file
|
19
|
+
# The file to which to save the currently present local file
|
20
|
+
# @option opts [Boolean] :interactive
|
21
|
+
# Will prompt yes or no for each file it creates
|
22
|
+
# @option opts [Boolean] :verbose Will print more info to terminal if true
|
23
|
+
def self.copy_files(opts = {})
|
24
|
+
# if there is an original dot file & no backup file in the backupdir
|
25
|
+
# Copy the dot file to the backup dir
|
26
|
+
if create_backup?(opts)
|
27
|
+
copy_file(opts[:local_file], opts[:backup_file], opts[:interactive])
|
28
|
+
end
|
29
|
+
|
30
|
+
# Copies from vps_cli/dotfiles to the location of the dot_file
|
31
|
+
copy_file(opts[:config_file], opts[:local_file], opts[:interactive])
|
32
|
+
end
|
33
|
+
|
34
|
+
# Copies directories instead of files, called by copy_all
|
35
|
+
# @see VpsCli::Copy#all
|
36
|
+
# @param [Hash] opts The options to copy with
|
37
|
+
# @option opts [File] :config_file The file from the repo to be copied locally
|
38
|
+
# @option opts [File] :dot_file The file that is currently present locally
|
39
|
+
# @option opts [File] :backup_file
|
40
|
+
# The file to which to save the currently present local file
|
41
|
+
# @option opts [Boolean] :interactive
|
42
|
+
# Will prompt yes or no for each file it creates
|
43
|
+
# @option opts [Boolean] :verbose Will print more info to terminal if true
|
44
|
+
def self.copy_dirs(opts = {})
|
45
|
+
mkdirs(opts[:local_file])
|
46
|
+
|
47
|
+
if create_backup?(opts)
|
48
|
+
copy_dir(opts[:local_file], opts[:backup_file], opts[:interactive])
|
49
|
+
end
|
50
|
+
|
51
|
+
Dir.each_child(opts[:config_file]) do |dir|
|
52
|
+
dir = File.join(opts[:config_file], dir)
|
53
|
+
|
54
|
+
# copies to local dir
|
55
|
+
copy_dir(dir, opts[:local_file], opts[:interactive])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Checks that a backup file does not exist
|
60
|
+
# @param file [File] File to be searched for
|
61
|
+
# @param verbose [Boolean] Will print to console if verbose == true
|
62
|
+
# @return [Boolean] Returns true if the file is not found
|
63
|
+
def self.backup_file_not_found?(file, verbose = false)
|
64
|
+
return true unless File.exist?(file)
|
65
|
+
|
66
|
+
puts "#{file} exists already. No backup created." if verbose
|
67
|
+
false
|
68
|
+
end
|
69
|
+
|
70
|
+
# Helper method for determining whether or not to create a backup file
|
71
|
+
# @param opts [Hash] options hash
|
72
|
+
# @option [File] :local_file current dot file
|
73
|
+
# @option [File] :backup_file Where to back the dot file up to
|
74
|
+
# @option [Boolean] :verbose Will print to terminal if verbose == true
|
75
|
+
# @return [Boolean] Returns true if there is a dotfile that exists
|
76
|
+
# And there is no current backup_file found
|
77
|
+
def self.create_backup?(opts = {})
|
78
|
+
return false unless file_found?(opts[:local_file], opts[:verbose])
|
79
|
+
unless backup_file_not_found?(opts[:backup_file], opts[:verbose])
|
80
|
+
return false
|
81
|
+
end
|
82
|
+
|
83
|
+
true
|
84
|
+
end
|
85
|
+
|
86
|
+
# Default way of checking if the dotfile already exists
|
87
|
+
# @param file [File] File to be searched for
|
88
|
+
# @param verbose [Boolean] Will print to console if verbose == true
|
89
|
+
# @return [Boolean] Returns true if the file exists
|
90
|
+
def self.file_found?(file, verbose = false)
|
91
|
+
return true if File.exist?(file)
|
92
|
+
|
93
|
+
puts "#{file} does not exist. No backup created." if verbose
|
94
|
+
false
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.retrieve_file(directory, name)
|
98
|
+
Dir.children(directory).select { |file| name == file }
|
99
|
+
end
|
100
|
+
|
101
|
+
# base method to copy a file and ask for permission prior to copying
|
102
|
+
# @see copy_files
|
103
|
+
# @see ask_permission
|
104
|
+
# @param from [File] File to copy from
|
105
|
+
# @param to [File] File to copy to
|
106
|
+
# @param config [VpsCli::Configuration] (VpsCli#configuration)
|
107
|
+
# uses the default config provided by the VpsCli module
|
108
|
+
def self.copy_file(from, to, interactive = false)
|
109
|
+
Rake.cp(from, to) if overwrite?(to, interactive)
|
110
|
+
end
|
111
|
+
|
112
|
+
# base method to copy a dir and ask for permission prior to copying
|
113
|
+
# @see copy_dirs
|
114
|
+
# @see ask_permission
|
115
|
+
# @param from [Dir] Directory to copy from
|
116
|
+
# @param to [Dir] Directory to copy to
|
117
|
+
# @param interactive [Boolean] (false) asks whether or not to create the file
|
118
|
+
def self.copy_dir(from, to, interactive = false)
|
119
|
+
mkdirs(to)
|
120
|
+
to_path = File.join(to, File.basename(from))
|
121
|
+
Rake.cp_r(from, to) if overwrite?(to_path, interactive)
|
122
|
+
end
|
123
|
+
|
124
|
+
# asks permission to copy a file
|
125
|
+
# @param file [File] The file to copy to
|
126
|
+
# @param interactive [Boolean] (false) If interactive equals false
|
127
|
+
# then automatically overwrite
|
128
|
+
# @return [Boolean]
|
129
|
+
# Decides whether or not the file will be created / overwritted
|
130
|
+
def self.overwrite?(file, interactive = false)
|
131
|
+
return true if interactive == false
|
132
|
+
|
133
|
+
string = "Attempting to overwrite file #{file}" if File.exist?(file)
|
134
|
+
string ||= "Attempting to create file #{file}"
|
135
|
+
|
136
|
+
# +string is equivalent to string.dup
|
137
|
+
string = +string + ' Is this okay? (Y/N)'
|
138
|
+
|
139
|
+
loop do
|
140
|
+
puts string
|
141
|
+
input = $stdin.gets.chomp.downcase.to_sym
|
142
|
+
return true if input == :y
|
143
|
+
return false if input == :n
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'net/http'
|
5
|
+
|
6
|
+
module VpsCli
|
7
|
+
# An http wrapper for github api request
|
8
|
+
class GithubHTTP
|
9
|
+
attr_accessor :uri, :title
|
10
|
+
attr_writer :token, :ssh_file
|
11
|
+
|
12
|
+
# @param uri [URI] the url to hit
|
13
|
+
# @param token [String] Github API token to use
|
14
|
+
# @param ssh_key [String] Your ssh file IE: ~/.ssh/id_rsa.pub
|
15
|
+
# @param title [String] The title of your ssh key
|
16
|
+
# Ensure it is in the format: "token 14942842859"
|
17
|
+
def initialize(uri:, token:, ssh_file:, title:)
|
18
|
+
@uri = uri
|
19
|
+
@token = token
|
20
|
+
@ssh_file = ssh_file
|
21
|
+
@ssh_key = File.read(ssh_file)
|
22
|
+
@headers = headers(token: token)
|
23
|
+
@title = title
|
24
|
+
end
|
25
|
+
|
26
|
+
# The headers need for authorization of a request
|
27
|
+
# @param token [String] (nil) Your github API token
|
28
|
+
# @see https://github.com/settings/keys
|
29
|
+
# make sure your token has write:public_key and read:public_key access
|
30
|
+
# @return [Hash] Returns a hash of headers
|
31
|
+
def headers(token:)
|
32
|
+
json = 'application/json'
|
33
|
+
|
34
|
+
{ 'Content-Type' => json,
|
35
|
+
'Accepts' => json,
|
36
|
+
'Authorization' => token }
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the appropriate json string to write an ssh key
|
40
|
+
# @return [String] Returns a json formatted string to write an ssh key
|
41
|
+
def ssh_json_string
|
42
|
+
{ 'title' => @title,
|
43
|
+
'key' => @ssh_key }.to_json
|
44
|
+
end
|
45
|
+
|
46
|
+
# base method for an http connection
|
47
|
+
# @yieldparam http [Net::HTTP] yields the http class
|
48
|
+
# @return Whatever the value of yield is
|
49
|
+
def start_connection
|
50
|
+
Net::HTTP.start(@uri.host, @uri.port, use_ssl: true) do |http|
|
51
|
+
yield(http)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Pushes your public key to github
|
56
|
+
# to push your ssh key to the github
|
57
|
+
# @return Net::HTTPResponse
|
58
|
+
def push_ssh_key
|
59
|
+
get = get_request
|
60
|
+
|
61
|
+
post = post_request(data: ssh_json_string)
|
62
|
+
|
63
|
+
response = start_connection do |http|
|
64
|
+
get_response = http.request(get)
|
65
|
+
|
66
|
+
ssh_keys_json = get_response.body
|
67
|
+
return ssh_key_found_msg if ssh_key_exist?(json_string: ssh_keys_json)
|
68
|
+
|
69
|
+
http.request(post)
|
70
|
+
end
|
71
|
+
|
72
|
+
VpsCli.errors << response if response != Net::HTTPCreated
|
73
|
+
|
74
|
+
puts 'ssh key pushed to github' if response.class == Net::HTTPCreated
|
75
|
+
response
|
76
|
+
end
|
77
|
+
|
78
|
+
# @param token [String] Your github api token
|
79
|
+
# @return [Net::HTTP::Get] Returns a new get request class
|
80
|
+
def get_request
|
81
|
+
Net::HTTP::Get.new(@uri, @headers)
|
82
|
+
end
|
83
|
+
|
84
|
+
# @param data [String] The data to send in the post request, must be json
|
85
|
+
# @return [Net::HTTP::Post] Returns a new post request class
|
86
|
+
def post_request(data:)
|
87
|
+
post = Net::HTTP::Post.new(@uri, @headers)
|
88
|
+
post.body = data
|
89
|
+
post
|
90
|
+
end
|
91
|
+
|
92
|
+
# Checks if the ssh key is already found
|
93
|
+
def ssh_key_exist?(json_string:)
|
94
|
+
# just in case your ssh key has a comment in it
|
95
|
+
# keys pulled from github will not have comments
|
96
|
+
ssh_key = @ssh_key.split('==')[0].concat('==')
|
97
|
+
|
98
|
+
JSON.parse(json_string).any? do |data|
|
99
|
+
data['key'] == ssh_key
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def ssh_key_found_msg
|
104
|
+
puts 'The ssh key provided is already on github, no post request made.'
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|