summaryrefslogtreecommitdiff
path: root/buildscripts/packager-enterprise.py
diff options
context:
space:
mode:
authorErnie Hershey <ernie.hershey@10gen.com>2013-03-15 20:04:26 -0400
committerErnie Hershey <ernie.hershey@10gen.com>2013-03-15 20:04:26 -0400
commitd4898c284b0b5b71e2ac96a7de685c5dce170fe6 (patch)
treed441cfff7cef4986bed94b26cb5c95cac836eabe /buildscripts/packager-enterprise.py
parentea168df93a2681edf003304123888a94f7f3da38 (diff)
downloadmongo-d4898c284b0b5b71e2ac96a7de685c5dce170fe6.tar.gz
SERVER-7692 modifed to build subscriber edition
Diffstat (limited to 'buildscripts/packager-enterprise.py')
-rw-r--r--buildscripts/packager-enterprise.py1020
1 files changed, 1020 insertions, 0 deletions
diff --git a/buildscripts/packager-enterprise.py b/buildscripts/packager-enterprise.py
new file mode 100644
index 00000000000..d90dd3ab3cf
--- /dev/null
+++ b/buildscripts/packager-enterprise.py
@@ -0,0 +1,1020 @@
+#!/usr/bin/python
+
+# This program makes Debian and RPM repositories for MongoDB, by
+# downloading our tarballs of statically linked executables and
+# insinuating them into Linux packages. It must be run on a
+# Debianoid, since Debian provides tools to make RPMs, but RPM-based
+# systems don't provide debian packaging crud.
+
+# Notes:
+#
+# * Almost anything that you want to be able to influence about how a
+# package construction must be embedded in some file that the
+# packaging tool uses for input (e.g., debian/rules, debian/control,
+# debian/changelog; or the RPM specfile), and the precise details are
+# arbitrary and silly. So this program generates all the relevant
+# inputs to the packaging tools.
+#
+# * Once a .deb or .rpm package is made, there's a separate layer of
+# tools that makes a "repository" for use by the apt/yum layers of
+# package tools. The layouts of these repositories are arbitrary and
+# silly, too.
+#
+# * Before you run the program on a new host, these are the
+# prerequisites:
+#
+# apt-get install dpkg-dev rpm debhelper fakeroot ia32-libs createrepo git-core libsnmp15
+# echo "Now put the dist gnupg signing keys in ~root/.gnupg"
+
+import errno
+import getopt
+import httplib
+import os
+import re
+import stat
+import subprocess
+import sys
+import tempfile
+import time
+import urlparse
+
+# For the moment, this program runs on the host that also serves our
+# repositories to the world, so the last thing the program does is
+# move the repositories into place. Make this be the path where the
+# web server will look for repositories.
+REPOPATH="/var/www/repo"
+
+# The 10gen names for the architectures we support.
+ARCHES=["x86_64"]
+
+# Made up names for the flavors of distribution we package for.
+DISTROS=["debian-sysvinit", "ubuntu-upstart", "redhat"]
+
+# When we're preparing a directory containing packaging tool inputs
+# and our binaries, use this relative subdirectory for placing the
+# binaries.
+BINARYDIR="BINARIES"
+
+sys.stderr.write("BINARYDIR: %s, REPOPATH: %s\n" % (BINARYDIR, REPOPATH))
+
+class Spec(object):
+ def __init__(self, specstr):
+ tup = specstr.split(":")
+ self.ver = tup[0]
+ # Hack: the second item in the tuple is treated as a suffix if
+ # it lacks an equals sign; otherwise it's the start of named
+ # parameters.
+ self.suf = None
+ if len(tup) > 1 and tup[1].find("=") == -1:
+ self.suf = tup[1]
+ # Catch-all for any other parameters to the packaging.
+ i = 2 if self.suf else 1
+ self.params = dict([s.split("=") for s in tup[i:]])
+ for key in self.params.keys():
+ assert(key in ["suffix", "revision"])
+
+ def version(self):
+ return self.ver
+
+ def version_better_than(self, version_string):
+ # FIXME: this is wrong, but I'm in a hurry.
+ # e.g., "1.8.2" < "1.8.10", "1.8.2" < "1.8.2-rc1"
+ return self.ver > version_string
+
+ def suffix(self):
+ # suffix is what we tack on after pkgbase.
+ if self.suf:
+ return self.suf
+ elif "suffix" in self.params:
+ return self.params["suffix"]
+ else:
+ return "-10gen-enterprise" if int(self.ver.split(".")[1])%2==0 else "-10gen-unstable"
+
+
+ def pversion(self, distro):
+ # Note: Debian packages have funny rules about dashes in
+ # version numbers, and RPM simply forbids dashes. pversion
+ # will be the package's version number (but we need to know
+ # our upstream version too).
+ if re.search("^(debian|ubuntu)", distro.name()):
+ return re.sub("-", "~", self.ver)
+ elif re.search("(redhat|fedora|centos)", distro.name()):
+ return re.sub("\\d+-", "", self.ver)
+ else:
+ raise Exception("BUG: unsupported platform?")
+
+ def param(self, param):
+ if param in self.params:
+ return self.params[param]
+ return None
+
+class Distro(object):
+ def __init__(self, string):
+ self.n=string
+
+ def name(self):
+ return self.n
+
+ def pkgbase(self):
+ # pkgbase is the first part of the package's name on
+ # this distro.
+ return "mongo" if re.search("(redhat|fedora|centos)", self.n) else "mongodb"
+
+ def archname(self, arch):
+ if re.search("^(debian|ubuntu)", self.n):
+ return "i386" if arch.endswith("86") else "amd64"
+ elif re.search("^(centos|redhat|fedora)", self.n):
+ return "i686" if arch.endswith("86") else "x86_64"
+ else:
+ raise Exception("BUG: unsupported platform?")
+
+ def repodir(self, arch):
+ """Return the directory where we'll place the package files for
+ (distro, distro_version) in that distro's preferred repository
+ layout (as distinct from where that distro's packaging building
+ tools place the package files)."""
+ if re.search("^(debian|ubuntu)", self.n):
+ return "repo/%s/dists/dist/10gen/binary-%s/" % (self.n, self.archname(arch))
+ elif re.search("(redhat|fedora|centos)", self.n):
+ return "repo/%s/os/%s/RPMS/" % (self.n, self.archname(arch))
+ else:
+ raise Exception("BUG: unsupported platform?")
+
+ def make_pkg(self, arch, spec, srcdir):
+ if re.search("^(debian|ubuntu)", self.n):
+ return make_deb(self, arch, spec, srcdir)
+ elif re.search("^(centos|redhat|fedora)", self.n):
+ return make_rpm(self, arch, spec, srcdir)
+ else:
+ raise Exception("BUG: unsupported platform?")
+
+ def build_os(self):
+ """Return the build os label in the binary package to download ("rhel62"
+ for redhat, "ubuntu1204" for Ubuntu and Debian)"""
+
+ if re.search("^(debian|ubuntu)", self.n):
+ return "ubuntu1204"
+ elif re.search("(redhat|fedora|centos)", self.n):
+ return "rhel62"
+ else:
+ raise Exception("BUG: unsupported platform?")
+def main(argv):
+ (flags, specs) = parse_args(argv[1:])
+ distros=[Distro(distro) for distro in DISTROS]
+
+ oldcwd=os.getcwd()
+ srcdir=oldcwd+"/../"
+
+ # We do all our work in a randomly-created directory. You can set
+ # TEMPDIR to influence where this program will do stuff.
+ prefix=tempfile.mkdtemp()
+ print "Working in directory %s" % prefix
+
+ # This will be a list of directories where we put packages in
+ # "repository layout".
+ repos=[]
+
+ os.chdir(prefix)
+ try:
+ # Download the binaries.
+ urlfmt="http://downloads.10gen.com/linux/mongodb-linux-%s-subscription-%s-%s.tgz"
+
+ # Build a pacakge for each distro/spec/arch tuple, and
+ # accumulate the repository-layout directories.
+ for (distro, spec, arch) in crossproduct(distros, specs, ARCHES):
+
+ httpget(urlfmt % (arch, distro.build_os(), spec.version()), ensure_dir(tarfile(distro, arch, spec)))
+
+ repos.append(make_package(distro, arch, spec, srcdir))
+
+ # Build the repos' metadatas.
+ for repo in set(repos):
+ print repo
+ make_repo(repo)
+
+ finally:
+ os.chdir(oldcwd)
+ if "-n" not in flags:
+ move_repos_into_place(prefix+"/repo", REPOPATH)
+ # FIXME: try shutil.rmtree some day.
+ sysassert(["rm", "-rv", prefix])
+
+
+def parse_args(args):
+ if len(args) == 0:
+ print """Usage: packager.py [OPTS] SPEC1 SPEC2 ... SPECn
+
+Options:
+
+ -n: Just build the packages, don't publish them as a repo
+ or clean out the working directory
+
+Each SPEC is a mongodb version string optionally followed by a colon
+and some parameters, of the form <paramname>=<value>. Supported
+parameters:
+
+ suffix -- suffix to append to the package's base name. (If
+ unsupplied, suffixes default based on the parity of the
+ middle number in the version.)
+
+ revision -- least-order version number to packaging systems
+"""
+ sys.exit(0)
+
+ try:
+ (flags, args) = getopt.getopt(args, "n")
+ except getopt.GetoptError, err:
+ print str(err)
+ sys.exit(2)
+ flags=dict(flags)
+ specs=[Spec(arg) for arg in args]
+ return (flags, specs)
+
+def crossproduct(*seqs):
+ """A generator for iterating all the tuples consisting of elements
+ of seqs."""
+ l = len(seqs)
+ if l == 0:
+ pass
+ elif l == 1:
+ for i in seqs[0]:
+ yield [i]
+ else:
+ for lst in crossproduct(*seqs[:-1]):
+ for i in seqs[-1]:
+ lst2=list(lst)
+ lst2.append(i)
+ yield lst2
+
+def sysassert(argv):
+ """Run argv and assert that it exited with status 0."""
+ print "In %s, running %s" % (os.getcwd(), " ".join(argv))
+ sys.stdout.flush()
+ sys.stderr.flush()
+ assert(subprocess.Popen(argv).wait()==0)
+
+def backtick(argv):
+ """Run argv and return its output string."""
+ print "In %s, running %s" % (os.getcwd(), " ".join(argv))
+ sys.stdout.flush()
+ sys.stderr.flush()
+ return subprocess.Popen(argv, stdout=subprocess.PIPE).communicate()[0]
+
+def ensure_dir(filename):
+ """Make sure that the directory that's the dirname part of
+ filename exists, and return filename."""
+ dirpart = os.path.dirname(filename)
+ try:
+ os.makedirs(dirpart)
+ except OSError: # as exc: # Python >2.5
+ exc=sys.exc_value
+ if exc.errno == errno.EEXIST:
+ pass
+ else:
+ raise exc
+ return filename
+
+
+def tarfile(distro, arch, spec):
+ """Return the location where we store the downloaded tarball for
+ (arch, spec)"""
+ return "dl/mongodb-linux-%s-subscription-%s-%s.tar.gz" % (spec.version(), distro.build_os(), arch)
+
+def setupdir(distro, arch, spec):
+ # The setupdir will be a directory containing all inputs to the
+ # distro's packaging tools (e.g., package metadata files, init
+ # scripts, etc), along with the already-built binaries). In case
+ # the following format string is unclear, an example setupdir
+ # would be dst/x86_64/debian-sysvinit/mongodb-10gen-unstable/
+ return "dst/%s/%s/%s%s-%s/" % (arch, distro.name(), distro.pkgbase(), spec.suffix(), spec.pversion(distro))
+
+def httpget(url, filename):
+ """Download the contents of url to filename, return filename."""
+ print "Fetching %s to %s." % (url, filename)
+ conn = None
+ u=urlparse.urlparse(url)
+ assert(u.scheme=='http')
+ try:
+ conn = httplib.HTTPConnection(u.hostname)
+ conn.request("GET", u.path)
+ t=filename+'.TMP'
+ res = conn.getresponse()
+ # FIXME: follow redirects
+ if res.status==200:
+ f = open(t, 'w')
+ try:
+ f.write(res.read())
+ finally:
+ f.close()
+
+ else:
+ raise Exception("HTTP error %d" % res.status)
+ os.rename(t, filename)
+ finally:
+ if conn:
+ conn.close()
+ return filename
+
+def unpack_binaries_into(distro, arch, spec, where):
+ """Unpack the tarfile for (distro, arch, spec) into directory where."""
+ rootdir=os.getcwd()
+ ensure_dir(where)
+ # Note: POSIX tar doesn't require support for gtar's "-C" option,
+ # and Python's tarfile module prior to Python 2.7 doesn't have the
+ # features to make this detail easy. So we'll just do the dumb
+ # thing and chdir into where and run tar there.
+ os.chdir(where)
+ try:
+ sysassert(["tar", "xvzf", rootdir+"/"+tarfile(distro, arch, spec), "mongodb-linux-%s-subscription-%s-%s/bin" % (arch, distro.build_os(), spec.version())])
+ os.rename("mongodb-linux-%s-subscription-%s-%s/bin" % (arch, distro.build_os(), spec.version()), "bin")
+ os.rmdir("mongodb-linux-%s-subscription-%s-%s" % (arch, distro.build_os(), spec.version()))
+ except Exception:
+ exc=sys.exc_value
+ os.chdir(rootdir)
+ raise exc
+ os.chdir(rootdir)
+
+def make_package(distro, arch, spec, srcdir):
+ """Construct the package for (arch, distro, spec), getting
+ packaging files from srcdir and any user-specified suffix from
+ suffixes"""
+
+ sdir=setupdir(distro, arch, spec)
+ ensure_dir(sdir)
+ # Note that the RPM packages get their man pages from the debian
+ # directory, so the debian directory is needed in all cases (and
+ # innocuous in the debianoids' sdirs).
+ for pkgdir in ["debian", "rpm"]:
+ print "Copying packaging files from %s to %s" % ("%s/%s" % (srcdir, pkgdir), sdir)
+ # FIXME: sh-dash-cee is bad. See if tarfile can do this.
+ sysassert(["sh", "-c", "(cd \"%s\" && git archive r%s %s/ ) | (cd \"%s\" && tar xvf -)" % (srcdir, spec.version(), pkgdir, sdir)])
+ # Splat the binaries under sdir. The "build" stages of the
+ # packaging infrastructure will move the binaries to wherever they
+ # need to go.
+ unpack_binaries_into(distro, arch, spec, sdir+("%s/usr/"%BINARYDIR))
+ # Remove the mongosniff binary due to libpcap dynamic
+ # linkage. FIXME: this removal should go away
+ # eventually.
+ if os.path.exists(sdir+("%s/usr/bin/mongosniff"%BINARYDIR)):
+ os.unlink(sdir+("%s/usr/bin/mongosniff"%BINARYDIR))
+ return distro.make_pkg(arch, spec, srcdir)
+
+def make_repo(repodir):
+ if re.search("(debian|ubuntu)", repodir):
+ make_deb_repo(repodir)
+ elif re.search("(centos|redhat|fedora)", repodir):
+ make_rpm_repo(repodir)
+ else:
+ raise Exception("BUG: unsupported platform?")
+
+def make_deb(distro, arch, spec, srcdir):
+ # I can't remember the details anymore, but the initscript/upstart
+ # job files' names must match the package name in some way; and
+ # see also the --name flag to dh_installinit in the generated
+ # debian/rules file.
+ suffix=spec.suffix()
+ sdir=setupdir(distro, arch, spec)
+ if re.search("sysvinit", distro.name()):
+ os.link(sdir+"debian/init.d", sdir+"debian/%s%s.mongodb.init" % (distro.pkgbase(), suffix))
+ os.unlink(sdir+"debian/mongodb.upstart")
+ elif re.search("upstart", distro.name()):
+ os.link(sdir+"debian/mongodb.upstart", sdir+"debian/%s%s.upstart" % (distro.pkgbase(), suffix))
+ os.unlink(sdir+"debian/init.d")
+ else:
+ raise Exception("unknown debianoid flavor: not sysvinit or upstart?")
+ # Rewrite the control and rules files
+ write_debian_control_file(sdir+"debian/control", spec)
+ write_debian_rules_file(sdir+"debian/rules", spec)
+ write_debian_changelog(sdir+"debian/changelog", spec, srcdir)
+ distro_arch=distro.archname(arch)
+ # Do the packaging.
+ oldcwd=os.getcwd()
+ try:
+ os.chdir(sdir)
+ sysassert(["dpkg-buildpackage", "-a"+distro_arch, "-k Richard Kreuter <richard@10gen.com>"])
+ finally:
+ os.chdir(oldcwd)
+ r=distro.repodir(arch)
+ ensure_dir(r)
+ # FIXME: see if shutil.copyfile or something can do this without
+ # much pain.
+ sysassert(["cp", "-v", sdir+"../%s%s_%s%s_%s.deb"%(distro.pkgbase(), suffix, spec.pversion(distro), "-"+spec.param("revision") if spec.param("revision") else"", distro_arch), r])
+ return r
+
+def make_deb_repo(repo):
+ # Note: the Debian repository Packages files must be generated
+ # very carefully in order to be usable.
+ oldpwd=os.getcwd()
+ os.chdir(repo+"../../../../")
+ try:
+ dirs=set([os.path.dirname(deb)[2:] for deb in backtick(["find", ".", "-name", "*.deb"]).split()])
+ for d in dirs:
+ s=backtick(["dpkg-scanpackages", d, "/dev/null"])
+ f=open(d+"/Packages", "w")
+ try:
+ f.write(s)
+ finally:
+ f.close()
+ b=backtick(["gzip", "-9c", d+"/Packages"])
+ f=open(d+"/Packages.gz", "wb")
+ try:
+ f.write(b)
+ finally:
+ f.close()
+ finally:
+ os.chdir(oldpwd)
+ # Notes: the Release{,.gpg} files must live in a special place,
+ # and must be created after all the Packages.gz files have been
+ # done.
+ s="""
+Origin: 10gen
+Label: 10gen
+Suite: 10gen
+Codename: %s
+Version: %s
+Architectures: i386 amd64
+Components: 10gen
+Description: 10gen packages
+""" % ("dist", "dist")
+ if os.path.exists(repo+"../../Release"):
+ os.unlink(repo+"../../Release")
+ if os.path.exists(repo+"../../Release.gpg"):
+ os.unlink(repo+"../../Release.gpg")
+ oldpwd=os.getcwd()
+ os.chdir(repo+"../../")
+ s2=backtick(["apt-ftparchive", "release", "."])
+ try:
+ f=open("Release", 'w')
+ try:
+ f.write(s)
+ f.write(s2)
+ finally:
+ f.close()
+
+ arg=None
+ for line in backtick(["gpg", "--list-keys"]).split("\n"):
+ tokens=line.split()
+ if len(tokens)>0 and tokens[0] == "uid":
+ arg=tokens[-1]
+ break
+ # Note: for some reason, I think --no-tty might be needed
+ # here, but maybe not.
+ sysassert(["gpg", "-r", arg, "--no-secmem-warning", "-abs", "--output", "Release.gpg", "Release"])
+ finally:
+ os.chdir(oldpwd)
+
+
+def move_repos_into_place(src, dst):
+ # Find all the stuff in src/*, move it to a freshly-created
+ # directory beside dst, then play some games with symlinks so that
+ # dst is a name the new stuff and dst+".old" names the previous
+ # one. This feels like a lot of hooey for something so trivial.
+
+ # First, make a crispy fresh new directory to put the stuff in.
+ i=0
+ while True:
+ date_suffix=time.strftime("%Y-%m-%d")
+ dname=dst+".%s.%d" % (date_suffix, i)
+ try:
+ os.mkdir(dname)
+ break
+ except OSError:
+ exc=sys.exc_value
+ if exc.errno == errno.EEXIST:
+ pass
+ else:
+ raise exc
+ i=i+1
+
+ # Put the stuff in our new directory.
+ for r in os.listdir(src):
+ sysassert(["cp", "-rv", src + "/" + r, dname])
+
+ # Make a symlink to the new directory; the symlink will be renamed
+ # to dst shortly.
+ i=0
+ while True:
+ tmpnam=dst+".TMP.%d" % i
+ try:
+ os.symlink(dname, tmpnam)
+ break
+ except OSError: # as exc: # Python >2.5
+ exc=sys.exc_value
+ if exc.errno == errno.EEXIST:
+ pass
+ else:
+ raise exc
+ i=i+1
+
+ # Make a symlink to the old directory; this symlink will be
+ # renamed shortly, too.
+ oldnam=None
+ if os.path.exists(dst):
+ i=0
+ while True:
+ oldnam=dst+".old.%d" % i
+ try:
+ os.symlink(os.readlink(dst), oldnam)
+ break
+ except OSError: # as exc: # Python >2.5
+ exc=sys.exc_value
+ if exc.errno == errno.EEXIST:
+ pass
+ else:
+ raise exc
+
+ os.rename(tmpnam, dst)
+ if oldnam:
+ os.rename(oldnam, dst+".old")
+
+
+def write_debian_changelog(path, spec, srcdir):
+ oldcwd=os.getcwd()
+ os.chdir(srcdir)
+ preamble=""
+ if spec.param("revision"):
+ preamble="""mongodb%s (%s-%s) unstable; urgency=low
+
+ * Bump revision number
+
+ -- Richard Kreuter <richard@10gen.com> %s
+
+""" % (spec.suffix(), spec.pversion(Distro("debian")), spec.param("revision"), time.strftime("%a, %d %b %Y %H:%m:%S %z"))
+ try:
+ s=preamble+backtick(["sh", "-c", "git archive r%s debian/changelog | tar xOf -" % spec.version()])
+ finally:
+ os.chdir(oldcwd)
+ f=open(path, 'w')
+ lines=s.split("\n")
+ # If the first line starts with "mongodb", it's not a revision
+ # preamble, and so frob the version number.
+ lines[0]=re.sub("^mongodb \\(.*\\)", "mongodb (%s)" % (spec.pversion(Distro("debian"))), lines[0])
+ # Rewrite every changelog entry starting in mongodb<space>
+ lines=[re.sub("^mongodb ", "mongodb%s " % (spec.suffix()), l) for l in lines]
+ lines=[re.sub("^ --", " --", l) for l in lines]
+ s="\n".join(lines)
+ try:
+ f.write(s)
+ finally:
+ f.close()
+
+def write_debian_control_file(path, spec):
+ s="""Source: @@PACKAGE_BASENAME@@
+Section: devel
+Priority: optional
+Maintainer: Richard Kreuter <richard@10gen.com>
+Build-Depends:
+Standards-Version: 3.8.0
+Homepage: http://www.mongodb.org
+
+Package: @@PACKAGE_BASENAME@@
+Conflicts: @@PACKAGE_CONFLICTS@@
+Architecture: any
+Depends: libc6 (>= 2.3.2), libgcc1 (>= 1:4.1.1), libstdc++6 (>= 4.1.1), libsnmp15, libgsasl7
+Description: An object/document-oriented database
+ MongoDB is a high-performance, open source, schema-free
+ document-oriented data store that's easy to deploy, manage
+ and use. It's network accessible, written in C++ and offers
+ the following features :
+ .
+ * Collection oriented storage - easy storage of object-
+ style data
+ * Full index support, including on inner objects
+ * Query profiling
+ * Replication and fail-over support
+ * Efficient storage of binary data including large
+ objects (e.g. videos)
+ * Auto-sharding for cloud-level scalability (Q209)
+ .
+ High performance, scalability, and reasonable depth of
+ functionality are the goals for the project.
+"""
+ s=re.sub("@@PACKAGE_BASENAME@@", "mongodb%s" % spec.suffix(), s)
+ conflict_suffixes=["", "-stable", "-unstable", "-nightly", "-10gen", "-10gen-unstable", "-10gen-enterprise"]
+ conflict_suffixes = [suff for suff in conflict_suffixes if suff != spec.suffix()]
+ s=re.sub("@@PACKAGE_CONFLICTS@@", ", ".join(["mongodb"+suffix for suffix in conflict_suffixes]), s)
+ f=open(path, 'w')
+ try:
+ f.write(s)
+ finally:
+ f.close()
+
+def write_debian_rules_file(path, spec):
+ # Note debian/rules is a makefile, so for visual disambiguation we
+ # make all tabs here \t.
+ s="""#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+
+configure: configure-stamp
+configure-stamp:
+\tdh_testdir
+ # Add here commands to configure the package.
+
+\ttouch configure-stamp
+
+
+build: build-stamp
+
+build-stamp: configure-stamp
+\tdh_testdir
+
+ # Add here commands to compile the package.
+# THE FOLLOWING LINE IS INTENTIONALLY COMMENTED.
+\t# scons
+ #docbook-to-man debian/mongodb.sgml > mongodb.1
+\tls debian/*.1 > debian/@@PACKAGE_NAME@@.manpages
+
+\ttouch $@
+
+clean:
+\tdh_testdir
+\tdh_testroot
+\trm -f build-stamp configure-stamp
+
+\t# FIXME: scons freaks out at the presence of target files
+\t# under debian/mongodb.
+\t#scons -c
+\trm -rf $(CURDIR)/debian/@@PACKAGE_NAME@@
+\trm -f config.log
+\trm -f mongo
+\trm -f mongod
+\trm -f mongoimportjson
+\trm -f mongoexport
+\trm -f mongorestore
+\trm -f mongodump
+\trm -f mongofiles
+\trm -f .sconsign.dblite
+\trm -f libmongoclient.a
+\trm -rf client/*.o
+\trm -rf tools/*.o
+\trm -rf shell/*.o
+\trm -rf .sconf_temp
+\trm -f buildscripts/*.pyc
+\trm -f *.pyc
+\trm -f buildinfo.cpp
+\tdh_clean debian/files
+
+install: build
+\tdh_testdir
+\tdh_testroot
+\tdh_prep
+\tdh_installdirs
+
+# THE FOLLOWING LINE IS INTENTIONALLY COMMENTED.
+\t# scons --prefix=$(CURDIR)/debian/mongodb/usr install
+\tcp -v $(CURDIR)/@@BINARYDIR@@/usr/bin/* $(CURDIR)/debian/@@PACKAGE_NAME@@/usr/bin
+\tmkdir -p $(CURDIR)/debian/@@PACKAGE_NAME@@/etc
+\tcp $(CURDIR)/debian/mongodb.conf $(CURDIR)/debian/@@PACKAGE_NAME@@/etc/mongodb.conf
+
+\tmkdir -p $(CURDIR)/debian/@@PACKAGE_NAME@@/usr/share/lintian/overrides/
+\tinstall -m 644 $(CURDIR)/debian/lintian-overrides \
+\t\t$(CURDIR)/debian/@@PACKAGE_NAME@@/usr/share/lintian/overrides/@@PACKAGE_NAME@@
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+\tdh_testdir
+\tdh_testroot
+\tdh_installchangelogs
+\tdh_installdocs
+\tdh_installexamples
+#\tdh_install
+#\tdh_installmenu
+#\tdh_installdebconf\t
+#\tdh_installlogrotate
+#\tdh_installemacsen
+#\tdh_installpam
+#\tdh_installmime
+\tdh_installinit --name=@@PACKAGE_BASENAME@@
+#\tdh_installinfo
+\tdh_installman
+\tdh_link
+# Appears to be broken on Ubuntu 11.10...?
+#\tdh_strip
+\tdh_compress
+\tdh_fixperms
+\tdh_installdeb
+\tdh_shlibdeps
+\tdh_gencontrol
+\tdh_md5sums
+\tdh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
+"""
+ s=re.sub("@@PACKAGE_NAME@@", "mongodb%s" % spec.suffix(), s)
+ s=re.sub("@@PACKAGE_BASENAME@@", "mongodb", s)
+ s=re.sub("@@BINARYDIR@@", BINARYDIR, s)
+ f=open(path, 'w')
+ try:
+ f.write(s)
+ finally:
+ f.close()
+ # FIXME: some versions of debianoids seem to
+ # need the rules file to be 755?
+ os.chmod(path, stat.S_IXUSR|stat.S_IWUSR|stat.S_IRUSR|stat.S_IXGRP|stat.S_IRGRP|stat.S_IXOTH|stat.S_IWOTH)
+
+def make_rpm(distro, arch, spec, srcdir):
+ # Create the specfile.
+ suffix=spec.suffix()
+ sdir=setupdir(distro, arch, spec)
+ specfile=sdir+"rpm/mongo%s.spec" % suffix
+ write_rpm_spec_file(specfile, spec)
+ topdir=ensure_dir(os.getcwd()+'/rpmbuild/')
+ for subdir in ["BUILD", "RPMS", "SOURCES", "SPECS", "SRPMS"]:
+ ensure_dir("%s/%s/" % (topdir, subdir))
+ distro_arch=distro.archname(arch)
+ # RPM tools take these macro files that define variables in
+ # RPMland. Unfortunately, there's no way to tell RPM tools to use
+ # a given file *in addition* to the files that it would already
+ # load, so we have to figure out what it would normally load,
+ # augment that list, and tell RPM to use the augmented list. To
+ # figure out what macrofiles ordinarily get loaded, older RPM
+ # versions had a parameter called "macrofiles" that could be
+ # extracted from "rpm --showrc". But newer RPM versions don't
+ # have this. To tell RPM what macros to use, older versions of
+ # RPM have a --macros option that doesn't work; on these versions,
+ # you can put a "macrofiles" parameter into an rpmrc file. But
+ # that "macrofiles" setting doesn't do anything for newer RPM
+ # versions, where you have to use the --macros flag instead. And
+ # all of this is to let us do our work with some guarantee that
+ # we're not clobbering anything that doesn't belong to us. Why is
+ # RPM so braindamaged?
+ macrofiles=[l for l in backtick(["rpm", "--showrc"]).split("\n") if l.startswith("macrofiles")]
+ flags=[]
+ macropath=os.getcwd()+"/macros"
+ write_rpm_macros_file(macropath, topdir)
+ if len(macrofiles)>0:
+ macrofiles=macrofiles[0]+":"+macropath
+ rcfile=os.getcwd()+"/rpmrc"
+ write_rpmrc_file(rcfile, macrofiles)
+ flags=["--rpmrc", rcfile]
+ else:
+ # This hard-coded hooey came from some box running RPM
+ # 4.4.2.3. It may not work over time, but RPM isn't sanely
+ # configurable.
+ flags=["--macros", "/usr/lib/rpm/macros:/usr/lib/rpm/%s-linux/macros:/etc/rpm/macros.*:/etc/rpm/macros:/etc/rpm/%s-linux/macros:~/.rpmmacros:%s" % (distro_arch, distro_arch, macropath)]
+ # Put the specfile and the tar'd up binaries and stuff in
+ # place. FIXME: see if shutil.copyfile can do this without too
+ # much hassle.
+ sysassert(["cp", "-v", specfile, topdir+"SPECS/"])
+ oldcwd=os.getcwd()
+ os.chdir(sdir+"/../")
+ try:
+ sysassert(["tar", "-cpzf", topdir+"SOURCES/mongo%s-%s.tar.gz" % (suffix, spec.pversion(distro)), os.path.basename(os.path.dirname(sdir))])
+ finally:
+ os.chdir(oldcwd)
+ # Do the build.
+ sysassert(["rpmbuild", "-ba", "--target", distro_arch] + flags + ["%s/SPECS/mongo%s.spec" % (topdir, suffix)])
+ r=distro.repodir(arch)
+ ensure_dir(r)
+ # FIXME: see if some combination of shutil.copy<hoohah> and glob
+ # can do this without shelling out.
+ sysassert(["sh", "-c", "cp -v \"%s/RPMS/%s/\"*.rpm \"%s\""%(topdir, distro_arch, r)])
+ return r
+
+def make_rpm_repo(repo):
+ oldpwd=os.getcwd()
+ os.chdir(repo+"../")
+ try:
+ sysassert(["createrepo", "."])
+ finally:
+ os.chdir(oldpwd)
+
+
+def write_rpmrc_file(path, string):
+ f=open(path, 'w')
+ try:
+ f.write(string)
+ finally:
+ f.close()
+
+def write_rpm_macros_file(path, topdir):
+ f=open(path, 'w')
+ try:
+ f.write("%%_topdir %s" % topdir)
+ finally:
+ f.close()
+
+def write_rpm_spec_file(path, spec):
+ s="""Name: @@PACKAGE_BASENAME@@
+Conflicts: @@PACKAGE_CONFLICTS@@
+Obsoletes: @@PACKAGE_OBSOLETES@@
+Version: @@PACKAGE_VERSION@@
+Release: mongodb_@@PACKAGE_REVISION@@%{?dist}
+Summary: mongo client shell and tools
+License: AGPL 3.0
+URL: http://www.mongodb.org
+Group: Applications/Databases
+Requires: libgsasl, net-snmp-libs
+
+Source0: %{name}-%{version}.tar.gz
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
+
+%description
+Mongo (from "huMONGOus") is a schema-free document-oriented database.
+It features dynamic profileable queries, full indexing, replication
+and fail-over support, efficient storage of large binary data objects,
+and auto-sharding.
+
+This package provides the mongo shell, import/export tools, and other
+client utilities.
+
+%package server
+Summary: mongo server, sharding server, and support scripts
+Group: Applications/Databases
+Requires: @@PACKAGE_BASENAME@@
+
+%description server
+Mongo (from "huMONGOus") is a schema-free document-oriented database.
+
+This package provides the mongo server software, mongo sharding server
+softwware, default configuration files, and init.d scripts.
+
+%package devel
+Summary: Headers and libraries for mongo development.
+Group: Applications/Databases
+
+%description devel
+Mongo (from "huMONGOus") is a schema-free document-oriented database.
+
+This package provides the mongo static library and header files needed
+to develop mongo client software.
+
+%prep
+%setup
+
+%build
+#scons --prefix=$RPM_BUILD_ROOT/usr all
+# XXX really should have shared library here
+
+%install
+#scons --prefix=$RPM_BUILD_ROOT/usr install
+mkdir -p $RPM_BUILD_ROOT/usr
+cp -rv @@BINARYDIR@@/usr/bin $RPM_BUILD_ROOT/usr
+mkdir -p $RPM_BUILD_ROOT/usr/share/man/man1
+cp debian/*.1 $RPM_BUILD_ROOT/usr/share/man/man1/
+# FIXME: remove this rm when mongosniff is back in the package
+rm -v $RPM_BUILD_ROOT/usr/share/man/man1/mongosniff.1*
+mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d
+cp -v rpm/init.d-mongod $RPM_BUILD_ROOT/etc/rc.d/init.d/mongod
+chmod a+x $RPM_BUILD_ROOT/etc/rc.d/init.d/mongod
+mkdir -p $RPM_BUILD_ROOT/etc
+cp -v rpm/mongod.conf $RPM_BUILD_ROOT/etc/mongod.conf
+mkdir -p $RPM_BUILD_ROOT/etc/sysconfig
+cp -v rpm/mongod.sysconfig $RPM_BUILD_ROOT/etc/sysconfig/mongod
+mkdir -p $RPM_BUILD_ROOT/var/lib/mongo
+mkdir -p $RPM_BUILD_ROOT/var/log/mongo
+touch $RPM_BUILD_ROOT/var/log/mongo/mongod.log
+
+%clean
+#scons -c
+rm -rf $RPM_BUILD_ROOT
+
+%pre server
+if ! /usr/bin/id -g mongod &>/dev/null; then
+ /usr/sbin/groupadd -r mongod
+fi
+if ! /usr/bin/id mongod &>/dev/null; then
+ /usr/sbin/useradd -M -r -g mongod -d /var/lib/mongo -s /bin/false \
+ -c mongod mongod > /dev/null 2>&1
+fi
+
+%post server
+if test $1 = 1
+then
+ /sbin/chkconfig --add mongod
+fi
+
+%preun server
+if test $1 = 0
+then
+ /sbin/chkconfig --del mongod
+fi
+
+%postun server
+if test $1 -ge 1
+then
+ /sbin/service mongod condrestart >/dev/null 2>&1 || :
+fi
+
+%files
+%defattr(-,root,root,-)
+#%doc README GNU-AGPL-3.0.txt
+
+%{_bindir}/bsondump
+%{_bindir}/mongo
+%{_bindir}/mongodump
+%{_bindir}/mongoexport
+#@@VERSION!=2.1.0@@%{_bindir}/mongofiles
+%{_bindir}/mongoimport
+#@@VERSION>=2.1.0@@%{_bindir}/mongooplog
+#@@VERSION>=2.1.0@@%{_bindir}/mongoperf
+%{_bindir}/mongorestore
+#@@VERSION>1.9@@%{_bindir}/mongotop
+%{_bindir}/mongostat
+# FIXME: uncomment when mongosniff is back in the package
+#%{_bindir}/mongosniff
+
+# FIXME: uncomment this when there's a stable release whose source
+# tree contains a bsondump man page.
+#@@VERSION>1.9@@%{_mandir}/man1/bsondump.1*
+%{_mandir}/man1/mongo.1*
+%{_mandir}/man1/mongodump.1*
+%{_mandir}/man1/mongoexport.1*
+%{_mandir}/man1/mongofiles.1*
+%{_mandir}/man1/mongoimport.1*
+%{_mandir}/man1/mongorestore.1*
+%{_mandir}/man1/mongostat.1*
+# FIXME: uncomment when mongosniff is back in the package
+#%{_mandir}/man1/mongosniff.1*
+
+%files server
+%defattr(-,root,root,-)
+%config(noreplace) /etc/mongod.conf
+%{_bindir}/mongod
+%{_bindir}/mongos
+%{_mandir}/man1/mongod.1*
+%{_mandir}/man1/mongos.1*
+/etc/rc.d/init.d/mongod
+/etc/sysconfig/mongod
+#/etc/rc.d/init.d/mongos
+%attr(0755,mongod,mongod) %dir /var/lib/mongo
+%attr(0755,mongod,mongod) %dir /var/log/mongo
+%attr(0640,mongod,mongod) %config(noreplace) %verify(not md5 size mtime) /var/log/mongo/mongod.log
+
+%changelog
+* Thu Jan 28 2010 Richard M Kreuter <richard@10gen.com>
+- Minor fixes.
+
+* Sat Oct 24 2009 Joe Miklojcik <jmiklojcik@shopwiki.com> -
+- Wrote mongo.spec.
+"""
+ suffix=spec.suffix()
+ s=re.sub("@@PACKAGE_BASENAME@@", "mongo%s" % suffix, s)
+ s=re.sub("@@PACKAGE_VERSION@@", spec.pversion(Distro("redhat")), s)
+ # FIXME, maybe: the RPM guide says that Release numbers ought to
+ # be integers starting at 1, but we use "mongodb_1{%dist}",
+ # whatever the hell that means.
+ s=re.sub("@@PACKAGE_REVISION@@", str(int(spec.param("revision"))+1) if spec.param("revision") else "1", s)
+ s=re.sub("@@BINARYDIR@@", BINARYDIR, s)
+ conflict_suffixes=["", "-10gen", "-10gen-unstable", "-10gen-enterprise"]
+ conflict_suffixes = [suff for suff in conflict_suffixes if suff != spec.suffix()]
+ s=re.sub("@@PACKAGE_CONFLICTS@@", ", ".join(["mongo"+_ for _ in conflict_suffixes]), s)
+ if suffix.endswith("-10gen"):
+ s=re.sub("@@PACKAGE_PROVIDES@@", "mongo-stable", s)
+ s=re.sub("@@PACKAGE_OBSOLETES@@", "mongo-stable", s)
+ elif suffix == "-10gen-unstable":
+ s=re.sub("@@PACKAGE_PROVIDES@@", "mongo-unstable", s)
+ s=re.sub("@@PACKAGE_OBSOLETES@@", "mongo-unstable", s)
+ elif suffix == "-10gen-enterprise":
+ s=re.sub("@@PACKAGE_PROVIDES@@", "mongo-enterprise", s)
+ s=re.sub("@@PACKAGE_OBSOLETES@@", "mongo-enterprise", s)
+ else:
+ raise Exception("BUG: unknown suffix %s" % suffix)
+
+ lines=[]
+ for line in s.split("\n"):
+ m = re.search("@@VERSION(>|>=|!=)(\d.*)@@(.*)", line)
+ if m:
+ op = m.group(1)
+ ver = m.group(2)
+ fn = m.group(3)
+ if op == '>':
+ if spec.version_better_than(ver):
+ lines.append(fn)
+ elif op == '>=':
+ if spec.version() == ver or spec.version_better_than(ver):
+ lines.append(fn)
+ elif op == '!=':
+ if spec.version() != ver:
+ lines.append(fn)
+ else:
+ # Since we're inventing our own template system for RPM
+ # specfiles here, we oughtn't use template syntax we don't
+ # support.
+ raise Exception("BUG: probable bug in packager script: %s, %s, %s" % (m.group(1), m.group(2), m.group(3)))
+ else:
+ lines.append(line)
+ s="\n".join(lines)
+
+ f=open(path, 'w')
+ try:
+ f.write(s)
+ finally:
+ f.close()
+
+if __name__ == "__main__":
+ main(sys.argv)