Change in bazel[master]: Add script to generate an RPM file

269 views
Skip to first unread message

John Cater (Gerrit)

unread,
Jan 31, 2017, 3:11:11 PM1/31/17
to bazel-de...@googlegroups.com

John Cater has uploaded this change for review.

View Change

Add script to generate an RPM file

Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
---
M scripts/packages/fedora/BUILD
M scripts/packages/fedora/bazel.spec
D scripts/packages/fedora/build_rpm.sh
M tools/build_defs/pkg/BUILD
A tools/build_defs/pkg/make_rpm.py
A tools/build_defs/pkg/rpm.bzl
6 files changed, 297 insertions(+), 76 deletions(-)

diff --git a/scripts/packages/fedora/BUILD b/scripts/packages/fedora/BUILD
index 36d8690..4cffb30 100644
--- a/scripts/packages/fedora/BUILD
+++ b/scripts/packages/fedora/BUILD
@@ -5,26 +5,18 @@
     srcs = glob(["**"]),
 )
 
-genrule(
-    name = "bazel-fedora",
-    srcs = [
-        "bazel.spec",
+load("//tools/build_defs/pkg:rpm.bzl", "pkg_rpm")
+
+pkg_rpm(
+    name = "bazel",
+    spec_file = "bazel.spec",
+    architecture = "x86_64",
+    changelog = "//:changelog-file",
+    version_file = "//scripts/packages:version.txt",
+    data = [
         "//scripts/packages:bazel",
         "//scripts/packages:bazel-real",
-        "//scripts/packages:debian/bazel.bazelrc",
+        "//scripts/packages:bazel.bazelrc",
         "//scripts:bash_completion",
     ],
-    outs = [
-        "bazel-fedora.rpm",
-    ],
-    cmd = """
-      $(location :build_rpm.sh) \
-        $(location :bazel.spec) \
-        $(location bazel-fedora.rpm) \
-        $(location //scripts/packages:bazel) \
-        $(location //scripts/packages:bazel-real) \
-        $(location //scripts/packages:debian/bazel.bazelrc) \
-        $(location //scripts:bash_completion)
-    """,
-    tools = ["build_rpm.sh"],
 )
diff --git a/scripts/packages/fedora/bazel.spec b/scripts/packages/fedora/bazel.spec
index 0d69e61..14cabfc 100644
--- a/scripts/packages/fedora/bazel.spec
+++ b/scripts/packages/fedora/bazel.spec
@@ -30,7 +30,7 @@
 install -m 755 bazel-real %{buildroot}%{_bindir}/bazel-real
 mkdir -p %{buildroot}%{_sysconfdir}/
 install -m 644 bazel.bazelrc %{buildroot}%{_sysconfdir}/bazel.bazelrc
-mkdir -p %{buildroot}%{_sysconfdir}/bash_completion.d
+mkdir -p %{buildroot}%{_sysconfdir}/bash_completion.d/
 install -m 644 bazel-complete.bash %{buildroot}%{_sysconfdir}/bash_completion.d/bazel
 
 %files
@@ -40,4 +40,6 @@
 %{_sysconfdir}/bash_completion.d/bazel
 
 %changelog
-# TODO: Include changelog.
+* Fri Jan 27 2017 jca...@google.com - devel-1
+- Initial package version released.
+
diff --git a/scripts/packages/fedora/build_rpm.sh b/scripts/packages/fedora/build_rpm.sh
deleted file mode 100755
index 525c858..0000000
--- a/scripts/packages/fedora/build_rpm.sh
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/bin/sh
-
-# Copyright 2016 The Bazel Authors. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-set -eu
-
-# Build a RPM archive from the Bazel sources.
-
-# Usage: build_rpm.sh spec_file dest_file [other files]
-
-spec_file=$1
-shift
-dest_file=$1
-shift
-
-echo "Building ${dest_file} from ${spec_file}."
-WORK_DIR="${PWD}/bazel-fedora"
-
-# Copy needed sources.
-rm -rf ${WORK_DIR}
-mkdir -p ${WORK_DIR}/SOURCES
-mkdir -p ${WORK_DIR}/BUILD
-cp $spec_file ${WORK_DIR}
-for i in "$@"; do
-  cp $i $WORK_DIR/BUILD
-done
-
-# Build the RPM.
-rpmbuild \
-  --define "_topdir ${WORK_DIR}" \
-  --define "_tmppath /tmp" \
-  -bb ${spec_file} > rpmbuild.log 2>&1
-if [ $? -ne 0 ]; then
-  err=$?
-  echo "Error in rpmbuild:"
-  cat rpmbuild.log
-  exit $err
-fi
-out_file=$(grep '^Wrote:' rpmbuild.log | cut -d ' ' -f 2)
-
-# Copy output back to the destination.
-cp $out_file $dest_file
-echo "Created $dest_file"
-
diff --git a/tools/build_defs/pkg/BUILD b/tools/build_defs/pkg/BUILD
index 1bc4786..63579d9 100644
--- a/tools/build_defs/pkg/BUILD
+++ b/tools/build_defs/pkg/BUILD
@@ -66,6 +66,16 @@
     ],
 )
 
+# Used by pkg_rpm in rpm.bzl.
+py_binary(
+    name = "make_rpm",
+    srcs = ["make_rpm.py"],
+    visibility = ["//visibility:public"],
+    deps = [
+        "@bazel_tools//third_party/py/gflags",
+    ],
+)
+
 # tests
 load("//tools/build_defs/pkg:pkg.bzl", "pkg_deb", "pkg_tar")
 
