dotfiler 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.
@@ -0,0 +1,21 @@
1
+ module Dotfiler
2
+ class Copier
3
+ include Dotfiler::Import["fs"]
4
+
5
+ def call(source, target, options = {})
6
+ check_paths!(source, target.parent_dir)
7
+
8
+ fs.copy(source.to_s, target.to_s, options)
9
+
10
+ target.join(source.name)
11
+ end
12
+
13
+ private
14
+
15
+ def check_paths!(*paths)
16
+ paths.each do |path|
17
+ raise Error, "Path '#{path}' does not exist" unless path.exists?
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ module Dotfiler
2
+ class Dotfile
3
+ attr_reader :name, :link, :path
4
+
5
+ def initialize(name:, link:, path:)
6
+ @name = name
7
+
8
+ to_path = Dotfiler.resolve["to_path"]
9
+
10
+ @link = to_path.(link)
11
+ @path = to_path.(path)
12
+ end
13
+
14
+ def to_h
15
+ { name: name, link: link.to_s, path: path.to_s }
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,101 @@
1
+ require "forwardable"
2
+
3
+ require "dotfiler/dotfile"
4
+
5
+ module Dotfiler
6
+ class Dotfiles
7
+ extend Forwardable
8
+ include Enumerable
9
+
10
+ include Dotfiler::Import["fs", "config", "to_path"]
11
+
12
+ HOME_PLACEHOLDER = "%home%".freeze
13
+ DOTFILES_PLACEHOLDER = "%dotfiles%".freeze
14
+
15
+ def_delegators :config, :home_path, :relative_home_path
16
+
17
+ def initialize(args)
18
+ super(args)
19
+ load_data!
20
+ end
21
+
22
+ def find(name)
23
+ @dotfiles.find { |dotfile| dotfile.name == name }
24
+ end
25
+
26
+ def each(&block)
27
+ @dotfiles.each(&block)
28
+ end
29
+
30
+ def names
31
+ @dotfiles.map(&:name)
32
+ end
33
+
34
+ def name_taken?(name)
35
+ names.include?(name)
36
+ end
37
+ alias_method :exists?, :name_taken?
38
+
39
+ def add!(*args)
40
+ dotfile = Dotfile.new(*args)
41
+
42
+ File.open(config.dotfiles_file_path.to_s, "a") do |file|
43
+ file << dotfile_to_line(dotfile)
44
+ end
45
+
46
+ reload!
47
+ end
48
+
49
+ def remove!(name)
50
+ content = @dotfiles.each_with_object("") do |dotfile, result|
51
+ next if dotfile.name == name
52
+
53
+ result << dotfile_to_line(dotfile)
54
+ end
55
+
56
+ File.open(config.dotfiles_file_path.to_s, "w+") { |file| file << content }
57
+
58
+ reload!
59
+ end
60
+
61
+ def list
62
+ @dotfiles.map(&:to_h)
63
+ end
64
+
65
+ def load_data!
66
+ @dotfiles = if config.set?
67
+ parse(File.readlines(config.dotfiles_file_path.to_s))
68
+ else
69
+ {}
70
+ end
71
+ end
72
+
73
+ alias_method :reload!, :load_data!
74
+
75
+ private
76
+
77
+ def parse(lines)
78
+ lines.sort.each_with_object([]) do |line, result|
79
+ sanitized_line = line.gsub("\n", "")
80
+
81
+ next if sanitized_line.empty?
82
+
83
+ name, link, path = sanitized_line.split(" :: ")
84
+
85
+ link = link.sub(HOME_PLACEHOLDER, home_path.to_s)
86
+ path = path.sub(DOTFILES_PLACEHOLDER, config[:dotfiles])
87
+
88
+ result << Dotfile.new(name: name, link: link, path: path)
89
+ end
90
+ end
91
+
92
+ def dotfile_to_line(dotfile)
93
+ name, link, path = dotfile.to_h.values_at(:name, :link, :path)
94
+
95
+ link = link.sub(home_path.to_s, HOME_PLACEHOLDER)
96
+ path = path.sub(config[:dotfiles], DOTFILES_PLACEHOLDER)
97
+
98
+ [name, link, path].join(" :: ") + "\n"
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,43 @@
1
+ require "fileutils"
2
+
3
+ module Dotfiler
4
+ class FileSystem
5
+ attr_reader :utils
6
+
7
+ def initialize(utils: FileUtils)
8
+ @utils = utils
9
+ end
10
+
11
+ def move(source_path, destination_path, *options)
12
+ utils.move(source_path, destination_path, *options)
13
+ end
14
+
15
+ def copy(source_path, destination_path, *options)
16
+ utils.cp_r(source_path, destination_path, *options)
17
+ end
18
+
19
+ def symlink(source, destination, *options)
20
+ utils.symlink(source, destination, *options)
21
+ end
22
+
23
+ def remove(path)
24
+ utils.remove_entry_secure(path)
25
+ end
26
+
27
+ def create_file(name, content = "")
28
+ file = File.new(name, "w+")
29
+ file.write(content)
30
+ file.close
31
+ end
32
+
33
+ def create_dir(path, *options)
34
+ utils.mkdir_p(path, *options)
35
+ end
36
+
37
+ def execute(command, *command_options, **options)
38
+ full_command = ([command] + command_options).join(" ")
39
+
40
+ options[:capture] == true ? `#{full_command}` : system(full_command)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,21 @@
1
+ module Dotfiler
2
+ class Mover
3
+ include Dotfiler::Import["fs"]
4
+
5
+ def call(source, target, options = { secure: true })
6
+ check_paths!(source, target.parent_dir)
7
+
8
+ fs.move(source.to_s, target.to_s, options)
9
+
10
+ target.join(source.name)
11
+ end
12
+
13
+ private
14
+
15
+ def check_paths!(*paths)
16
+ paths.each do |path|
17
+ raise Error, "Path '#{path}' does not exist" unless path.exists?
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,77 @@
1
+ require "pathname"
2
+
3
+ module Dotfiler
4
+ class Path
5
+ include Comparable
6
+
7
+ def initialize(raw_path, expand: true)
8
+ @path = raw_path.nil? ? "" : raw_path
9
+ @full_path = Pathname.new(raw_path)
10
+ @full_path = @full_path.expand_path if expand == true
11
+ end
12
+
13
+ def <=>(other_path)
14
+ self.full <=> other_path.full
15
+ end
16
+
17
+ def full
18
+ @full_path
19
+ end
20
+
21
+ def to_s
22
+ @full_path.to_s
23
+ end
24
+
25
+ def join(*paths)
26
+ new_path = @full_path
27
+
28
+ paths.each { |path| new_path = new_path.join(path) }
29
+
30
+ self.class.new(new_path.to_s)
31
+ end
32
+
33
+ def contains?(other_path)
34
+ other_path = self.class.new(other_path) if other_path.is_a?(String)
35
+
36
+ children.any? { |child| child == other_path }
37
+ end
38
+
39
+ def within?(other_path)
40
+ other_path = self.class.new(other_path) if other_path.is_a?(String)
41
+
42
+ other_path.children.any? { |child| child == self }
43
+ end
44
+
45
+ def children
46
+ @full_path.children.map { |child| self.class.new(child.to_s) }
47
+ end
48
+
49
+ def parent_dir
50
+ self.class.new(@full_path.parent.to_s)
51
+ end
52
+
53
+ def real
54
+ @full_path.realpath
55
+ end
56
+
57
+ def name
58
+ @full_path.basename
59
+ end
60
+
61
+ def exists?
62
+ File.exists?(self.to_s)
63
+ end
64
+
65
+ def file?
66
+ !dir? && File.file?(@full_path)
67
+ end
68
+
69
+ def dir?
70
+ File.directory?(@full_path)
71
+ end
72
+
73
+ def symlink?
74
+ File.symlink?(@full_path)
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,15 @@
1
+ module Dotfiler
2
+ class Remover
3
+ include Dotfiler::Import["fs"]
4
+
5
+ def call(path, only_symlinks: true)
6
+ if only_symlinks && !path.symlink?
7
+ raise(Error, "Cannot remove '#{path}' since it is not a symbolic link")
8
+ end
9
+
10
+ fs.remove(path.to_s)
11
+
12
+ path
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,60 @@
1
+ module Dotfiler
2
+ class Shell
3
+ TERMINATION_CODES = {
4
+ clean: 0,
5
+ info: 0,
6
+ error: 1
7
+ }.freeze
8
+
9
+ def initialize(output: $stdout, input: $stdin, error: $stderr)
10
+ @output = output
11
+ @error = error
12
+ @input = input
13
+ end
14
+
15
+ def print(content, type = nil)
16
+ case type
17
+ when :error
18
+ error.puts("ERROR: #{content}")
19
+ when :info
20
+ output.puts("# #{content}")
21
+ else
22
+ output.puts("#{content}")
23
+ end
24
+ end
25
+
26
+ def prompt(text, available_answers = {})
27
+ question = text
28
+
29
+ if available_answers.any?
30
+ question += "\n\n"
31
+ available_answers.each { |key, details| question += " #{key}) #{details[:desc]}\n" }
32
+ else
33
+ available_answers = default_prompt_answer
34
+ question += " [y/N] "
35
+ end
36
+
37
+ print(question)
38
+
39
+ answer_key = input.gets.strip.downcase
40
+
41
+ return :other unless available_answers.key?(answer_key)
42
+
43
+ available_answers[answer_key].fetch(:value)
44
+ end
45
+
46
+ def terminate(type, message: nil)
47
+ print(message, type) unless message.nil?
48
+ exit(TERMINATION_CODES[type])
49
+ end
50
+
51
+ private
52
+
53
+ attr_reader :output, :error, :input
54
+
55
+ def default_prompt_answer
56
+ { "y" => { value: :yes }, "n" => { value: :no } }
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,23 @@
1
+ module Dotfiler
2
+ class Symlinker
3
+ include Dotfiler::Import["fs"]
4
+
5
+ def call(source, link_path, options = {})
6
+ check_paths!(source, link_path.parent_dir)
7
+
8
+ options[:force] = true if link_path.symlink?
9
+
10
+ fs.symlink(source.to_s, link_path.to_s, options)
11
+
12
+ link_path
13
+ end
14
+
15
+ private
16
+
17
+ def check_paths!(*paths)
18
+ paths.each do |path|
19
+ raise Error, "Path '#{path}' does not exist" unless path.exists?
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ module Dotfiler
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,156 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dotfiler
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Aleksandar Radunovic
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-06-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dry-container
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.6.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.6.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: dry-auto_inject
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 0.4.6
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 0.4.6
41
+ - !ruby/object:Gem::Dependency
42
+ name: hanami-cli
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 0.2.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 0.2.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.16'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.16'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.0'
97
+ description: CLI gem for managing dotfiles
98
+ email:
99
+ - aleksandar@radunovic.io
100
+ executables:
101
+ - dotfiler
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - LICENSE.txt
106
+ - README.md
107
+ - dotfiler.gemspec
108
+ - exe/dotfiler
109
+ - lib/dotfiler.rb
110
+ - lib/dotfiler/cli/commands.rb
111
+ - lib/dotfiler/cli/commands/add.rb
112
+ - lib/dotfiler/cli/commands/backup.rb
113
+ - lib/dotfiler/cli/commands/command.rb
114
+ - lib/dotfiler/cli/commands/edit.rb
115
+ - lib/dotfiler/cli/commands/init.rb
116
+ - lib/dotfiler/cli/commands/install.rb
117
+ - lib/dotfiler/cli/commands/list.rb
118
+ - lib/dotfiler/cli/commands/remove.rb
119
+ - lib/dotfiler/cli/commands/version.rb
120
+ - lib/dotfiler/config.rb
121
+ - lib/dotfiler/container.rb
122
+ - lib/dotfiler/copier.rb
123
+ - lib/dotfiler/dotfile.rb
124
+ - lib/dotfiler/dotfiles.rb
125
+ - lib/dotfiler/file_system.rb
126
+ - lib/dotfiler/mover.rb
127
+ - lib/dotfiler/path.rb
128
+ - lib/dotfiler/remover.rb
129
+ - lib/dotfiler/shell.rb
130
+ - lib/dotfiler/symlinker.rb
131
+ - lib/dotfiler/version.rb
132
+ homepage: https://github.com/aradunovic/dotfiler
133
+ licenses:
134
+ - MIT
135
+ metadata: {}
136
+ post_install_message:
137
+ rdoc_options: []
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '2.3'
145
+ required_rubygems_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ requirements: []
151
+ rubyforge_project:
152
+ rubygems_version: 2.6.8
153
+ signing_key:
154
+ specification_version: 4
155
+ summary: CLI gem for managing dotfiles
156
+ test_files: []