cmt 0.0.1

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 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: []