dotter_dotfiles 0.2.0 → 0.3.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.
- checksums.yaml +4 -4
- data/.codeclimate.yml +10 -0
- data/.rubocop.yml +1171 -0
- data/ChangeLog.md +5 -0
- data/README.md +30 -5
- data/bin/dotter +1 -1
- data/lib/dotter/cli.rb +195 -180
- data/lib/dotter/configuration.rb +52 -35
- data/lib/dotter/foreigngitrepo.rb +29 -0
- data/lib/dotter/gitrepo.rb +49 -40
- data/lib/dotter/package.rb +76 -55
- data/lib/dotter/publicgitrepo.rb +42 -37
- data/lib/dotter/utilities.rb +39 -33
- data/lib/dotter/version.rb +1 -1
- metadata +5 -2
data/ChangeLog.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
### 0.3.0 / 2015-11-10
|
2
|
+
* Attempted (and failed) to implement a smart clone command.
|
3
|
+
* Implemented a dumb clone command that wipes away VCS history and package state after cloning.
|
4
|
+
* Sorry for this taking forever to release.
|
5
|
+
|
1
6
|
### 0.2.0 / 2015-11-10
|
2
7
|
* Implemented the update_all command
|
3
8
|
* Minor internal refactoring
|
data/README.md
CHANGED
@@ -14,11 +14,36 @@ It is very new, unfinished software that likely has multiple bugs. However, due
|
|
14
14
|
|
15
15
|
Due to the name 'dotter' already being used, the gem is available under the name 'dotter_dotfiles'. Install it with `gem install dotter_dotfiles`
|
16
16
|
|
17
|
-
To see all available commands, use `dotter help
|
17
|
+
To see all available commands, use `dotter help` or look at the list of commands below. All commands are implemented, but the clone command is dumb due to the difficulties
|
18
|
+
involved in reconstructing the entire structure and state ` ~/dotfiles` from a single, flat git repository.
|
19
|
+
|
20
|
+
Commands:
|
21
|
+
```
|
22
|
+
dotter add PACKAGE FILE # Add a file from a package to the next commit of that package.
|
23
|
+
dotter clone REPO_URL # Clones the dotfiles / packages of the specified repository into ~/dotfiles. Will overwrite any existing data.
|
24
|
+
dotter commit PACKAGE -m, --commit-message=COMMIT_MESSAGE # Commit your changes to a Git-tracked package.
|
25
|
+
dotter help [COMMAND] # Describe available commands or one specific command
|
26
|
+
dotter import PATH PACKAGE # Imports a file or directory into the specified package
|
27
|
+
dotter import_repo REPO_URL PACKAGE # Clones the specified git repository as the contents of the specified Package.
|
28
|
+
dotter init # Initialise the directory structure for ~/dotfiles
|
29
|
+
dotter list # List all packages present in ~/dotfiles
|
30
|
+
dotter log PACKAGE # View the commit log of a package.
|
31
|
+
dotter publish PACKAGE # Make a package available in your public dotfiles repository
|
32
|
+
dotter reset PACKAGE # Reset what will be commmitted in the next commit to the given package.
|
33
|
+
dotter status PACKAGE # Obtain the repository status of a Git-tracked package.
|
34
|
+
dotter stow PACKAGE # Stow the given package name.
|
35
|
+
dotter track PACKAGE # Begin tracking the given package with Git
|
36
|
+
dotter unpublish PACKAGE # Make a package private after publishing it.
|
37
|
+
dotter unstow PACKAGE # Unstow the given package name.
|
38
|
+
dotter update PACKAGE # Updates the specified package
|
39
|
+
dotter update_all # Updates all stowed packages.
|
40
|
+
dotter version # Print the dotter version
|
41
|
+
```
|
18
42
|
This project tries to follow [Semantic Versioning](http://semver.org/) but no guarantees are made in this regard.
|
19
43
|
## TODO
|
20
44
|
1. Refactor and clean up the code.
|
21
|
-
2. Implement all unimplemented commands
|
22
|
-
3.
|
23
|
-
4.
|
24
|
-
5.
|
45
|
+
2. ~~Implement all unimplemented commands.~~
|
46
|
+
3. Make the `clone` command smarter
|
47
|
+
4. Implement error handling
|
48
|
+
5. Add any useful suggested features.
|
49
|
+
6. Port to Crystal so it can be a single executable.
|
data/bin/dotter
CHANGED
data/lib/dotter/cli.rb
CHANGED
@@ -5,186 +5,201 @@ require 'dotter/version'
|
|
5
5
|
require 'dotter/configuration'
|
6
6
|
require 'dotter/package'
|
7
7
|
require 'dotter/publicgitrepo'
|
8
|
+
require 'dotter/foreigngitrepo'
|
8
9
|
require 'pathname'
|
10
|
+
require 'git'
|
9
11
|
module Dotter
|
10
|
-
class CLI < Thor
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
12
|
+
class CLI < Thor
|
13
|
+
include Utilities
|
14
|
+
desc 'version', 'Print the dotter version'
|
15
|
+
def version
|
16
|
+
puts "This is dotter #{Dotter::VERSION}"
|
17
|
+
end
|
18
|
+
desc 'init', 'Initialise the directory structure for ~/dotfiles'
|
19
|
+
def init
|
20
|
+
puts 'Initialising ~/dotfiles'
|
21
|
+
puts 'Creating the dotfiles directory.'
|
22
|
+
FileUtils.mkpath(dotfiles_path)
|
23
|
+
go_to_dotfiles
|
24
|
+
puts 'Creating the directory for the combined public dotfiles.'
|
25
|
+
FileUtils.mkpath('public')
|
26
|
+
puts 'Creating an initial package for dotter.'
|
27
|
+
FileUtils.mkpath('dotter/.dotter/gitrepos')
|
28
|
+
FileUtils.mkpath('dotter/.dotter/indexes/')
|
29
|
+
# If we don't do this now, we'll get a nasty exception if we ever access the configuration.
|
30
|
+
FileUtils.touch('dotter/.dotter/Dotfile')
|
31
|
+
end
|
32
|
+
desc 'list', 'List all packages present in ~/dotfiles'
|
33
|
+
def list
|
34
|
+
puts 'List of packages in ~/dotfiles'
|
35
|
+
all_package_names.each do |package|
|
36
|
+
puts package
|
37
|
+
end
|
38
|
+
end
|
39
|
+
desc 'stow PACKAGE', 'Stow the given package name.'
|
40
|
+
def stow(package)
|
41
|
+
package = Package.new(package)
|
42
|
+
if package.stowed?
|
43
|
+
error "Package #{package} is already stowed."
|
44
|
+
exit(1)
|
45
|
+
end
|
46
|
+
puts "Stowing package #{package}"
|
47
|
+
puts package.stow
|
48
|
+
end
|
49
|
+
desc 'unstow PACKAGE', 'Unstow the given package name.'
|
50
|
+
def unstow(package)
|
51
|
+
package = Package.new(package)
|
52
|
+
if package.unstowed?
|
53
|
+
error "Package #{package} is not stowed."
|
54
|
+
exit(1)
|
55
|
+
end
|
56
|
+
puts "Unstowing package #{package}"
|
57
|
+
puts package.unstow
|
58
|
+
end
|
59
|
+
desc 'track PACKAGE', 'Begin tracking the given package with Git'
|
60
|
+
def track(package)
|
61
|
+
puts "Initialising Git repository for package #{package}"
|
62
|
+
package = Package.new(package)
|
63
|
+
package.track
|
64
|
+
puts "Repository for package #{package} initialised. Git's metadata is stored in #{package.repo.metadata_path}"
|
65
|
+
puts 'Creating an initial snapshot to serve as a starting point.'
|
66
|
+
repo = package.repo
|
67
|
+
repo.add('.')
|
68
|
+
repo.commit_all("Initial snapshot of the package's contents")
|
69
|
+
puts 'Initial snapshot created.'
|
70
|
+
end
|
71
|
+
desc 'publish PACKAGE', 'Make a package available in your public dotfiles repository'
|
72
|
+
def publish(package)
|
73
|
+
puts "Making package #{package} public"
|
74
|
+
public_repo = PublicGitRepo.new
|
75
|
+
puts public_repo.add_package(package)
|
76
|
+
end
|
77
|
+
desc 'unpublish PACKAGE', 'Make a package private after publishing it.'
|
78
|
+
def unpublish(package)
|
79
|
+
puts "Making package #{package} private again"
|
80
|
+
public_repo = PublicGitRepo.new
|
81
|
+
public_repo.remove_package(package)
|
82
|
+
end
|
83
|
+
method_option :commit_message, required: true, aliases: '-m'
|
84
|
+
method_option :all, type: :boolean, aliases: '-a'
|
85
|
+
desc 'commit PACKAGE', 'Commit your changes to a Git-tracked package.'
|
86
|
+
def commit(package)
|
87
|
+
package = Package.new(package)
|
88
|
+
if package.untracked?
|
89
|
+
error "Package #{package} is not tracked by Git."
|
90
|
+
exit 1
|
91
|
+
end
|
92
|
+
puts "Committing the changes to package #{package} with commit message #{options.commit_message}."
|
93
|
+
commit_message = options.commit_message
|
94
|
+
repo = package.repo
|
95
|
+
if options.all
|
96
|
+
repo.commit_all(commit_message)
|
97
|
+
else
|
98
|
+
repo.commit(commit_message)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
desc 'update PACKAGE', 'Updates the specified package. For packages imported from external repositories, also updates the repository.'
|
102
|
+
def update(package)
|
103
|
+
puts "Updating the contents / symlinks for package #{package}"
|
104
|
+
package = Package.new(package)
|
105
|
+
if package.unstowed?
|
106
|
+
error "Package #{package} is not stowed and therefore cannot be updated."
|
107
|
+
exit 1
|
108
|
+
end
|
109
|
+
package.update
|
110
|
+
end
|
111
|
+
desc 'update_all', 'Updates all stowed packages.'
|
112
|
+
def update_all
|
113
|
+
puts 'Updating all stowed packages'
|
114
|
+
all_packages = []
|
115
|
+
all_package_names.each do |package|
|
116
|
+
all_packages.push(Package.new(package.to_s))
|
117
|
+
end
|
118
|
+
stowed_packages = all_packages.select(&:stowed?)
|
119
|
+
stowed_packages.each do |package|
|
120
|
+
puts "Updating #{package}"
|
121
|
+
package.update
|
122
|
+
end
|
123
|
+
end
|
124
|
+
desc 'import PATH PACKAGE', 'Imports a file or directory into the specified package'
|
125
|
+
def import(path, package)
|
126
|
+
puts "Importing #{path} into package #{package}"
|
127
|
+
filepath = Pathname.new(File.expand_path(path))
|
128
|
+
packagepath = package_path(package)
|
129
|
+
FileUtils.mkpath(packagepath.to_s) unless Dir.exist?(packagepath.to_s)
|
130
|
+
homepath = Pathname.new(File.expand_path('~'))
|
131
|
+
relative_filepath = filepath.relative_path_from(homepath)
|
132
|
+
complete_path = packagepath + relative_filepath
|
133
|
+
FileUtils.copy(File.expand_path(path), complete_path.to_s)
|
134
|
+
puts 'File imported successfully. Update the package to make the symlink.'
|
135
|
+
end
|
136
|
+
desc 'import_repo REPO_URL PACKAGE', 'Clones the specified git repository as the contents of the specified Package.'
|
137
|
+
def import_repo(repo_url, package)
|
138
|
+
puts "Cloning repository #{repo_url} into package #{package}"
|
139
|
+
ForeignGitRepo.new(package, true, repo_url)
|
140
|
+
puts "Repository #{repo_url} successfully cloned into #{package}."
|
141
|
+
# We need to manually set the package as tracked to avoid calling init() again.
|
142
|
+
config = Configuration.new
|
143
|
+
config.track(package)
|
144
|
+
config.set_type(package, 'git_repo')
|
145
|
+
config.set_url(package, repo_url)
|
146
|
+
end
|
147
|
+
desc 'clone REPO_URL', 'Clones the dotfiles / packages of the specified repository into ~/dotfiles. Will overwrite any existing data.'
|
148
|
+
def clone(repo_url)
|
149
|
+
puts "Cloning repository #{repo_url} directly into ~/dotfiles"
|
150
|
+
repo = Git.clone(repo_url, @@dotfiles_path.to_s)
|
151
|
+
puts "Due to implementation difficulties, all the the commit history and state information will be lost."
|
152
|
+
go_to_dotfiles
|
153
|
+
`rm -rf .git`
|
154
|
+
`rm -rf dotter/*`
|
155
|
+
`touch dotter/Dotfile`
|
156
|
+
end
|
157
|
+
desc 'status PACKAGE', 'Obtain the repository status of a Git-tracked package.'
|
158
|
+
def status(package)
|
159
|
+
package = Package.new(package)
|
160
|
+
if package.untracked?
|
161
|
+
error "Package #{package} is not tracked by Git."
|
162
|
+
exit 1
|
163
|
+
end
|
164
|
+
metadata_path = repo_path(package.to_s)
|
165
|
+
metadata_indexes_path = index_path(package.to_s)
|
166
|
+
# Punt because it does this better than ruby-git.
|
167
|
+
system({ 'GIT_DIR' => metadata_path.to_s, 'GIT_INDEX_FILE' => metadata_indexes_path.to_s }, 'git status')
|
168
|
+
end
|
169
|
+
desc 'add PACKAGE FILE', 'Add a file from a package to the next commit of that package.'
|
170
|
+
def add(package, file)
|
171
|
+
package = Package.new(package)
|
172
|
+
if package.untracked?
|
173
|
+
error "Package #{package} is not tracked by Git."
|
174
|
+
exit 1
|
175
|
+
end
|
176
|
+
puts "Marking #{file} to be committed for package #{package}"
|
177
|
+
repo = package.repo
|
178
|
+
repo.add(file)
|
179
|
+
end
|
180
|
+
desc 'reset PACKAGE', 'Reset what will be commmitted in the next commit to the given package.'
|
181
|
+
def reset(package)
|
182
|
+
package = Package.new(package)
|
183
|
+
if package.untracked?
|
184
|
+
error "Package #{package} is not tracked by Git."
|
185
|
+
exit 1
|
186
|
+
end
|
187
|
+
puts "Resetting what will be committed to package #{package}"
|
188
|
+
repo = package.repo
|
189
|
+
repo.reset
|
190
|
+
end
|
191
|
+
desc 'log PACKAGE', 'View the commit log of a package.'
|
192
|
+
def log(package)
|
193
|
+
package = Package.new(package)
|
194
|
+
if package.untracked?
|
195
|
+
error "Package #{package} is not tracked by Git."
|
196
|
+
exit 1
|
197
|
+
end
|
198
|
+
puts "Obtaining the log of package #{package}"
|
199
|
+
repo = package.repo
|
200
|
+
repo.log.each do |commit|
|
201
|
+
puts "[#{commit.date}] #{commit.message} (#{commit.author.name})"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
190
205
|
end
|
data/lib/dotter/configuration.rb
CHANGED
@@ -1,39 +1,56 @@
|
|
1
1
|
require 'dotter/utilities'
|
2
2
|
require 'inifile'
|
3
3
|
module Dotter
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
4
|
+
class Configuration
|
5
|
+
include Utilities
|
6
|
+
attr_reader :config_file
|
7
|
+
attr_accessor :config
|
8
|
+
def initialize(config_file = package_path('dotter') + '.dotter/Dotfile')
|
9
|
+
@config_file = config_file
|
10
|
+
@config = IniFile.load(config_file)
|
11
|
+
end
|
12
|
+
|
13
|
+
def package_config(package)
|
14
|
+
@config[package]
|
15
|
+
end
|
16
|
+
|
17
|
+
def save
|
18
|
+
@config.write
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_state(package, state)
|
22
|
+
package_conf = package_config(package)
|
23
|
+
package_conf['state'] = state
|
24
|
+
save
|
25
|
+
end
|
26
|
+
|
27
|
+
def track(package)
|
28
|
+
package_conf = package_config(package)
|
29
|
+
package_conf['tracked'] = true
|
30
|
+
save
|
31
|
+
end
|
32
|
+
|
33
|
+
def publish(package)
|
34
|
+
package_conf = package_config(package)
|
35
|
+
package_conf['public'] = true
|
36
|
+
save
|
37
|
+
end
|
38
|
+
|
39
|
+
def unpublish(package)
|
40
|
+
package_conf = package_config(package)
|
41
|
+
package_conf['public'] = false
|
42
|
+
save
|
43
|
+
end
|
44
|
+
|
45
|
+
def set_type(package, type)
|
46
|
+
package_conf = package_config(package)
|
47
|
+
package_conf['type'] = type
|
48
|
+
save
|
49
|
+
end
|
50
|
+
def set_url(package,url)
|
51
|
+
package_conf = package_config(package)
|
52
|
+
package_conf['url'] = url
|
53
|
+
save
|
54
|
+
end
|
55
|
+
end
|
39
56
|
end
|