takelage 0.1.0

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