diff --git a/tools/build_defs/pkg/make_rpm.py b/tools/build_defs/pkg/make_rpm.py
new file mode 100644
index 0000000..91a58ad
--- /dev/null
+++ b/tools/build_defs/pkg/make_rpm.py
@@ -0,0 +1,190 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""A simple cross-platform helper to create an RPM package."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import contextlib
+import fileinput
+import os
+import re
+import shutil
+import subprocess
+import sys
+from tempfile import mkdtemp
+
+from third_party.py import gflags
+
+
+gflags.DEFINE_string('name', '',
+                     'The name of the software being packaged.')
+gflags.DEFINE_string('version', '',
+                     'The version of the software being packaged.')
+gflags.DEFINE_string('arch', '',
+                     'The CPU architecture of the software being packaged.')
+
+gflags.DEFINE_string('spec_file', '',
+                     'The file containing the RPM specification.')
+gflags.DEFINE_string('out_file', '',
+                     'The destination to save the resulting RPM file to.')
+
+# Debugging options.
+gflags.DEFINE_string('debug_tempdir', None,
+                     'A directory to use instead of the temporary directory.')
+
+
+# Setup to safely create a temporary directory and clean it up when done.
+...@contextlib.contextmanager
+def Cd(newdir, cleanup=lambda: True):
+  prevdir = os.getcwd()
+  os.chdir(os.path.expanduser(newdir))
+  try:
+    yield
+  finally:
+    os.chdir(prevdir)
+    cleanup()
+
+
+...@contextlib.contextmanager
+def Tempdir():
+  if FLAGS.debug_tempdir:
+    with Cd(FLAGS.debug_tempdir):
+      yield FLAGS.debug_tempdir
+  else:
+    dirpath = mkdtemp()
+
+    def Cleanup():
+      shutil.rmtree(dirpath)
+
+    with Cd(dirpath, Cleanup):
+      yield dirpath
+
+
+def GetFlagValue(flagvalue, strip=True):
+  if flagvalue:
+    if flagvalue[0] == '@':
+      with open(flagvalue[1:], 'r') as f:
+        flagvalue = f.read()
+    if strip:
+      return flagvalue.strip()
+  return flagvalue
+
+
+class RpmBuilder(object):
+  """A helper class to manage building the RPM file."""
+
+  SOURCE_DIR = 'SOURCES'
+  BUILD_DIR = 'BUILD'
+  TEMP_DIR = 'TMP'
+  DIRS = [SOURCE_DIR, BUILD_DIR, TEMP_DIR]
+  WROTE_FILE_RE = re.compile(r'Wrote: (?P<rpm_path>.+)', re.MULTILINE)
+
+  def __init__(self, name, version, arch):
+    self.name = name
+    self.version = GetFlagValue(version)
+    self.arch = arch
+    self.files = []
+    self.rpm_path = None
+
+  def AddFiles(self, files):
+    """Add a set of files to the current RPM."""
+    self.files += files
+
+  def SetupWorkdir(self, spec_file, original_dir):
+    """Create the needed structure in the workdir."""
+
+    # Create directory structure.
+    for name in RpmBuilder.DIRS:
+      if not os.path.exists(name):
+        os.makedirs(name, 0777)
+
+    shutil.copy(spec_file, '.')
+
+    # Copy the files.
+    for f in self.files:
+      shutil.copy(os.path.join(original_dir, f), RpmBuilder.BUILD_DIR)
+
+    # Copy the spec file, updating with the correct version.
+    self.spec_file = os.path.basename(spec_file)
+    with open(self.spec_file, 'w') as output:
+      for line in fileinput.input(spec_file):
+        if self.version and line.startswith('Version: '):
+          line = 'Version: %s\n' % self.version
+        output.write(line)
+
+  def CallRpmBuild(self, dirname):
+    """Call rpmbuild with the correct arguments."""
+
+    args = [
+        'rpmbuild',
+        '--define', '_topdir %s' % dirname,
+        '--define', '_tmppath %s/TMP' % dirname,
+        '--bb',
+        self.spec_file,
+    ]
+    #print('Calling: %s' % ' '.join(args))
+    p = subprocess.Popen(args,
+                         stdout=subprocess.PIPE,
+                         stderr=subprocess.STDOUT)
+    output = p.communicate()[0]
+
+    if p.returncode == 0:
+      # Find the created file.
+      m = RpmBuilder.WROTE_FILE_RE.search(output)
+      if m:
+        self.rpm_path = m.group('rpm_path')
+
+    if p.returncode != 0 or not self.rpm_path:
+      print('Error calling rpmbuild:')
+      print(output)
+
+    # Return the status.
+    return p.returncode
+
+  def SaveResult(self, out_file):
+    """Save the result RPM out of the temporary working directory."""
+
+    if self.rpm_path:
+      shutil.copy(self.rpm_path, out_file)
+      print('Saved RPM file to %s' % out_file)
+    else:
+      print('No RPM file created.')
+
+  def Build(self, spec_file, out_file):
+    """Build the RPM described by the spec_file."""
+    print('Building RPM for %s at %s' % (self.name, out_file))
+
+    original_dir = os.getcwd()
+    spec_file = os.path.join(original_dir, spec_file)
+    out_file = os.path.join(original_dir, out_file)
+    with Tempdir() as dirname:
+      self.SetupWorkdir(spec_file, original_dir)
+      status = self.CallRpmBuild(dirname)
+      self.SaveResult(out_file)
+
+    return status
+
+
+def main(argv=()):
+  builder = RpmBuilder(FLAGS.name, FLAGS.version, FLAGS.arch)
+  builder.AddFiles(argv[1:])
+  return builder.Build(FLAGS.spec_file, FLAGS.out_file)
+
+
+if __name__ == '__main__':
+  FLAGS = gflags.FLAGS
+  main(FLAGS(sys.argv))
+
diff --git a/tools/build_defs/pkg/rpm.bzl b/tools/build_defs/pkg/rpm.bzl
new file mode 100644
index 0000000..d4899a2
--- /dev/null
+++ b/tools/build_defs/pkg/rpm.bzl
@@ -0,0 +1,83 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Rules to create RPM archives."""
+
+rpm_filetype = [".rpm"]
+spec_filetype = [".spec"]
+
+def _pkg_rpm_impl(ctx):
+  """Implements to pkg_rpm rule."""
+
+  files = []
+  args = ["--name=" + ctx.label.name]
+
+  # Version can be specified by a file or inlined
+  if ctx.attr.version_file:
+    if ctx.attr.version:
+      fail("Both version and version_file attributes were specified")
+    args += ["--version=@" + ctx.file.version_file.path]
+    files += [ctx.file.version_file]
+  elif ctx.attr.version:
+    args += ["--version=" + ctx.attr.version]
+  else:
+    fail("Neither version_file nor version attribute was specified")
+
+  if ctx.attr.architecture:
+    args += ["--arch=" + ctx.attr.architecture]
+
+  if ctx.attr.spec_file:
+    args += ["--spec_file=" + ctx.file.spec_file.path]
+    files += [ctx.file.spec_file]
+  else:
+    fail("spec_file was not specified")
+
+  args += ["--out_file=" + ctx.outputs.out.path]
+
+  # Add data files.
+  files += [ctx.file.changelog] + ctx.files.data
+  args += [ctx.file.changelog.path]
+  for f in ctx.files.data:
+    args += [f.path]
+
+  # Call the generator script.
+  # TODO(katre): Generate a source RPM.
+  ctx.action(
+      executable = ctx.executable._make_rpm,
+      arguments = args,
+      inputs = files,
+      outputs = [ctx.outputs.out],
+      mnemonic = "MakeRpm")
+
+# Define the rule.
+pkg_rpm = rule(
+    implementation = _pkg_rpm_impl,
+    attrs = {
+        "spec_file" : attr.label(mandatory=True, allow_files=spec_filetype, single_file=True),
+        "architecture": attr.string(default="all"),
+        "version_file": attr.label(allow_files=True, single_file=True),
+        "version": attr.string(),
+        "changelog" : attr.label(mandatory=True, allow_files=True, single_file=True),
+        "data": attr.label_list(mandatory=True, allow_files=True),
+
+        # Implicit dependencies.
+        "_make_rpm": attr.label(
+            default=Label("//tools/build_defs/pkg:make_rpm"),
+            cfg="host",
+            executable=True,
+            allow_files=True),
+    },
+    outputs = {
+        "out": "%{name}.rpm",
+    },
+    executable = False)

To view, visit change 8590. To unsubscribe, visit settings.

Gerrit-Project: bazel
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
Gerrit-Change-Number: 8590
Gerrit-PatchSet: 1
Gerrit-Owner: John Cater <jca...@google.com>

John Cater (Gerrit)

unread,
Jan 31, 2017, 3:12:14 PM1/31/17
to bazel-de...@googlegroups.com

John Cater uploaded patch set #2 to this change.

View Change

Create a pkg_rpm rule, and use it to generate a releasable RPM for Bazel.

Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
---
M scripts/packages/fedora/BUILD
M scripts/packages/fedora/bazel.spec
D scripts/packages/fedora/build_rpm.sh
M tools/build_defs/pkg/BUILD
A tools/build_defs/pkg/make_rpm.py
A tools/build_defs/pkg/rpm.bzl
6 files changed, 297 insertions(+), 76 deletions(-)

To view, visit change 8590. To unsubscribe, visit settings.

Gerrit-Project: bazel
Gerrit-Branch: master
Gerrit-MessageType: newpatchset
Gerrit-Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
Gerrit-Change-Number: 8590
Gerrit-PatchSet: 2
Gerrit-Owner: John Cater <jca...@google.com>

John Cater (Gerrit)

unread,
Jan 31, 2017, 3:12:42 PM1/31/17
to Damien Martin-guillerez, Kristina Chodorow

John Cater posted comments on this change.

View Change

Patch set 2:Verified +1

    To view, visit change 8590. To unsubscribe, visit settings.

    Gerrit-Project: bazel
    Gerrit-Branch: master
    Gerrit-MessageType: comment
    Gerrit-Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
    Gerrit-Change-Number: 8590
    Gerrit-PatchSet: 2
    Gerrit-Owner: John Cater <jca...@google.com>
    Gerrit-Reviewer: Damien Martin-guillerez <dmar...@google.com>
    Gerrit-Reviewer: John Cater <jca...@google.com>
    Gerrit-Reviewer: Kristina Chodorow <kcho...@google.com>
    Gerrit-Comment-Date: Tue, 31 Jan 2017 20:12:40 +0000
    Gerrit-HasComments: No

    Damien Martin-guillerez (Gerrit)

    unread,
    Feb 1, 2017, 5:04:43 AM2/1/17
    to John Cater, Bazel CI, Kristina Chodorow

    Damien Martin-guillerez posted comments on this change.

    View Change

    Patch set 2:Verified +1

    Also edit the README of tools/build_defs/pkg to add the new rule.

    (1 comment)

    To view, visit change 8590. To unsubscribe, visit settings.

    Gerrit-Project: bazel
    Gerrit-Branch: master
    Gerrit-MessageType: comment
    Gerrit-Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
    Gerrit-Change-Number: 8590
    Gerrit-PatchSet: 2
    Gerrit-Owner: John Cater <jca...@google.com>
    Gerrit-Reviewer: Bazel CI <ci.b...@gmail.com>
    Gerrit-Reviewer: Damien Martin-guillerez <dmar...@google.com>
    Gerrit-Reviewer: John Cater <jca...@google.com>
    Gerrit-Reviewer: Kristina Chodorow <kcho...@google.com>
    Gerrit-Comment-Date: Wed, 01 Feb 2017 10:04:38 +0000
    Gerrit-HasComments: Yes

    Kristina Chodorow (Gerrit)

    unread,
    Feb 1, 2017, 9:49:07 AM2/1/17
    to John Cater, Damien Martin-guillerez, Bazel CI

    Kristina Chodorow posted comments on this change.

    View Change

    Patch set 2:

    (4 comments)

    To view, visit change 8590. To unsubscribe, visit settings.

    Gerrit-Project: bazel
    Gerrit-Branch: master
    Gerrit-MessageType: comment
    Gerrit-Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
    Gerrit-Change-Number: 8590
    Gerrit-PatchSet: 2
    Gerrit-Owner: John Cater <jca...@google.com>
    Gerrit-Reviewer: Bazel CI <ci.b...@gmail.com>
    Gerrit-Reviewer: Damien Martin-guillerez <dmar...@google.com>
    Gerrit-Reviewer: John Cater <jca...@google.com>
    Gerrit-Reviewer: Kristina Chodorow <kcho...@google.com>
    Gerrit-Comment-Date: Wed, 01 Feb 2017 14:49:05 +0000
    Gerrit-HasComments: Yes

    John Cater (Gerrit)

    unread,
    Feb 1, 2017, 11:42:30 AM2/1/17
    to Damien Martin-guillerez, Kristina Chodorow, Bazel CI

    John Cater uploaded patch set #3 to this change.

    View Change

    Add script to generate an RPM file
    
    Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
    ---
    M scripts/packages/fedora/BUILD
    M scripts/packages/fedora/bazel.spec
    D scripts/packages/fedora/build_rpm.sh
    M tools/build_defs/pkg/BUILD
    A tools/build_defs/pkg/make_rpm.py
    A tools/build_defs/pkg/make_rpm_test.py
    A tools/build_defs/pkg/rpm.bzl
    7 files changed, 457 insertions(+), 76 deletions(-)
    
    

    To view, visit change 8590. To unsubscribe, visit settings.

    Gerrit-Project: bazel
    Gerrit-Branch: master
    Gerrit-MessageType: newpatchset
    Gerrit-Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
    Gerrit-Change-Number: 8590
    Gerrit-PatchSet: 3

    John Cater (Gerrit)

    unread,
    Feb 1, 2017, 11:43:04 AM2/1/17
    to Kristina Chodorow, Damien Martin-guillerez, Bazel CI

    John Cater posted comments on this change.

    View Change

    Patch set 3:-Verified

    (5 comments)

    To view, visit change 8590. To unsubscribe, visit settings.

    Gerrit-Project: bazel
    Gerrit-Branch: master
    Gerrit-MessageType: comment
    Gerrit-Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
    Gerrit-Change-Number: 8590
    Gerrit-PatchSet: 3
    Gerrit-Owner: John Cater <jca...@google.com>
    Gerrit-Reviewer: Bazel CI <ci.b...@gmail.com>
    Gerrit-Reviewer: Damien Martin-guillerez <dmar...@google.com>
    Gerrit-Reviewer: John Cater <jca...@google.com>
    Gerrit-Reviewer: Kristina Chodorow <kcho...@google.com>
    Gerrit-Comment-Date: Wed, 01 Feb 2017 16:42:58 +0000
    Gerrit-HasComments: Yes

    Damien Martin-guillerez (Gerrit)

    unread,
    Feb 1, 2017, 5:58:50 PM2/1/17
    to John Cater, Kristina Chodorow, Bazel CI

    Damien Martin-guillerez removed a vote from this change.

    View Change

    Removed Verified-1 by Bazel CI <ci.b...@gmail.com>

    To view, visit change 8590. To unsubscribe, visit settings.

    Gerrit-Project: bazel
    Gerrit-Branch: master
    Gerrit-MessageType: deleteVote
    Gerrit-Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
    Gerrit-Change-Number: 8590

    Damien Martin-guillerez (Gerrit)

    unread,
    Feb 1, 2017, 5:58:59 PM2/1/17
    to John Cater, Bazel CI, Kristina Chodorow

    Damien Martin-guillerez removed Bazel CI from this change.

    View Change

    To view, visit change 8590. To unsubscribe, visit settings.

    Gerrit-Project: bazel
    Gerrit-Branch: master
    Gerrit-MessageType: deleteReviewer
    Gerrit-Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
    Gerrit-Change-Number: 8590
    Gerrit-PatchSet: 3
    Gerrit-Owner: John Cater <jca...@google.com>

    Damien Martin-guillerez (Gerrit)

    unread,
    Feb 1, 2017, 6:03:26 PM2/1/17
    to John Cater, Kristina Chodorow

    Damien Martin-guillerez posted comments on this change.

    View Change

    Patch set 3:Code-Review +1

    Also please modify pkg/README.md to add the new rule.

    (2 comments)

    To view, visit change 8590. To unsubscribe, visit settings.

    Gerrit-Project: bazel
    Gerrit-Branch: master
    Gerrit-MessageType: comment
    Gerrit-Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
    Gerrit-Change-Number: 8590
    Gerrit-PatchSet: 3
    Gerrit-Owner: John Cater <jca...@google.com>
    Gerrit-Reviewer: Damien Martin-guillerez <dmar...@google.com>
    Gerrit-Reviewer: John Cater <jca...@google.com>
    Gerrit-Reviewer: Kristina Chodorow <kcho...@google.com>
    Gerrit-Comment-Date: Wed, 01 Feb 2017 23:03:23 +0000
    Gerrit-HasComments: Yes

    John Cater (Gerrit)

    unread,
    Feb 2, 2017, 10:02:23 AM2/2/17
    to Damien Martin-guillerez, Kristina Chodorow, Bazel CI

    John Cater uploaded patch set #4 to this change.

    View Change

    Add script to generate an RPM file
    
    Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
    ---
    M scripts/packages/fedora/BUILD
    M scripts/packages/fedora/bazel.spec
    D scripts/packages/fedora/build_rpm.sh
    M tools/build_defs/pkg/BUILD
    M tools/build_defs/pkg/README.md
    A tools/build_defs/pkg/make_rpm.py
    A tools/build_defs/pkg/make_rpm_test.py
    A tools/build_defs/pkg/rpm.bzl
    8 files changed, 548 insertions(+), 76 deletions(-)
    
    

    To view, visit change 8590. To unsubscribe, visit settings.

    Gerrit-Project: bazel
    Gerrit-Branch: master
    Gerrit-MessageType: newpatchset
    Gerrit-Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
    Gerrit-Change-Number: 8590
    Gerrit-PatchSet: 4
    Gerrit-Owner: John Cater <jca...@google.com>
    Gerrit-Reviewer: Bazel CI <ci.b...@gmail.com>

    John Cater (Gerrit)

    unread,
    Feb 2, 2017, 10:02:33 AM2/2/17
    to Bazel CI, Damien Martin-guillerez, Kristina Chodorow

    John Cater posted comments on this change.

    View Change

    Patch set 3:

    Patch Set 3: Code-Review+1

    (2 comments)

    Also please modify pkg/README.md to add the new rule.

    Updated README.md, sorry about that.

    (2 comments)

    To view, visit change 8590. To unsubscribe, visit settings.

    Gerrit-Project: bazel
    Gerrit-Branch: master
    Gerrit-MessageType: comment
    Gerrit-Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
    Gerrit-Change-Number: 8590
    Gerrit-PatchSet: 3
    Gerrit-Owner: John Cater <jca...@google.com>
    Gerrit-Reviewer: Bazel CI <ci.b...@gmail.com>
    Gerrit-Reviewer: Damien Martin-guillerez <dmar...@google.com>
    Gerrit-Reviewer: John Cater <jca...@google.com>
    Gerrit-Reviewer: Kristina Chodorow <kcho...@google.com>
    Gerrit-Comment-Date: Thu, 02 Feb 2017 15:02:31 +0000
    Gerrit-HasComments: Yes

    Kristina Chodorow (Gerrit)

    unread,
    Feb 2, 2017, 11:00:14 AM2/2/17
    to John Cater, Bazel CI, Damien Martin-guillerez

    Kristina Chodorow posted comments on this change.

    View Change

    Patch set 4:Code-Review +2

      To view, visit change 8590. To unsubscribe, visit settings.

      Gerrit-Project: bazel
      Gerrit-Branch: master
      Gerrit-MessageType: comment
      Gerrit-Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
      Gerrit-Change-Number: 8590
      Gerrit-PatchSet: 4
      Gerrit-Owner: John Cater <jca...@google.com>
      Gerrit-Reviewer: Bazel CI <ci.b...@gmail.com>
      Gerrit-Reviewer: Damien Martin-guillerez <dmar...@google.com>
      Gerrit-Reviewer: John Cater <jca...@google.com>
      Gerrit-Reviewer: Kristina Chodorow <kcho...@google.com>
      Gerrit-Comment-Date: Thu, 02 Feb 2017 16:00:11 +0000
      Gerrit-HasComments: No

      Damien Martin-guillerez (Gerrit)

      unread,
      Feb 3, 2017, 3:57:39 AM2/3/17
      to John Cater, Kristina Chodorow, Bazel CI

      Damien Martin-guillerez posted comments on this change.

      View Change

      Patch set 4:Code-Review +2

        To view, visit change 8590. To unsubscribe, visit settings.

        Gerrit-Project: bazel
        Gerrit-Branch: master
        Gerrit-MessageType: comment
        Gerrit-Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
        Gerrit-Change-Number: 8590
        Gerrit-PatchSet: 4
        Gerrit-Owner: John Cater <jca...@google.com>
        Gerrit-Reviewer: Bazel CI <ci.b...@gmail.com>
        Gerrit-Reviewer: Damien Martin-guillerez <dmar...@google.com>
        Gerrit-Reviewer: John Cater <jca...@google.com>
        Gerrit-Reviewer: Kristina Chodorow <kcho...@google.com>
        Gerrit-Comment-Date: Fri, 03 Feb 2017 08:57:33 +0000
        Gerrit-HasComments: No

        Kristina Chodorow (Gerrit)

        unread,
        Feb 6, 2017, 2:36:24 PM2/6/17
        to John Cater, Damien Martin-guillerez, Bazel CI

        Kristina Chodorow uploaded patch set #5 to this change.

        View Change

        Add pkg_rpm build rule to help generating RPM packages. 
        
        RELNOTES: Adds pkg_rpm rule for generating RPM packages.
        
        --
        Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
        Reviewed-on: https://cr.bazel.build/8590
        PiperOrigin-RevId: 146477490
        MOS_MIGRATED_REVID=146477490
        ---
        M scripts/packages/fedora/BUILD
        M scripts/packages/fedora/bazel.spec
        D scripts/packages/fedora/build_rpm.sh
        M tools/build_defs/pkg/BUILD
        M tools/build_defs/pkg/README.md
        A tools/build_defs/pkg/make_rpm.py
        A tools/build_defs/pkg/make_rpm_test.py
        A tools/build_defs/pkg/rpm.bzl
        8 files changed, 546 insertions(+), 78 deletions(-)
        
        

        To view, visit change 8590. To unsubscribe, visit settings.

        Gerrit-Project: bazel
        Gerrit-Branch: master
        Gerrit-MessageType: newpatchset
        Gerrit-Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
        Gerrit-Change-Number: 8590
        Gerrit-PatchSet: 5

        Kristina Chodorow (Gerrit)

        unread,
        Feb 6, 2017, 2:36:25 PM2/6/17
        to John Cater, Damien Martin-guillerez, Bazel CI

        Kristina Chodorow merged this change.

        View Change

        Approvals: Kristina Chodorow: Looks good to me, approved Damien Martin-guillerez: Looks good to me, approved; Verified Objections: Bazel CI: Fails
        Add pkg_rpm build rule to help generating RPM packages. 
        
        RELNOTES: Adds pkg_rpm rule for generating RPM packages.
        
        --
        Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
        Reviewed-on: https://cr.bazel.build/8590
        PiperOrigin-RevId
        : 146477490
        MOS_MIGRATED_REVID=146477490
        ---
        M scripts/packages/fedora/BUILD
        M scripts/packages/fedora/bazel.spec
        D scripts/packages/fedora/build_rpm.sh
        M tools/build_defs/pkg/BUILD
        M tools/build_defs/pkg/README.md
        A tools/build_defs/pkg/make_rpm.py
        A tools/build_defs/pkg/make_rpm_test.py
        A tools/build_defs/pkg/rpm.bzl
        8 files changed, 546 insertions(+), 78 deletions(-)
        
        
        diff --git a/scripts/packages/fedora/BUILD b/scripts/packages/fedora/BUILD
        index 36d8690..2ee91d0 100644
        --- a/scripts/packages/fedora/BUILD
        +++ b/scripts/packages/fedora/BUILD
        @@ -5,26 +5,18 @@
             srcs = glob(["**"]),
         )
         
        -genrule(
        -    name = "bazel-fedora",
        -    srcs = [
        -        "bazel.spec",
        -        "//scripts/packages:bazel",
        -        "//scripts/packages:bazel-real",
        -        "//scripts/packages:debian/bazel.bazelrc",
        +load("//tools/build_defs/pkg:rpm.bzl", "pkg_rpm")
        +
        +pkg_rpm(
        +    name = "bazel",
        +    architecture = "x86_64",
        +    changelog = "//:changelog-file",
        +    data = [
                 "//scripts:bash_completion",
        +        "//scripts/packages:bazel",
        +        "//scripts/packages:bazel.bazelrc",
        +        "//scripts/packages:bazel-real",
             ],
        -    outs = [
        -        "bazel-fedora.rpm",
        -    ],
        -    cmd = """
        -      $(location :build_rpm.sh) \
        -        $(location :bazel.spec) \
        -        $(location bazel-fedora.rpm) \
        -        $(location //scripts/packages:bazel) \
        -        $(location //scripts/packages:bazel-real) \
        -        $(location //scripts/packages:debian/bazel.bazelrc) \
        -        $(location //scripts:bash_completion)
        -    """,
        -    tools = ["build_rpm.sh"],
        +    spec_file = "bazel.spec",
        +    version_file = "//scripts/packages:version.txt",
         )
        diff --git a/scripts/packages/fedora/bazel.spec b/scripts/packages/fedora/bazel.spec
        index 0d69e61..14cabfc 100644
        --- a/scripts/packages/fedora/bazel.spec
        +++ b/scripts/packages/fedora/bazel.spec
        @@ -30,7 +30,7 @@
         install -m 755 bazel-real %{buildroot}%{_bindir}/bazel-real
         mkdir -p %{buildroot}%{_sysconfdir}/
         install -m 644 bazel.bazelrc %{buildroot}%{_sysconfdir}/bazel.bazelrc
        -mkdir -p %{buildroot}%{_sysconfdir}/bash_completion.d
        +mkdir -p %{buildroot}%{_sysconfdir}/bash_completion.d/
         install -m 644 bazel-complete.bash %{buildroot}%{_sysconfdir}/bash_completion.d/bazel
         
         %files
        @@ -40,4 +40,6 @@
         %{_sysconfdir}/bash_completion.d/bazel
         
         %changelog
        -# TODO: Include changelog.
        +* Fri Jan 27 2017 jca...@google.com - devel-1
        +- Initial package version released.
        +
        diff --git a/scripts/packages/fedora/build_rpm.sh b/scripts/packages/fedora/build_rpm.sh
        deleted file mode 100755
        index 525c858..0000000
        --- a/scripts/packages/fedora/build_rpm.sh
        +++ /dev/null
        @@ -1,56 +0,0 @@
        -#!/bin/sh
        -
        -# Copyright 2016 The Bazel Authors. All rights reserved.
        -#
        -# Licensed under the Apache License, Version 2.0 (the "License");
        -# you may not use this file except in compliance with the License.
        -# You may obtain a copy of the License at
        -#
        -#    http://www.apache.org/licenses/LICENSE-2.0
        -#
        -# Unless required by applicable law or agreed to in writing, software
        -# distributed under the License is distributed on an "AS IS" BASIS,
        -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        -# See the License for the specific language governing permissions and
        -# limitations under the License.
        -
        -set -eu
        -
        -# Build a RPM archive from the Bazel sources.
        -
        -# Usage: build_rpm.sh spec_file dest_file [other files]
        -
        -spec_file=$1
        -shift
        -dest_file=$1
        -shift
        -
        -echo "Building ${dest_file} from ${spec_file}."
        -WORK_DIR="${PWD}/bazel-fedora"
        -
        -# Copy needed sources.
        -rm -rf ${WORK_DIR}
        -mkdir -p ${WORK_DIR}/SOURCES
        -mkdir -p ${WORK_DIR}/BUILD
        -cp $spec_file ${WORK_DIR}
        -for i in "$@"; do
        -  cp $i $WORK_DIR/BUILD
        -done
        -
        -# Build the RPM.
        -rpmbuild \
        -  --define "_topdir ${WORK_DIR}" \
        -  --define "_tmppath /tmp" \
        -  -bb ${spec_file} > rpmbuild.log 2>&1
        -if [ $? -ne 0 ]; then
        -  err=$?
        -  echo "Error in rpmbuild:"
        -  cat rpmbuild.log
        -  exit $err
        -fi
        -out_file=$(grep '^Wrote:' rpmbuild.log | cut -d ' ' -f 2)
        -
        -# Copy output back to the destination.
        -cp $out_file $dest_file
        -echo "Created $dest_file"
        -
        diff --git a/tools/build_defs/pkg/BUILD b/tools/build_defs/pkg/BUILD
        index 1bc4786..266a205 100644
        --- a/tools/build_defs/pkg/BUILD
        +++ b/tools/build_defs/pkg/BUILD
        @@ -66,6 +66,24 @@
             ],
         )
         
        +# Used by pkg_rpm in rpm.bzl.
        +py_binary(
        +    name = "make_rpm",
        +    srcs = ["make_rpm.py"],
        +    visibility = ["//visibility:public"],
        +    deps = [
        +        "@bazel_tools//third_party/py/gflags",
        +    ],
        +)
        +
        +py_test(
        +    name = "make_rpm_test",
        +    srcs = ["make_rpm_test.py"],
        +    deps = [
        +        ":make_rpm",
        +    ],
        +)
        +
         # tests
         load("//tools/build_defs/pkg:pkg.bzl", "pkg_deb", "pkg_tar")
         
        diff --git a/tools/build_defs/pkg/README.md b/tools/build_defs/pkg/README.md
        index 8fda666..4369777 100644
        --- a/tools/build_defs/pkg/README.md
        +++ b/tools/build_defs/pkg/README.md
        @@ -5,6 +5,7 @@
           <ul>
             <li><a href="#pkg_tar">pkg_tar</a></li>
             <li><a href="#pkg_deb">pkg_deb</a></li>
        +    <li><a href="#pkg_rpm">pkg_rpm</a></li>
           </ul>
         </div>
         
        @@ -386,3 +387,72 @@
           </tbody>
           </tbody>
         </table>
        +
        +<a name="pkg_rpm"></a>
        +### pkg_rpm
        +
        +```python
        +pkg_rpm(name, spec_file, architecture, version, version_file, changelog, data)
        +```
        +
        +Create an RPM package. See <a
        +href="http://rpm.org/documentation.html">http://rpm.org/documentation.html</a>
        +for more details on this.
        +
        +<table class="table table-condensed table-bordered table-params">
        +  <colgroup>
        +    <col class="col-param" />
        +    <col class="param-description" />
        +  </colgroup>
        +  <thead>
        +    <tr>
        +      <th colspan="2">Attributes</th>
        +    </tr>
        +  </thead>
        +  <tbody>
        +    <tr>
        +      <td><code>name</code></td>
        +      <td>
        +        <code>Name, required</code>
        +        <p>A unique name for this rule. Used to name the output package.</p>
        +      </td>
        +    </tr>
        +    <tr>
        +      <td><code>spec_file</code></td>
        +      <td>
        +        <code>File, required</code>
        +        <p>The RPM specification file used to generate the package.</p>
        +        <p>
        +          See <a href="http://rpm.org/max-rpm-snapshot/s1-rpm-build-creating-spec-file.html">http://rpm.org/max-rpm-snapshot/s1-rpm-build-creating-spec-file.html</a>.
        +        </p>
        +      </td>
        +    </tr>
        +    <tr>
        +      <td><code>architecture</code></td>
        +      <td>
        +        <code>String, default to 'all'</code>
        +        <p>The architecture that this package target.</p>
        +      </td>
        +    </tr>
        +    <tr>
        +      <td><code>version</code>, <code>version_file</code></td>
        +      <td>
        +        <code>String or File, required</code>
        +        <p>
        +          The package version provided either inline (with <code>version</code>)
        +          or from a file (with <code>version_file</code>).
        +        </p>
        +      </td>
        +    </tr>
        +    <tr>
        +      <td><code>data</code></td>
        +      <td>
        +        <code>Files, required</code>
        +        <p>
        +          Files to include in the generated package.
        +        </p>
        +      </td>
        +    </tr>
        +  </tbody>
        +  </tbody>
        +</table>
        diff --git a/tools/build_defs/pkg/make_rpm.py b/tools/build_defs/pkg/make_rpm.py
        new file mode 100644
        index 0000000..9f0f40a
        --- /dev/null
        +++ b/tools/build_defs/pkg/make_rpm.py
        @@ -0,0 +1,228 @@
        +# Copyright 2017 The Bazel Authors. All rights reserved.
        +#
        +# Licensed under the Apache License, Version 2.0 (the "License");
        +# you may not use this file except in compliance with the License.
        +# You may obtain a copy of the License at
        +#
        +#    http://www.apache.org/licenses/LICENSE-2.0
        +#
        +# Unless required by applicable law or agreed to in writing, software
        +# distributed under the License is distributed on an "AS IS" BASIS,
        +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        +# See the License for the specific language governing permissions and
        +# limitations under the License.
        +"""A simple cross-platform helper to create an RPM package."""
        +
        +from __future__ import absolute_import
        +from __future__ import division
        +from __future__ import print_function
        +
        +import contextlib
        +import fileinput
        +import os
        +import re
        +import shutil
        +import subprocess
        +import sys
        +from tempfile import mkdtemp
        +
        +from third_party.py import gflags
        +
        +gflags.DEFINE_string('name', '', 'The name of the software being packaged.')
        +gflags.DEFINE_string('version', '',
        +                     'The version of the software being packaged.')
        +gflags.DEFINE_string('arch', '',
        +                     'The CPU architecture of the software being packaged.')
        +
        +gflags.DEFINE_string('spec_file', '',
        +                     'The file containing the RPM specification.')
        +gflags.DEFINE_string('out_file', '',
        +                     'The destination to save the resulting RPM file to.')
        +
        +
        +# Setup to safely create a temporary directory and clean it up when done.
        +...@contextlib.contextmanager
        +def Cd(newdir, cleanup=lambda: True):
        +  """Change the current working directory.
        +
        +  This will run the provided cleanup function when the context exits and the
        +  previous working directory is restored.
        +
        +  Args:
        +    newdir: The directory to change to. This must already exist.
        +    cleanup: An optional cleanup function to be executed when the context exits.
        +
        +  Yields:
        +    Nothing.
        +  """
        +
        +  prevdir = os.getcwd()
        +  os.chdir(os.path.expanduser(newdir))
        +  try:
        +    yield
        +  finally:
        +    os.chdir(prevdir)
        +    cleanup()
        +
        +
        +...@contextlib.contextmanager
        +def Tempdir():
        +  """Create a new temporary directory and change to it.
        +
        +  The temporary directory will be removed when the context exits.
        +
        +  Yields:
        +    The full path of the temporary directory.
        +  """
        +
        +  dirpath = mkdtemp()
        +
        +  def Cleanup():
        +    shutil.rmtree(dirpath)
        +
        +  with Cd(dirpath, Cleanup):
        +    yield dirpath
        +
        +
        +def GetFlagValue(flagvalue, strip=True):
        +  if flagvalue:
        +    if flagvalue[0] == '@':
        +      with open(flagvalue[1:], 'r') as f:
        +        flagvalue = f.read()
        +    if strip:
        +      return flagvalue.strip()
        +  return flagvalue
        +
        +
        +WROTE_FILE_RE = re.compile(r'Wrote: (?P<rpm_path>.+)', re.MULTILINE)
        +
        +
        +def FindOutputFile(log):
        +  """Find the written file from the log information."""
        +
        +  m = WROTE_FILE_RE.search(log)
        +  if m:
        +    return m.group('rpm_path')
        +  return None
        +
        +
        +def CopyAndRewrite(input_file, output_file, replacements=None):
        +  """Copies the given file and optionally rewrites with replacements.
        +
        +  Args:
        +    input_file: The file to copy.
        +    output_file: The file to write to.
        +    replacements: A dictionary of replacements.
        +      Keys are prefixes scan for, values are the replacements to write after
        +      the prefix.
        +  """
        +  with open(output_file, 'w') as output:
        +    for line in fileinput.input(input_file):
        +      if replacements:
        +        for prefix, text in replacements.iteritems():
        +          if line.startswith(prefix):
        +            line = prefix + ' ' + text + '\n'
        +            break
        +      output.write(line)
        +
        +
        +class RpmBuilder(object):
        +  """A helper class to manage building the RPM file."""
        +
        +  SOURCE_DIR = 'SOURCES'
        +  BUILD_DIR = 'BUILD'
        +  TEMP_DIR = 'TMP'
        +  DIRS = [SOURCE_DIR, BUILD_DIR, TEMP_DIR]
        +
        +  def __init__(self, name, version, arch):
        +    self.name = name
        +    self.version = GetFlagValue(version)
        +    self.arch = arch
        +    self.files = []
        +    self.rpm_path = None
        +
        +  def AddFiles(self, files):
        +    """Add a set of files to the current RPM."""
        +    self.files += files
        +
        +  def SetupWorkdir(self, spec_file, original_dir):
        +    """Create the needed structure in the workdir."""
        +
        +    # Create directory structure.
        +    for name in RpmBuilder.DIRS:
        +      if not os.path.exists(name):
        +        os.makedirs(name, 0777)
        +
        +    shutil.copy(os.path.join(original_dir, spec_file), os.getcwd())
        +
        +    # Copy the files.
        +    for f in self.files:
        +      shutil.copy(os.path.join(original_dir, f), RpmBuilder.BUILD_DIR)
        +
        +    # Copy the spec file, updating with the correct version.
        +    spec_origin = os.path.join(original_dir, spec_file)
        +    self.spec_file = os.path.basename(spec_file)
        +    replacements = {}
        +    if self.version:
        +      replacements['Version:'] = self.version
        +    CopyAndRewrite(spec_origin, self.spec_file, replacements)
        +
        +  def CallRpmBuild(self, dirname):
        +    """Call rpmbuild with the correct arguments."""
        +
        +    args = [
        +        'rpmbuild',
        +        '--define',
        +        '_topdir %s' % dirname,
        +        '--define',
        +        '_tmppath %s/TMP' % dirname,
        +        '--bb',
        +        self.spec_file,
        +    ]
        +    p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        +    output = p.communicate()[0]
        +
        +    if p.returncode == 0:
        +      # Find the created file.
        +      self.rpm_path = FindOutputFile(output)
        +
        +    if p.returncode != 0 or not self.rpm_path:
        +      print('Error calling rpmbuild:')
        +      print(output)
        +
        +    # Return the status.
        +    return p.returncode
        +
        +  def SaveResult(self, out_file):
        +    """Save the result RPM out of the temporary working directory."""
        +
        +    if self.rpm_path:
        +      shutil.copy(self.rpm_path, out_file)
        +      print('Saved RPM file to %s' % out_file)
        +    else:
        +      print('No RPM file created.')
        +
        +  def Build(self, spec_file, out_file):
        +    """Build the RPM described by the spec_file."""
        +    print('Building RPM for %s at %s' % (self.name, out_file))
        +
        +    original_dir = os.getcwd()
        +    spec_file = os.path.join(original_dir, spec_file)
        +    out_file = os.path.join(original_dir, out_file)
        +    with Tempdir() as dirname:
        +      self.SetupWorkdir(spec_file, original_dir)
        +      status = self.CallRpmBuild(dirname)
        +      self.SaveResult(out_file)
        +
        +    return status
        +
        +
        +def main(argv=()):
        +  builder = RpmBuilder(FLAGS.name, FLAGS.version, FLAGS.arch)
        +  builder.AddFiles(argv[1:])
        +  return builder.Build(FLAGS.spec_file, FLAGS.out_file)
        +
        +
        +if __name__ == '__main__':
        +  FLAGS = gflags.FLAGS
        +  main(FLAGS(sys.argv))
        diff --git a/tools/build_defs/pkg/make_rpm_test.py b/tools/build_defs/pkg/make_rpm_test.py
        new file mode 100644
        index 0000000..f8f7710
        --- /dev/null
        +++ b/tools/build_defs/pkg/make_rpm_test.py
        @@ -0,0 +1,105 @@
        +# Copyright 2017 The Bazel Authors. All rights reserved.
        +#
        +# Licensed under the Apache License, Version 2.0 (the "License");
        +# you may not use this file except in compliance with the License.
        +# You may obtain a copy of the License at
        +#
        +#    http://www.apache.org/licenses/LICENSE-2.0
        +#
        +# Unless required by applicable law or agreed to in writing, software
        +# distributed under the License is distributed on an "AS IS" BASIS,
        +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        +# See the License for the specific language governing permissions and
        +# limitations under the License.
        +"""Tests for make_rpm."""
        +
        +from __future__ import absolute_import
        +from __future__ import division
        +from __future__ import print_function
        +
        +import os
        +import unittest
        +
        +from tools.build_defs.pkg import make_rpm
        +
        +
        +def WriteFile(filename, *contents):
        +  with open(filename, 'w') as text_file:
        +    text_file.write('\n'.join(contents))
        +
        +
        +def DirExists(dirname):
        +  return os.path.exists(dirname) and os.path.isdir(dirname)
        +
        +
        +def FileExists(filename):
        +  return os.path.exists(filename) and not os.path.isdir(filename)
        +
        +
        +def FileContents(filename):
        +  with open(filename, 'r') as text_file:
        +    return [s.strip() for s in text_file.readlines()]
        +
        +
        +class MakeRpmTest(unittest.TestCase):
        +
        +  def testFindOutputFile(self):
        +    log = """
        +    Lots of data.
        +    Wrote: /path/to/file/here.rpm
        +    More data present.
        +    """
        +
        +    result = make_rpm.FindOutputFile(log)
        +    self.assertEquals('/path/to/file/here.rpm', result)
        +
        +  def testFindOutputFile_missing(self):
        +    log = """
        +    Lots of data.
        +    More data present.
        +    """
        +
        +    result = make_rpm.FindOutputFile(log)
        +    self.assertEquals(None, result)
        +
        +  def testCopyAndRewrite(self):
        +    with make_rpm.Tempdir():
        +      WriteFile('test.txt', 'Some: data1', 'Other: data2', 'More: data3')
        +      make_rpm.CopyAndRewrite('test.txt', 'out.txt', {
        +          'Some:': 'data1a',
        +          'More:': 'data3a',
        +      })
        +
        +      self.assertTrue(FileExists('out.txt'))
        +      self.assertItemsEqual(['Some: data1a', 'Other: data2', 'More: data3a'],
        +                            FileContents('out.txt'))
        +
        +  def testSetupWorkdir(self):
        +    builder = make_rpm.RpmBuilder('test', '1.0', 'x86')
        +    with make_rpm.Tempdir() as outer:
        +      # Create spec_file, test files.
        +      WriteFile('test.spec', 'Name: test', 'Version: 0.1', 'Summary: test data')
        +      WriteFile('file1.txt', 'Hello')
        +      WriteFile('file2.txt', 'Goodbye')
        +      builder.AddFiles(['file1.txt', 'file2.txt'])
        +
        +      with make_rpm.Tempdir():
        +        # Call RpmBuilder.
        +        builder.SetupWorkdir('test.spec', outer)
        +
        +        # Make sure files exist.
        +        self.assertTrue(DirExists('SOURCES'))
        +        self.assertTrue(DirExists('BUILD'))
        +        self.assertTrue(DirExists('TMP'))
        +        self.assertTrue(FileExists('test.spec'))
        +        self.assertItemsEqual(
        +            ['Name: test', 'Version: 1.0', 'Summary: test data'],
        +            FileContents('test.spec'))
        +        self.assertTrue(FileExists('BUILD/file1.txt'))
        +        self.assertItemsEqual(['Hello'], FileContents('BUILD/file1.txt'))
        +        self.assertTrue(FileExists('BUILD/file2.txt'))
        +        self.assertItemsEqual(['Goodbye'], FileContents('BUILD/file2.txt'))
        +
        +
        +if __name__ == '__main__':
        +  unittest.main()
        diff --git a/tools/build_defs/pkg/rpm.bzl b/tools/build_defs/pkg/rpm.bzl
        new file mode 100644
        index 0000000..2322dfa
        --- /dev/null
        +++ b/tools/build_defs/pkg/rpm.bzl
        @@ -0,0 +1,109 @@
        +# Copyright 2017 The Bazel Authors. All rights reserved.
        +#
        +# Licensed under the Apache License, Version 2.0 (the "License");
        +# you may not use this file except in compliance with the License.
        +# You may obtain a copy of the License at
        +#
        +#    http://www.apache.org/licenses/LICENSE-2.0
        ]
        +
        +  # Version can be specified by a file or inlined
        +  if ctx.attr.version_file:
        +    if ctx.attr.version:
        +      fail("Both version and version_file attributes were specified")
        +    args += ["--version=@" + ctx.file.version_file.path]
        +    files += [ctx.file.version_file]
        +  elif ctx.attr.version:
        +    args += ["--version=" + ctx.attr.version]
        +  else:
        +    fail("Neither version_file nor version attribute was specified")
        +
        +  if ctx.attr.architecture:
        +    args += ["--arch=" + ctx.attr.architecture]
        +
        +  if ctx.attr.spec_file:
        +    args += ["--spec_file=" + ctx.file.spec_file.path]
        +    files += [ctx.file.spec_file]
        +  else:
        +    fail("spec_file was not specified")
        +
        +  args += ["--out_file=" + ctx.outputs.rpm.path]
        +
        +  # Add data files.
        +  files += [ctx.file.changelog] + ctx.files.data
        +  args += [ctx.file.changelog.path]
        +  for f in ctx.files.data:
        +    args += [f.path]
        +
        +  # Call the generator script.
        +  # TODO(katre): Generate a source RPM.
        +  ctx.action(
        +      executable = ctx.executable._make_rpm,
        +      arguments = args,
        +      inputs = files,
        +      outputs = [ctx.outputs.rpm],
        +      mnemonic = "MakeRpm")
        +
        +  # Link the RPM to the expected output name.
        +  ctx.action(
        +      command = "ln -s %s %s" % (ctx.outputs.rpm.basename, ctx.outputs.out.path),
        +      inputs = [ctx.outputs.rpm],
        +      outputs = [ctx.outputs.out])
        +
        +# Define the rule.
        +pkg_rpm = rule(
        +    implementation = _pkg_rpm_impl,
        +    attrs = {
        +        "spec_file" : attr.label(mandatory=True, allow_files=spec_filetype, single_file=True),
        +        "architecture": attr.string(default="all"),
        +        "version_file": attr.label(allow_files=True, single_file=True),
        +        "version": attr.string(),
        +        "changelog" : attr.label(mandatory=True, allow_files=True, single_file=True),
        +        "data": attr.label_list(mandatory=True, allow_files=True),
        +
        +        # Implicit dependencies.
        +        "_make_rpm": attr.label(
        +            default=Label("//tools/build_defs/pkg:make_rpm"),
        +            cfg="host",
        +            executable=True,
        +            allow_files=True),
        +    },
        +    outputs = {
        +        "out": "%{name}.rpm",
        +        "rpm": "%{name}-%{architecture}.rpm",
        +    },
        +    executable = False)
        +"""Creates an RPM format package from the data files.
        +
        +This runs rpmbuild (and requires it to be installed beforehand) to generate
        +an RPM package based on the spec_file and data attributes.
        +
        +Args:
        +  spec_file: The RPM spec file to use. If the version or version_file
        +    attributes are provided, the Version in the spec will be overwritten.
        +    Any Sources listed in the spec file must be provided as data dependencies.
        +  version: The version of the package to generate. This will overwrite any
        +    Version provided in the spec file. Only specify one of version and
        +    version_file.
        +  version_file: A file containing the version of the package to generate. This
        +    will overwrite any Version provided in the spec file. Only specify one of
        +    version and version_file.
        +  changelog: A changelog file to include. This will not be written to the spec
        +    file, which should only list changes to the packaging, not the software itself.
        +  data: List all files to be included in the package here.
        +"""
        

        To view, visit change 8590. To unsubscribe, visit settings.

        Gerrit-Project: bazel
        Gerrit-Branch: master
        Gerrit-MessageType: merged
        Gerrit-Change-Id: I2e83161e29218700bbe7e62186b0b1667e555a7c
        Gerrit-Change-Number: 8590
        Reply all
        Reply to author
        Forward
        0 new messages