cmt 0.0.1

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: f22c54538014ff0c05f465f326f35db0237f25498df57aebdc36d3ebf574fbef
4
+ data.tar.gz: b26bf08d47349d909f22565a2fdcefb5c3194e32ff89c62d0114b1e5bb77ee0d
5
+ SHA512:
6
+ metadata.gz: 4c89b40790bffff57a425db4219f28022893baa814223a7a8cd480b1e0edfa92abfae41dc8e280154fa1c372dcbe39243128bb125055c092ba96959f63ccdcc0
7
+ data.tar.gz: 4f157269c19116c1fd02962745e0e4ff458d762520840a67049686cbab995463ebc8915faa3c8b728c414dcf0ffddbc49d5f558213a4df7f50ec1d32472f74b8
data/bin/cmt ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/cmt.rb'
data/lib/cmt.rb ADDED
@@ -0,0 +1,29 @@
1
+ require "thor"
2
+ require 'pathname'
3
+ require 'fileutils'
4
+ require 'json'
5
+ require "logger"
6
+
7
+ require_relative './config/git_config'
8
+ require_relative './dotfiles/dotfiles_cli'
9
+ require_relative './pkg/pkg'
10
+
11
+ $logger = Logger.new(STDOUT)
12
+ $logger.formatter = proc do |severity, datetime, progname, msg|
13
+ date_format = datetime.strftime("%Y-%m-%d %H:%M:%S")
14
+ JSON.dump(date: "#{date_format}", severity:"#{severity.ljust(5)}", pid:"##{Process.pid}", message: msg) + "\n"
15
+ end
16
+
17
+ class Cmt < Thor
18
+ desc "config SUBCOMMAND ...ARGS", "manage set of tracked repositories"
19
+ subcommand "config", GitConfig
20
+
21
+ desc "dotfiles SUBCOMMAND ...ARGS", "manage set of tracked repositories"
22
+ subcommand "dotfiles", DotfilesCli
23
+
24
+ desc "pkg SUBCOMMAND ...ARGS", "manage set of tracked repositories"
25
+ subcommand "pkg", Pkg
26
+ end
27
+
28
+ Cmt.start(ARGV)
29
+
@@ -0,0 +1,20 @@
1
+ require "thor"
2
+ require 'fileutils'
3
+
4
+ $CONFIG_DIR = File.join(Dir.home, '.config', 'cmt')
5
+
6
+ class Config
7
+ def self.get_config_json(file, default_config)
8
+ FileUtils.mkdir_p File.dirname(file)
9
+ if !File.exists?(file)
10
+ File.open(file, 'w') {|f| JSON.dump(default_config, f)}
11
+ end
12
+
13
+ config = JSON.load_file(file)
14
+ return default_config.merge(config)
15
+ end
16
+
17
+ def self.write_config_file(file, config)
18
+ File.open(file, 'w') {|f| f.write(JSON.pretty_generate(config, {indent: ' '}))}
19
+ end
20
+ end
@@ -0,0 +1,63 @@
1
+ require "thor"
2
+
3
+ require_relative './config'
4
+
5
+ class GitConfig < Thor
6
+ desc "init", "Init"
7
+ option :force, :type => :boolean, :default => false
8
+ def init(repo)
9
+ force = options['force']
10
+
11
+ if File.exists? $CONFIG_DIR
12
+ if force
13
+ FileUtils.rm_rf($CONFIG_DIR)
14
+ else
15
+ $logger.error("Config already exists at '#{$CONFIG_DIR}'")
16
+ abort("Config already exists at '#{$CONFIG_DIR}'")
17
+ end
18
+ end
19
+
20
+ `git clone #{repo} #{$CONFIG_DIR}`
21
+ end
22
+
23
+ desc "update", "update"
24
+ option :message, :default => "Update config"
25
+ def update()
26
+ message = options['message']
27
+ Dir.chdir($CONFIG_DIR) do
28
+ changes = `git status --porcelain=v1`
29
+ num_changes = changes.split(' ').length()
30
+
31
+ if num_changes == 0
32
+ $logger.error("No changes to commit in '#{$CONFIG_DIR}'")
33
+ abort("No changes to commit in '#{$CONFIG_DIR}'")
34
+ else
35
+ $logger.info("Commit changes")
36
+ system 'git', 'add', '.'
37
+ system 'git', 'commit', '-m', "'#{message}'"
38
+ system 'git', 'push'
39
+ end
40
+ end
41
+ end
42
+
43
+ desc "status", "Show git status in '#{$CONFIG_DIR}'"
44
+ def status(*args)
45
+ Dir.chdir($CONFIG_DIR) do
46
+ system 'git', 'status', *args
47
+ end
48
+ end
49
+
50
+ desc "pull", "Pull newest changes in '#{$CONFIG_DIR}'"
51
+ def status(*args)
52
+ Dir.chdir($CONFIG_DIR) do
53
+ system 'git', 'pull', *args
54
+ end
55
+ end
56
+
57
+ desc "exec", "Execute any git command in '#{$CONFIG_DIR}'"
58
+ def exec(*args)
59
+ Dir.chdir($CONFIG_DIR) do
60
+ system 'git', *args
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,142 @@
1
+ require "thor"
2
+ require 'pathname'
3
+ require 'fileutils'
4
+ require 'json'
5
+ require "logger"
6
+
7
+ require_relative '../config/config'
8
+ require_relative '../util/file_util'
9
+
10
+ class Dotfiles
11
+ CONFIG_SUB_DIR = 'dotfiles'
12
+ ROOT_PATH = File.join($CONFIG_DIR, CONFIG_SUB_DIR)
13
+ CONFIG_FILE = File.join(ROOT_PATH, 'dotfiles.json')
14
+ FILES_PATH = File.join(ROOT_PATH, 'files')
15
+ FOLDERS_PATH = File.join(ROOT_PATH, 'folders')
16
+
17
+ DEFAULT_CONFIG = {
18
+ "files" => [],
19
+ "folders" => [],
20
+ }
21
+
22
+ def add(file)
23
+
24
+ abs_file = File.absolute_path(file.dup)
25
+
26
+ config = Config.get_config_json(CONFIG_FILE, DEFAULT_CONFIG)
27
+ list = get_sync_list(config, abs_file)
28
+
29
+ parsed_file = FileUtil.to_local_file(abs_file)
30
+
31
+ local_path = get_local_path(file)
32
+
33
+ if !list.include? parsed_file
34
+ dir = File.dirname(parsed_file)
35
+
36
+ puts File.join(local_path, dir)
37
+
38
+ FileUtils.mkdir_p File.join(local_path, dir)
39
+
40
+ if File.file?(abs_file)
41
+ FileUtils.cp(abs_file, File.join(local_path, parsed_file))
42
+ else
43
+ FileUtils.cp_r(abs_file, File.join(local_path, parsed_file))
44
+ end
45
+
46
+ if File.exists? File.join(local_path, parsed_file)
47
+ list.append(parsed_file)
48
+ end
49
+ end
50
+
51
+ Config.write_config_file(CONFIG_FILE, config)
52
+
53
+ $logger.info("Added '#{parsed_file}'")
54
+ end
55
+
56
+ def remove(file)
57
+ local_file = FileUtil.to_local_file(file)
58
+ local_file_abs = File.join(get_local_path(file), local_file)
59
+
60
+ config = Config.get_config_json(CONFIG_FILE, DEFAULT_CONFIG)
61
+ list = get_sync_list(config, local_file_abs)
62
+
63
+
64
+ if list.include? local_file
65
+ puts(local_file_abs)
66
+ FileUtils.rm_rf(local_file_abs)
67
+
68
+ list.delete(local_file)
69
+ end
70
+
71
+ Config.write_config_file(CONFIG_FILE, config)
72
+
73
+
74
+ $logger.info("Removed '#{local_file}'")
75
+ end
76
+
77
+ def apply()
78
+ $logger.info('Start apply')
79
+
80
+ config = Config.get_config_json(CONFIG_FILE, DEFAULT_CONFIG)
81
+ files = config['files']
82
+
83
+ files.each { |file|
84
+ dest_file = FileUtil.to_system_file(file)
85
+
86
+ abs_file = File.join(FILES_PATH, file)
87
+ $logger.debug("Copy #{abs_file} to #{dest_file}")
88
+
89
+ FileUtils.cp_r(abs_file, dest_file, remove_destination: true)
90
+ }
91
+
92
+ folders = config['folders']
93
+
94
+ folders.each { |folder|
95
+ dest_file = File.dirname(FileUtil.to_system_file(folder))
96
+
97
+ abs_file = File.join(FOLDERS_PATH, folder)
98
+ $logger.debug("Copy #{abs_file} to #{dest_file}")
99
+
100
+ FileUtils.cp_r(abs_file, dest_file, remove_destination: true)
101
+ }
102
+
103
+ $logger.info('Finished apply')
104
+ end
105
+
106
+ def sync()
107
+ $logger.info('Start sync')
108
+
109
+ config = Config.get_config_json(CONFIG_FILE, DEFAULT_CONFIG)
110
+ files = config['files']
111
+
112
+ files.each { |file|
113
+ dest_file = FileUtil.to_system_file(file)
114
+
115
+ abs_file = File.join(FILES_PATH, file)
116
+ $logger.debug("Copy #{dest_file} to #{abs_file}")
117
+
118
+ FileUtils.cp_r(dest_file, abs_file, remove_destination: true)
119
+ }
120
+
121
+ folders = config['folders']
122
+
123
+ folders.each { |folder|
124
+ dest_file = FileUtil.to_system_file(folder)
125
+
126
+ abs_file = File.dirname(File.join(FOLDERS_PATH, folder))
127
+ $logger.debug("Copy #{dest_file} to #{abs_file}")
128
+
129
+ FileUtils.cp_r(dest_file, abs_file, remove_destination: true)
130
+ }
131
+
132
+ $logger.info('Finished sync')
133
+ end
134
+
135
+ def get_local_path(file)
136
+ return File.file?(file) ? FILES_PATH : FOLDERS_PATH
137
+ end
138
+
139
+ def get_sync_list(config, file)
140
+ return File.file?(file) ? config['files'] : config['folders']
141
+ end
142
+ end
@@ -0,0 +1,30 @@
1
+ require_relative './dotfiles'
2
+
3
+ class DotfilesCli < Thor
4
+ DOTFILES = Dotfiles.new
5
+
6
+ desc "init", "Download objects and refs from another repository"
7
+ def init()
8
+ DOTFILES.init()
9
+ end
10
+
11
+ desc "add <file>", "Download objects and refs from another repository"
12
+ def add(file)
13
+ DOTFILES.add(file)
14
+ end
15
+
16
+ desc "remove <file>", "Download objects and refs from another repository"
17
+ def remove(file)
18
+ DOTFILES.remove(file)
19
+ end
20
+
21
+ desc "apply", "Copies all dotfiles defined in the user config to the system"
22
+ def apply()
23
+ DOTFILES.apply()
24
+ end
25
+
26
+ desc "sync", "Updates all files defined in the user config from the system to the config dir"
27
+ def sync()
28
+ DOTFILES.sync()
29
+ end
30
+ end
data/lib/pkg/pkg.rb ADDED
@@ -0,0 +1,105 @@
1
+ require 'thor'
2
+
3
+ require_relative './pkgm/pacman'
4
+ require_relative './pkgm/yay'
5
+ require_relative './pkgm/pip'
6
+ require_relative './pkgm/snap'
7
+ require_relative './pkgm/winget'
8
+ require_relative './pkg_config'
9
+
10
+ class Pkg < Thor
11
+ SYSTEM_PACKAGE_MANGER = {
12
+ 'manjaro' => Pacman,
13
+ 'windows' => Winget
14
+ }
15
+ OTHER_PACKAGE_MANGER = {
16
+ 'pip' => Pip,
17
+ 'snap' => Snap,
18
+ 'yay' => Yay
19
+ }
20
+ RELEASE_FILE = '/etc/os-release'
21
+
22
+
23
+ desc 'install_all', 'Install'
24
+ option 'pkgm', default: 'system'
25
+ def install_all(*args)
26
+ manager = get_package_manager(options['pkgm'])
27
+
28
+ config_file = PkgConfig.get_config_file(manager)
29
+ config = Config.get_config_json(config_file, PkgConfig.get_default_config())
30
+
31
+ packages = config['packages']
32
+
33
+ installed = manager.install_all(packages, *args)
34
+ end
35
+
36
+ desc 'install', 'Install'
37
+ option 'pkgm', default: 'system'
38
+ def install(package, *args)
39
+ manager = get_package_manager(options['pkgm'])
40
+
41
+ installed = manager.install(package, *args)
42
+
43
+ if installed
44
+ PkgConfig.add(manager, package)
45
+ end
46
+ end
47
+
48
+ desc 'update', 'update'
49
+ option 'pkgm', default: 'system'
50
+ def update(*args)
51
+ manager = get_package_manager(options['pkgm'])
52
+
53
+ installed = manager.update(*args)
54
+ end
55
+
56
+
57
+ desc 'uninstall', 'uninstall'
58
+ option 'pkgm', default: 'system'
59
+ def uninstall(package, *args)
60
+ manager = get_package_manager(options['pkgm'])
61
+
62
+ uninstalled = manager.uninstall(package, *args)
63
+
64
+ if uninstalled
65
+ PkgConfig.remove(manager, package)
66
+ end
67
+ end
68
+
69
+ no_commands do
70
+ def get_package_manager(pkgm)
71
+ manager = nil
72
+
73
+ if pkgm == 'system'
74
+
75
+ if Gem.win_platform?
76
+ manager = SYSTEM_PACKAGE_MANGER['windows']
77
+ else
78
+ r = { 'distro' => nil}
79
+ if !File.exists?(RELEASE_FILE)
80
+ $logger.error("'#{RELEASE_FILE}' does not exist")
81
+ abort("'#{RELEASE_FILE}' does not exist")
82
+ end
83
+
84
+ File.open(RELEASE_FILE, 'r').read.each_line do |line|
85
+ r = { 'distro' => $1 } if line =~ /^ID=(.*)/
86
+ end
87
+
88
+ manager = SYSTEM_PACKAGE_MANGER[r['distro']]
89
+ end
90
+ else
91
+ manager = OTHER_PACKAGE_MANGER[pkgm]
92
+ end
93
+
94
+ if manager == nil
95
+ $logger.error("'#{pkgm}' is not supported")
96
+ abort("'#{pkgm}' is not supported")
97
+ end
98
+
99
+ $logger.info("Using package manager '#{manager}'")
100
+
101
+ return manager
102
+ end
103
+ end
104
+
105
+ end
@@ -0,0 +1,49 @@
1
+ require 'json'
2
+
3
+ require_relative '../config/config'
4
+
5
+ class PkgConfig
6
+ CONFIG_SUB_DIR = 'pkg'
7
+ ROOT_PATH = File.join($CONFIG_DIR, CONFIG_SUB_DIR)
8
+ DEFAULT_CONFIG = {
9
+ 'repos' => [],
10
+ 'packages' => []
11
+ }
12
+
13
+ def self.add(pkgm, package)
14
+ config_file = PkgConfig.get_config_file(pkgm)
15
+
16
+ config = Config.get_config_json(config_file, DEFAULT_CONFIG)
17
+
18
+ packages = config['packages']
19
+
20
+ if !packages.include? package
21
+ packages.append package
22
+ end
23
+
24
+ Config.write_config_file(config_file, config)
25
+ end
26
+
27
+ def self.remove(pkgm, package)
28
+ config_file = PkgConfig.get_config_file(pkgm)
29
+
30
+ config = Config.get_config_json(config_file, DEFAULT_CONFIG)
31
+
32
+ packages = config['packages']
33
+
34
+ if packages.include? package
35
+ packages.delete package
36
+ end
37
+
38
+ Config.write_config_file(config_file, config)
39
+ end
40
+
41
+ def self.get_config_file(pkgm)
42
+ pkgm = "#{pkgm}".downcase
43
+ return File.join(ROOT_PATH, "#{pkgm}.json")
44
+ end
45
+
46
+ def self.get_default_config()
47
+ return DEFAULT_CONFIG
48
+ end
49
+ end
@@ -0,0 +1,18 @@
1
+
2
+ class Pacman
3
+ def self.install_all(packages, *args)
4
+ return system 'sudo', 'pacman', '-Sy', *args, *packages
5
+ end
6
+
7
+ def self.install(package, *args)
8
+ return system 'sudo', 'pacman', '-Sy', *args, package
9
+ end
10
+
11
+ def self.update(*args)
12
+ return system 'sudo', 'pacman', '-Syu', *args
13
+ end
14
+
15
+ def self.uninstall(package, *args)
16
+ return system 'sudo', 'pacman', '-R', *args, package
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+
2
+ class Pip
3
+ def self.install_all(packages, *args)
4
+ return system 'python3', '-m', 'pip', 'install', *args, *packages
5
+ end
6
+
7
+ def self.install(package, *args)
8
+ return system 'python3', '-m', 'pip', 'install', *args, package
9
+ end
10
+
11
+ def self.update(*args)
12
+ $logger.error("Update is not supported for pip")
13
+ abort("Update is not supported for pip")
14
+ end
15
+
16
+ def self.uninstall(package, *args)
17
+ return system 'python3', '-m', 'pip', 'uninstall', *args, package
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+
2
+ class Snap
3
+ def self.install_all(packages, *args)
4
+ return system 'snap', 'install', *args, *packages
5
+ end
6
+
7
+ def self.install(package, *args)
8
+ return system 'snap', 'install', *args, package
9
+ end
10
+
11
+ def self.update(*args)
12
+ $logger.error("Update is not supported for snap")
13
+ abort("Update is not supported for snap")
14
+ end
15
+
16
+ def self.uninstall(package, *args)
17
+ return system 'snap', 'remove', *args, package
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+
2
+ class Winget
3
+ def self.install_all(packages, *args)
4
+ packages.each { |package|
5
+ Winget.install(package, *args)
6
+ }
7
+ end
8
+
9
+ def self.install(package, *args)
10
+ return system 'winget', 'install', *args, "--id=#{package}", "-e"
11
+ end
12
+
13
+ def self.update(*args)
14
+ return system 'winget', 'upgrade'
15
+
16
+ end
17
+
18
+ def self.uninstall(package, *args)
19
+ return system 'winget', 'uninstall', *args, "--id=#{package}", "-e"
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+
2
+ class Yay
3
+ def self.install_all(packages, *args)
4
+ return system 'yay', '-Sy', *args, *packages
5
+ end
6
+
7
+ def self.install(package, *args)
8
+ return system 'yay', '-Sy', *args, package
9
+ end
10
+
11
+ def self.update(*args)
12
+ return system 'yay', '-Syu', *args
13
+ end
14
+
15
+ def self.uninstall(package, *args)
16
+ return system 'yay', '-R', *args, package
17
+ end
18
+ end
@@ -0,0 +1,27 @@
1
+ class FileUtil
2
+ USER_HOME = 'user-home'
3
+
4
+ def self.to_local_file(file)
5
+ local_file = File.absolute_path(file.dup)
6
+
7
+ if local_file.include? Dir.home
8
+ local_file[Dir.home] = USER_HOME
9
+ elsif local_file.start_with?("/")
10
+ local_file = local_file[1..-1]
11
+ end
12
+
13
+ return local_file
14
+ end
15
+
16
+ def self.to_system_file(file)
17
+ system_file = file.dup
18
+
19
+ if system_file.start_with? USER_HOME
20
+ system_file[USER_HOME] = Dir.home
21
+ else
22
+ system_file = "/#{system_file}"
23
+ end
24
+
25
+ return system_file
26
+ end
27
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cmt
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Simon Schuster
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-07-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.2'
27
+ description: "[C]onfiguration [M]anagment [T]ool"
28
+ email: simon.schuster@outlook.com
29
+ executables:
30
+ - cmt
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - bin/cmt
35
+ - lib/cmt.rb
36
+ - lib/config/config.rb
37
+ - lib/config/git_config.rb
38
+ - lib/dotfiles/dotfiles.rb
39
+ - lib/dotfiles/dotfiles_cli.rb
40
+ - lib/pkg/pkg.rb
41
+ - lib/pkg/pkg_config.rb
42
+ - lib/pkg/pkgm/pacman.rb
43
+ - lib/pkg/pkgm/pip.rb
44
+ - lib/pkg/pkgm/snap.rb
45
+ - lib/pkg/pkgm/winget.rb
46
+ - lib/pkg/pkgm/yay.rb
47
+ - lib/util/file_util.rb
48
+ homepage: https://github.com/kpurdon/rumr
49
+ licenses:
50
+ - GPLv3
51
+ metadata: {}
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubygems_version: 3.3.26
68
+ signing_key:
69
+ specification_version: 4
70
+ summary: configuration managment tool
71
+ test_files: []