qrpm 0.0.3 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 84aec760efd4d34c3de41e77edeeb5cc925ee195bea84243dad283c2ec50005e
4
- data.tar.gz: 99a8f384f3913952ce99ad80f0be8718d3cb4a91d882a5eb82675a5cc63b41b3
3
+ metadata.gz: ed3b4b8014d9d4c6c8ca2f32e5d9a1809c3580bf30e65109bb3211d5a1ab8894
4
+ data.tar.gz: 8266de1abdbbcb6bfe1c1b17eeb88a511a1d7901aa24fe966c9d4a36a401468e
5
5
  SHA512:
6
- metadata.gz: 7416eba4e7747d1fb5603d62a985671e2b8ba40c90d95636c737dbd1c998a3431d2ffeba919e5cff1575efe8dd88b3f43173bddf48e22a3de7cae2e5c30ed868
7
- data.tar.gz: 17108a42af16ffe022c72dda457d4d868e16e98a807e1e61296df1a9f2da02cf7a0ef3322334d04b30b85e782723587bad7b6bb15b537fc4d339fba1c14bc6ae
6
+ metadata.gz: 0223c49eea6b54208c2581ab434a13f8fb1853a44b8f53142401f9d781ff1f490b5b27833a6b63e2efe0881feec546c4549c89d1345e5fb531ddf9a41651b987
7
+ data.tar.gz: b495af8ac986d3032b764bc1cdac6200f57b2f0d967c1950de7edc6da895f21d5c1ce623185d3d98c45ceb18a4b269e2c63f204ae1701d1f460154bb6495cc84
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- ruby-2.7.1
1
+ ruby-3.1.2
data/NOTES ADDED
@@ -0,0 +1,7 @@
1
+
2
+ Random notes that should make it into the documention
3
+
4
+ o Directory nodes are top-level array definitions, optionally suffix with a /
5
+ o Only DirectoryNode keys can include a '/'
6
+ o Only DirectoryNode keys can include variables. What about this:
7
+ o DirectoryNodes can't be referenced
data/TODO ADDED
@@ -0,0 +1,30 @@
1
+ o Rule: Symbol keys are variables, String keys are directories
2
+
3
+ o Use Nodes everywhere -> makes a lot of stuff much easier
4
+
5
+ o Check "dir: file" vs. "dir:\n - file"
6
+
7
+ o Allow shell escapes to return arrays and hashes
8
+
9
+ o Allow directories within directories:
10
+ dir/
11
+ - file
12
+ - subdir/
13
+ - element # Oops: Illegal YAML syntax
14
+
15
+ o What happens if directory declarations maps to the same:
16
+ dir1: dir
17
+ dir2: dir
18
+ $dir1:
19
+ - file
20
+ $dir2:
21
+ - file
22
+
23
+ o Use same naming everywhere: field vs. value, name vs. path etc.
24
+ - "fields" are variables that also are RPM fields
25
+ - "variables" are QRPM variables
26
+
27
+ o Better references to source in error messages: Read input file(s) in parallel
28
+ with parsing of the YAML document (doesn't work with YAML merge/include). Maybe
29
+ decorate strings with lineno/charno and if the YAML module fails we catch the
30
+ error and remove the decoration from the error message
data/doc/pg.yml ADDED
@@ -0,0 +1,37 @@
1
+
2
+ # Default Redhat Postgres definititions
3
+ pg:
4
+ name: "postgres" # Name of the package. It is also the default name for package-specific diretories
5
+ vendor: "redhat"
6
+ version: null # To be specified explicitly or detected dynamically using detect.pg.version
7
+ major_version: $(sed 's/\..*//' <<<${{pg.version}})
8
+ pckdir: pgsql
9
+ etcdir: $pg.vardir/data
10
+ vardir: $vardir/$pg.pckdir
11
+ libdir: $libdir/$pg.pckdir # Assuming libdir points to /usr/lib64
12
+ extdir: $pg.libdir/extension
13
+ sharedir: $sharedir/$pg.pckdir
14
+
15
+ conf_file: $pg.etcdir/postgresql.conf
16
+ hba_file: $pg.etcdir/pg_hba.conf
17
+ ident_file: $pg.etcdir/pg_ident.conf
18
+
19
+ # Detections
20
+ detect:
21
+ pg:
22
+ version: $(pg_config --version | sed 's/^[^0-9]* \([0-9]\+\).*$/\1/')
23
+
24
+ # pgdg overrides
25
+ pg:
26
+ name: postgresql$pg.version
27
+ vendor: "pgdg"
28
+ version: null
29
+ vardir: $vardir/$pg.pckdir/$pg.major_version
30
+ usrdir: /usr/pgsql-$pg.major_version
31
+ libdir: $pg.usrdir/lib
32
+ extdir: $pg.libdir/extension
33
+ sharedir: $pg.usrdir/share
34
+
35
+ pg.version: $detect.pg.version
36
+
37
+
data/doc/qrpm2.rb ADDED
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'yaml'
4
+
5
+ p YAML.load(IO.read("t.yml"))
6
+
7
+ exit
8
+
9
+
10
+
11
+
12
+
13
+ require 'indented_io'
14
+
15
+ s = "member"
16
+
17
+ s =~ /^(\w+)|\[(\d+)\](?:\.|$)/
18
+ p $1
19
+ p $2
20
+
21
+
22
+ __END__
23
+
24
+ a = "1. $a 2. \\$a 3. \\\\$a 4. \\\\\\$a 5. \\\\\\\\$a rest"
25
+ b = "1. ${a} 2. \\${a} 3. \\\\${a} 4. \\\\\\${a} 5. \\\\\\\\${a} rest"
26
+ c = "1. $(a)"
27
+ d = "1. $a $(b $b ${b} ${{b}}) $c \\"
28
+
29
+ IDENT_RE = /(?:[\w_][\w\d_.]*)/
30
+
31
+ # Return an array of prefix/interpolated-variable tuples. The prefix is the
32
+ # string leading up to the variable. $NAME, ${NAME}, and $(COMMAND)
33
+ # interpolations are recognized
34
+ def parse_string(path, string)
35
+ r = string.scan(/(.*?)(\\*)(\$#{IDENT_RE}|\$\{#{IDENT_RE}\}|\$\(.+\)|$)/).map {
36
+ |prefix, backslashes, interpolation|
37
+ p [prefix, backslashes, interpolation]
38
+
39
+
40
+ str = prefix + '\\' * (backslashes.size / 2)
41
+ if backslashes.size % 2 == 0
42
+ var = interpolation
43
+ else
44
+ str += '\\' * (backslashes.size % 2) + interpolation
45
+ end
46
+ [str, var]
47
+ }[0..-2]
48
+ puts
49
+ r
50
+ end
51
+
52
+ #parse_string("a", a).each { |e| p e }
53
+ #exit
54
+
55
+ for s in [a, b, c, d]
56
+ puts "\"#{s}\""
57
+ indent {
58
+ parse_string("fake", s).each { |a|
59
+ p a
60
+ }
61
+ }
62
+ puts
63
+ end
64
+
65
+ #p a.scan(/\S+\s\S+/)
66
+
67
+
68
+ exit
69
+
data/doc/qrpm2.yml ADDED
@@ -0,0 +1,55 @@
1
+ # Qrpm with "functions"
2
+ ---
3
+
4
+ # User-code
5
+ #
6
+ pg:
7
+ vendor: pgdg
8
+
9
+ $user_dir:
10
+ - $pg.postgresql_conf
11
+
12
+ # Standard global variables
13
+ # platform (redhat/debian/etc)
14
+ # vendor (only defined for third-party packages)
15
+ # domain (the network)
16
+ # host (the host)
17
+ #
18
+ # The standard variables are ordered
19
+
20
+ pg:
21
+ etcdir: $(detect)
22
+ datadir: $(detect)
23
+ postgresql_conf: ${pg.etcdir}/postgresql.conf
24
+ pg_hba_conf: ${pg.etcdir}/pg_hba.conf
25
+ pg_ident_conf: ${pg.etcdir}/pg_ident.conf
26
+
27
+ pg(platform=redhat):
28
+ etcdir: ${pg.datadir}
29
+ datadir: $pcklidir/data
30
+
31
+ pg(platform=debian):
32
+ etcdir: $pcketcdir
33
+ datadir: /var/lib/pgsql/data
34
+
35
+ # 'plaform=*' to make this more specific than the default. Not needed if
36
+ # standard variables are ordered
37
+ pg(platform=*,vendor=pgdg):
38
+ datadir: $pcklibdir/${pg.version}/data
39
+
40
+ pg(platform=debian,vendor=pgdg):
41
+ etcdir: $pcketcdir/${pg.version}
42
+
43
+ pg(platform=redhat,vendor=pgdg):
44
+ etcdir: ${pg.datadir}
45
+
46
+ # nested expressions
47
+ #
48
+ pg(vendor=pgdg):
49
+ datadir: $pcklibdir/${pg.version}/data
50
+ platform=redhat:
51
+ etcdir: ${pg.datadir}
52
+ platform=debian:
53
+ etcdir: $pckectdir/${pg.version}
54
+
55
+
data/example/configure ADDED
File without changes
data/example/make ADDED
File without changes
@@ -0,0 +1,49 @@
1
+
2
+ Name: my_package_name
3
+ Summary: This is a summary of the package
4
+ Version: 1.2.3
5
+ Release: 4
6
+ License: GPL
7
+ Packager: clr
8
+ Requires: ruby
9
+ Requires: httpd
10
+ Requires: postgresql13
11
+ Source: %{name}.tar.gz
12
+ BuildRoot: /tmp/d20220502-22446-8neiew/tmp/%{name}-%{version}
13
+
14
+ %description
15
+ Optional longer description of the package
16
+
17
+ %prep
18
+ %setup -n my_package_name
19
+
20
+ %build
21
+ my_configure; my_make
22
+
23
+ %install
24
+ mkdir -p %{buildroot}/usr/bin %{buildroot}/usr/sbin %{buildroot}/usr/share/my_package_name %{buildroot}/var/lib
25
+ cp bin/a_file %{buildroot}/usr/bin/a_file
26
+ cp bin/another_file %{buildroot}/usr/bin/another_file
27
+ cp bin/a_file %{buildroot}/usr/bin/an_alias
28
+ cp share/some_data %{buildroot}/usr/share/my_package_name/some_data
29
+ cp share/some_other_data %{buildroot}/var/lib/some_other_data
30
+ touch %{buildroot}/usr/sbin/a_file
31
+
32
+ %files
33
+ /usr/bin/a_file
34
+ /usr/bin/another_file
35
+ /usr/bin/an_alias
36
+ /usr/share/my_package_name/some_data
37
+ /var/lib/some_other_data
38
+ %ghost /usr/sbin/a_file
39
+
40
+ %clean
41
+ %if "%{clean}" != ""
42
+ rm -rf %{_topdir}/BUILD/%{name}
43
+ [ $(basename %{buildroot}) == "%{name}-%{version}-%{release}.%{_target_cpu}" ] && rm -rf %{buildroot}
44
+ %endif
45
+
46
+ %post
47
+
48
+ ln -sf /bin/a_file /usr/sbin/a_file
49
+
data/example.yml ADDED
@@ -0,0 +1,84 @@
1
+ # QRPM configuration file. See https://github.com/clrgit/qrpm
2
+
3
+ # program ::= directory...
4
+ # directory ::= field... directory...
5
+ # field ::= key '*' value
6
+ # directory ::= array(string)
7
+ #
8
+ # TODO
9
+ # o Use '@' instead of '$'. Yields @name and @{name} that doesn't interfere
10
+ # with bash expansion
11
+ #
12
+ #
13
+ # ${{name}} in $(...)
14
+ # QRPM dependency check variable definitions and needs to be able to detect
15
+ # variable usages in $(...) constructs
16
+
17
+ # @include git-project
18
+ # -> version: $(cd ${{srcdir}}; git tag | tail -1 | sed 's/^v//')
19
+ #
20
+ # @include postgres-project prefix: pg_
21
+ # -> pg_name
22
+ # pg_version
23
+ # pg_libdir
24
+ # pg_sharedir
25
+ #
26
+ # @include postgres-project git@github.com:... commit-id
27
+ #
28
+ # @include redhat/httpd
29
+ # @include redhat/pg
30
+ # @include pgdg
31
+ #
32
+ # pg.version: 14
33
+ # pg: pgdg[14]
34
+
35
+ name: $pg_name-url_encode
36
+ summary: Adds the 'url_encode' extension to postgres ${pg.version}
37
+ description: RPM wrapper for the postgres url_encode extension (https://github.com/okbob/url_encode)
38
+ version: $(cd ${{srcdir}}; git tag | tail -1 | sed 's/^v//')
39
+ # ^Oops, hardcoded FIXME: Have a dependency graph and use some standard algorithm
40
+
41
+ include:
42
+ - ./qrpm.includes
43
+
44
+ requires:
45
+ - $pg_name-server
46
+ - $pg_name-libs
47
+
48
+ a: $b
49
+ b: $c
50
+ c: $a
51
+ # Idea
52
+ #submod: url_encode
53
+ #subdir: url_encode
54
+ #patches:
55
+ # - patch/patch1.patch
56
+ srcdir: url_encode
57
+
58
+ root: ""
59
+
60
+ pg:
61
+ name: $(rpm -q --qf '%{NAME}\n' -f $(readlink -f $(which pg_config)))
62
+ version: $(pg_config --version | sed 's/^[^0-9]* \([0-9]\+\).*$/\1/')
63
+ major: $version
64
+ libdir: $(pg_config --libdir)
65
+ sharedir: $(pg_config --sharedir)
66
+
67
+ #init: # FIXME Doesn't work atm
68
+ # - git submodule init
69
+ # - git submodule update
70
+
71
+ make:
72
+ - cd $srcdir; make
73
+
74
+ ${pg.sharedir}/extension:
75
+ - $srcdir/url_encode.control
76
+ - $srcdir/sql/url_encode--1.2.sql
77
+
78
+ ${pg.libdir}:
79
+ - $srcdir/src/url_encode.so
80
+ - $srcdir/postgresql$version
81
+
82
+ $root/somedir:
83
+ - $srcdir/somefile
84
+
data/exe/qrpm CHANGED
@@ -7,30 +7,69 @@ require_relative '../lib/qrpm.rb'
7
7
 
8
8
  require 'yaml'
9
9
  require 'shellopts'
10
- require 'indented_io'
11
10
 
12
11
  # TODO
13
12
  # o Fix BuildRoot (contains absolute path)
14
- # o Enable escape of $
15
- # o Separate standard variable from user-variables in dump
13
+ #
14
+ # + Separate standard variables from user-variables in dump
15
+ # + Enable escape of $
16
+ # + Support for $(...) constructs
16
17
 
17
18
  begin
18
19
  SPEC = %(
19
- @ Quick RPM builder
20
+ @ Make simple RPMs simple
20
21
 
21
- 'qrpm' creates a RPM package from a simple YAML specification file
22
+ -- VARIABLE=VALUE... [QRPM-FILE]
22
23
 
23
- A template YAML qrpm configuration file can be generated by the --template
24
- option. It is in YAML format with the extension that a single '__END__'
25
- terminates the file and that $NAME or ${NAME} are variables that will be
26
- expanded. The variables can either be specified in the configuration file
27
- or given on the command line in <variable>=<value> format
24
+ 'qrpm' creates a RPM package from a qrpm.yml specification file. It aims at
25
+ packaging shell scripts or simple executables/libraries with minimum effort
28
26
 
29
- -- VARIABLE=VALUE... [QRPM-FILE]
27
+ The qrpm.yml specification file is a YAML file. The simplest qrpm file
28
+ contains just one line:
30
29
 
31
- -t,template=OFILE?
32
- Generate a template qrpm.yml file in the current directory. Customize it
33
- to create RPM packages of your project
30
+ $bindir: my_executable_script
31
+
32
+ Running qrpm using this file will yield a RPM package that installs the
33
+ script into the standard /usr/bin directory. The name of the package
34
+ is set to the name of the current directory and version to the latest tag
35
+ in git (which needs to be present). Other defaults are detailed below
36
+
37
+ VARIABLES
38
+
39
+ The configuration file can define and use variables. They are defined by
40
+ key/value definitions and the value can refer to values of other
41
+ variables using $NAME or ${NAME}. Variables can also be given on the
42
+ command line in <variable>=<value> format
43
+
44
+ $(...) constructs are commands that are executed by bash(1). The parser
45
+ considers everything from the opening '$(' to the last ')' on the line as
46
+ part of the command so only one command is allowed. This restriction keeps
47
+ the parser simple, it may change in the future
48
+
49
+ INCLUDE FILES
50
+
51
+ The qrpm file can include other files that are searched for in a list of
52
+ directories. Relative paths are relative to the directory of the qrpm file
53
+ (but see the -C option). The search directories can be set on the command
54
+ line using the -I option
55
+
56
+ BUILT-IN VARIABLES
57
+
58
+ INSTALLATION DIRECTORIES
59
+
60
+ OPTIONS
61
+
62
+ -f,force
63
+ Create package even if repository is dirty. Normally qrpm checks if the
64
+ current directory is clean
65
+
66
+ -C,directory=EDIR
67
+ Change to directory before doing anything else but include the current
68
+ directory in the search path. This makes it possible to override parts of
69
+ a spec file
70
+
71
+ +I,include=EDIR
72
+ Include directory, later definitions are searched first
34
73
 
35
74
  -s,spec=OFILE?
36
75
  Only create the spec file and not the RPM package. Use this option to
@@ -39,62 +78,115 @@ begin
39
78
  -S,source
40
79
  Create a source RPM file instead of a regular RPM file
41
80
 
42
- -f,force
43
- Create package even if repository is dirty. Normally qrpm checks if the
44
- current directory is a Git directory and then if there are no changed
45
- files
81
+ -t,template=OFILE?
82
+ Generate a QRPM template. It is in YAML format with the extension that a
83
+ single '__END__' terminates the file immediately. The name of the file
84
+ defaults to 'qrpm.yml'. It is an error if the file exists
46
85
 
47
- -C,directory=EDIR
48
- Change to directory before doing anything else
86
+ -T,force-template=OFILE?
87
+ Like --template but overwrites file if it exists
88
+
89
+ -b,builddir=NPATH?
90
+ Use the given path as the RPM build dir, default is 'builddir'. Doesn't
91
+ remove the directory afterwards. It it is an error if the directory exists
92
+
93
+ -B,force-builddir=PATH?
94
+ Like --builddir but overwrites the directory if it exists beforehand
49
95
 
50
96
  -d,dump
51
- Dump internal data and exit
97
+ Dump internal data and exit. For debug
52
98
  )
53
99
 
54
- opts, args = ShellOpts.process(SPEC, ARGV)
100
+ opts, args = ShellOpts.process(SPEC, ARGV, verbose: true, quiet: true)
55
101
 
56
- Dir.chdir(opts.directory) if opts.directory?
57
-
58
- if opts.template?
59
- outfile = opts.template || Qrpm::QRPM_CONFIG_FILE
102
+ if opts.template? || opts.force_template?
103
+ outfile = opts.template || opts.force_template || Qrpm::QRPM_CONFIG_FILE
104
+ opts.force_template? || !File.exists?(outfile) or ShellOpts.error "Won't overwrite existing file: #{outfile}"
60
105
  FileUtils::cp Qrpm::QRPM_CONFIG_FILE_TEMPLATE, outfile
106
+ puts "Generated #{outfile}" if !opts.quiet?
61
107
  exit
62
108
  end
63
109
 
64
- # Collect var=val settings in the dict hash and sets the configuration file
65
- dict = {}
110
+ # Process arguments. The overrides hash is constructed from var=val arguments
111
+ # on the command line
112
+ overrides = {}
113
+ file = nil
66
114
  while arg = args.extract(0..1)
67
115
  if arg =~ /^(.*?)=(.*)$/
68
- dict[$1] = $2
69
- else
116
+ overrides[$1] = $2
117
+ elsif file.nil?
70
118
  file = arg
71
- break
119
+ else
120
+ args.expect(-1, "More than one file argument")
72
121
  end
73
122
  end
74
- args.empty? or args.expect(0) # Generates an illegal-number-of-arguments error
123
+ args.expect(0)
124
+
125
+ # Compute/normalize currdir and qrpmdir and add them to the dictionary
126
+ currdir = overrides["currdir"] = File.expand_path(overrides["currdir"] || Dir.getwd)
127
+ qrpmdir = overrides["qrpmdir"] = File.expand_path(overrides["qrpmdir"] || opts.directory || ".")
128
+
129
+ # Compute builddir
130
+ if opts.builddir? && opts.force_builddir?
131
+ ShellOpts.error "Can't use both --builddir and --force-builddir"
132
+ elsif opts.builddir? || opts.force_builddir?
133
+ builddir = opts.builddir || opts.force_builddir || "builddir"
134
+ opts.force_builddir? || !File.exist?(builddir) or
135
+ ShellOpts.error "Build directory 'builddir' exists - use -B to override"
136
+ builddir = File.expand_path(builddir)
137
+ else
138
+ builddir = nil
139
+ end
140
+
141
+ # Check if repository is clean
142
+ opts.force? || opts.dump? || `git status --porcelain | grep -v '??' 2>/dev/null` == "" or
143
+ ShellOpts.error "Repository is dirty"
75
144
 
76
145
  # Check configuration file
77
146
  file ||= Qrpm::QRPM_CONFIG_FILE
78
- ::File.exist?(file) or raise "Can't find '#{file}'"
147
+ ::File.exist?(file) or ShellOpts.error "Can't find '#{file}'"
148
+
149
+ # Create lexer
150
+ lexer = Qrpm::Lexer.new([currdir, qrpmdir].uniq, opts.include.reverse)
79
151
 
80
152
  # Load the qrpm configuration file
81
- yaml = YAML.load(IO.read(file).sub(/^__END__\s*$/m, ""))
153
+ conf = lexer.lex(File.expand_path file)
154
+
155
+ # Change to qrpm directory
156
+ Dir.chdir(qrpmdir)
82
157
 
83
- # Parse QRPM file
84
- rpm = Qrpm::Parser.parse(dict, yaml)
158
+ # Parse QRPM configuration file. Include paths are still resolved with the
159
+ # context of the original directory while filesystem paths are relative to
160
+ # the source directory
161
+ compiler = Qrpm::Compiler.new(overrides)
162
+ qrpm = compiler.compile(conf)
163
+ rpm = qrpm.rpm
85
164
 
86
165
  if opts.dump?
87
- rpm.dump
166
+ puts "Compiler"
167
+ indent { compiler.dump }
168
+
169
+ puts "Qrpm"
170
+ indent { qrpm.dump_parts }
171
+
172
+ puts "Rpm"
173
+ indent { rpm.dump }
174
+
88
175
  exit
89
176
  end
90
177
 
91
- # Check if repository is clean
92
- opts.force? || `git status --porcelain 2>/dev/null` == "" or raise "Repository is dirty"
93
-
178
+ # Create spec/srpm/rpm file
94
179
  target = (opts.spec? ? :spec : (opts.source? ? :srpm : :rpm))
95
- rpm.build(target: target, file: opts.spec)
180
+ files = rpm.build(
181
+ target: target,
182
+ file: opts.spec,
183
+ verbose: opts.verbose?,
184
+ destdir: currdir,
185
+ builddir: builddir)
186
+
187
+ puts "Built #{files.map { |f| File.basename(f) }.join(" ")}" if !opts.quiet?
96
188
 
97
189
  rescue RuntimeError => ex
98
- ShellOpts.error ex.message
190
+ ShellOpts.failure ex.message
99
191
  end
100
192