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 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
+
@@ -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).
@@ -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
+
@@ -0,0 +1,8 @@
1
+
2
+ # Namespace for child classes.
3
+ module Solaris
4
+
5
+ require 'solaris/prototype'
6
+
7
+ end # Solaris
8
+
@@ -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