gjp 0.15.7 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +186 -26
- data/lib/gjp/package_spec_adapter.rb +16 -4
- data/lib/gjp/version.rb +1 -1
- data/lib/template/kit.spec +2 -3
- data/lib/template/package.spec +11 -4
- data/spec/lib/scaffolder_spec.rb +1 -1
- metadata +2 -2
data/README.md
CHANGED
@@ -1,44 +1,204 @@
|
|
1
|
-
gjp – Green Java Packager's tools
|
2
|
-
===
|
1
|
+
# gjp – Green Java Packager's tools
|
3
2
|
|
4
3
|
`gjp` (pronounced _/ˈdʒiː ˈaɪ ˈd͡ʒəʊ/_) is a set of tools to ease and partially automate Linux packaging of Java projects.
|
5
4
|
|
6
|
-
The project
|
5
|
+
The project objective is to strongly reduce manual packaging efforts by enabling a new and much simpler workflow.
|
6
|
+
|
7
|
+
## Status
|
8
|
+
|
9
|
+
`gjp` is a research project currently in alpha state. Basic concepts seem to be viable, packages are currently being built with the new approach to identify problem areas but not all basic features have been coded yet. If you are a packager you can try to use it (any feedback would be **very** welcome!), but be warned that anything can still change at this point.
|
10
|
+
|
11
|
+
## Contact
|
12
|
+
|
13
|
+
Are you using `gjp` or even just reading this? Let's get in touch!
|
14
|
+
|
15
|
+
smoioli at suse dot de
|
7
16
|
|
8
17
|
|
9
18
|
## Install
|
10
19
|
|
11
|
-
|
20
|
+
Via RubyGems:
|
12
21
|
|
13
22
|
$ gem install gjp
|
14
23
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
* `gjp
|
26
|
-
*
|
27
|
-
*
|
28
|
-
|
29
|
-
|
30
|
-
*
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
24
|
+
Note: `gjp` requires `git` in order to work. Some non-essential subcommands also need `iptables`, `sudo` and a JDK.
|
25
|
+
|
26
|
+
## Workflow
|
27
|
+
|
28
|
+
Building a package with `gjp` is quite unusual — this is a [deliberate choice](#motivation) to minimize packaging efforts.
|
29
|
+
|
30
|
+
### Overview
|
31
|
+
|
32
|
+
The basic process is:
|
33
|
+
|
34
|
+
* a `gjp` project is created;
|
35
|
+
* sources are added to the project, `gjp` keeps track of them;
|
36
|
+
* any other file that is needed for the build, except the JDK, is added in binary form (jars, the Maven executable, its plugins, etc.). Again, `gjp` keeps track of what you add, noting that those were binary build dependencies and not sources;
|
37
|
+
* a build is attempted. After the build is successful, `gjp` notes what files were produced and restores sources in their original state, making it a "repeatable dry-run build". `gjp` also retains any files that were automatically downloaded by Maven or other similar tools during the dry-run as binary build dependencies;
|
38
|
+
* `gjp` produces spec files for two packages: one for the project itself and one for all of its binary build dependencies, called a **kit**;
|
39
|
+
* kit and project packages can be submitted to [OBS](http://en.opensuse.org/openSUSE:Build_Service). Project package will rebuild cleanly because it needs no Internet access - all files were already downloaded during the dry-run above and are included in the kit.
|
40
|
+
|
41
|
+
Note that:
|
42
|
+
|
43
|
+
* the project's build time dependency graph is very simple: just its kit and the JDK;
|
44
|
+
* the kit is basically a binary blob. If its sources are needed for proper packaging, for example to comply with the GPL, [a separate step](#kit-sources) is needed to add them;
|
45
|
+
* the kit is needed at build time only (by OBS), no end user should ever install it;
|
46
|
+
* a `gjp` project can be used to build a number of packages that share one binary kit. This can help if the kit becomes big in size;
|
47
|
+
* `gjp` will take advantage of Maven's pom files to generate its specs if they are available. This allows to precompile most spec fields automatically.
|
48
|
+
|
49
|
+
In `gjp`, the build process can be in one of the following phases at any given moment:
|
50
|
+
|
51
|
+
* gathering: in this phase you add sources and kit files. New projects start in this phase, you can always enter it later with `gjp gather`;
|
52
|
+
* dry-running: in this phase you attempt a build. Any change in the sources will be reverted after it ends, while files added to the kit will be retained. You can enter this phase with `gjp dry-run`;
|
53
|
+
* finishing: in this phase `gjp` generates specs and archive files. You can enter it running `gjp finish`;
|
54
|
+
|
55
|
+
### Sample project (commons-io)
|
56
|
+
|
57
|
+
Ceate a new `gjp` project, in this example named "galaxy":
|
58
|
+
|
59
|
+
mkdir galaxy
|
60
|
+
cd galaxy
|
61
|
+
gjp init
|
62
|
+
|
63
|
+
As you can see from the output, `gjp init` starts a new gathering phase in which you can add sources and kit files. It also generated a folder structure and assumes you respect it, in particular, you should place all your projects' source files in `src`. Every `src` subfolder will become a separate package named after the folder itself, so use the following commands to create a `commons-collections` folders and populate it:
|
64
|
+
|
65
|
+
cd src
|
66
|
+
mkdir commons-collections
|
67
|
+
cd commons-collections
|
68
|
+
wget http://archive.apache.org/dist/commons/collections/source/commons-collections-3.2.1-src.zip
|
69
|
+
unzip commons-collections-3.2.1-src.zip
|
70
|
+
rm commons-collections-3.2.1-src.zip
|
71
|
+
|
72
|
+
Now let's move to the kit (which, unsurprisingly, should be placed in the `kit` folder). commons-lang needs Maven 3 to build, so we should simply unzip a copy in `kit`:
|
73
|
+
|
74
|
+
cd ../../kit
|
75
|
+
wget http://apache.fastbull.org/maven/maven-3/3.1.0/binaries/apache-maven-3.1.0-bin.zip
|
76
|
+
unzip apache-maven-3.1.0-bin.zip
|
77
|
+
rm apache-maven-3.1.0-bin.zip
|
78
|
+
cd ..
|
79
|
+
|
80
|
+
Nothing else is needed for a first build. Let's call `gjp dry-run` to let `gjp` know we are building and then call Maven. Note that `gjp mvn` is used instead of plain `mvn`: `gjp` will take care of locating the Maven installation we have in the `kit` and ensure it will store all downloaded files there.
|
81
|
+
|
82
|
+
gjp dry-run
|
83
|
+
cd src/commons-collections/commons-collections-3.2.1-src/
|
84
|
+
gjp mvn package
|
85
|
+
gjp finish
|
86
|
+
|
87
|
+
Success! At this point `gjp` took note of all needed files, and restored `src` as it was before the build. This should be sufficient to be able to repeat the build on a machine with no Internet access, but what if we wanted to be 100% sure of that?
|
88
|
+
|
89
|
+
`gjp` has a subcommand to setup a `nonet` user without Internet access, courtesy of `iptables`. You can simply retry the build using that user to see if it works. Note that the following commands will alter group permissions to allow both your current user and `nonet` to work on the same files.
|
90
|
+
|
91
|
+
gjp set-up-nonet-user
|
92
|
+
chmod -R g+rw ../../..
|
93
|
+
gjp dry-run
|
94
|
+
su nonet
|
95
|
+
ping www.google.com #this should fail!
|
96
|
+
gjp mvn package
|
97
|
+
chmod -R g+rw .
|
98
|
+
exit
|
99
|
+
|
100
|
+
The above is obviously not mandatory, but it can be useful for debugging purposes.
|
101
|
+
|
102
|
+
One last thing before generating packages is to setup a build script. By default `gjp` will generate a spec file which assumes a `build.sh` script in the source folder of your project that contains all commands needed to build the package itself. At the moment, this needs to be done manually, but it will hopefully be automated in a future release.
|
103
|
+
|
104
|
+
Let's start a new gathering phase and add that:
|
105
|
+
|
106
|
+
gjp gather
|
107
|
+
vi ../build.sh
|
108
|
+
|
109
|
+
Add the following lines:
|
110
|
+
|
111
|
+
#!/bin/sh
|
112
|
+
cd src/commons-collections/commons-collections-3.2.1-src/
|
113
|
+
../../../kit/apache-maven-3.1.0/bin/mvn -Dmaven.repo.local=`readlink -e ../../../kit/m2` -s`readlink -e ../../../kit/m2/settings.xml` package
|
114
|
+
|
115
|
+
Now complete the gathering:
|
116
|
+
|
117
|
+
gjp finish
|
118
|
+
cd ../../..
|
119
|
+
|
120
|
+
Note that `build.sh` gets called from the `gjp` project root, hence the `cd` line, and the Maven line was taken directly from `gjp mvn` output above and pasted verbatim.
|
121
|
+
|
122
|
+
The following command will generate the kit spec:
|
123
|
+
|
124
|
+
gjp generate-kit-spec
|
125
|
+
less specs/galaxy-kit.spec
|
126
|
+
|
127
|
+
Nothing fancy here, just a bunch of binaries installed in a proper location. You can also edit the spec file manually if you want. When you later regenerate it, `gjp` will automatically try to reconcile changes with a [three-way merge](http://en.wikipedia.org/wiki/Three-way_merge#Three-way_merge).
|
128
|
+
|
129
|
+
You can also generate the corresponding .tar.xz file with:
|
130
|
+
|
131
|
+
gjp generate-kit-archive
|
132
|
+
|
133
|
+
The contents of this file were tracked by `gjp` during gathering and dry-run phases, and are listed in `file_lists/kit`. You can also edit it if you want.
|
134
|
+
|
135
|
+
You can then generate the project spec and archive files provided you have a pom file (more formats will be supported in future). In this case:
|
136
|
+
|
137
|
+
gjp generate-package-spec commons-collections src/commons-collections/commons-collections-3.2.1-src/pom.xml
|
138
|
+
gjp generate-package-archive commons-collections
|
139
|
+
less specs/commons-collections.spec
|
140
|
+
|
141
|
+
As you can see, this package BuildRequires its kit, contains only the source files and installs any .jar files that were produced during dry runs. Archive is generated from `file_lists/commons-collections_input`, which lists source files. Output files are in `file_lists/commons-collections_output` and are used to compile the `%install` and `%files` sections of the project spec (by default jar files are included, see `gjp generate-package-spec --help`).
|
142
|
+
|
143
|
+
less file_lists/commons-collections_input
|
144
|
+
less file_lists/commons-collections_output
|
145
|
+
|
146
|
+
Packages are ready to be submitted to an OBS project. As OBS integration is not yet implemented, refer to OBS documentation to do that.
|
147
|
+
|
148
|
+
### Kit sources
|
149
|
+
|
150
|
+
If kit sources are needed for license compliance, some extra work is needed. Fortunately, finding jar source files and adding them to the kit is much easier than packaging its contents in proper RPMs!
|
151
|
+
|
152
|
+
If the project you are packaging uses Maven, you can ask Maven itself to find source jars for dependencies. Running the following command will add them to the kit:
|
153
|
+
|
154
|
+
gjp mvn dependency:sources
|
155
|
+
|
156
|
+
Unfortunately this will not take care of Maven itself, Maven's plugins and their dependencies so some extra work might be needed.
|
157
|
+
|
158
|
+
At the moment `gjp`'s supprort to kit source retrieval is limited to the following subcommands:
|
159
|
+
|
35
160
|
* `gjp get-pom NAME` will attempt to find a pom. `NAME` can be a jar file on your disk, a project directory, or simply a `name-version` string. `gjp` will get the pom either from the package itself or through search.maven.org using heuristic searching;
|
36
161
|
* `gjp get-parent-pom POM` will attempt to download a pom's parent from search.maven.org, where `POM` is a filename or URI;
|
37
162
|
* `gjp get-source-address POM` will attempt to find the SCM Internet address of a pom.xml from the file itself or through api.github.com. `POM` can either be a filename or a URI;
|
38
163
|
* `gjp get-source POM ADDRESS` downloads the source of a pom.xml's project from its SCM at ADDRESS;
|
39
|
-
* `gjp scaffold-jar-table DIRECTORY` looks for jars in the project's DIRECTORY and classifies them as build-time dependencies (b), run-time dependencies (r) or products (p);
|
40
164
|
|
41
|
-
|
165
|
+
More comprehensive support is planned in future releases.
|
166
|
+
|
167
|
+
You are advised to use [Maven Central](http://search.maven.org/) to search for sources and other information about projects.
|
168
|
+
|
169
|
+
### Implementation note
|
170
|
+
|
171
|
+
`gjp` internally uses `git` to keep track of files, any gjp project is actually also a `git` repo. Feel free to navigate it, you can commit, push and pull freely as long as the `gjp` tags are preserved.
|
172
|
+
|
173
|
+
## Motivation
|
174
|
+
|
175
|
+
The Java developer world has packages (jars, wars, ears...), tools ([ant](http://ant.apache.org/), [Maven](http://maven.apache.org/), [Ivy](http://ant.apache.org/ivy/), [Gradle](http://www.gradle.org/)...) and established workflows to handle software distribution while Linux distros have their own ([zypper](http://en.opensuse.org/Portal:Zypper), [yum](http://en.wikipedia.org/wiki/Yellowdog_Updater,_Modified), [apt](http://en.wikipedia.org/wiki/Advanced_Packaging_Tool)...). Since the two communities have different goals and requirements, Linux distros typically want to repackage Java software with their own format, tools and workflows. Reasons range from ease of installation, predictable rebuildability, support to (security) patching, management tools, legal issues, etc.
|
176
|
+
|
177
|
+
Unfortunately those two "schemes" became very different over time, so automatic translation/repackaging is not possible except in very simple cases. This leads to a lot of tedious, error-prone manual work that Linux packagers have to do in order to fit the "alien" Java model into distro packaging rules that were thought and optimized with a different ecosystem in mind.
|
178
|
+
|
179
|
+
A typical example is packaging any software built by Maven on SUSE distros. A number of pain points arise:
|
180
|
+
|
181
|
+
* Maven requires Internet access and downloads precompiled code as part of the build. RPMs have to be built on a standalone machine in [OBS](http://en.opensuse.org/openSUSE:Build_Service), and they should build code from sources they are provided beforehands exclusively;
|
182
|
+
* [Maven is basically a plugin container](http://maven.apache.org/plugins/), so hundreds of different plugins have to be installed to build real-life projects (the exact plugin set and their dependencies is determined at build time). While this is no big deal for Java developers, since they get the corresponding jars prebuilt from Maven itself, it is a nightmare for distros, because all shipping code is supposed to be built from scratch and packaged!
|
183
|
+
* Maven often uses multiple versions of a same library or plugin during the same build. Usually distros do not maintain more than one version of any given library to reduce maintenance;
|
184
|
+
* Maven requires itself in order to build. To be more exact, Maven needs Nexus, which in turn needs Maven and Nexus. To be more exact, its build dependency graph is a very complicated mess with lots of cycles that have to be broken manually.
|
185
|
+
|
186
|
+
The current solution in openSUSE is having the packager handle those differences, but this limits the amount of software the community is able to package due to the high effort required to overcome them.
|
187
|
+
|
188
|
+
The Fedora community is experimenting with another set of tools, [XMvn](http://mizdebsk.fedorapeople.org/xmvn/site/), which goals are similar to `gjp`'s.
|
189
|
+
|
190
|
+
### Kit rationale
|
191
|
+
|
192
|
+
`gjp` simplifies the packaging process mostly because of its use of a binary blob package that contains all build time dependencies for a set of packages called a **kit**.
|
193
|
+
|
194
|
+
Building software from a binary blob is unusual for Linux distros, and it surely has some drawbacks. It is anyway believed that benefits outweigh them, in fact using prebuilt software:
|
195
|
+
|
196
|
+
* drastically reduces packaging efforts. A very basic and relatively simple package like [commons-lang](http://commons.apache.org/proper/commons-lang/) needs about [150 jars](https://build.opensuse.org/package/show/home:SilvioMoioli/galaxy-kit) just to be compiled and tested. Those should be packaged, roughly, one-by-one!
|
197
|
+
* is just the way all Java developers out there build, test and use their software — this is how they expect it to work. Any different approach is necessarily error-prone and could result in unexpected bugs;
|
198
|
+
* does not affect the ability of providing patches to Java projects, as only build time requirements are in the kit. In virtually all cases patching a piece of software does not require to patch its build toolchain;
|
199
|
+
* does not affect the ability of complying to software licenses like the GPL. In fact those licenses only require to redistribute a project's source code - not the whole toolchain needed to build it. [Sources can be added](#kit-sources) for GPL'd parts of the kit, if any.
|
200
|
+
|
201
|
+
## Sources
|
42
202
|
|
43
203
|
`gjp`'s Git repo is available on GitHub, which can be browsed at:
|
44
204
|
|
@@ -20,16 +20,19 @@ module Gjp
|
|
20
20
|
def initialize(project, package_name, pom, filter)
|
21
21
|
@name = package_name
|
22
22
|
@version = pom.version
|
23
|
-
@license = pom.license_name
|
24
|
-
|
25
|
-
|
23
|
+
@license = if pom.license_name != ""
|
24
|
+
pom.license_name
|
25
|
+
else
|
26
|
+
"Apache-2.0"
|
27
|
+
end
|
28
|
+
@summary = cleanup_description(pom.description, 60)
|
26
29
|
@url = pom.url
|
27
30
|
@project_name = project.name
|
28
31
|
@group_id = pom.group_id
|
29
32
|
@artifact_id = pom.artifact_id
|
30
33
|
@version = pom.version
|
31
34
|
@runtime_dependency_ids = pom.runtime_dependency_ids
|
32
|
-
@description =
|
35
|
+
@description = cleanup_description(pom.description, 1500)
|
33
36
|
|
34
37
|
output_list = File.join(project.full_path, "file_lists", "#{@name}_output")
|
35
38
|
@outputs = File.open(output_list).readlines.map do |line|
|
@@ -42,6 +45,15 @@ module Gjp
|
|
42
45
|
def get_binding
|
43
46
|
binding
|
44
47
|
end
|
48
|
+
|
49
|
+
def cleanup_description(raw, max_length)
|
50
|
+
raw
|
51
|
+
.gsub(/[\s]+/, " ")
|
52
|
+
.strip
|
53
|
+
.slice(0..max_length -1)
|
54
|
+
.sub(/\s\w+$/, "")
|
55
|
+
.sub(/\.+$/, "")
|
56
|
+
end
|
45
57
|
end
|
46
58
|
end
|
47
59
|
|
data/lib/gjp/version.rb
CHANGED
data/lib/template/kit.spec
CHANGED
@@ -24,8 +24,8 @@ Url: https://github.com/SilvioMoioli/gjp
|
|
24
24
|
Group: Development/Libraries/Java
|
25
25
|
Source0: %{name}.tar.xz
|
26
26
|
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
27
|
-
BuildRequires: java-devel
|
28
27
|
BuildArch: noarch
|
28
|
+
BuildRequires: xz
|
29
29
|
Provides: gjp(kit)
|
30
30
|
# no two kits should ever be installed at any given time
|
31
31
|
Conflicts: otherproviders(gjp(kit))
|
@@ -50,7 +50,6 @@ cp -a * %{buildroot}%{_datadir}/gjp/%{name}/
|
|
50
50
|
%files
|
51
51
|
%defattr(-,root,root)
|
52
52
|
%doc ../README.SUSE
|
53
|
-
%{_datadir}/gjp
|
54
|
-
%{_datadir}/gjp/%{name}/
|
53
|
+
%{_datadir}/gjp/
|
55
54
|
|
56
55
|
%changelog
|
data/lib/template/package.spec
CHANGED
@@ -24,6 +24,8 @@ Url: <%= url %>
|
|
24
24
|
Group: Development/Libraries/Java
|
25
25
|
Source0: %{name}.tar.xz
|
26
26
|
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
27
|
+
BuildRequires: xz
|
28
|
+
BuildRequires: java-devel
|
27
29
|
BuildRequires: <%= project_name %>-kit
|
28
30
|
BuildArch: noarch
|
29
31
|
Provides: mvn(<%= group_id %>:<%= artifact_id %>) == <%= version %>
|
@@ -32,15 +34,20 @@ Requires: mvn(<%= dependency_id[0] %>:<%= dependency_id[1] %>) <% if depen
|
|
32
34
|
<% end %>
|
33
35
|
|
34
36
|
%description
|
35
|
-
<%=
|
37
|
+
<%=
|
38
|
+
description
|
39
|
+
%>
|
36
40
|
|
37
41
|
%prep
|
38
|
-
%setup -q -c
|
42
|
+
%setup -q -c -n src/<%= name %>
|
43
|
+
ln -sf %{_datadir}/gjp/<%= project_name %>-kit ../../kit
|
39
44
|
|
40
45
|
%build
|
41
|
-
|
46
|
+
cd ../../
|
47
|
+
sh src/<%= name %>/build.sh
|
42
48
|
|
43
49
|
%install
|
50
|
+
mkdir -p %{buildroot}%{_javadir}
|
44
51
|
<% outputs.each do |output| %>
|
45
52
|
cp -a <%= output %> %{buildroot}%{_javadir}/<%= File.basename(output) %>
|
46
53
|
<% end %>
|
@@ -48,7 +55,7 @@ cp -a <%= output %> %{buildroot}%{_javadir}/<%= File.basename(output) %>
|
|
48
55
|
%files
|
49
56
|
%defattr(-,root,root)
|
50
57
|
<% outputs.each do |output| %>
|
51
|
-
|
58
|
+
%{_javadir}/<%= File.basename(output) %>
|
52
59
|
<% end %>
|
53
60
|
|
54
61
|
%changelog
|
data/spec/lib/scaffolder_spec.rb
CHANGED
@@ -115,7 +115,7 @@ describe Gjp::Scaffolder do
|
|
115
115
|
spec_lines = File.readlines(File.join("specs", "test.spec"))
|
116
116
|
spec_lines.should include("Name: test\n")
|
117
117
|
spec_lines.should include("License: The Apache Software License, Version 2.0\n")
|
118
|
-
spec_lines.should include("Summary: Nailgun is a client, protocol, and server for running Java
|
118
|
+
spec_lines.should include("Summary: Nailgun is a client, protocol, and server for running Java\n")
|
119
119
|
spec_lines.should include("Url: http://martiansoftware.com/nailgun\n")
|
120
120
|
spec_lines.should include("BuildRequires: #{@project.name}-kit\n")
|
121
121
|
spec_lines.should include("Provides: mvn(com.martiansoftware:nailgun-all) == 0.9.1\n")
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gjp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.16.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-10-
|
12
|
+
date: 2013-10-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|