homedir 3.0.alpha2 → 3.0.alpha4
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.
- data/.travis.yml +0 -1
- data/Guardfile +8 -4
- data/README.mkd +11 -1
- data/homedir.gemspec +1 -0
- data/lib/homedir.rb +3 -2
- data/lib/homedir/catalog.rb +4 -1
- data/lib/homedir/cli.rb +34 -3
- data/lib/homedir/errors.rb +4 -0
- data/lib/homedir/hacks.rb +9 -0
- data/lib/homedir/package.rb +47 -18
- data/lib/homedir/package_discovery_loader.rb +29 -0
- data/lib/homedir/package_loader.rb +48 -0
- data/lib/homedir/package_version1_loader.rb +70 -0
- data/lib/homedir/package_version2_loader.rb +48 -0
- data/lib/homedir/package_version3_loader.rb +45 -0
- data/lib/homedir/version.rb +1 -1
- data/spec/acceptance/load_packages_spec.rb +17 -0
- data/spec/examples/version1-example/.homedir.control +11 -0
- data/spec/examples/version1-example/combined/version1-file +3 -0
- data/spec/examples/version1-example/version1/separate-file +2 -0
- data/spec/examples/version2-example/.homedir/control +13 -0
- data/spec/examples/version2-example/.homedir/post-install +2 -0
- data/spec/examples/version2-example/.homedir/post-remove +2 -0
- data/spec/examples/version2-example/.homedir/pre-install +2 -0
- data/spec/examples/version2-example/.homedir/pre-remove +2 -0
- data/spec/examples/version2-example/combined/version2-file +3 -0
- data/spec/examples/version2-example/version2/separate-file +2 -0
- data/spec/examples/version3-example/.gitignore +1 -0
- data/spec/examples/version3-example/description.txt +3 -0
- data/spec/examples/version3-example/homedir.yml +4 -0
- data/spec/examples/version3-example/homedir/combined/version3-file +3 -0
- data/spec/examples/version3-example/homedir/version3/separate-file +2 -0
- data/spec/examples/version3-example/post-install.sh +2 -0
- data/spec/examples/version3-example/post-remove.sh +2 -0
- data/spec/examples/version3-example/post-update.sh +2 -0
- data/spec/examples/version3-example/pre-install.sh +2 -0
- data/spec/examples/version3-example/pre-remove.sh +2 -0
- data/spec/examples/version3-example/pre-update.sh +2 -0
- data/spec/integration/catalog_packages_spec.rb +27 -0
- data/spec/lib/homedir/package_loader_spec.rb +30 -0
- data/spec/lib/homedir/package_spec.rb +49 -4
- data/spec/lib/homedir/package_version1_loader_spec.rb +66 -0
- data/spec/lib/homedir/package_version2_loader_spec.rb +41 -0
- data/spec/lib/homedir/package_version3_loader_spec.rb +41 -0
- data/spec/spec_helper.rb +15 -8
- data/spec/support/package_shared_examples.rb +59 -0
- metadata +93 -20
data/Guardfile
CHANGED
|
@@ -7,11 +7,15 @@ guard 'bundler' do
|
|
|
7
7
|
# watch(/^.+\.gemspec/)
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
-
guard 'rspec', :version => 2, :cli => "--color --format doc
|
|
10
|
+
guard 'rspec', :version => 2, :cli => "--color --format doc" do
|
|
11
11
|
watch(%r{^spec/.+_spec\.rb$})
|
|
12
|
-
watch(%r{^lib/
|
|
13
|
-
watch(
|
|
14
|
-
watch(
|
|
12
|
+
watch(%r{^lib/}) { "spec/integration" }
|
|
13
|
+
#watch(%r{^(lib|bin)/}) { "spec/acceptance" }
|
|
14
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
|
15
|
+
watch('spec/spec_helper.rb') { "spec" }
|
|
16
|
+
watch('spec/factories.rb') { "spec" }
|
|
17
|
+
watch(%r{^spec/support/.+\.rb}) { "spec" }
|
|
18
|
+
watch(%r{^spec/examples/}) { "spec" }
|
|
15
19
|
end
|
|
16
20
|
|
|
17
21
|
|
data/README.mkd
CHANGED
|
@@ -22,7 +22,17 @@ That's it!
|
|
|
22
22
|
|
|
23
23
|
## Support
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
* File an [issue](https://github.com/docwhat/homedir/issues).
|
|
26
|
+
* Freenode IRC in [`#homedir`](http://webchat.freenode.net/?channels=rvm).
|
|
27
|
+
* Contact me [directly](http://docwhat.org/email).
|
|
28
|
+
|
|
29
|
+
## Contributing
|
|
30
|
+
|
|
31
|
+
I love having people help me. All changes are welcome!
|
|
32
|
+
|
|
33
|
+
* Submit a [pull request](https://github.com/docwhat/homedir/pulls)
|
|
34
|
+
* Add to the [wiki](https://github.com/docwhat/homedir/wiki).
|
|
35
|
+
* Use the github instant editing feature.
|
|
26
36
|
|
|
27
37
|
## The Story So Far…
|
|
28
38
|
|
data/homedir.gemspec
CHANGED
|
@@ -24,6 +24,7 @@ Gem::Specification.new do |gem|
|
|
|
24
24
|
gem.add_development_dependency('factory_girl', ["~> 2.5.2"])
|
|
25
25
|
|
|
26
26
|
gem.add_development_dependency('yard')
|
|
27
|
+
gem.add_development_dependency('redcarpet')
|
|
27
28
|
|
|
28
29
|
gem.add_development_dependency('guard')
|
|
29
30
|
gem.add_development_dependency('guard-rspec')
|
data/lib/homedir.rb
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
# COPYRIGHT:: Copyright (c) 2012 Christian Höltje
|
|
3
3
|
# LICENSE:: The MIT License. See the file LICENSE distributed with this source.
|
|
4
4
|
require 'homedir/package'
|
|
5
|
+
require 'homedir/catalog'
|
|
6
|
+
require 'homedir/package_discovery_loader'
|
|
7
|
+
require 'homedir/errors'
|
|
5
8
|
|
|
6
9
|
module Homedir
|
|
7
|
-
class Error < StandardError
|
|
8
|
-
end
|
|
9
10
|
end
|
data/lib/homedir/catalog.rb
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
require 'homedir/errors'
|
|
2
|
+
require 'set'
|
|
2
3
|
|
|
3
4
|
module Homedir
|
|
4
|
-
class Catalog < Set
|
|
5
|
+
class Catalog < ::Set
|
|
5
6
|
|
|
7
|
+
# Find the package with the name `name`
|
|
8
|
+
#
|
|
6
9
|
# @param {String} name The name of the {Homedir::Package package} to find.
|
|
7
10
|
# @return {Homedir::Package} The package that matches the `name`
|
|
8
11
|
def find_by_name name
|
data/lib/homedir/cli.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
require 'thor'
|
|
2
|
+
require 'homedir'
|
|
3
|
+
require 'pathname'
|
|
2
4
|
|
|
3
5
|
module Homedir
|
|
4
6
|
# The command line interface for {Homedir}.
|
|
@@ -7,7 +9,28 @@ module Homedir
|
|
|
7
9
|
# information
|
|
8
10
|
class CLI < Thor
|
|
9
11
|
|
|
10
|
-
|
|
12
|
+
no_tasks do
|
|
13
|
+
# The directories to scan for repositories
|
|
14
|
+
#
|
|
15
|
+
# @return {Enumerable} A list of Pathname objects
|
|
16
|
+
def repositories
|
|
17
|
+
[ Pathname.new(ENV['HOME']) + '.homedir' + 'packages']
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Helper method to initialize the catalog, if needed.
|
|
21
|
+
#
|
|
22
|
+
# @return {Homedir::Catalog} A populated catalog
|
|
23
|
+
def catalog
|
|
24
|
+
@catalog ||= Catalog.new.tap do |cat|
|
|
25
|
+
pdl = PackageDiscoveryLoader.new(cat)
|
|
26
|
+
repositories.each do |repo|
|
|
27
|
+
pdl.load_from_directory(repo)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
desc "list", "Lists available packages."
|
|
11
34
|
method_option(
|
|
12
35
|
:remote,
|
|
13
36
|
:type => :boolean,
|
|
@@ -15,8 +38,11 @@ module Homedir
|
|
|
15
38
|
:aliases => '-r',
|
|
16
39
|
:description => "Queries the remote server")
|
|
17
40
|
def list
|
|
18
|
-
|
|
19
|
-
puts "
|
|
41
|
+
packages = catalog.to_a # TODO sort
|
|
42
|
+
puts "#{packages.length} local packages found:"
|
|
43
|
+
packages.each do |package|
|
|
44
|
+
puts " * #{package}"
|
|
45
|
+
end
|
|
20
46
|
end
|
|
21
47
|
|
|
22
48
|
desc "info PACKAGE", "Describe a specific PACKAGE in detail."
|
|
@@ -50,6 +76,11 @@ module Homedir
|
|
|
50
76
|
puts "Not implemented yet #{package_name.inspect}"
|
|
51
77
|
end
|
|
52
78
|
|
|
79
|
+
desc "repair", "Scans through your home directory and repairs all links. Warning: This can take a long time."
|
|
80
|
+
def repair
|
|
81
|
+
# FIXME: needs to do something
|
|
82
|
+
puts "Not implemented yet"
|
|
83
|
+
end
|
|
53
84
|
end
|
|
54
85
|
end
|
|
55
86
|
|
data/lib/homedir/errors.rb
CHANGED
data/lib/homedir/package.rb
CHANGED
|
@@ -20,12 +20,16 @@ module Homedir
|
|
|
20
20
|
:directory,
|
|
21
21
|
].freeze
|
|
22
22
|
DEFAULT_VALUES = {
|
|
23
|
-
:name
|
|
24
|
-
:description
|
|
25
|
-
:dependencies
|
|
26
|
-
:
|
|
27
|
-
:
|
|
28
|
-
:
|
|
23
|
+
:name => nil,
|
|
24
|
+
:description => nil,
|
|
25
|
+
:dependencies => [],
|
|
26
|
+
:pre_install => nil,
|
|
27
|
+
:post_install => nil,
|
|
28
|
+
:pre_remove => nil,
|
|
29
|
+
:post_remove => nil,
|
|
30
|
+
:pre_update => nil,
|
|
31
|
+
:post_update => nil,
|
|
32
|
+
:directory => nil,
|
|
29
33
|
}.freeze
|
|
30
34
|
|
|
31
35
|
# The name of the package.
|
|
@@ -44,16 +48,40 @@ module Homedir
|
|
|
44
48
|
# A list of package names this package depends on.
|
|
45
49
|
#
|
|
46
50
|
# When assigning a list, they can either be {Homedir::Package Package} objects or strings.
|
|
47
|
-
# @return [
|
|
51
|
+
# @return [Set] The set of package {#name names}.
|
|
48
52
|
attr_reader :dependencies
|
|
49
53
|
|
|
50
|
-
# A script
|
|
54
|
+
# A script to run before a package is enabled.
|
|
55
|
+
#
|
|
56
|
+
# @return {String}
|
|
57
|
+
attr_accessor :pre_install
|
|
58
|
+
|
|
59
|
+
# A script to run after a package is enabled.
|
|
51
60
|
#
|
|
52
61
|
# @return {String}
|
|
53
62
|
attr_accessor :post_install
|
|
54
63
|
|
|
55
|
-
# A script to run before
|
|
56
|
-
|
|
64
|
+
# A script to run before the package is disabled.
|
|
65
|
+
# @return {String}
|
|
66
|
+
attr_accessor :pre_remove
|
|
67
|
+
|
|
68
|
+
# A script to run after the package is disabled
|
|
69
|
+
# @return {String}
|
|
70
|
+
attr_accessor :post_remove
|
|
71
|
+
|
|
72
|
+
# A script to run before upgrading the package's source
|
|
73
|
+
#
|
|
74
|
+
# This is run before any upgrade steps run for the package source.
|
|
75
|
+
# @return {String}
|
|
76
|
+
attr_accessor :pre_update
|
|
77
|
+
|
|
78
|
+
# A script that runs after upgrading the package's source
|
|
79
|
+
#
|
|
80
|
+
# This is run after a package is upgraded and after the
|
|
81
|
+
# the package has been re-enabled but before the pre_install
|
|
82
|
+
# script.
|
|
83
|
+
# @return {String}
|
|
84
|
+
attr_accessor :post_update
|
|
57
85
|
|
|
58
86
|
# The directory where the package is stored.
|
|
59
87
|
#
|
|
@@ -62,15 +90,15 @@ module Homedir
|
|
|
62
90
|
# @return {Pathname}
|
|
63
91
|
attr_reader :directory
|
|
64
92
|
|
|
65
|
-
# Create a new {
|
|
93
|
+
# Create a new {Package} instance.
|
|
66
94
|
#
|
|
67
95
|
# @param {Hash} options
|
|
68
|
-
# @option options
|
|
69
|
-
# @option options
|
|
70
|
-
# @option options
|
|
71
|
-
# @option options
|
|
72
|
-
# @option options
|
|
73
|
-
# @option options
|
|
96
|
+
# @option options {String} :name The name of the package.
|
|
97
|
+
# @option options {String} :description The description of the package.
|
|
98
|
+
# @option options {Enumerable} :dependencies A list of {Homedir::Package packages} or {String strings}.
|
|
99
|
+
# @option options {Pathname} :directory The directory the packages is located at.
|
|
100
|
+
# @option options {String} :post_install Commands to run after installing the package.
|
|
101
|
+
# @option options {String} :pre_uninstall Commands to run before uninstalling the package.
|
|
74
102
|
def initialize(options = {})
|
|
75
103
|
options = DEFAULT_VALUES.merge(options)
|
|
76
104
|
|
|
@@ -100,7 +128,7 @@ module Homedir
|
|
|
100
128
|
|
|
101
129
|
# {include:#dependencies}
|
|
102
130
|
def dependencies= value
|
|
103
|
-
@dependencies = value.map { |p| p.to_s }
|
|
131
|
+
@dependencies = Set.new( value.map { |p| p.to_s } )
|
|
104
132
|
end
|
|
105
133
|
|
|
106
134
|
# {include:#directory}
|
|
@@ -159,5 +187,6 @@ module Homedir
|
|
|
159
187
|
def to_s
|
|
160
188
|
@name
|
|
161
189
|
end
|
|
190
|
+
|
|
162
191
|
end
|
|
163
192
|
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'homedir/package_loader'
|
|
2
|
+
|
|
3
|
+
module Homedir
|
|
4
|
+
class PackageDiscoveryLoader
|
|
5
|
+
attr_reader :catalog
|
|
6
|
+
def initialize(catalog=nil)
|
|
7
|
+
@catalog = catalog
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def loader
|
|
11
|
+
@loader ||= PackageLoader.new
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Recursively loads packages from the directory into {#catalog}
|
|
15
|
+
#
|
|
16
|
+
# @params {Pathname} path The directory to start scanning from
|
|
17
|
+
# @return {Homedir::PackageDiscoveryLoader} self
|
|
18
|
+
def load_from_directory path
|
|
19
|
+
if loader.path_is_valid?(path)
|
|
20
|
+
catalog << loader.load_from_path(path)
|
|
21
|
+
else
|
|
22
|
+
path.children.each do |child|
|
|
23
|
+
load_from_directory(child) if child.directory?
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
return self
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require 'homedir/errors'
|
|
2
|
+
require 'homedir/package_version1_loader'
|
|
3
|
+
require 'homedir/package_version2_loader'
|
|
4
|
+
require 'homedir/package_version3_loader'
|
|
5
|
+
|
|
6
|
+
module Homedir
|
|
7
|
+
class PackageLoader
|
|
8
|
+
|
|
9
|
+
# The list of loaders, in the order they should be tried
|
|
10
|
+
#
|
|
11
|
+
# @return {Enumerable} A list of package loaders
|
|
12
|
+
def loaders
|
|
13
|
+
# The order is important
|
|
14
|
+
@loaders ||= [
|
|
15
|
+
PackageVersion3Loader.new,
|
|
16
|
+
PackageVersion2Loader.new,
|
|
17
|
+
PackageVersion1Loader.new,
|
|
18
|
+
].freeze
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Loads a package from a path
|
|
22
|
+
#
|
|
23
|
+
# @param {Pathname} path The directory of the package
|
|
24
|
+
# @return {Homedir::Package} The package object
|
|
25
|
+
def load_from_path path
|
|
26
|
+
loaders.each do |loader|
|
|
27
|
+
begin
|
|
28
|
+
return loader.load_from_path(path) if loader.path_is_valid?(path)
|
|
29
|
+
rescue InvalidPackageDirectoryError
|
|
30
|
+
next
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
raise InvalidPackageDirectoryError.new("The directory '#{path}' doesn't contain a valid package")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Is the path a valid version1 package directory?
|
|
38
|
+
#
|
|
39
|
+
# @return {Boolean} Returns true if the path is a valid package directory.
|
|
40
|
+
def path_is_valid? path
|
|
41
|
+
loaders.each do |loader|
|
|
42
|
+
return true if loader.path_is_valid?(path)
|
|
43
|
+
end
|
|
44
|
+
return false
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
require 'homedir/package'
|
|
2
|
+
require 'homedir/errors'
|
|
3
|
+
|
|
4
|
+
module Homedir
|
|
5
|
+
class PackageVersion1Loader
|
|
6
|
+
|
|
7
|
+
# Loads a package from a path
|
|
8
|
+
#
|
|
9
|
+
# @param {Pathname} path The directory of the package
|
|
10
|
+
# @return {Homedir::Package} The package object
|
|
11
|
+
def load_from_path(path)
|
|
12
|
+
raise InvalidPackageDirectoryError.new("The directory '#{path}' is not a version 1 package.") unless path_is_valid?(path)
|
|
13
|
+
control_path = path + '.homedir.control'
|
|
14
|
+
|
|
15
|
+
control = parse_control_file control_path
|
|
16
|
+
|
|
17
|
+
pkg = Package.new( :directory => path )
|
|
18
|
+
|
|
19
|
+
pkg.name = control[:package]
|
|
20
|
+
pkg.description = control[:description] || ''
|
|
21
|
+
pkg.dependencies = (control[:depends] || '').split("\n")
|
|
22
|
+
|
|
23
|
+
return pkg
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Is the path a valid version1 package directory?
|
|
27
|
+
#
|
|
28
|
+
# @return {Boolean} Returns true if the path is a valid package directory.
|
|
29
|
+
def path_is_valid? path
|
|
30
|
+
return false unless (path).directory?
|
|
31
|
+
return false unless (path + '.homedir.control').file?
|
|
32
|
+
return true
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Parse a control file
|
|
36
|
+
#
|
|
37
|
+
# @param {Pathname} path The path to control file
|
|
38
|
+
# @return {Hash} A hash containing the keys/values.
|
|
39
|
+
# @see {#parse_control_stream}
|
|
40
|
+
def parse_control_file path
|
|
41
|
+
path.open('r') { |f| parse_control_stream f }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Parse a version 1 control from a stream
|
|
45
|
+
#
|
|
46
|
+
# This is *not* a robust parser.
|
|
47
|
+
# @param {IO} stream An IO stream to read from
|
|
48
|
+
# @return {Hash} A hash containing the keys/values.
|
|
49
|
+
def parse_control_stream stream
|
|
50
|
+
contents = stream.read()
|
|
51
|
+
|
|
52
|
+
hash = {}
|
|
53
|
+
last_key = nil
|
|
54
|
+
last_value = nil
|
|
55
|
+
contents.split(/[\r\n]+/).each do |line|
|
|
56
|
+
next if line =~ /^\s*#/
|
|
57
|
+
if line =~ /^\s/
|
|
58
|
+
last_value << line.strip unless last_key.nil?
|
|
59
|
+
elsif line.include? ":"
|
|
60
|
+
hash[last_key.to_sym] = last_value.join("\n") unless last_key.nil?
|
|
61
|
+
last_key, value = line.split(/\s*:\s*/, 2)
|
|
62
|
+
last_value = value.strip.empty? ? [] : [ value.strip ]
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
hash[last_key.to_sym] = last_value.join("\n") unless last_key.nil?
|
|
66
|
+
|
|
67
|
+
return hash
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require 'homedir/package'
|
|
2
|
+
require 'homedir/package_version1_loader'
|
|
3
|
+
require 'homedir/errors'
|
|
4
|
+
|
|
5
|
+
module Homedir
|
|
6
|
+
class PackageVersion2Loader < PackageVersion1Loader
|
|
7
|
+
|
|
8
|
+
# Loads a package from a path
|
|
9
|
+
#
|
|
10
|
+
# @param {Pathname} path The directory of the package
|
|
11
|
+
# @return {Homedir::Package} The package object
|
|
12
|
+
def load_from_path(path)
|
|
13
|
+
raise InvalidPackageDirectoryError.new("The directory '#{path}' is not a version 2 package.") unless path_is_valid?(path)
|
|
14
|
+
control_path = path + '.homedir' + 'control'
|
|
15
|
+
|
|
16
|
+
control = parse_control_file control_path
|
|
17
|
+
|
|
18
|
+
pkg = Package.new( :directory => path )
|
|
19
|
+
|
|
20
|
+
pkg.name = control[:package]
|
|
21
|
+
pkg.description = control[:description] || ''
|
|
22
|
+
pkg.dependencies = (control[:depends] || '').split("\n")
|
|
23
|
+
|
|
24
|
+
['pre', 'post'].each do |prefix|
|
|
25
|
+
['install', 'remove'].each do |action|
|
|
26
|
+
filepath = (path + ".homedir" + "#{prefix}-#{action}")
|
|
27
|
+
if filepath.file? and filepath.executable?
|
|
28
|
+
filepath.open('r') do |f|
|
|
29
|
+
pkg.send("#{prefix}_#{action}=", f.read())
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
return pkg
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Is the path a valid version2 package directory?
|
|
39
|
+
#
|
|
40
|
+
# @return {Boolean} Returns true if the path is a valid package directory.
|
|
41
|
+
def path_is_valid? path
|
|
42
|
+
return false unless (path).directory?
|
|
43
|
+
return false unless (path + '.homedir').directory?
|
|
44
|
+
return false unless (path + '.homedir' + 'control').file?
|
|
45
|
+
return true
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|