solaris-prototype 1.0.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.
- data/LICENSE +26 -0
- data/README.rdoc +27 -0
- data/Rakefile +28 -0
- data/lib/solaris.rb +8 -0
- data/lib/solaris/prototype.rb +183 -0
- data/test/test_prototype.rb +108 -0
- data/test/test_solaris.rb +17 -0
- metadata +57 -0
data/LICENSE
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Copyright 2011 Martin Carpenter. All rights reserved.
|
2
|
+
|
3
|
+
Redistribution and use in source and binary forms, with or without modification, are
|
4
|
+
permitted provided that the following conditions are met:
|
5
|
+
|
6
|
+
1. Redistributions of source code must retain the above copyright notice, this list of
|
7
|
+
conditions and the following disclaimer.
|
8
|
+
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list
|
10
|
+
of conditions and the following disclaimer in the documentation and/or other materials
|
11
|
+
provided with the distribution.
|
12
|
+
|
13
|
+
THIS SOFTWARE IS PROVIDED BY Martin Carpenter ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
14
|
+
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Martin Carpenter OR
|
16
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
17
|
+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
18
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
19
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
20
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
21
|
+
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
22
|
+
|
23
|
+
The views and conclusions contained in the software and documentation are those of the
|
24
|
+
authors and should not be interpreted as representing official policies, either expressed
|
25
|
+
or implied, of Martin Carpenter.
|
26
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
= solaris-prototype
|
3
|
+
|
4
|
+
Author:: Martin Carpenter
|
5
|
+
Email:: mcarpenter@free.fr
|
6
|
+
Copyright:: Copyright (c) Martin Carpenter 2011
|
7
|
+
|
8
|
+
== About
|
9
|
+
|
10
|
+
The solaris-prototype gem helps with the manipulation of SunOS and Solaris
|
11
|
+
prototype entries for SysV packages.
|
12
|
+
|
13
|
+
== Examples
|
14
|
+
|
15
|
+
=== Prepare a prototype for installation as another user
|
16
|
+
|
17
|
+
p = Solaris::Prototype.from_path './usr/local/bin/foo'
|
18
|
+
p.to_s
|
19
|
+
=> "f none ./usr/local/bin/foo 0755 martin staff"
|
20
|
+
p.owner = 'root'
|
21
|
+
p.group = 'sys'
|
22
|
+
p.to_s
|
23
|
+
=> "f none ./usr/local/bin/foo 0755 root sys"
|
24
|
+
p.pathname = "/usr/local/bin/foo=./usr/local/bin/foo"
|
25
|
+
=> "f none /usr/local/bin/foo=./usr/local/bin/foo 0755 root sys"
|
26
|
+
|
27
|
+
This can then be fed into pkgmk(1M).
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/clean'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rdoc/task'
|
5
|
+
require 'rubygems/package_task'
|
6
|
+
|
7
|
+
desc 'Default task (package)'
|
8
|
+
task :default => [:package]
|
9
|
+
|
10
|
+
Rake::TestTask.new( 'test' )
|
11
|
+
|
12
|
+
SPECFILE = 'solaris-prototype.gemspec'
|
13
|
+
if File.exist?( SPECFILE )
|
14
|
+
spec = eval( File.read( SPECFILE ) )
|
15
|
+
#Rake::GemPackageTask.new( spec ).define
|
16
|
+
Gem::PackageTask.new( spec ).define
|
17
|
+
end
|
18
|
+
|
19
|
+
Rake::RDocTask.new do |rdoc|
|
20
|
+
rdoc.rdoc_dir = 'rdoc'
|
21
|
+
rdoc.title = 'solaris-prototype'
|
22
|
+
rdoc.options << '--charset' << 'utf-8'
|
23
|
+
rdoc.options << '--all'
|
24
|
+
rdoc.rdoc_files.include( 'README.rdoc' )
|
25
|
+
rdoc.rdoc_files.include( FileList[ 'lib/**/*' ] )
|
26
|
+
rdoc.rdoc_files.include( FileList[ 'test/**/*' ] )
|
27
|
+
end
|
28
|
+
|
data/lib/solaris.rb
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
|
2
|
+
require 'etc'
|
3
|
+
|
4
|
+
module Solaris
|
5
|
+
|
6
|
+
# Class to represent Solaris package file prototypes.
|
7
|
+
# A prototype line contains information regarding file
|
8
|
+
# type, location, ownership, permisions.
|
9
|
+
#
|
10
|
+
# See Solaris' prototype(4) man-page for information on
|
11
|
+
# attributes.
|
12
|
+
#
|
13
|
+
# This class does not support special lines (those
|
14
|
+
# beginning with !), pathname variable substitution or
|
15
|
+
# prototype parts.
|
16
|
+
class Prototype
|
17
|
+
|
18
|
+
attr_accessor :part
|
19
|
+
attr_accessor :ftype
|
20
|
+
attr_accessor :install_class
|
21
|
+
attr_accessor :pathname
|
22
|
+
attr_accessor :major
|
23
|
+
attr_accessor :minor
|
24
|
+
attr_accessor :mode
|
25
|
+
attr_accessor :owner
|
26
|
+
attr_accessor :group
|
27
|
+
|
28
|
+
# Install class to use if not specified.
|
29
|
+
DEFAULT_INSTALL_CLASS = 'none'
|
30
|
+
|
31
|
+
# Part to use if not specified. Solaris 10 documentation
|
32
|
+
# for prototype(4) states that no part given implies
|
33
|
+
# "part 1".
|
34
|
+
DEFAULT_PART = nil
|
35
|
+
|
36
|
+
# Regular expression for filetype.
|
37
|
+
RE_FTYPE = '([bcdefpvxils])'
|
38
|
+
|
39
|
+
# Regular expression for install class.
|
40
|
+
RE_INSTALL_CLASS = '(\w{1,12})'
|
41
|
+
|
42
|
+
# Regular expression for path.
|
43
|
+
RE_PATH = '(\S+)'
|
44
|
+
|
45
|
+
# Regular expression for major device mode.
|
46
|
+
RE_MAJOR = '(\d+)'
|
47
|
+
|
48
|
+
# Regular expression for minor device mode.
|
49
|
+
RE_MINOR = '(\d+)'
|
50
|
+
|
51
|
+
# Regular expression for octal file mode.
|
52
|
+
RE_MODE = '([0-7]{4})'
|
53
|
+
|
54
|
+
# Regular expression for user name.
|
55
|
+
RE_OWNER = '(\S+)'
|
56
|
+
|
57
|
+
# Regular expression for group name.
|
58
|
+
RE_GROUP = '(\S+)'
|
59
|
+
|
60
|
+
# Create a Prototype object from a line from a prototype(4) file.
|
61
|
+
def self.from_line(line)
|
62
|
+
ftype = $1.to_sym if line =~ /^#{RE_FTYPE} /
|
63
|
+
re = case ftype
|
64
|
+
when :b, :c
|
65
|
+
/^#{ftype} #{RE_INSTALL_CLASS} #{RE_PATH} #{RE_MAJOR} #{RE_MINOR} #{RE_MODE} #{RE_OWNER} #{RE_GROUP}$/
|
66
|
+
when :d, :e, :f, :p, :v, :x
|
67
|
+
/^#{ftype} #{RE_INSTALL_CLASS} #{RE_PATH} #{RE_MODE} #{RE_OWNER} #{RE_GROUP}$/
|
68
|
+
when :i
|
69
|
+
/^#{ftype} #{RE_PATH}/ # perhaps not really path
|
70
|
+
when :l, :s
|
71
|
+
/^#{ftype} #{RE_INSTALL_CLASS} #{RE_PATH}/
|
72
|
+
else
|
73
|
+
raise ArgumentError, 'Unknown filetype'
|
74
|
+
end
|
75
|
+
if line =~ re
|
76
|
+
proto = self.new
|
77
|
+
proto.ftype = ftype
|
78
|
+
case ftype
|
79
|
+
when :b, :c
|
80
|
+
proto.install_class = $1
|
81
|
+
proto.pathname =$2
|
82
|
+
proto.major = $3.to_i
|
83
|
+
proto.minor = $4.to_i
|
84
|
+
proto.mode = $5.to_i(8)
|
85
|
+
proto.owner = $6
|
86
|
+
proto.group = $7
|
87
|
+
when :d, :e, :f, :p, :v, :x
|
88
|
+
proto.install_class = $1
|
89
|
+
proto.pathname = $2
|
90
|
+
proto.mode = $3.to_i(8)
|
91
|
+
proto.owner = $4
|
92
|
+
proto.group = $5
|
93
|
+
when :i
|
94
|
+
proto.pathname = $1
|
95
|
+
when :l, :s
|
96
|
+
proto.install_class = $1
|
97
|
+
proto.pathname = $2
|
98
|
+
end
|
99
|
+
else
|
100
|
+
if line =~ /^!/
|
101
|
+
raise ArgumentError, "Prototype commands not supported #{line.inspect}"
|
102
|
+
else
|
103
|
+
raise ArgumentError, "Could not parse line #{line.inspect}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
proto
|
107
|
+
end
|
108
|
+
|
109
|
+
# Create a Prototype from the file at the +path+ on the local
|
110
|
+
# filesystem.
|
111
|
+
#
|
112
|
+
# If +actual+ is provided then this is the path that is used for the
|
113
|
+
# object's pathname property although all other properties are
|
114
|
+
# created from the +path+ argument. The process must be able to
|
115
|
+
# stat(1) the file at +path+ to determine these properties.
|
116
|
+
#
|
117
|
+
# If this object is to be fed to pkgmk(1M) to be installed at
|
118
|
+
# +real_location+ and the file that will be used to construct the
|
119
|
+
# package currently lives at +current_location+ then the second
|
120
|
+
# argument should take the form +real_location+=+current_location+.
|
121
|
+
# The first argument (+path+) is always the file from which the
|
122
|
+
# Prototype's properties only (eg. owner, mode) are created.
|
123
|
+
#
|
124
|
+
# For example, to take the object attributes from the already
|
125
|
+
# installed file in /opt/MYpkg/foo, but to subsequently package the
|
126
|
+
# file ./foo in that same location using pkgmk(1M) call:
|
127
|
+
# from_path( '/opt/MYpkg/foo', '/opt/MYpkg/foo=./foo' )
|
128
|
+
def self.from_path(path, actual=nil)
|
129
|
+
proto = self.new
|
130
|
+
proto.part = DEFAULT_PART
|
131
|
+
# Use #lstat since we are always interested in the link source,
|
132
|
+
# not the target.
|
133
|
+
stat = File.lstat( path )
|
134
|
+
raise RuntimeError, 'Unknown file type' if stat.ftype == 'unknown'
|
135
|
+
# Stat returns "link" for symlink, not "symlink"
|
136
|
+
proto.ftype = stat.symlink? ? :s : stat.ftype[0].to_sym
|
137
|
+
proto.pathname = actual ? actual : path
|
138
|
+
proto.part = nil
|
139
|
+
proto.install_class = DEFAULT_INSTALL_CLASS
|
140
|
+
if [ :b, :c ].include?( proto.ftype )
|
141
|
+
proto.major = stat.dev_major
|
142
|
+
proto.minor = stat.dev_minor
|
143
|
+
end
|
144
|
+
proto.mode = stat.mode & 07777
|
145
|
+
proto.owner = Etc.getpwuid( stat.uid ).name
|
146
|
+
proto.group = Etc.getgrgid( stat.gid ).name
|
147
|
+
proto
|
148
|
+
end
|
149
|
+
|
150
|
+
# Convert the object to a prototype(4) line (string).
|
151
|
+
def to_s
|
152
|
+
( ( @part ? [ @part ] : [] ) +
|
153
|
+
case @ftype
|
154
|
+
when :b, :c
|
155
|
+
[ @ftype.to_s, @install_class, @pathname, @major, @minor, '%04o' % @mode, @owner, @group ]
|
156
|
+
when :d, :e, :f, :p, :v, :x
|
157
|
+
[ @ftype.to_s, @install_class, @pathname, '%04o' % @mode, @owner, @group ]
|
158
|
+
when :i
|
159
|
+
[ @ftype.to_s, @pathname ]
|
160
|
+
when :l, :s
|
161
|
+
[ @ftype.to_s, @install_class, @pathname ]
|
162
|
+
else
|
163
|
+
raise RuntimeError, "Unknown ftype #{@ftype.inspect}"
|
164
|
+
end ).join(' ')
|
165
|
+
end
|
166
|
+
|
167
|
+
# Returns true if the object is a valid prototype specification, false
|
168
|
+
# otherwise.
|
169
|
+
def valid?
|
170
|
+
begin
|
171
|
+
self.class.from_line( to_s )
|
172
|
+
rescue ArgumentError, RuntimeError
|
173
|
+
false
|
174
|
+
else
|
175
|
+
true
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
|
180
|
+
end # Prototype
|
181
|
+
|
182
|
+
end # Solaris
|
183
|
+
|
@@ -0,0 +1,108 @@
|
|
1
|
+
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
# Unit tests for Solaris::Prototype.
|
5
|
+
class TestPrototype < Test::Unit::TestCase #:nodoc:
|
6
|
+
|
7
|
+
# These don't work on Cygwin. They might work on proper unices.
|
8
|
+
#def test_from_path_file
|
9
|
+
# assert( Solaris::Prototype.from_path( __FILE__ ).valid? )
|
10
|
+
#end
|
11
|
+
#
|
12
|
+
#def test_from_path_root
|
13
|
+
# assert( Solaris::Prototype.from_path( '/' ).valid? )
|
14
|
+
#end
|
15
|
+
|
16
|
+
def test_character_device
|
17
|
+
line = 'c none /dev/null 13 2 0666 root sys'
|
18
|
+
proto = Solaris::Prototype.from_line( line )
|
19
|
+
assert_equal( :c, proto.ftype )
|
20
|
+
assert_equal( 'none', proto.install_class )
|
21
|
+
assert_equal( '/dev/null', proto.pathname )
|
22
|
+
assert_equal( 13, proto.major )
|
23
|
+
assert_equal( 2, proto.minor )
|
24
|
+
assert_equal( 438, proto.mode )
|
25
|
+
assert_equal( 'root', proto.owner )
|
26
|
+
assert_equal( 'sys', proto.group )
|
27
|
+
assert( proto.valid? )
|
28
|
+
assert_equal( line, proto.to_s )
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_symbolic_link
|
32
|
+
line = 's none /etc/hosts=./inet/hosts'
|
33
|
+
proto = Solaris::Prototype.from_line( line )
|
34
|
+
assert_equal( :s, proto.ftype )
|
35
|
+
assert_equal( 'none', proto.install_class )
|
36
|
+
assert_equal( '/etc/hosts=./inet/hosts', proto.pathname )
|
37
|
+
assert_equal( nil, proto.major )
|
38
|
+
assert_equal( nil, proto.minor )
|
39
|
+
assert_equal( nil, proto.mode )
|
40
|
+
assert_equal( nil, proto.owner )
|
41
|
+
assert_equal( nil, proto.group )
|
42
|
+
assert( proto.valid? )
|
43
|
+
assert_equal( line, proto.to_s )
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_directory
|
47
|
+
line = 'd none /export/home/martin 0755 mcarpenter staff'
|
48
|
+
proto = Solaris::Prototype.from_line( line )
|
49
|
+
assert_equal( :d, proto.ftype )
|
50
|
+
assert_equal( 'none', proto.install_class )
|
51
|
+
assert_equal( '/export/home/martin', proto.pathname )
|
52
|
+
assert_equal( nil, proto.major )
|
53
|
+
assert_equal( nil, proto.minor )
|
54
|
+
assert_equal( 493, proto.mode )
|
55
|
+
assert_equal( 'mcarpenter', proto.owner )
|
56
|
+
assert_equal( 'staff', proto.group )
|
57
|
+
assert( proto.valid? )
|
58
|
+
assert_equal( line, proto.to_s )
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_file
|
62
|
+
line = 'f none /export/home/martin/.profile 0755 mcarpenter staff'
|
63
|
+
proto = Solaris::Prototype.from_line( line )
|
64
|
+
assert_equal( :f, proto.ftype )
|
65
|
+
assert_equal( 'none', proto.install_class )
|
66
|
+
assert_equal( '/export/home/martin/.profile', proto.pathname )
|
67
|
+
assert_equal( nil, proto.major )
|
68
|
+
assert_equal( nil, proto.minor )
|
69
|
+
assert_equal( 493, proto.mode )
|
70
|
+
assert_equal( 'mcarpenter', proto.owner )
|
71
|
+
assert_equal( 'staff', proto.group )
|
72
|
+
assert( proto.valid? )
|
73
|
+
assert_equal( line, proto.to_s )
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_part
|
77
|
+
line = 'f none /export/home/martin/.profile 0755 mcarpenter staff'
|
78
|
+
proto = Solaris::Prototype.from_line( line )
|
79
|
+
proto.part = 'part'
|
80
|
+
assert_equal( "part #{line}", proto.to_s )
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_unknown_ftype
|
84
|
+
line = 'X none /export/home/martin/.profile 0755 mcarpenter staff'
|
85
|
+
assert_raise ArgumentError do
|
86
|
+
Solaris::Prototype.from_line( line )
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_unparseable_line
|
91
|
+
line = 'f nonsense'
|
92
|
+
assert_raise ArgumentError do
|
93
|
+
Solaris::Prototype.from_line( line )
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_valid
|
98
|
+
line = 'f none /export/home/martin/.profile 0755 mcarpenter staff'
|
99
|
+
proto = Solaris::Prototype.from_line( line )
|
100
|
+
assert( proto.valid? )
|
101
|
+
proto.ftype = :invalid
|
102
|
+
assert( ! proto.valid? )
|
103
|
+
proto.ftype = :d
|
104
|
+
assert( proto.valid? )
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
require 'test/unit'
|
3
|
+
require 'solaris'
|
4
|
+
|
5
|
+
# Unit tests for top level require.
|
6
|
+
class TestSolaris < Test::Unit::TestCase #:nodoc:
|
7
|
+
|
8
|
+
def test_solaris
|
9
|
+
assert_nothing_raised { Solaris }
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_solaris_prototype
|
13
|
+
assert_nothing_raised { Solaris::Prototype }
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: solaris-prototype
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Martin Carpenter
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-09-15 00:00:00.000000000Z
|
13
|
+
dependencies: []
|
14
|
+
description: Parse and write Solaris package prototype records
|
15
|
+
email: mcarpenter@free.fr
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files:
|
19
|
+
- LICENSE
|
20
|
+
- Rakefile
|
21
|
+
- README.rdoc
|
22
|
+
files:
|
23
|
+
- lib/solaris/prototype.rb
|
24
|
+
- lib/solaris.rb
|
25
|
+
- test/test_solaris.rb
|
26
|
+
- test/test_prototype.rb
|
27
|
+
- LICENSE
|
28
|
+
- Rakefile
|
29
|
+
- README.rdoc
|
30
|
+
homepage: http://mcarpenter.org/projects/solaris-prototype
|
31
|
+
licenses:
|
32
|
+
- BSD
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ! '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ! '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
requirements: []
|
50
|
+
rubyforge_project:
|
51
|
+
rubygems_version: 1.8.10
|
52
|
+
signing_key:
|
53
|
+
specification_version: 3
|
54
|
+
summary: Parse and write Solaris package prototype records
|
55
|
+
test_files:
|
56
|
+
- test/test_solaris.rb
|
57
|
+
- test/test_prototype.rb
|