qrpm 0.0.1

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
+ SHA256:
3
+ metadata.gz: 5a7181b2cc45c65645e039fc5fba4d758698e2558acafe9f9173a955f7af7895
4
+ data.tar.gz: 714b179b5f0f235ddd7b6098ea674579fc8dec671db6d76570e9c9128d7edae7
5
+ SHA512:
6
+ metadata.gz: eaf5dc6516f01dcc9a912f1982f7008f2d1ff667aff8cabf9197945726d43690bc4d28836a186d2a3f5b245f17ecf2d8c7744facbdd7fe6f81d8d32aaf6ce3c3
7
+ data.tar.gz: eb40981a98a3408f545ef8b42ce6a9f1f70657393886542857911f74865759e2227de458648a04c94a0b9edcc3d18a8a5b54ca3035f6c15fc8ddca5a057f7501
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.7.1
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in qrpm.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "rspec", "~> 3.0"
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # Qrpm
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/qrpm`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'qrpm'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle install
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install qrpm
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/qrpm.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "qrpm"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require "irb"
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/clean ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/bash
2
+
3
+ rm -rf example/{my_package_name,tmp,my_package_name.tar.gz}
data/cmd ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/bash
2
+
3
+ set -e
4
+
5
+ VERSION=1.2.4
6
+ PG_VERSION=13
7
+
8
+ rm -f example/*.rpm
9
+ #sudo rpm -e my_package_name 2>/dev/null || true
10
+ bundle exec exe/qrpm $@ --force -C example VERSION=$VERSION PG_VERSION=$PG_VERSION qrpm.yml
11
+ #sudo rpm -i example/my_package_name-1.2.3-4.x86_64.rpm
12
+
@@ -0,0 +1 @@
1
+ hej
File without changes
data/example/qrpm.yml ADDED
@@ -0,0 +1,31 @@
1
+
2
+ name: my_package_name
3
+ summary: This is a summary of the package
4
+ description: Optional longer description of the package
5
+ version: 1.2.3
6
+ release: 4
7
+ packager: null
8
+ requires:
9
+ - ruby
10
+ - httpd
11
+ - postgresql13
12
+
13
+ make: # List of commands to build project
14
+ - echo "Hej du" > bin/another_file
15
+
16
+ bindir:
17
+ - bin/a_file
18
+ - bin/another_file
19
+ - name: an_alias
20
+ file: bin/a_file
21
+
22
+ sbindir:
23
+ - link: /bin/a_file
24
+
25
+ pcksharedir:
26
+ - share/some_data
27
+
28
+ vardir:
29
+ - share/some_other_data
30
+
31
+
@@ -0,0 +1 @@
1
+ hejdu
File without changes
data/exe/qrpm ADDED
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #$LOAD_PATH.unshift "/home/clr/prj/shellopts/lib"
4
+
5
+ require_relative '../lib/qrpm/qrpm.rb'
6
+ require_relative '../lib/qrpm.rb'
7
+
8
+ require 'yaml'
9
+ require 'shellopts'
10
+ require 'indented_io'
11
+
12
+ # TODO
13
+ # o Fix BuildRoot (contains absolute path)
14
+ # o Enable escape of $
15
+
16
+ begin
17
+ SPEC = %(
18
+ @ Quick RPM builder
19
+
20
+ 'qrpm' creates a RPM package from a simple YAML specification file
21
+
22
+ A template YAML qrpm configuration file can be generated by the --template
23
+ option. It is in YAML format with the extension that a single '__END__'
24
+ terminates the file and that $NAME or ${NAME} are variables that will be
25
+ expanded. The variables can either be specified in the configuration file
26
+ or given on the command line in <variable>=<value> format
27
+
28
+ -- VARIABLE=VALUE... [QRPM-FILE]
29
+
30
+ -t,template=OFILE?
31
+ Generate a template qrpm.yml file in the current directory. Customize it
32
+ to create RPM packages of your project
33
+
34
+ -s,spec=OFILE?
35
+ Only create the spec file and not the RPM package. Use this option to
36
+ inspect what RPM is going to do
37
+
38
+ -S,source
39
+ Create a source RPM file instead of a regular RPM file
40
+
41
+ -f,force
42
+ Create package even if repository is dirty. Normally qrpm checks if the
43
+ current directory is a Git directory and then if there are no changed
44
+ files
45
+
46
+ -C,directory=EDIR
47
+ Change to directory before doing anything else
48
+
49
+ -d,dump
50
+ Dump internal data and exit
51
+ )
52
+
53
+ opts, args = ShellOpts.process(SPEC, ARGV)
54
+
55
+ Dir.chdir(opts.directory) if opts.directory?
56
+
57
+ if opts.template?
58
+ outfile = opts.template || Qrpm::QRPM_CONFIG_FILE
59
+ FileUtils::cp Qrpm::QRPM_CONFIG_FILE_TEMPLATE, outfile
60
+ exit
61
+ end
62
+
63
+ # Collect var=val settings in the dict hash and sets the configuration file
64
+ dict = {}
65
+ while arg = args.extract(0..1)
66
+ if arg =~ /^(.*?)=(.*)$/
67
+ dict[$1] = $2
68
+ else
69
+ file = arg
70
+ break
71
+ end
72
+ end
73
+ args.empty? or args.expect(0) # Generates an illegal-number-of-arguments error
74
+
75
+ # Check configuration file
76
+ file ||= QRPM_CONFIG_FILE
77
+ ::File.exist?(file) or raise "Can't find '#{file}'"
78
+
79
+ # Check if repository is clean
80
+ opts.force? || `git status --porcelain 2>/dev/null` == "" or raise "Repository is dirty"
81
+
82
+ # Load the qrpm configuration file
83
+ yaml = YAML.load(IO.read(file).sub(/^__END__\s*$/m, ""))
84
+
85
+ # Parse QRPM file
86
+ rpm = Qrpm::Parser.parse(dict, yaml)
87
+
88
+ if opts.dump?
89
+ rpm.dump
90
+ exit
91
+ end
92
+
93
+ target = (opts.spec? ? :spec : (opts.source? ? :srpm : :rpm))
94
+ rpm.build(target: target, file: opts.spec)
95
+
96
+ rescue RuntimeError => ex
97
+ ShellOpts.error ex.message
98
+ end
99
+
data/lib/qrpm/node.rb ADDED
@@ -0,0 +1,54 @@
1
+
2
+ module Qrpm
3
+ class Node
4
+ attr_reader :directory # Destination directory
5
+ attr_reader :name # Defaults to last element of file/link
6
+ def path() "#{directory}/#{name}" end
7
+
8
+ def initialize(directory, name)
9
+ @directory, @name = directory, name
10
+ end
11
+
12
+ def file?() self.class == Qrpm::File end
13
+ def link?() self.class == Qrpm::Link end
14
+
15
+ def dump(&block)
16
+ puts self.class
17
+ indent {
18
+ puts "directory: #{directory}"
19
+ puts "name : #{name}"
20
+ yield if block_given?
21
+ }
22
+ end
23
+ end
24
+
25
+ class File < Node
26
+ attr_reader :file # Path to file in the source repository
27
+ attr_reader :perm # Defaults to nil - using the current permissions
28
+ def initialize(directory, name, file, perm = nil)
29
+ super(directory, name || file.sub(/.*\//, ""))
30
+ @file, @perm = file, perm
31
+ end
32
+ def dump
33
+ super {
34
+ puts "file : #{file}"
35
+ puts "perm : #{perm}"
36
+ }
37
+ end
38
+ end
39
+
40
+ class Link < Node
41
+ attr_reader :link # Destination file of link
42
+
43
+ def initialize(directory, name, link)
44
+ super(directory, name || link.sub(/.*\//, ""))
45
+ @link = link
46
+ end
47
+ def dump
48
+ super {
49
+ puts "link : #{link}"
50
+ }
51
+ end
52
+ end
53
+ end
54
+
@@ -0,0 +1,173 @@
1
+
2
+ module Qrpm
3
+ class Parser
4
+ DICT_FIELDS = (Rpm::FIELDS - %w(requires)).map { |f| [f, true] }.to_h
5
+
6
+ attr_reader :fields # Hash from field to value (which can be of any type)
7
+ attr_reader :dirs # Hash from directory to list of entries
8
+ attr_reader :files # List of files
9
+ attr_reader :rpm # Resulting RPM object
10
+
11
+ def initialize(fields)
12
+ @fields = fields.dup
13
+ @dirs = {}
14
+ @files = []
15
+ end
16
+
17
+ def parse(yaml)
18
+ # Collect .qrpm file variables and directories and the list of required
19
+ # packages. Variables are merged into +fields+
20
+ yaml.each { |k,v|
21
+ if k =~ /[\/.]/ || DIRS.key?(k) || DIRS.key?(k.sub(/^pck/, ""))
22
+ (dirs[k] ||= []).concat v
23
+ elsif k =~ /^[\w_]+$/
24
+ fields[k] = v if !fields.key?(k)
25
+ else
26
+ raise "Illegal key/value: #{k}: #{v}"
27
+ end
28
+ }
29
+
30
+ # Check for mandatory variables
31
+ Rpm::MANDATORY_FIELDS.each { |f|
32
+ fields.key?(f) or raise "Missing mandatory variable: #{f}"
33
+ }
34
+
35
+ # Defaults for description and packager fields
36
+ fields["description"] ||= fields["summary"]
37
+ fields["packager"] ||= ENV['USER']
38
+ fields["release"] ||= "0"
39
+ fields["license"] ||= "GPL"
40
+
41
+ # Expand variables in fields. The expansion mechanism doesn't depend on the order
42
+ # of the variables
43
+ expand_fields
44
+
45
+ # Replace symbolic directory names
46
+ @dirs = dirs.map { |dir, files|
47
+ if DIRS.key?(dir)
48
+ dir = DIRS[dir]
49
+ elsif dir =~ /^pck(.*)$/ && DIRS.key?($1)
50
+ dir = "#{DIRS[$1]}/#{fields["name"]}"
51
+ end
52
+ [dir, files]
53
+ }.to_h
54
+
55
+ # Build files
56
+ dirs.each { |dir, nodes|
57
+ nodes.each { |node|
58
+ case node
59
+ when Hash
60
+ node = node.dup
61
+ if node.key?("file")
62
+ name = node.delete("name")
63
+ file = node.delete("file")
64
+ perm = node.delete("perm")
65
+ node.empty? or raise "Illegal keys for file in directory #{dir}: #{node.keys}"
66
+ files << Qrpm::File.new(dir, name, file, perm)
67
+ elsif node.key?("link")
68
+ name = node.delete("name")
69
+ link = node.delete("link")
70
+ node.empty? or raise "Illegal keys for link in directory #{dir}: #{node.keys}"
71
+ files << Qrpm::Link.new(dir, name, link)
72
+ else
73
+ raise "Need either a 'file' or 'link' field for directory #{dir}"
74
+ end
75
+ when String
76
+ files << Qrpm::File.new(dir, nil, node, nil)
77
+ else
78
+ raise "Illegal value for directory #{dir}: #{node}"
79
+ end
80
+ }
81
+ }
82
+
83
+ @rpm = Rpm.new(fields, files)
84
+ end
85
+
86
+ def self.parse(dict, yaml)
87
+ Parser.new(dict).parse(yaml)
88
+ end
89
+
90
+ private
91
+ MANDATORY_FIELDS = %w(name summary version)
92
+
93
+ DIRS = {
94
+ "etcdir" => "/etc",
95
+ "bindir" => "/usr/bin",
96
+ "sbindir" => "/usr/sbin",
97
+ "libdir" => "/usr/lib",
98
+ "libexecdir" => "/usr/libexec",
99
+ "sharedir" => "/usr/share",
100
+ "vardir" => "/var/lib",
101
+ "spooldir" => "/var/spool",
102
+ "rundir" => "/var/run",
103
+ "lockdir" => "/var/lock",
104
+ "cachedir" => "/var/cache",
105
+ "tmpdir" => "/tmp",
106
+ "logdir" => "/var/log"
107
+ }
108
+
109
+ # Returns array of variables in the object. Variables can be either '$name' or
110
+ # '${name}'. The variables are returned in left-to-right order
111
+ #
112
+ def collect_variables(object, include_keys: false)
113
+ case object
114
+ when Array; object.map { |obj| collect_variables(obj) }
115
+ when Hash; object.map { |k,v| (include_keys ? collect_variables(k) : []) + collect_variables(v) }
116
+ when String; object.scan(/\$([\w_]+)|\$\{([\w_]+)\}/)
117
+ when Integer, Float, true, false, nil; []
118
+ else
119
+ raise "Illegal object: #{object}"
120
+ end.flatten.compact.uniq
121
+ end
122
+
123
+ # Expand variables in the given string
124
+ #
125
+ # The method takes case to substite left-to-rigth to avoid a variable expansion
126
+ # to infer with the name of an immediately preceding variable. Eg. $a$b; if $b
127
+ # is resolved to 'c' then a search would otherwise be made for a variable named
128
+ # '$ac'
129
+ #
130
+ def expand_variables(object, include_key: false)
131
+ case object
132
+ when Array; object.map { |e| expand_variables(e) }
133
+ when Hash; object.map { |k,v| [expand_variables(k), expand_variables(v)] }.to_h
134
+ when String
135
+ s = object.dup
136
+ collect_variables(object).each { |k| s.sub!(/\$#{k}|\$\{#{k}\}/, fields[k].to_s) }
137
+ s
138
+ when Integer, Float, true, false, nil; object
139
+ else
140
+ raise "Illegal object: #{object}"
141
+ end
142
+ end
143
+
144
+ # Expands fields (but not directories). The algorithm allows fields to be
145
+ # defined in any order
146
+ #
147
+ def expand_fields
148
+ variables = fields.map { |k,v| [k, collect_variables(v)] }.to_h
149
+ variables.values.flatten.uniq.each { |var|
150
+ fields[var].nil? || fields[var].is_a?(String) or "Can't use '#{var}' as variable"
151
+ }
152
+
153
+ @fields, unresolved = fields.partition { |k,v| variables[k].empty? }.map(&:to_h)
154
+ changed = true
155
+ while changed && !unresolved.empty?
156
+ changed = false
157
+ unresolved.delete_if { |k,v|
158
+ if variables[k].all? { |var| fields.key? var }
159
+ fields[k] = expand_variables(unresolved[k])
160
+ changed = true
161
+ end
162
+ }
163
+ end
164
+ unresolved.empty? or raise "Unresolved variables: #{unresolved.join(", ")}"
165
+ end
166
+
167
+ def expand_dirs
168
+ @dirs = expand_variables(dirs)
169
+ end
170
+ end
171
+ end
172
+
173
+
data/lib/qrpm/qrpm.rb ADDED
@@ -0,0 +1,63 @@
1
+
2
+ __END__
3
+ # Returns array of variables in the string. Variables can be either '$name' or
4
+ # '${name}'. The variables are returned in left-to-right order
5
+ #
6
+ def collect_exprs(expr)
7
+ expr.scan(/\$([\w_]+)|\$\{([\w_]+)\}/).flatten.compact
8
+ end
9
+
10
+ # Expand variables in the given string
11
+ #
12
+ # The method takes case to substite left-to-rigth to avoid a variable expansion
13
+ # to infer with the name of an immediately preceding variable. Eg. $a$b; if $b
14
+ # is resolved to 'c' then a search would otherwise be made for a variable named
15
+ # '$ac'
16
+ #
17
+ def expand_expr(dict, value)
18
+ value = value.dup
19
+ collect_exprs(value).each { |k| value.sub!(/\$#{k}|\$\{#{k}\}/, dict[k]) }
20
+ value
21
+ end
22
+
23
+ def expand_dict(dict)
24
+ expressions = dict.map { |k,v| [k, collect_exprs(v)] }.to_h
25
+ result = expressions.select { |k, v| v.empty? }.map { |k,v| [k, dict[k]] }.to_h
26
+ unresolved = dict.keys - result.keys
27
+
28
+ changed = true
29
+ while changed && !unresolved.empty?
30
+ changed = false
31
+ unresolved.delete_if { |k|
32
+ if expressions[k].all? { |var| result.key? var }
33
+ result[k] = expand_expr(result, dict[k])
34
+ changed = true
35
+ end
36
+ }
37
+ end
38
+ unresolved.empty? or raise "Unresolved variables: #{unresolved.join(", ")}"
39
+
40
+ result
41
+ end
42
+
43
+ # +value+ will typically be a dirs hash
44
+ def expand_object(dict, object)
45
+ case object
46
+ when Array; object.map { |v| expand_object(dict, v) }
47
+ when Hash
48
+ object.map { |k,v|
49
+ key = expand_expr(dict, k)
50
+ object = expand_object(dict, v)
51
+ [key, object]
52
+ }.to_h
53
+ when String
54
+ expand_expr(dict, object)
55
+ else
56
+ object
57
+ end
58
+ end
59
+
60
+ def expand_dirs(dict, dirs)
61
+ expand_object(dict, dirs)
62
+ end
63
+
@@ -0,0 +1,25 @@
1
+ module Qrpm
2
+ class RpmBuilder
3
+ def initialize
4
+ end
5
+
6
+ def build
7
+ # Create directories
8
+
9
+ # Collect sources
10
+
11
+ # Copy sources
12
+
13
+ # Create spec file
14
+ end
15
+
16
+
17
+ end
18
+
19
+
20
+
21
+
22
+ def render(dict, files)
23
+
24
+ end
25
+ end
data/lib/qrpm/rpm.rb ADDED
@@ -0,0 +1,114 @@
1
+ require 'erb'
2
+ require 'fileutils'
3
+
4
+ module Qrpm
5
+ class Rpm
6
+ # Defines the following member methods:
7
+ #
8
+ # name Package name
9
+ # version Version
10
+ # release Release
11
+ # license License (defaults to GPL)
12
+ # summary Short one-line description of package
13
+ # description Description
14
+ # packager Name of the packager (defaults to the value of the $USER
15
+ # environment variable)
16
+ # require Array of required packages
17
+ # make Controls the build process:
18
+ # null Search the top-level directory for configure or
19
+ # make files and runs them. Skip building if not
20
+ # found. This is the default
21
+ # true Expect the top-level directory to contain
22
+ # configure make files and runs them. It is an
23
+ # error if the Makefile is missing
24
+ # (array of commands)
25
+ # Runs the commands to build the project
26
+ #
27
+ FIELDS = %w(name version release group license summary description packager requires make)
28
+ MANDATORY_FIELDS = %w(name summary version)
29
+ TEMPLATE = "#{::File.dirname(__FILE__)}/template.erb"
30
+
31
+ RPM_DIRS = %w(SOURCES BUILD RPMS SPECS SRPMS tmp)
32
+
33
+ # Field accessor methods
34
+ FIELDS.each { |f| eval "def #{f}() @fields[\"#{f}\"] end" }
35
+
36
+ attr_reader :fields
37
+ attr_reader :nodes
38
+
39
+ # The content of the SPEC file
40
+ attr_reader :spec
41
+
42
+ def files() @files ||= nodes.select(&:file?) end
43
+ def links() @lines ||= nodes.select(&:link?) end
44
+
45
+ def has_configure?() ::File.exist? "configure" end
46
+ def has_make?() ::File.exist? "make" end
47
+
48
+ def initialize(fields, nodes, template: TEMPLATE)
49
+ @fields, @nodes = fields, nodes
50
+ @template = template
51
+ end
52
+
53
+ def build(target: :rpm, file: nil)
54
+ Dir.mktmpdir { |rootdir|
55
+ rootdir = "/home/clr/prj/qrpm/tmp"
56
+ FileUtils.rm_rf(rootdir)
57
+ FileUtils.mkdir_p(rootdir)
58
+
59
+ spec_file = file || "#{name}.spec"
60
+ tar_file = "#{name}.tar.gz"
61
+ spec_path = "#{rootdir}/SPECS/#{spec_file}"
62
+ tar_path = "#{rootdir}/SOURCES/#{tar_file}"
63
+
64
+ # Create directories
65
+ RPM_DIRS.each { |dir| FileUtils.mkdir_p "#{rootdir}/#{dir}" }
66
+
67
+ # Directory for tarball creation. This lives inside the RPM directory
68
+ # structure and is removed before we start rpmbuild
69
+ tarroot = "#{rootdir}/tmp/#{name}"
70
+ FileUtils.mkdir(tarroot)
71
+
72
+ # Copy files
73
+ FileUtils.cp_r(".", tarroot, preserve: true)
74
+
75
+ # Roll tarball and put it in the SOURCES directory
76
+ system "tar zcf #{tar_path} -C #{rootdir}/tmp #{name}" or raise "Can't roll tarball"
77
+
78
+ # Remove temporary tar dir
79
+ FileUtils.rm_rf tarroot
80
+
81
+ # Create spec file
82
+ renderer = ERB.new(IO.read(@template).sub(/^__END__\n.*/m, ""), trim_mode: "-")
83
+ @spec = renderer.result(binding)
84
+
85
+ # Emit spec or build RPM
86
+ if target == :spec
87
+ IO.write(spec_file, @spec)
88
+ else
89
+ IO.write(spec_path, @spec)
90
+ system "rpmbuild -v -ba --define \"_topdir #{rootdir}\" #{rootdir}/SPECS/#{name}.spec" or
91
+ raise "Failed building RPM file"
92
+ if target == :srpm
93
+ system "cp #{rootdir}/SRPMS/* ." or raise "Failed copying SRPM file"
94
+ elsif target == :rpm
95
+ system "cp #{rootdir}/RPMS/*/#{name}-[0-9]* ." or raise "Failed copying RPM file"
96
+ else
97
+ raise ArgumentError, "Not a valid value for :target - #{target.inspect}"
98
+ end
99
+ end
100
+ }
101
+ end
102
+
103
+ def dump
104
+ puts self.class
105
+ indent {
106
+ puts "fields"
107
+ indent { fields.each { |k,v| puts "#{k}: #{v.inspect}" } }
108
+ puts "nodes"
109
+ indent { nodes.map(&:dump) }
110
+ }
111
+ end
112
+ end
113
+ end
114
+
@@ -0,0 +1,73 @@
1
+
2
+ Name: <%= name %>
3
+ Summary: <%= summary %>
4
+ Version: <%= version %>
5
+ Release: <%= release %>
6
+ License: <%= license %>
7
+ Packager: <%= packager %>
8
+ <% if group -%>
9
+ Group: <%= group %>
10
+ <% end -%>
11
+ <% for pck in requires || [] -%>
12
+ Requires: <%= pck %>
13
+ <% end -%>
14
+ Source: %{name}.tar.gz
15
+ BuildRoot: <%= rootdir %>/tmp/%{name}-%{version}
16
+
17
+ %description
18
+ <%= description %>
19
+
20
+ %prep
21
+ %setup -n <%= name %>
22
+
23
+ %build
24
+ <% if make.nil? -%>
25
+ <% if has_configure? -%>
26
+ ./configure
27
+ <% end -%>
28
+ <% if has_make? -%>
29
+ make
30
+ <% end -%>
31
+ <% elsif make == false -%>
32
+ <% elsif make == true -%>
33
+ <% if has_configure? -%>
34
+ ./configure
35
+ <% end -%>
36
+ make
37
+ <% elsif make.is_a? Array -%>
38
+ <% for cmd in make -%>
39
+ <%= cmd %>
40
+ <% end -%>
41
+ <% end -%>
42
+
43
+ %install
44
+ mkdir -p <%= nodes.map { |f| "%{buildroot}#{f.directory}" }.uniq.join(" ") %>
45
+ <% for file in files -%>
46
+ cp <%= file.file %> %{buildroot}<%= file.path %>
47
+ <% end -%>
48
+ <% for link in links -%>
49
+ touch %{buildroot}<%= link.path %>
50
+ <% end -%>
51
+
52
+ %files
53
+ <% for file in files -%>
54
+ <%= file.path %>
55
+ <% end -%>
56
+ <% for link in links -%>
57
+ %ghost <%= link.path %>
58
+ <% end -%>
59
+
60
+ %clean
61
+ %if "%{clean}" != ""
62
+ rm -rf %{_topdir}/BUILD/%{name}
63
+ [ $(basename %{buildroot}) == "%{name}-%{version}-%{release}.%{_target_cpu}" ] && rm -rf %{buildroot}
64
+ %endif
65
+
66
+ %post
67
+ <% for file in files.select(&:perm) -%>
68
+ chmod <%= file.perm %> <%= file.path %>
69
+ <% end -%>
70
+ <% for file in links -%>
71
+ ln -sf <%= link.link %> <%= link.path %>
72
+ <% end -%>
73
+
@@ -0,0 +1,88 @@
1
+
2
+ # Package information
3
+ #
4
+ name: # Name of package. It is used in the package name
5
+ summary: # Short summary of package
6
+ description: # Optional longer description
7
+ version: # Version
8
+ release: # Release. Optional
9
+ packager: # Packager, default $USER
10
+ requires: # List of required packages
11
+
12
+ # Build information
13
+ #
14
+ make: null # make can be undefined or null (use make if present), false
15
+ # (don't use make), true (use make), or a list of shell
16
+ # commands to build the project
17
+
18
+ # Directories, files, and links
19
+ #
20
+ # This section contains entries that are (possibly empty) directories with a
21
+ # array of files or links. Directories can either identify a builtin standard
22
+ # directory or be a path to a directory. In the typical case, the directory
23
+ # will contain a simple list of files from the build directory:
24
+ #
25
+ # bindir:
26
+ # - my_bin_files/my_program
27
+ # - my_sh_files/my_shell_script
28
+ #
29
+ # /opt/my_files:
30
+ # - src/my_data
31
+ #
32
+ # The example will create the following files and directories
33
+ #
34
+ # /usr/bin/my_program
35
+ # /usr/bin/my_shell_script
36
+ # /opt/my_files/
37
+ # /opt/my_files/my_data
38
+ #
39
+ # Files can also be specified using the following attributes
40
+ #
41
+ # name: Destination file name. Default is the last path component in :file
42
+ # file: Path to source file
43
+ # perm: Octal permissions. Defaults are the source file's permissions
44
+ #
45
+ # It is used like this
46
+ #
47
+ # /opt/my_files
48
+ # - name: data
49
+ # file: src/my_data
50
+ # perm: 600
51
+ #
52
+ # This will copy src/my_data to a 'data' file in the /opt/my_files directory
53
+ # with permissions 0600
54
+ #
55
+ # Links can only be specified using attributes
56
+ #
57
+ # name: Destination file name. Default is the last path component in :link
58
+ # link: Path to the file that will be pointed to by the link
59
+ #
60
+ # To create a symbolic link in /var/lib/ from my_app to /opt/my_files/data:
61
+ #
62
+ # libdir:
63
+ # - name: my_app
64
+ # link: /opt/my_files/data
65
+ #
66
+ # The following standard directories are defined:
67
+ #
68
+ # etcdir /etc Configuration files
69
+ # bindir /usr/bin Executables
70
+ # sbindir /usr/sbin System executables
71
+ # libdir /usr/lib Libraries (both binary and clear text)
72
+ # libexecdir /usr/libexec Executable subprograms (not meant to be
73
+ # called indepentently)
74
+ # sharedir /usr/share Constant data files. FIXME: Always a subdir
75
+ # vardir /var/lib Variable data files
76
+ # spooldir /var/spool Spool files
77
+ # rundir /var/run Run files
78
+ # lockdir /var/lock Lock files
79
+ # cachedir /var/cache Cache directory
80
+ # tmpdir /tmp Temporary directory (deleted when the '
81
+ # machine starts)
82
+ # logdir /var/log Log directory
83
+ #
84
+ # Each standard directory can also be prefixed a 'pck'. That will create a
85
+ # subdirectory with the package's name in the base standard directory. Eg.
86
+ # 'pcketcdir' will create the directory '/etc/<name>'
87
+ #
88
+
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Qrpm
4
+ VERSION = "0.0.1"
5
+ end
data/lib/qrpm.rb ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "qrpm/version"
4
+ require_relative "qrpm/node.rb"
5
+ require_relative "qrpm/rpm.rb"
6
+ require_relative "qrpm/parser.rb"
7
+
8
+ module Qrpm
9
+ class Error < RuntimeError; end
10
+
11
+ QRPM_CONFIG_FILE = "qrpm.yml"
12
+
13
+ QRPM_SHARE_DIR = "#{::File.dirname(__FILE__)}/../lib/qrpm"
14
+ QRPM_CONFIG_FILE_TEMPLATE = "#{QRPM_SHARE_DIR}/template.yml"
15
+ QRPM_ERB_FILE = "#{QRPM_SHARE_DIR}/template.erb"
16
+ end
data/packager.sh ADDED
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/bash
2
+
3
+ # This scripts creates and build a simple RPM package
4
+ #
5
+ # Prerequisites:
6
+ # - rpm-build, make and gcc (as it's a c file) packages must be installed
7
+ #
8
+
9
+ # Ref. http://aerostitch.github.io/linux_and_unix/RedHat/build_sample_rpm.html
10
+
11
+ # Holds the name of the root directory containing the necessary structure to
12
+ # build RPM packages.
13
+ RPM_ROOT_DIR=~/rpm_factory
14
+
15
+ PKG_NAME=dummy_package
16
+ PKG_TAR=/tmp/${PKG_NAME}.tar.gz
17
+ BINARY_FILE=hello_world
18
+ # Recreate the root directory and its structure if necessary
19
+ mkdir -p ${RPM_ROOT_DIR}/{SOURCES,BUILD,RPMS,SPECS,SRPMS,tmp}
20
+ pushd $RPM_ROOT_DIR
21
+ cp ${PKG_TAR} ${RPM_ROOT_DIR}/SOURCES/
22
+
23
+ # Creating a basic spec file
24
+ cat << __EOF__ > ${RPM_ROOT_DIR}/SPECS/${PKG_NAME}.spec
25
+ Summary: This package is a sample for quickly build dummy RPM package.
26
+ Name: $PKG_NAME
27
+ Version: 1.0
28
+ Release: 0
29
+ License: GPL
30
+ Packager: $USER
31
+ Group: Development/Tools
32
+ Source: %{name}.tar.gz
33
+ BuildRequires: coreutils
34
+ BuildRoot: ${RPM_ROOT_DIR}/tmp/%{name}-%{version}
35
+
36
+ %description
37
+ %{summary}
38
+
39
+ %prep
40
+ %setup -n ${PKG_NAME}
41
+
42
+ %build
43
+ make $BINARY_FILE
44
+
45
+ %install
46
+ mkdir -p "%{buildroot}/opt/${PKG_NAME}"
47
+ cp $BINARY_FILE "%{buildroot}/opt/${PKG_NAME}/"
48
+
49
+ %files
50
+ /opt/${PKG_NAME}/hello_world
51
+
52
+ %clean
53
+ %if "%{clean}" != ""
54
+ rm -rf %{_topdir}/BUILD/%{name}
55
+ [ $(basename %{buildroot}) == "%{name}-%{version}-%{release}.%{_target_cpu}" ] && rm -rf %{buildroot}
56
+ %endif
57
+
58
+ %post
59
+ chmod 755 -R /opt/${PKG_NAME}
60
+ __EOF__
61
+
62
+ rpmbuild -v -bb --define "_topdir ${RPM_ROOT_DIR}" SPECS/${PKG_NAME}.spec
63
+ popd
64
+
65
+
data/packager.yml ADDED
@@ -0,0 +1,32 @@
1
+
2
+ name: my_package_name$pg_version
3
+ summary: This is a summary of the package
4
+ description: Optional longer description of the package
5
+ version: 1.2.3
6
+ release: $pg_version.$perm
7
+ packager: null
8
+ requires:
9
+ - ruby
10
+ - apache
11
+ - postgres$pg_version
12
+
13
+ pg_version: 13
14
+ perm: 755
15
+ root: example
16
+
17
+ bindir:
18
+ - $root/bin/a_file
19
+ - $root/bin/another_file
20
+ - name: an_alias
21
+ file: $root/bin/a_file
22
+
23
+ sbindir:
24
+ - link: /bin/a_file
25
+
26
+ pcksharedir:
27
+ - $root/share/some_data
28
+
29
+ vardir:
30
+ - $root/share/some_other_data
31
+
32
+
data/program.sh ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/bash
2
+
3
+ # Ref. http://aerostitch.github.io/linux_and_unix/RedHat/build_sample_rpm.html
4
+
5
+ PKG_NAME=dummy_package
6
+ PKG_DIR=/tmp/${PKG_NAME}
7
+ mkdir -p ${PKG_DIR}
8
+
9
+ cat << __EOF__ > ${PKG_DIR}/hello_world.c
10
+ #include <stdio.h>
11
+ int main(){
12
+ printf("Hello world!\n");
13
+ return 0;
14
+ }
15
+ __EOF__
16
+
17
+ pushd ${PKG_DIR}/..
18
+ tar czvf ${PKG_NAME}.tar.gz ${PKG_NAME}
19
+ popd
data/qrpm.gemspec ADDED
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/qrpm/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "qrpm"
7
+ spec.version = Qrpm::VERSION
8
+ spec.authors = ["Claus Rasmussen"]
9
+ spec.email = ["claus.l.rasmussen@gmail.com"]
10
+
11
+ spec.summary = "Gem qrpm"
12
+ spec.description = "Gem qrpm"
13
+ spec.homepage = "http://www.nowhere.com/"
14
+ spec.required_ruby_version = ">= 2.4.0"
15
+
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
22
+ `git ls-files -z`.split("\x0").reject do |f|
23
+ (f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
24
+ end
25
+ end
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_dependency "shellopts", "~> 2.0.0"
31
+ spec.add_dependency "indented_io"
32
+
33
+ # Uncomment to register a new dependency of your gem
34
+ # spec.add_dependency "example-gem", "~> 1.0"
35
+
36
+ # For more information and examples about making a new gem, checkout our
37
+ # guide at: https://bundler.io/guides/creating_gem.html
38
+
39
+ # Add your production dependencies here
40
+ # spec.add_dependency GEM [, VERSION]
41
+
42
+ # Add your development dependencies here
43
+ # spec.add_development_dependency GEM [, VERSION]
44
+
45
+ # Also un-comment in spec/spec_helper to use simplecov
46
+ # spec.add_development_dependency "simplecov"
47
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: qrpm
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Claus Rasmussen
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-05-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: shellopts
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: indented_io
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Gem qrpm
42
+ email:
43
+ - claus.l.rasmussen@gmail.com
44
+ executables:
45
+ - qrpm
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".rspec"
50
+ - ".ruby-version"
51
+ - Gemfile
52
+ - README.md
53
+ - Rakefile
54
+ - bin/console
55
+ - bin/setup
56
+ - clean
57
+ - cmd
58
+ - example/bin/a_file
59
+ - example/bin/another_file
60
+ - example/qrpm.yml
61
+ - example/share/some_data
62
+ - example/share/some_other_data
63
+ - exe/qrpm
64
+ - lib/qrpm.rb
65
+ - lib/qrpm/node.rb
66
+ - lib/qrpm/parser.rb
67
+ - lib/qrpm/qrpm.rb
68
+ - lib/qrpm/render.rb
69
+ - lib/qrpm/rpm.rb
70
+ - lib/qrpm/template.erb
71
+ - lib/qrpm/template.yml
72
+ - lib/qrpm/version.rb
73
+ - packager.sh
74
+ - packager.yml
75
+ - program.sh
76
+ - qrpm.gemspec
77
+ homepage: http://www.nowhere.com/
78
+ licenses: []
79
+ metadata:
80
+ homepage_uri: http://www.nowhere.com/
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 2.4.0
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements: []
96
+ rubygems_version: 3.1.4
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: Gem qrpm
100
+ test_files: []