takelage 0.1.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.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +674 -0
  3. data/README.md +159 -0
  4. data/bin/tau +5 -0
  5. data/lib/Thorfile +1 -0
  6. data/lib/takelage/bit/cli.rb +18 -0
  7. data/lib/takelage/bit/clipboard/cli.rb +68 -0
  8. data/lib/takelage/bit/clipboard/module.rb +174 -0
  9. data/lib/takelage/bit/scope/cli.rb +58 -0
  10. data/lib/takelage/bit/scope/module.rb +81 -0
  11. data/lib/takelage/completion/cli.rb +21 -0
  12. data/lib/takelage/default.yml +30 -0
  13. data/lib/takelage/docker/cli.rb +16 -0
  14. data/lib/takelage/docker/container/check/cli.rb +40 -0
  15. data/lib/takelage/docker/container/check/module.rb +44 -0
  16. data/lib/takelage/docker/container/cli.rb +127 -0
  17. data/lib/takelage/docker/container/module.rb +168 -0
  18. data/lib/takelage/docker/image/cli.rb +41 -0
  19. data/lib/takelage/docker/image/module.rb +33 -0
  20. data/lib/takelage/docker/image/tag/check/cli.rb +47 -0
  21. data/lib/takelage/docker/image/tag/check/module.rb +56 -0
  22. data/lib/takelage/docker/image/tag/cli.rb +16 -0
  23. data/lib/takelage/docker/image/tag/latest/cli.rb +49 -0
  24. data/lib/takelage/docker/image/tag/latest/module.rb +31 -0
  25. data/lib/takelage/docker/image/tag/list/cli.rb +46 -0
  26. data/lib/takelage/docker/image/tag/list/module.rb +44 -0
  27. data/lib/takelage/docker/socket/cli.rb +61 -0
  28. data/lib/takelage/docker/socket/module.rb +137 -0
  29. data/lib/takelage/git/check/cli.rb +46 -0
  30. data/lib/takelage/git/check/module.rb +64 -0
  31. data/lib/takelage/git/cli.rb +10 -0
  32. data/lib/takelage/info/cli.rb +10 -0
  33. data/lib/takelage/info/project/cli.rb +47 -0
  34. data/lib/takelage/lib/config.rb +80 -0
  35. data/lib/takelage/lib/logging.rb +30 -0
  36. data/lib/takelage/lib/project.rb +57 -0
  37. data/lib/takelage/lib/subcmd.rb +13 -0
  38. data/lib/takelage/lib/system.rb +107 -0
  39. data/lib/takelage/self/cli.rb +40 -0
  40. data/lib/takelage/self/config/cli.rb +70 -0
  41. data/lib/takelage/self/module.rb +26 -0
  42. data/lib/takelage/version +1 -0
  43. data/lib/takelage.rb +198 -0
  44. metadata +185 -0
