On Wed, 2006-12-06 at 11:57 -0500, Jason van Zyl wrote: > On 6 Dec 06, at 11:38 AM 6 Dec 06, Carl Trieloff wrote: > > > I have spoken with a few committers over IRC, ApacheCon etc about > > this so here it comes. Some of us would like to include maven into > > Fedora distributions. There are two components to this, one > > technical and the other process similar to the Apache incubator > > process in that you need a sponsor, need to pass review etc... > > > > To be frank, I'm not so sure this would be a good thing for Maven > users. It's not terribly hard to install and here are some of the > problems I see: > > 1. Who is going to maintain this? It seems rather complicated when we > have something that works pretty easily. >
The patch's goals are twofold. 1: Ensure full offline mode (the -o switch still allows maven to try and check for plugin updates and what not in valid repositories) 2: Ensure that projects can build against a single version of a dependency, rather than multiple. > 2. On Redhat would Maven be laid out differently then our stock > install? For documentation, and learning purposes having Maven be > laid out different and work differently on different platforms is not > something I would like to see. It will just make it more difficult > for Maven users. Maven does more then Java but we are about platform > neutrality and having something that works in a specific way on > Redhat that doesn't translate to working on OS/X is not a good thing. > Maven is laid out differently by the rpm. However, this has nothing to do with Red Hat specifically. The RPM adheres to the Filesystem Heirarchy Standard (FHS), which a reference for install locations for *nix systems: http://www.pathname.com/fhs/ > 3. What about multiple versions? This would make Maven bound to the > OS which is also not a good thing. I have often run into many problem > where multiple versions are not allowed. I run 4 different versions > of Maven and using RPMs here would make this difficult. > As I mentioned in point 2 in #1 above, this is actually one of the things we want (optionally, ofcourse). JPackage (used by Red Hat, Suse, Mandriva, etc.) currently does not support multiple version installations of a package in parallel. Due to this limitation, we need a maven there that can work with 1 version of each package. > I would be extremely hesitant to make this the standard offering for > Maven users on Redhat. I would be hesitant to off anything that did > not work in a standard way, or as much of a standard way as possible, > between all platforms. I do not see this as a great benefit to Maven > users. > All of the stuff done by the patch is optional, and not enabled by default. Everything is controlled by properties (e.g. -Dmaven2.ignore.versions has to be there for maven to ignore versions and go with 1 version per dependency, and so on). Whatever the patch does, is intended to be used on a range of distributions, not just in Fedora. Cheers, Deepak > Jason. > > > > > A few of us have been working on working out all the issues to meet > > the Fedora and Linux distro guidelines. Thanks to Deepak he has > > worked out most of this and has created a set of patches for maven > > in addition to identifying the work that needs to be done each time > > an update needs to be included into Fedora. It would be ideal if we > > could create a maven target with each release that met these > > guidelines and work in a Linux distro build environment. Once we > > get through the technical, Deepak, and I can help drive the > > process with Fedora. > > > > Please take a look, Deepak can JIRA all the patches and a few of us > > can > > help with this. > > > > Regards > > Carl, Deepak > > > > > > The following provided by Deepak > > > > > > Since there is a strict "must build offline" requirement, the > > maven2 rpm > > is designed to build completely disconnected from the Internet. To > > this > > end, the rpm is self-contained -- it contains poms, necessary jars for > > bootstrapping, etc. > > > > Here is where all the maven2 sources are (explanation of source > > files is > > at the end): > > http://people.redhat.com/dbhole/maven/ > > > > It is strongly recommended that whoever plans to help out with this, > > reads the maven2-jpp-readme.html file, as it gives a brief idea as to > > how the mapping system works. Changes from maven2-jpprepolayout.patch > > (or their equivalent), and new files > > maven2-JPackageRepositoryLayout.java and maven2- > > MavenJPackageDepmap.java > > (or their equivalent) need to go upstream in order to make everything > > work with jpackage smoothly. > > > > In order to put maven2 into Fedora, here are the brief set of steps > > for > > all dependencies, and maven itself: > > > > 1. Get rpm from jpackage. Check if it is set to build natively. > > If not, > > Build it, run it through spec-gcj-convert (file attached), verify > > new spec, rebuild it, make sure it conforms to Fedora guidelines > > for everything except the release number and all, that should be > > jpackage specific. Then upload this to jpackage. > > If it is: > > Do nothing > > > > 2. Then, use the latest spec from jpackage after doing #1, update the > > release to match fc guidelines, merge changelog, build into Fedora. > > > > > > A brief explanation what the files are for: > > -> m2_jar_repo.tar.gz - An archive of certain jar files needed for > > building (some maven2 dependencies need maven2 to build -- so maven2 > > has a bootstrap mode where pre-built jars are used. Once such a > > maven > > is built, it is then used to build all dependencies, and then maven > > is re-built in non-bootstrap mode against those dependencies) > > -> m2_pom_repo.tar.gz - An archive of all the pom files needed for > > building > > -> maven2-addjdom-depmap.xml - Adds a jdom dependency to maven. > > jdom is > > used by the jpp mapping system > > -> maven2-addjdomtobootstrappath.patch - Adds jdom to the bootstrap > > classpath (see above note) > > -> maven2-buildallplugins.patch - Patch to enable plugins that maven > > disables by default (we always build as much as possible in our > > packages). > > -> maven2-disable-itests.patch - Patch to disable integration > > tests. The > > tests take a long time to run, so this patch is used to disable them > > (unless the --with itests switch is given) > > -> maven2-empty-dep.jar/pom - Certain jars in maven repositories are > > monolithic and not needed when building against JPackage packages. > > e.g. velocity-dep, which contains all of velocity's dependencies. > > Since the jpp mapping system can only map one-to-one, we need to > > maven dependencies such as velocity-dep to something... that > > something is this empty-dep which contains no classes. > > -> maven2-enable-unbuilt-modules.patch - As with plugins, we also > > try to > > build as many modules as possible. This patch enables it such > > modules. > > -> maven2-it-jppfixes.patch - This patch was originally needed with > > the > > old rpm. In theory, only the first chunk of patch should be needed > > (to enable the -s switch), but I am not certain -- it needs to be > > investigated. > > -> maven2-JPackageRepositoryLayout.java -> The "JPackage layout". > > In the > > Jpackage layout, a file location is $groupId/$artifactId.jar with > > any > > "."'s in the groupId converted to "/"'s first. *This file, or an > > equivalent needs to go upstream* > > -> maven2-jpp-readme.html - A readme for how packages should be built > > around this maven. > > -> maven2-jpprepolayout.patch - The most critical component of all. > > This > > patch wires in usage of the jpackage repository. Additionally, it > > also ensures that maven will not go online -- not for dependencies, > > not for checking plugin updates, not for anything. It also adds > > the jpackage repository (/usr/share/maven2/repository) to the > > default > > list. *The changes in here are the ones that need to go upstream* > > -> maven2-jpp-script - The init script for jpackage building. It is a > > wrapper around the mvn script -- it calls mvn with certain > > properties > > that causes maven to behave in an offline manner, > > use /usr/share/maven2/repository, etc. > > -> maven2-MavenJPackageDepmap.java - A helper package that loads the > > dependency map, provides the value based on key requested, etc. > > *This > > file, or an equivalent needs to go upstream* > > -> maven2-maven-site-plugin.tar.gz - The maven-site-plugin. The > > version > > in the plugins tarball cannot build against the new doxia. > > -> maven2-model-v3.tar.gz - The model v3 class > > -> maven2-plugins-060420-src.tar.gz - The plugins tarball. > > See .spec to > > see how it was generated > > -> maven2-plugins-plexus151.patch - Disabled a code stub that causes > > build to fail against plexus-utils 1.5.1+ > > -> maven2-run-it-tests.sh - Script to run integration tests > > -> maven2-script - The mvn wrapper script > > -> maven2-settings.xml - I don't think this is used anymore.. > > -> maven2-src.tar.gz - The maven2-2.0.4 source tarball from svn. > > > > > > Cheers, > > Deepak > > > > > > #!/usr/bin/env python > > > > # spec-convert-gcj > > # ================ > > # > > # Create a JPackage spec file that contains GCJ support from a > > JPackage > > # SRPM and its corresponding RPMs. spec-convert-gcj uses the > > binary RPMs > > # to determine each sub-package's list of jar files. > > # > > # Example: > > # spec-convert-gcj ~/rpmbuild/SRPMS/bsh-*1.3.0-6jpp* ~/rpmbuild/ > > RPMS/noarch/bsh-*1.3.0-6jpp* > > > > import sys > > import os > > import warnings > > > > class Error(Exception): > > pass > > > > # parsing state > > state = "PREAMBLE" > > > > partList = [ "PREAMBLE", > > "%package", > > "%prep", > > "%build", > > "%install", > > "%check", > > "%clean", > > "%preun", > > "%postun", > > "%pre", > > "%post", > > "%files", > > "%changelog", > > "%description", > > "%triggerpostun", > > "%triggerun", > > "%triggerin", > > "%trigger", > > "%verifyscript", > > "END" ] > > > > packages = {} > > > > macroizedpackagenames = {} > > > > currentpackage = None > > > > doneuptofiles = False > > > > mainpackageempty = False > > > > NAME = "spec-convert-gcj" > > VERSION = "1.1" > > > > class Package: > > name = "" > > jarfilenames = [] > > postdone = False > > postundone = False > > > > def __init__(self, name, jarfilenames): > > self.name = name > > self.jarfilenames = jarfilenames > > > > def contains_jars(self): > > return len(self.jarfilenames) != 0 > > > > def get_name(self): > > return self.name > > > > def get_jar_file_names(self): > > return self.jarfilenames > > > > def set_post_done(self): > > self.postdone = True > > > > def get_post_done(self): > > return self.postdone > > > > def set_postun_done(self): > > self.postundone = True > > > > def get_postun_done(self): > > return self.postdone > > > > def __str__(self): > > return self.name > > > > def get_package_name(rpmfilename): > > rpmoutput = os.popen("rpm --queryformat %{name} -qp " + > > rpmfilename) > > packagename = rpmoutput.read() > > status = rpmoutput.close() > > if status is not None or packagename == "": > > raise Error, "spec file name lookup failed" > > else: > > print "spec file name lookup passed" > > return packagename > > > > def extract_files(rpmfilename, filenamepattern): > > status = os.system("rpm2cpio " + rpmfilename + " | cpio -id " + > > filenamepattern) > > if status > 0: > > raise Error, "%s exited with code %d" % ("cpio", status) > > elif status < 0: > > raise Error, "%s killed by signal %d" % ("cpio", -status) > > else: > > print "rpm2cpio passed" > > > > def get_jar_file_names_callback(jarfilenames, dirname, fnames): > > for fname in fnames: > > if fname.endswith(".jar") \ > > and os.path.isfile(os.path.join(dirname, fname)) \ > > and not os.path.islink(os.path.join(dirname, fname)): > > jarfilenames.append(fname) > > os.remove(os.path.join(dirname, fname)) > > > > def note_package(rpmfilename): > > global packages > > unmacroizedpackagename = get_package_name(rpmfilename) > > if unmacroizedpackagename != mainpackagename + "-debuginfo": > > if unmacroizedpackagename == mainpackagename: > > packagename = mainpackagename > > else: > > packagename = macroizedpackagenames > > [unmacroizedpackagename] > > jarfilenames = [] > > extract_files(rpmfilename, "*.jar") > > os.path.walk(".", get_jar_file_names_callback, jarfilenames) > > packages[packagename] = Package(packagename, jarfilenames) > > > > def filter_preamble(line): > > if line.lower().startswith("buildarch:"): > > if line.lower().split()[1] == "noarch": > > add_buildarch(line) > > else: > > outputspecfile.write(line) > > else: > > outputspecfile.write(line) > > > > def add_buildarch(line): > > outputspecfile.write("%if ! %{gcj_support}\n") > > outputspecfile.write(line) > > outputspecfile.write("%endif\n") > > > > def add_requires(): > > outputspecfile.write("%if %{gcj_support}\n") > > outputspecfile.write("BuildRequires:\t\tjava-gcj-compat-devel\n") > > outputspecfile.write("Requires(post):\t\tjava-gcj-compat\n") > > outputspecfile.write("Requires(postun):\tjava-gcj-compat\n") > > outputspecfile.write("%endif\n") > > outputspecfile.write("\n") > > > > def add_aot_compile_rpm(): > > outputspecfile.write("%if %{gcj_support}\n") > > outputspecfile.write("%{_bindir}/aot-compile-rpm\n") > > outputspecfile.write("%endif\n") > > outputspecfile.write("\n") > > > > def add_so_and_db_files(): > > outputspecfile.write("%if %{gcj_support}\n") > > outputspecfile.write("%dir %attr(-,root,root) %{_libdir}/gcj/% > > {name}\n") > > for jarfilename in currentpackage.get_jar_file_names(): > > outputspecfile.write("%attr(-,root,root) %{_libdir}/gcj/% > > {name}/" + jarfilename + ".*\n") > > outputspecfile.write("%endif\n") > > outputspecfile.write("\n") > > > > def add_rebuild_gcj_db(): > > outputspecfile.write("%if %{gcj_support}\n") > > add_rebuild_gcj_db_no_condition() > > outputspecfile.write("%endif\n") > > outputspecfile.write("\n") > > > > def add_rebuild_gcj_db_no_condition(): > > outputspecfile.write("if [ -x %{_bindir}/rebuild-gcj-db ]\n") > > outputspecfile.write("then\n") > > outputspecfile.write(" %{_bindir}/rebuild-gcj-db\n") > > outputspecfile.write("fi\n") > > > > def add_name(name): > > if name.startswith(mainpackagename): > > if name != mainpackagename: > > outputspecfile.write(" " + name.replace(mainpackagename + > > "-", "", 1)) > > else: > > # full name > > outputspecfile.write(" -n " + name) > > outputspecfile.write("\n") > > > > def add_post(name): > > outputspecfile.write("%if %{gcj_support}\n") > > outputspecfile.write("%post") > > add_name(name) > > add_rebuild_gcj_db_no_condition() > > outputspecfile.write("%endif\n") > > outputspecfile.write("\n") > > > > def add_postun(name): > > outputspecfile.write("%if %{gcj_support}\n") > > outputspecfile.write("%postun") > > add_name(name) > > add_rebuild_gcj_db_no_condition() > > outputspecfile.write("%endif\n") > > outputspecfile.write("\n") > > > > def add_before_part(state): > > global doneuptofiles > > > > if state == "%files": > > if doneuptofiles == False: > > for packagename in packages: > > package = packages[packagename] > > if package.contains_jars(): > > if not package.get_post_done(): > > add_post(package.get_name()) > > if not package.get_postun_done(): > > add_postun(package.get_name()) > > doneuptofiles = True > > > > def add_to_part(state): > > if state == "PREAMBLE": > > if currentpackage is not None \ > > and currentpackage.contains_jars(): > > add_requires() > > if state == "%package": > > if currentpackage is not None \ > > and currentpackage.contains_jars(): > > add_requires() > > elif state == "%install": > > add_aot_compile_rpm() > > elif state == "%files": > > if currentpackage is not None \ > > and currentpackage.contains_jars(): > > add_so_and_db_files() > > elif state == "%post": > > if currentpackage is not None \ > > and currentpackage.contains_jars(): > > add_rebuild_gcj_db() > > currentpackage.set_post_done() > > elif state == "%postun": > > if currentpackage is not None \ > > and currentpackage.contains_jars(): > > add_rebuild_gcj_db() > > currentpackage.set_postun_done() > > > > def set_currentpackage(line): > > global currentpackage > > > > fields = line.split() > > if len(fields) == 1: > > if not mainpackageempty: > > try: > > currentpackage = packages[mainpackagename] > > except KeyError, e: > > pass > > else: > > currentpackage = None > > else: > > if fields[1] == "-n": > > # full name specified > > try: > > currentpackage = packages[fields[2]] > > except KeyError, e: > > pass > > else: > > try: > > currentpackage = packages[mainpackagename + "-" + fields[1]] > > except KeyError, e: > > pass > > > > def set_macroized_package_names(): > > global macroizedpackagenames > > > > packagelines = os.popen("cat " + specfilename + " | grep '^% > > package'") > > packagenames = os.popen("rpm -q --specfile --queryformat='% > > {name}\n' " + specfilename + " | grep -v " + mainpackagename + "- > > debuginfo") > > > > packageline = packagelines.readline() > > # skip main package name > > packagename = packagenames.readline() > > packagename = packagenames.readline() > > > > if packagename != "": > > while packageline != "": > > fields = packageline.split() > > if len(fields) == 2: > > macroizedpackagenames[packagename.strip()] = > > mainpackagename + "-" + fields[1] > > else: > > if len(fields) == 3: > > macroizedpackagenames[packagename.strip()] = > > fields[2] > > packageline = packagelines.readline() > > packagename = packagenames.readline() > > > > packagelines.close() > > packagenames.close() > > > > if packageline != "" or packagename !="": > > raise Error, "number of Name: and %package lines does not > > match number of names returned by spec file query" > > else: > > print "macroized package names creation passed" > > > > print "map of unmacroized names to macroized names:" > > print macroizedpackagenames > > > > def next_state(line): > > global state > > if line == "": > > add_to_part(state) > > state = "END" > > return > > for part in partList: > > if line.startswith(part): > > add_to_part(state) > > state = part > > add_before_part(state) > > set_currentpackage(line) > > > > def print_version(): > > print NAME, VERSION > > sys.exit(0) > > > > def print_usage(): > > print "Usage: " + NAME + " SRPM RPMS" > > print "Create a JPackage spec file that contains GCJ support > > from a JPackage" > > print "SRPM and its corresponding RPMs. " + NAME + " uses the > > binary RPMs" > > print "to determine each sub-package's list of jar files." > > print "" > > print "Example:" > > print " " + NAME + " ~/rpmbuild/SRPMS/bsh-*1.3.0-6jpp* ~/ > > rpmbuild/RPMS/noarch/bsh-*1.3.0-6jpp*" > > sys.exit(0) > > > > if __name__ == "__main__": > > try: > > > > options = sys.argv[1:] > > > > if len(options) == 0: > > print NAME + ": no input files" > > print_usage() > > > > origdir = os.getcwd() > > > > # find SRPM within arguments > > srpmfilename = "" > > rpmfilenames = [] > > for option in options: > > if option.endswith(".src.rpm"): > > if srpmfilename != "": > > raise Error, "more than one SRPM specified" > > else: > > srpmfilename = os.path.join(origdir, option) > > elif option.endswith(".rpm"): > > rpmfilenames.append(os.path.join(origdir, option)) > > elif option == "--version": > > print_version() > > elif option == "--help": > > print_usage() > > > > warnings.filterwarnings("ignore", message="tmpnam is a > > potential security risk to your program") > > tmpdir = os.path.basename(os.tmpnam()) > > os.mkdir(tmpdir) > > os.chdir(tmpdir) > > > > # get spec file name: assumes that the spec file is called > > # %{name}.spec > > print "processing: " + srpmfilename > > mainpackagename = get_package_name(srpmfilename) > > specfilename = mainpackagename + ".spec" > > > > # extract spec file > > print "extracting spec file: " + specfilename > > extract_files(srpmfilename, specfilename) > > > > # check for existing gcj support > > checkconverted = os.popen("grep gcj_support " + specfilename) > > checksupport = checkconverted.readline() > > if checksupport != "": > > raise Error, "these rpms already support gcj" > > status = checkconverted.close() > > if status is None: > > raise Error, "failed to close grep pipe" > > else: > > print "no gcj support detected" > > > > # calculate unmacroized name-to-macroized name mapping > > set_macroized_package_names() > > > > for rpmfilename in rpmfilenames: > > note_package(rpmfilename) > > > > # open spec file for reading > > specfile = open(specfilename, 'r') > > > > # open output spec file for writing > > outputspecfile = open(os.path.join(origdir, mainpackagename > > + "-gcj.spec"), 'w') > > > > # check if there is a main package or only sub-packages > > if mainpackagename in packages: > > currentpackage = packages[mainpackagename] > > else: > > mainpackageempty = True > > > > print "main package:", currentpackage > > > > line = specfile.readline() > > next_state(line) > > > > # skip license block > > while line.startswith("#"): > > outputspecfile.write(line) > > line = specfile.readline() > > > > outputspecfile.write("\n%define gcj_support %{?_with_gcj_support: > > 1}%{!?_with_gcj_support:%{?_without_gcj_support:0}%{!? > > _without_gcj_support:%{?_gcj_support:%{_gcj_support}}%{!? > > _gcj_support:0}}}\n") > > > > while line != "": > > if state == "PREAMBLE": > > filter_preamble(line) > > else: > > outputspecfile.write(line) > > > > line = specfile.readline() > > next_state(line) > > > > outputspecfile.close() > > > > os.chdir(origdir) > > > > except Error, e: > > print >> sys.stderr, "%s: error: %s" % ( > > os.path.basename(sys.argv[0]), e) > > sys.exit(1) > > > > > > --------------------------------------------------------------------- > > To unsubscribe, e-mail: [EMAIL PROTECTED] > > For additional commands, e-mail: [EMAIL PROTECTED] > --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]