dotfiler 0.1.0

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
+ SHA1:
3
+ metadata.gz: 448eb71751e98c9d2495abeafd02e88eddcd1d06
4
+ data.tar.gz: cfc6c4ee8ba52e8608fd6b30963fe4152fecceb1
5
+ SHA512:
6
+ metadata.gz: e10921ffd3f69aa7a9f8142e899ad8f6703197ff30c43dc0708e496bc6b1947bdf204da927721a54cc720b4638a972f8d0e04044041df40616922678bb8514a1
7
+ data.tar.gz: 9bf9de86945ec7329618fafcaae297ad5ea22dcdc81f28766a3d390c49a6151cfcc97ccb66757bd0cfb202db19968be4fc3afa8f23b2a2c3bd9cd7b4da7f825a
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Aleksandar Radunovic
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,302 @@
1
+ # Dotfiler
2
+
3
+ Dotfiler is a CLI gem for managing dotfiles.
4
+
5
+ ## Contents
6
+
7
+ * [**Installation**](#installation)
8
+ * [**Usage**](#usage)
9
+ * [Initial setup](#initial-setup)
10
+ * [Creating new dotfile](#creating-new-dotfile)
11
+ * [Listing managed dotfiles](#listing-managed-dotfiles)
12
+ * [Removing existing dotfile](#removing-existing-dotfile)
13
+ * [Editing dotfiles](#editing-dotfiles)
14
+ * [Installing dotfiles](#installing-dotfiles)
15
+ * [Backing up existing dotfiles](#backing-up-existing-dotfiles)
16
+ * [Help](#help)
17
+ * [Checking the version](#checking-the-version)
18
+ * [**Code of Conduct**](#code-of-conduct)
19
+ * [**License**](#license)
20
+
21
+ ## Installation
22
+
23
+ Make sure you have Ruby >= 2.3 installed.
24
+
25
+ To install Dotfiler, run:
26
+
27
+ $ gem install dotfiler
28
+
29
+ Dotfiler works Linux and MacOS only.
30
+
31
+ ## Usage
32
+
33
+ ### Initial setup
34
+
35
+ $ dotfiler init --help
36
+ Command:
37
+ dotfiler init
38
+
39
+ Usage:
40
+ dotfiler init PATH
41
+
42
+ Description:
43
+ Create config file. Create dotfiles directory at specified path. Initialize git repo.
44
+
45
+ Arguments:
46
+ PATH # REQUIRED Path where the Dotfiles directory will be created
47
+
48
+ Options:
49
+ --[no-]git # Initialize git repo for dotfiles directory, default: true
50
+ --help, -h # Print this help
51
+
52
+ Example:
53
+
54
+ $ dotfiler init ~/code/my_dotfiles
55
+ # Creating config file (/Users/aleksandar/.dotfiler)...
56
+ # Creating dotfiles directory (/Users/aleksandar/code/my_dotfiles)...
57
+ # Creating dotfiles file (/Users/aleksandar/code/my_dotfiles/.dotfiles)...
58
+ # Initialized empty Git repository in /Users/aleksandar/code/my_dotfiles/.git/
59
+
60
+ As you can see, `init` command does 4 things:
61
+
62
+ 1. Creates Dotfiler configuration (YAML) file (`.dotfiler`) in your home directory.
63
+ 2. Creates a directory where dotfiles will be kept, at specified location.
64
+ 3. Creates a file (`.dotfiles`) which holds necessary info about each dotfile
65
+ you add. The file is created in dotfiles directory.
66
+ 4. Initializes Git repo in dotfiles directory. You can skip this by passing
67
+ `--no-git` option.
68
+
69
+ **NOTE:** If any of the files/dirs already exist, you will be prompted to either overwrite or
70
+ keep them.
71
+
72
+ ### Adding new dotfile
73
+
74
+ To add a file/directory to your dotfiles, use `add` command.
75
+
76
+ $ dotfiler add --help
77
+ Command:
78
+ dotfiler add
79
+
80
+ Usage:
81
+ dotfiler add PATH
82
+
83
+ Description:
84
+ Add specified file/directory to dotfiles
85
+
86
+ Arguments:
87
+ PATH # REQUIRED File/directory path
88
+
89
+ Options:
90
+ --name=VALUE, -n VALUE # Name which will be assigned to dotfile
91
+ --target=VALUE, -t VALUE # Path to where the symlink will be created
92
+ --help, -h # Print this help
93
+
94
+ Example:
95
+
96
+ $ dotfiler add ~/.zshrc
97
+ # Moving /Users/aleksandar/.zshrc to dotfiles directory (/Users/aleksandar/code/my_dotfiles)...
98
+ # Symlinking dotfile (/Users/aleksandar/code/my_dotfiles/.zshrc) to /Users/aleksandar/.zshrc...
99
+ # Adding zshrc to dotfiles...
100
+
101
+ `add` command does 3 things:
102
+
103
+ 1. Moves specified file/directory to dotfiles directory.
104
+ 2. Creates a symbolic link in file's/dir's original location which points to
105
+ it's new location in dotfiles directory. If you want to change the symlink's
106
+ location, use `--target` option.
107
+ 3. Updates `.dotfiles` file.
108
+
109
+ Dotfile consists of **name**, **path** and **link**:
110
+
111
+ - **Name** serves as a unique identifier for a dotfile. By default, name of the
112
+ file will be used as a dotfile name (without starting dots/underscores). You can
113
+ set a custom name for a dotfile with `--name` option.
114
+ Name is used for specifying which dotfile to remove or edit.
115
+ - **Path** is an actual dotfile path (in dotfiles directory).
116
+ - **Link** is a symbolic link path
117
+
118
+ Aliases: `a`
119
+
120
+ ### Listing managed dotfiles
121
+
122
+ To get a list of all currently managed dotfiles, use `list` command.
123
+
124
+ $ dotfiler list --help
125
+ Command:
126
+ dotfiler list
127
+
128
+ Usage:
129
+ dotfiler list [NAMES]
130
+
131
+ Description:
132
+ List all managed dotfiles
133
+
134
+ Arguments:
135
+ NAMES # List only names of managed dotfiles
136
+
137
+ Options:
138
+ --help, -h # Print this help
139
+
140
+ Example:
141
+
142
+ $ dotfiler list
143
+ zsh
144
+ - LINK: /Users/aleksandar/.zshrc
145
+ - PATH: /Users/aleksandar/code/my_dotfiles/.zshrc
146
+
147
+
148
+ # to list dotfiles names only
149
+
150
+ $ dotfiler list names
151
+
152
+
153
+ Aliases: `ls`
154
+
155
+ ### Removing existing dotfile
156
+
157
+ To remove a dotfile, use `remove` command.
158
+
159
+ $ dotfiler remove --help
160
+ Command:
161
+ dotfiler remove
162
+
163
+ Usage:
164
+ dotfiler remove NAME
165
+
166
+ Description:
167
+ Remove specified dotfile from dotfiles and restore it to it's original location
168
+
169
+ Arguments:
170
+ NAME # REQUIRED Name of the dotfile that should be removed
171
+
172
+ Options:
173
+ --help, -h # Print this help
174
+
175
+ Example:
176
+
177
+ $ dotfiler remove zshrc
178
+ # Removing symlink (/Users/aleksandar/.zshrc)...
179
+ # Restoring dotfile (/Users/aleksandar/code/my_dotfiles/.zshrc) to its original location (/Users/aleksandar/.zshrc)...
180
+ # Removing 'zsh' from dotfiles...
181
+
182
+ `remove` command does 3 things:
183
+
184
+ 1. Removes dotfile symbolic link.
185
+ 2. Moves the file/dir from dotfiles directory to a location of previously removed symlink.
186
+ 3. Updates `.dotfiles` file.
187
+
188
+ Aliases: `rm`
189
+
190
+ ### Editing dotfiles
191
+
192
+ To edit a dotfile, use `edit` command.
193
+
194
+ $ dotfiler edit --help
195
+ Command:
196
+ dotfiler edit
197
+
198
+ Usage:
199
+ dotfiler edit NAME
200
+
201
+ Description:
202
+ Edit specified dotfile. By default, dotfile will be opened in $EDITOR
203
+
204
+ Arguments:
205
+ NAME # REQUIRED Name of the dotfile you want to edit
206
+
207
+ Options:
208
+ --with=VALUE, w VALUE # Editor in which to open the specified dotfile
209
+ --help, -h # Print this help
210
+
211
+ $ dotfiler edit zshrc
212
+ #### This will open ~/code/my_dotfiles/.zshrc file in $EDITOR ####
213
+
214
+ You can specify a different editor by using `--with` option:
215
+
216
+ $ dotfiler edit zshrc --with=vim
217
+
218
+ Aliases: `e`
219
+
220
+ ### Installing dotfiles
221
+
222
+ To install all dotfiles, use `install` command.
223
+
224
+ $ dotfiler install --help
225
+ Command:
226
+ dotfiler install
227
+
228
+ Usage:
229
+ dotfiler install PATH
230
+
231
+ Description:
232
+ Install dotfiles from existing dotfiles directory
233
+
234
+ Arguments:
235
+ PATH # REQUIRED Path to existing dotfiles directory
236
+
237
+ Options:
238
+ --help, -h # Print this help
239
+
240
+ Example:
241
+
242
+ $ dotfiler install ~/code/my_dotfiles
243
+
244
+ `install` command will create symlinks of files located in specified dotfiles directory,
245
+ by looking at `.dotfiles` file. If symlink's location is already taken, it will:
246
+
247
+ - Overwrite the file if it is **a symbolic link**
248
+ - Backup file/dir if it is **not a symbolic link**
249
+
250
+ Backed up files will be placed in `dotfiler_installation_backup_{{CURRENT_TIMESTAMP}}`
251
+ directory, located in your home directory,
252
+
253
+ ### Backing up existing dotfiles
254
+
255
+ To back up existing dotfiles, use `backup` command.
256
+
257
+ $ dotfiler backup --help
258
+ Command:
259
+ dotfiler backup
260
+
261
+ Usage:
262
+ dotfiler backup
263
+
264
+ Description:
265
+ Backup existing dotfiles directory
266
+
267
+ Options:
268
+ --help, -h # Print this help
269
+
270
+ Example:
271
+
272
+ $ dotfiler backup
273
+ # Backing up dotfiles directory (/Users/aleksandar/code/my_dotfiles) to Users/aleksandar/.dotfiler_backup_2018-29-05-10-00-00
274
+
275
+ ### Help
276
+
277
+ To see what commands are available, use `help` command:
278
+
279
+ $ dotfiler help
280
+
281
+ Aliases: `-h, --help`
282
+
283
+ ### Checking the version
284
+
285
+ To check Dotfiler version, run:
286
+
287
+ $ dotfiler version
288
+
289
+ Aliases: `v, -v, --version`
290
+
291
+ ## Contributing
292
+
293
+ Bug reports and pull requests are welcome on GitHub at https://github.com/aradunovic/dotfiler. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
294
+
295
+ ## Code of Conduct
296
+
297
+ Everyone interacting in the Dotfiler project’s codebases and issue trackers is expected to follow the [code of conduct](https://github.com/aradunovic/dotfiler/blob/master/CODE_OF_CONDUCT.md).
298
+
299
+ ## License
300
+
301
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
302
+
data/dotfiler.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ require File.expand_path("../lib/dotfiler/version", __FILE__)
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "dotfiler"
5
+ spec.version = Dotfiler::VERSION
6
+ spec.authors = ["Aleksandar Radunovic"]
7
+ spec.email = ["aleksandar@radunovic.io"]
8
+
9
+ spec.summary = "CLI gem for managing dotfiles"
10
+ spec.description = spec.summary
11
+ spec.homepage = "https://github.com/aradunovic/dotfiler"
12
+ spec.license = "MIT"
13
+
14
+ spec.files = Dir["README.md", "LICENSE.txt", "lib/**/*.rb", "dotfiler.gemspec"]
15
+ spec.require_path = "lib"
16
+ spec.bindir = "exe"
17
+ spec.executables = ["dotfiler"]
18
+
19
+ spec.required_ruby_version = ">= 2.3"
20
+
21
+ spec.add_dependency "dry-container", "0.6.0"
22
+ spec.add_dependency "dry-auto_inject", "0.4.6"
23
+ spec.add_dependency "hanami-cli", "0.2.0"
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.16"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ spec.add_development_dependency "rspec", "~> 3.0"
28
+ end
data/exe/dotfiler ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift File.expand_path("../../lib", __FILE__)
3
+
4
+ require "dotfiler"
5
+ require "dotfiler/cli/commands"
6
+
7
+ Hanami::CLI.new(Dotfiler::CLI::Commands).call
data/lib/dotfiler.rb ADDED
@@ -0,0 +1,11 @@
1
+ require "dotfiler/version"
2
+
3
+ module Dotfiler
4
+ Error = Class.new(StandardError)
5
+
6
+ def self.resolve
7
+ @_container ||= Container
8
+ end
9
+ end
10
+
11
+ require "dotfiler/container"
@@ -0,0 +1,39 @@
1
+ require "hanami/cli"
2
+
3
+ require "dotfiler/cli/commands/command"
4
+
5
+ require "dotfiler/cli/commands/init"
6
+ require "dotfiler/cli/commands/install"
7
+ require "dotfiler/cli/commands/add"
8
+ require "dotfiler/cli/commands/remove"
9
+ require "dotfiler/cli/commands/list"
10
+ require "dotfiler/cli/commands/edit"
11
+ require "dotfiler/cli/commands/backup"
12
+ require "dotfiler/cli/commands/version"
13
+
14
+ module Dotfiler
15
+ module CLI
16
+ module Commands
17
+ extend Hanami::CLI::Registry
18
+
19
+ register "init", Init
20
+ register "install", Install
21
+ register "add", Add, aliases: ["a"]
22
+ register "remove", Remove, aliases: ["rm"]
23
+ register "list", List, aliases: ["ls"]
24
+ register "edit", Edit, aliases: ["e"]
25
+ register "backup", Backup
26
+ register "version", Version, aliases: ["v", "-v", "--version"]
27
+
28
+ %w(add remove list edit backup).each do |cmd|
29
+ before(cmd) do
30
+ unless Dotfiler.resolve[:config].set?
31
+ $stderr.puts("ERROR: Dotfiler needs to be set up first. Check `dotfiler init -h`")
32
+ exit(1)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+
@@ -0,0 +1,105 @@
1
+ module Dotfiler
2
+ module CLI
3
+ module Commands
4
+ class Add < Command
5
+ include Dotfiler::Import["dotfiles", "symlinker", "mover"]
6
+
7
+ desc "Add specified file/directory to dotfiles"
8
+
9
+ argument :path, required: true, desc: "File/directory path"
10
+ option :name, required: false, desc: "Name which will be assigned to dotfile", aliases: ["-n"]
11
+ option :target, required: false, desc: "Path to where the symlink will be created", aliases: ["-t"]
12
+
13
+ def call(path:, **options)
14
+ handle_errors do
15
+ path = to_path.(path)
16
+
17
+ validate_path!(path)
18
+
19
+ name = options.fetch(:name, generate_dotfile_name(path))
20
+
21
+ validate_name!(name)
22
+
23
+ dotfiles_path = to_path.(config[:dotfiles])
24
+ dotfile_path = resolve_dotfile_path(path, dotfiles_path, options)
25
+ target_path = to_path.(options.fetch(:target, path.to_s))
26
+
27
+ info("Symlinking dotfile (#{dotfile_path}) to #{target_path}...")
28
+ symlink_path = symlinker.call(dotfile_path, target_path)
29
+
30
+
31
+ info("Adding #{name} to dotfiles...")
32
+ dotfiles.add!(name: name, link: symlink_path.to_s, path: dotfile_path.to_s)
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def validate_path!(path)
39
+ error!("Path #{path} does not exist") unless path.exists?
40
+ end
41
+
42
+ def validate_name!(name)
43
+ error!("Dotfile with the name '#{name}' already exists") if dotfiles.name_taken?(name)
44
+ end
45
+
46
+ def resolve_dotfile_path(path, dotfiles_path, options)
47
+ if dotfiles_path.contains?(path)
48
+ error!(already_dotfile_error(path, dotfiles_path)) if options[:target].nil?
49
+
50
+ path
51
+ else
52
+ safely_move(path, dotfiles_path)
53
+ end
54
+ end
55
+
56
+ def already_dotfile_error(path, dotfiles_path)
57
+ "Specified #{path.file? ? "file" : "directory"} (#{path}) " +
58
+ "is already in dotfiles directory (#{dotfiles_path})." +
59
+ "\nIf you want to symlink it, please provide `--target` option"
60
+ end
61
+
62
+ def safely_move(source, destination)
63
+ full_destination_path = destination.join(source.name)
64
+
65
+ if full_destination_path.exists?
66
+ available_options = {
67
+ "1" => { value: :overwrite, desc: "Overwrite it" },
68
+ "2" => { value: :backup_and_overwrite, desc: "Backup and overwrite it" },
69
+ "3" => { value: :cancel, desc: "Cancel"}
70
+ }
71
+ answer = prompt(
72
+ "Dotfile (#{full_destination_path}) already exists.\nWould you like to:",
73
+ available_options
74
+ )
75
+
76
+ case answer
77
+ when :overwrite
78
+ # fall-through
79
+ when :backup_and_overwrite
80
+ backup(full_destination_path)
81
+ else
82
+ terminate!(:clean, message: "Cancelling...")
83
+ end
84
+ end
85
+
86
+ move(source, destination)
87
+ end
88
+
89
+ def backup(path)
90
+ info("Backing up #{path} to #{path}_old")
91
+ mover.call(path, to_path.(path.to_s + "_old"))
92
+ end
93
+
94
+ def move(source, destination)
95
+ info("Moving #{source} to dotfiles directory (#{destination})...")
96
+ mover.call(source, destination)
97
+ end
98
+
99
+ def generate_dotfile_name(path)
100
+ path.name.to_s.gsub(/\A[._]+/, "")
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end