@@ -0,0 +1,44 @@
1
+ # takelage docker image tag list module
2
+ module DockerImageTagListModule
3
+
4
+ # Backend method for docker image tag list local.
5
+ # @return [Array] local docker image tags
6
+ def docker_image_tag_list_local
7
+ tags = []
8
+
9
+ cmd_docker_images = 'docker images'
10
+ images = run cmd_docker_images
11
+
12
+ images.scan(/.*#{@docker_repo}\/#{@docker_image}.*/) do |line|
13
+ tags << line.split(/\s+/)[1]
14
+ end
15
+
16
+ tags.sort_by(&Gem::Version.method(:new))
17
+ end
18
+
19
+ # Backend method for docker image tag list remote.
20
+ # @return [Array] remote docker image tags
21
+ def docker_image_tag_list_remote
22
+ log.debug "Getting docker remote tags from \"#{@docker_tagsurl}\""
23
+
24
+ begin
25
+ @res = Net::HTTP.get_response URI(@docker_tagsurl)
26
+ unless @res.code.eql? '200'
27
+ log.error "Unable to connect to \"#{@docker_tagsurl}\""
28
+ return
29
+ end
30
+ rescue SocketError => e
31
+ log.debug e
32
+ exit false
33
+ end
34
+
35
+ begin
36
+ tags = JSON.parse @res.body
37
+ rescue JSON::ParserError
38
+ log.error 'Unable to parse JSON'
39
+ exit false
40
+ end
41
+
42
+ tags['tags'].sort_by(&Gem::Version.method(:new))
43
+ end
44
+ end
@@ -0,0 +1,61 @@
1
+ module Takelage
2
+
3
+ # takelage docker socket
4
+ class DockerSocket < SubCommandBase
5
+
6
+ include LoggingModule
7
+ include ConfigModule
8
+ include SystemModule
9
+ include DockerSocketModule
10
+
11
+ # Initialize docker socket
12
+ def initialize(args = [], local_options = {}, configuration = {})
13
+
14
+ # initialize thor parent class
15
+ super args, local_options, configuration
16
+
17
+ @sockets = {
18
+ :'agent-socket' => {
19
+ :path => nil,
20
+ :host => '127.0.0.1',
21
+ :port => config.active['docker_socket_agent_port']},
22
+ :'agent-ssh-socket' => {
23
+ :path => nil,
24
+ :host => '127.0.0.1',
25
+ :port => config.active['docker_socket_agent_ssh_port']},
26
+ :'agent-extra-socket' => {
27
+ :path => nil,
28
+ :host => '127.0.0.1',
29
+ :port => config.active['docker_socket_agent_extra_port']},
30
+ :'agent-browser-socket' => {
31
+ :path => nil,
32
+ :host => '127.0.0.1',
33
+ :port => config.active['docker_socket_agent_browser_port']}}
34
+ _get_socket_paths
35
+ end
36
+
37
+ #
38
+ # docker socket start
39
+ #
40
+ desc 'start', 'Start sockets for docker container'
41
+ long_desc <<-LONGDESC.gsub("\n", "\x5")
42
+ Start sockets for docker container
43
+ LONGDESC
44
+ # Start sockets for docker container.
45
+ def start
46
+ docker_socket_start
47
+ end
48
+
49
+ #
50
+ # docker socket stop
51
+ #
52
+ desc 'stop', 'Stop sockets for docker container'
53
+ long_desc <<-LONGDESC.gsub("\n", "\x5")
54
+ Stop sockets for docker container
55
+ LONGDESC
56
+ # Stop sockets for docker container.
57
+ def stop
58
+ docker_socket_stop
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,137 @@
1
+ # takelage docker socket module
2
+ module DockerSocketModule
3
+
4
+ # Backend method for docker socket start.
5
+ def docker_socket_start
6
+ log.debug 'Starting sockets for docker container'
7
+
8
+ cmds_start_socket = _get_socket_start_commands sockets_up = false
9
+
10
+ unless cmds_start_socket.empty?
11
+ log.debug 'Request sudo so that subsequent background tasks run without delay'
12
+
13
+ cmd_sudo_true = 'sudo true'
14
+
15
+ run cmd_sudo_true
16
+ end
17
+
18
+ cmds_start_socket.each do |cmd_start_socket|
19
+ run_and_fork cmd_start_socket
20
+ end
21
+ end
22
+
23
+ # Backend method for docker socket stop.
24
+ def docker_socket_stop
25
+ log.debug 'Stopping sockets for docker container'
26
+
27
+ cmd_ps = config.active['docker_socket_ps']
28
+
29
+ # get process list
30
+ # assuming format: "pid command"
31
+ stdout_str, stderr_str, status = run_and_check cmd_ps
32
+
33
+ cmds_start_socket = _get_socket_start_commands sockets_up = true
34
+
35
+ # loop over process list
36
+ stdout_str.split(/\n+/).each do |process|
37
+
38
+ # split processes in process id and process command
39
+ pid_command = process.strip.split(/ /, 2)
40
+ pid = pid_command[0]
41
+ command = pid_command[1]
42
+
43
+ # loop over socket start commands
44
+ cmds_start_socket.each do |cmd_start_socket|
45
+
46
+ if command == cmd_start_socket
47
+ log.debug "Killing PID #{pid}"
48
+
49
+ cmd_kill = config.active['docker_socket_kill'] % {pid: pid}
50
+
51
+ run cmd_kill
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ # get socket start commands
58
+ # sockets_up is a boolean which defines if the sockets need to be up
59
+ # to be included in the resulting array of socket start commands
60
+ def _get_socket_start_commands sockets_up
61
+ cmds_start_socket = []
62
+
63
+ # loop over sockets
64
+ @sockets.each do |socket, socket_config|
65
+ cmd_start_socket = config.active['docker_socket_start'] % {
66
+ host: socket_config[:host],
67
+ port: socket_config[:port],
68
+ path: socket_config[:path],
69
+ }
70
+
71
+ if sockets_up
72
+ if _socket_up? socket, socket_config
73
+ cmds_start_socket << cmd_start_socket
74
+ end
75
+ else
76
+ unless _socket_up? socket, socket_config
77
+ cmds_start_socket << cmd_start_socket
78
+ end
79
+ end
80
+ end
81
+
82
+ cmds_start_socket
83
+ end
84
+
85
+ # get socket paths
86
+ def _get_socket_paths
87
+ cmd_gpgconf_listdirs = config.active['docker_socket_gpgconf']
88
+ stdout_str, stderr_str, status = run_and_check cmd_gpgconf_listdirs
89
+
90
+ stdout_str.split(/\n+/).each do |gpg_path|
91
+ @sockets.each do |socket, socket_config|
92
+ gpg_socket = gpg_path.split(':')
93
+ if gpg_socket[0] == socket.to_s
94
+ @sockets[socket][:path] = gpg_socket[1]
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ # check if a socket is available
101
+ # but trying to connect to it via TCP
102
+ def _socket_up? socket, socket_config
103
+ host = socket_config[:host]
104
+ port = socket_config[:port]
105
+ path = socket_config[:path]
106
+
107
+ error_message = "failed to connect to " +
108
+ "socket \"#{socket}\" " +
109
+ "using host \"#{host}\", " +
110
+ "port \"#{port}\", " +
111
+ "path \"#{path}\""
112
+
113
+ # check if socket is available
114
+ begin
115
+ Timeout::timeout(1) do
116
+ begin
117
+ s = TCPSocket.new host, port
118
+ s.close
119
+ log.debug "Socket \"#{socket}\" available"
120
+ return true
121
+ rescue Errno::ECONNREFUSED
122
+ log.debug "Connection refused: #{error_message}"
123
+ return false
124
+ rescue Errno::EHOSTUNREACH
125
+ log.debug "Host unreachable: #{error_message}"
126
+ return false
127
+ rescue SocketError
128
+ log.debug "Socket error: #{error_message}"
129
+ return false
130
+ end
131
+ end
132
+ rescue Timeout::Error
133
+ log.debug "Timeout: #{error_message}"
134
+ return false
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,46 @@
1
+ module Takelage
2
+
3
+ # takelage docker container check
4
+ class GitCheck < SubCommandBase
5
+
6
+ include LoggingModule
7
+ include SystemModule
8
+ include GitCheckModule
9
+
10
+ #
11
+ # git check clean
12
+ #
13
+ desc 'clean', 'Check if the git workspace is clean'
14
+ long_desc <<-LONGDESC.gsub("\n", "\x5")
15
+ Check if the git workspace is clean
16
+ LONGDESC
17
+ # Check if the git workspace is clean.
18
+ def clean
19
+ exit git_check_clean
20
+ end
21
+
22
+ #
23
+ # git check master
24
+ #
25
+ desc 'master', 'Check if we are on the git master branch'
26
+ long_desc <<-LONGDESC.gsub("\n", "\x5")
27
+ Check if we are on the git master branch
28
+ LONGDESC
29
+ # Check if we are on the git master branch.
30
+ def master
31
+ exit git_check_master
32
+ end
33
+
34
+ #
35
+ # git check workspace
36
+ #
37
+ desc 'workspace', 'Check if a git workspace exists'
38
+ long_desc <<-LONGDESC.gsub("\n", "\x5")
39
+ Check if a git workspace exists
40
+ LONGDESC
41
+ # Check if a git workspace exists.
42
+ def workspace
43
+ exit git_check_workspace
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,64 @@
1
+ # takelage git check module
2
+ module GitCheckModule
3
+
4
+ # Backend method for git check clean.
5
+ # @return [Boolean] is git workspace clean?
6
+ def git_check_clean
7
+ log.debug "Checking if git workspace is clean"
8
+
9
+ return false unless git_check_workspace
10
+
11
+ cmd_git_unstaged = 'git diff --exit-code'
12
+ cmd_git_uncommitted = 'git diff --cached --exit-code'
13
+ cmd_git_status = 'git status --porcelain'
14
+
15
+ stdout_str, stderr_str, status_unstaged = run_and_check cmd_git_unstaged
16
+ stdout_str, stderr_str, status_uncommitted = run_and_check cmd_git_uncommitted
17
+ stdout_str_status, stderr_str, status = run_and_check cmd_git_status
18
+
19
+ # only return true if neither unstaged nor uncommitted nor empty files
20
+ sum = status_unstaged.exitstatus +
21
+ status_uncommitted.exitstatus +
22
+ stdout_str_status.length
23
+
24
+ sum.zero?
25
+ end
26
+
27
+ # Backend method for git check master.
28
+ # @return [Boolean] are we on the git master branch?
29
+ def git_check_master
30
+ log.debug 'Check if we are on the git master branch'
31
+
32
+ return false unless git_check_workspace
33
+
34
+ cmd_get_branch = 'git symbolic-ref HEAD'
35
+ stdout_str, stderr_str, status = run_and_check cmd_get_branch
36
+
37
+ branch = stdout_str.strip.split('/')[-1]
38
+
39
+ log.debug "We are on git branch \"#{branch}\""
40
+
41
+ branch == 'master'
42
+ end
43
+
44
+ # Backend method for git check workspace.
45
+ # @return [Boolean] is this a git workspace?
46
+ def git_check_workspace
47
+ log.debug 'Check if this is a git workspace'
48
+
49
+ cmd_check_git_repo = 'git -C . rev-parse'
50
+ stdout_str_repo, stderr_str_repo, status_repo = run_and_check cmd_check_git_repo
51
+
52
+ cmd_pwd = 'pwd'
53
+ stdout_str_dir, stderr_str_dir, status_dir = run_and_check cmd_pwd
54
+
55
+ dir = stdout_str_dir.strip
56
+
57
+ unless status_repo.exitstatus.zero?
58
+ log.debug "No git workspace found in \"#{dir}\""
59
+ return false
60
+ end
61
+
62
+ true
63
+ end
64
+ end
@@ -0,0 +1,10 @@
1
+ module Takelage
2
+
3
+ # takelage git
4
+ class Git < SubCommandBase
5
+
6
+ desc 'check [COMMAND]', 'Check git state'
7
+ subcommand 'check', GitCheck
8
+
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module Takelage
2
+
3
+ # takelage info
4
+ class Info < SubCommandBase
5
+
6
+ desc 'project [COMMAND]', 'Get project info'
7
+ subcommand 'project', InfoProject
8
+
9
+ end
10
+ end
@@ -0,0 +1,47 @@
1
+ module Takelage
2
+
3
+ # takelage info project
4
+ class InfoProject < SubCommandBase
5
+
6
+ include LoggingModule
7
+ include SystemModule
8
+ include ConfigModule
9
+ include ProjectModule
10
+
11
+ #
12
+ # info project active
13
+ #
14
+ desc 'active', 'Print active project info'
15
+ long_desc <<-LONGDESC.gsub("\n", "\x5")
16
+ Print active project info
17
+ LONGDESC
18
+ # Print active project info.
19
+ def active
20
+ say hash_to_yaml(project.active)
21
+ end
22
+
23
+ #
24
+ # info project private
25
+ #
26
+ desc 'private', 'Print private project info'
27
+ long_desc <<-LONGDESC.gsub("\n", "\x5")
28
+ Print private project info
29
+ LONGDESC
30
+ # Print private project info.
31
+ def private
32
+ say hash_to_yaml(project.private)
33
+ end
34
+
35
+ #
36
+ # info project main
37
+ #
38
+ desc 'main', 'Print main project info'
39
+ long_desc <<-LONGDESC.gsub("\n", "\x5")
40
+ Print main project info
41
+ LONGDESC
42
+ # Print main project info.
43
+ def main
44
+ say hash_to_yaml(project.main)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,80 @@
1
+ # takelage config module
2
+ module ConfigModule
3
+
4
+ # takelage config class.
5
+ class TakelageConfig
6
+
7
+ include LoggingModule
8
+ include SystemModule
9
+
10
+ attr_accessor :active, :default, :home, :project
11
+
12
+ def initialize
13
+ @active = Hash.new
14
+ @default = Hash.new
15
+ @home = Hash.new
16
+ @project = Hash.new
17
+ end
18
+ end
19
+
20
+ # Global singleton config
21
+ @@config = TakelageConfig.new
22
+
23
+ # Initialze config
24
+ def initialize_config
25
+ log.debug "takelage version: #{Takelage::VERSION}"
26
+ log.debug "Current working directory: #{Dir.pwd}"
27
+
28
+ # read default config file in lib
29
+ default_file = "#{File.dirname(__FILE__)}/../default.yml"
30
+ default_file = File.expand_path default_file
31
+ if File.exist? default_file
32
+ @@config.default = read_yaml_file(default_file) || Hash.new
33
+ @@config.default = @@config.default.sort.to_h
34
+ end
35
+
36
+ # read custom config file in $HOME
37
+ home_file = "#{Dir.home}/.takelage.yml"
38
+ if File.exist? home_file
39
+ @@config.home = read_yaml_file(home_file) || Hash.new
40
+ @@config.home = @@config.home.sort.to_h
41
+ end
42
+
43
+ # read custom config file next to Rakefile
44
+ file, path = Rake.application.find_rakefile_location
45
+ if path
46
+ project_file = "#{path}/takelage.yml"
47
+ @@config.project = read_yaml_file(project_file) || Hash.new
48
+ @@config.project = @@config.project.sort.to_h
49
+ end
50
+
51
+ # make a clone or else we'll change the original hash
52
+ default = @@config.default.clone
53
+ home = @@config.home.clone
54
+ project = @@config.project.clone
55
+
56
+ # merge default and home and project to active
57
+ # project wins against home wins against default
58
+ project_over_home = home.merge!(project)
59
+
60
+ @@config.active = default.merge!(project_over_home)
61
+ @@config.active = @@config.active.sort.to_h
62
+ end
63
+
64
+ # @return [Object] global singleton config
65
+ def config
66
+ @@config
67
+ end
68
+
69
+ # @return [Boolean] check if config keys are configured
70
+ def configured?(config_keys)
71
+ @configured = true
72
+ config_keys.each do |config_key|
73
+ unless @@config.active.key? config_key
74
+ log.error "Please configure \"#{config_key}\""
75
+ @configured = false
76
+ end
77
+ end
78
+ @configured
79
+ end
80
+ end
@@ -0,0 +1,30 @@
1
+ # takelage logging module
2
+ module LoggingModule
3
+
4
+ # Global singleton logger
5
+ @@log = Logger.new(STDOUT)
6
+
7
+ # Initialize logger with loglevel.
8
+ def initialize_logging(loglevel)
9
+
10
+ # logger: format
11
+ log.formatter = proc do |severity, datetime, progname, msg|
12
+ "[#{severity}] #{msg}\n"
13
+ end
14
+
15
+ # logger: level
16
+ if %w(FATAL ERROR WARN INFO DEBUG).include? loglevel
17
+ log.level = loglevel
18
+ log.debug "Using loglevel #{loglevel}"
19
+ else
20
+ log.level = Logger::INFO
21
+ log.error 'The parameter "loglevel" must be one of FATAL, ERROR, WARN, INFO, DEBUG'
22
+ log.info 'Using loglevel INFO'
23
+ end
24
+ end
25
+
26
+ # @return [Object] global singleton logger
27
+ def log
28
+ @@log
29
+ end
30
+ end
@@ -0,0 +1,57 @@
1
+ # takelage project module
2
+ module ProjectModule
3
+
4
+ # takelage config class.
5
+ class TakelageProject
6
+
7
+ include LoggingModule
8
+ include SystemModule
9
+ include ConfigModule
10
+
11
+ attr_accessor :active, :private, :main
12
+
13
+ def initialize
14
+ @active = Hash.new
15
+ @private = Hash.new
16
+ @main = Hash.new
17
+ end
18
+ end
19
+
20
+ # Global singleton config
21
+ @@project = TakelageProject.new
22
+
23
+ # Initialze project
24
+ def initialize_project
25
+
26
+ rakefile, path = Rake.application.find_rakefile_location
27
+
28
+ main_file = "#{path}/#{@@project.config.active['info_project_main']}"
29
+ private_file = "#{path}/#{@@project.config.active['info_project_private']}"
30
+
31
+ # read main project info
32
+ if File.exist? main_file
33
+ @@project.main = read_yaml_file(main_file) || Hash.new
34
+ @@project.main = @@project.main.sort.to_h
35
+ end
36
+
37
+ # read private project info
38
+ if File.exist? private_file
39
+ @@project.private = read_yaml_file(private_file) || Hash.new
40
+ @@project.private = @@project.private.sort.to_h
41
+ end
42
+
43
+ # make a clone or else we'll change the original hash
44
+ main = @@project.main.clone
45
+ private = @@project.private.clone
46
+
47
+ # merge main and private to active
48
+ # private wins against main
49
+ @@project.active = main.merge!(private)
50
+ @@project.active = @@project.active.sort.to_h
51
+ end
52
+
53
+ # @return [Object] global singleton project
54
+ def project
55
+ @@project
56
+ end
57
+ end
@@ -0,0 +1,13 @@
1
+ # Thor with subcommands that work correctly with help
2
+ class SubCommandBase < Thor
3
+
4
+ # Set the subcommand banner
5
+ def self.banner(command, namespace = nil, subcommand = false)
6
+ "#{basename} #{subcommand_prefix} #{command.usage}"
7
+ end
8
+
9
+ # Set the subcommand prefix
10
+ def self.subcommand_prefix
11
+ self.name.gsub(%r{.*::}, '').gsub(%r{^[A-Z]}) { |match| match[0].downcase }.gsub(%r{[A-Z]}) { |match| " #{match[0].downcase}" }
12
+ end
13
+ end