| OLD | NEW |
| (Empty) |
| 1 # Copyright 2009, Google Inc. | |
| 2 # All rights reserved. | |
| 3 # | |
| 4 # Redistribution and use in source and binary forms, with or without | |
| 5 # modification, are permitted provided that the following conditions are | |
| 6 # met: | |
| 7 # | |
| 8 # * Redistributions of source code must retain the above copyright | |
| 9 # notice, this list of conditions and the following disclaimer. | |
| 10 # * Redistributions in binary form must reproduce the above | |
| 11 # copyright notice, this list of conditions and the following disclaimer | |
| 12 # in the documentation and/or other materials provided with the | |
| 13 # distribution. | |
| 14 # * Neither the name of Google Inc. nor the names of its | |
| 15 # contributors may be used to endorse or promote products derived from | |
| 16 # this software without specific prior written permission. | |
| 17 # | |
| 18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 29 | |
| 30 import os | |
| 31 import subprocess | |
| 32 import SCons | |
| 33 | |
| 34 Import('env') | |
| 35 | |
| 36 # Check if Debian packaging tools are installed. If so, make a .deb package. | |
| 37 if subprocess.Popen(["which", "dpkg-buildpackage"], | |
| 38 stdout=open(os.devnull, "w")).wait() == 0: | |
| 39 | |
| 40 print('Found dpkg-buildpackage in PATH; will create Debian packages.'); | |
| 41 | |
| 42 current_source_dir = os.path.join(env['SCONSTRUCT_DIR'], 'installer/linux') | |
| 43 | |
| 44 def OutputFromShellCommand(command): | |
| 45 process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) | |
| 46 return process.communicate()[0].strip() | |
| 47 | |
| 48 def _InternalBuildDebianPackage(env, src_dir, obj_dir, debian_files, | |
| 49 package_files, output_dir=None, force_version=None): | |
| 50 """Creates build rules to build a Debian package from the specified sources. | |
| 51 | |
| 52 Args: | |
| 53 env: SCons Environment. | |
| 54 src_dir: Current source path, to which the debian_files are | |
| 55 relative. | |
| 56 obj_dir: Directory to place object files in. | |
| 57 debian_files: Array of the Debian control file sources that should be | |
| 58 copied into the package source tree, e.g., changelog, control, rules, | |
| 59 etc. Must be relative to current source dir. | |
| 60 package_files: An array of 2-tuples listing the files that should be | |
| 61 copied into the package source tree. | |
| 62 The first element is the path where the file should be placed for the | |
| 63 .install control file to find it, relative to the generated debian | |
| 64 package source directory. | |
| 65 The second element is the file source. | |
| 66 output_dir: An optional directory to place the files in. If omitted, the | |
| 67 current output directory is used. | |
| 68 force_version: Optional. Forces the version of the package to start with | |
| 69 this version string if specified. If the last entry in the changelog | |
| 70 is not for a version that starts with this then a dummy entry is | |
| 71 generated with this version and a ~prerelease suffix (so that the | |
| 72 final version will compare as greater). | |
| 73 | |
| 74 Return: | |
| 75 A list of the targets (at least two). | |
| 76 """ | |
| 77 # Read the control file and changelog file to determine the package name, | |
| 78 # version, and arch that the Debian build tools will use to name the | |
| 79 # generated files. | |
| 80 control_file = None | |
| 81 changelog_file = None | |
| 82 for file in debian_files: | |
| 83 if os.path.basename(file) == "control": | |
| 84 control_file = os.path.join(src_dir, file) | |
| 85 elif os.path.basename(file) == "changelog": | |
| 86 changelog_file = os.path.join(src_dir, file) | |
| 87 if control_file == None: | |
| 88 raise Exception("Need to have a control file") | |
| 89 if changelog_file == None: | |
| 90 raise Exception("Need to have a changelog file") | |
| 91 source = OutputFromShellCommand( | |
| 92 "awk '/^Source:/ { print $2; }' " + control_file) | |
| 93 packages = OutputFromShellCommand( | |
| 94 "awk '/^Package:/ { print $2; }' " + control_file).split("\n") | |
| 95 version = OutputFromShellCommand( | |
| 96 "sed -nr '1 { s/.*\\((.*)\\).*/\\1/; p }' " + changelog_file) | |
| 97 arch = OutputFromShellCommand( | |
| 98 "awk '/^Architecture:/ { print $2; }' %s | head -n 1" % control_file) | |
| 99 add_dummy_changelog_entry = False | |
| 100 if force_version != None and not version.startswith(force_version): | |
| 101 print('Warning: no entry in ' + changelog_file + ' for version ' + | |
| 102 force_version + ' (last is ' + version +'). A dummy entry will be ' + | |
| 103 'generated. Remember to add the real changelog entry before ' + | |
| 104 'releasing.'); | |
| 105 version = force_version + '~prerelease' | |
| 106 add_dummy_changelog_entry = True | |
| 107 source_dir_name = source + "_" + version + "_" + arch | |
| 108 target_file_names = [ source_dir_name + ".changes" ] | |
| 109 for package in packages: | |
| 110 package_file_name = package + "_" + version + "_" + arch + ".deb" | |
| 111 target_file_names.append(package_file_name) | |
| 112 # The targets | |
| 113 if output_dir != None: | |
| 114 targets = [os.path.join(output_dir, s) for s in target_file_names] | |
| 115 else: | |
| 116 targets = target_file_names | |
| 117 # Path to where we will construct the debian build tree. | |
| 118 deb_build_tree = os.path.join(obj_dir, source_dir_name, "deb_build_tree") | |
| 119 # First copy the files. | |
| 120 for file in package_files: | |
| 121 env.Command(os.path.join(deb_build_tree, file[0]), file[1], | |
| 122 SCons.Defaults.Copy('$TARGET', '$SOURCE')) | |
| 123 env.Depends(targets, os.path.join(deb_build_tree, file[0])) | |
| 124 # Now copy the Debian metadata sources. We have to do this all at once so | |
| 125 # that we can remove the target directory before copying, because there | |
| 126 # can't be any other stale files there or else dpkg-buildpackage may use | |
| 127 # them and give incorrect build output. | |
| 128 copied_debian_files_paths = [] | |
| 129 for file in debian_files: | |
| 130 copied_debian_files_paths.append(os.path.join(deb_build_tree, "debian", | |
| 131 os.path.basename(file))) | |
| 132 copy_commands = [ | |
| 133 """dir=$$(dirname $TARGET) && \ | |
| 134 rm -Rf $$dir && \ | |
| 135 mkdir -p $$dir && \ | |
| 136 cp $SOURCES $$dir && \ | |
| 137 chmod -R u+w $$dir""" | |
| 138 ] | |
| 139 if add_dummy_changelog_entry: | |
| 140 copy_commands += [ | |
| 141 """debchange -c $$(dirname $TARGET)/changelog --newversion %s \ | |
| 142 --distribution UNRELEASED \ | |
| 143 'Developer preview build. (This entry was auto-generated.)'""" % | |
| 144 version | |
| 145 ] | |
| 146 env.Command(copied_debian_files_paths, debian_files, copy_commands) | |
| 147 env.Depends(targets, copied_debian_files_paths) | |
| 148 # TODO(tschmelcher): Change this to sign the package for Google builds once | |
| 149 # we start putting out Linux releases. | |
| 150 # Must explicitly specify -a because otherwise cross-builds won't work. | |
| 151 # Must explicitly specify -D because -a disables it. | |
| 152 # Must explicitly specify fakeroot because old dpkg tools don't assume that. | |
| 153 env.Command(targets, None, | |
| 154 """dir=%(dir)s && \ | |
| 155 cd $$dir && \ | |
| 156 dpkg-buildpackage -b -uc -a%(arch)s -D -rfakeroot && \ | |
| 157 cd $$OLDPWD && \ | |
| 158 for file in %(targets)s; do \ | |
| 159 mv $$dir/../$$file $$(dirname $TARGET); \ | |
| 160 done""" % | |
| 161 {'dir':env.Dir(deb_build_tree).path, | |
| 162 'arch':arch, | |
| 163 'targets':" ".join(target_file_names)}) | |
| 164 return targets | |
| 165 | |
| 166 def BuildDebianPackage(debian_files, package_files, output_dir=None, | |
| 167 force_version=None): | |
| 168 return _InternalBuildDebianPackage(env, current_source_dir, ".", | |
| 169 debian_files, package_files, output_dir, force_version) | |
| 170 | |
| 171 # Build amd64 package. | |
| 172 BuildDebianPackage(["debian_common/changelog", | |
| 173 "debian_amd64/control", | |
| 174 "debian_amd64/google-o3d.install", | |
| 175 "debian_common/links", | |
| 176 "debian_amd64/postinst", | |
| 177 "debian_amd64/prerm", | |
| 178 "debian_amd64/rules" | |
| 179 ], | |
| 180 [("libnpo3dautoplugin.so", | |
| 181 '$ARTIFACTS_DIR/libnpo3dautoplugin.so'), | |
| 182 ("libGLEW.so.1.5", '$ARTIFACTS_DIR/libGLEW.so.1.5'), | |
| 183 ("libCg.so", '$ARTIFACTS_DIR/libCg.so'), | |
| 184 ("libCgGL.so", '$ARTIFACTS_DIR/libCgGL.so') | |
| 185 ], | |
| 186 output_dir='$ARTIFACTS_DIR', | |
| 187 force_version=env.get('O3D_PLUGIN_VERSION')) | |
| 188 | |
| 189 # Build i386 package. | |
| 190 BuildDebianPackage(["debian_common/changelog", | |
| 191 "debian_i386/control", | |
| 192 "debian_i386/google-o3d.install", | |
| 193 "debian_common/links", | |
| 194 "debian_i386/rules" | |
| 195 ], | |
| 196 [("libnpo3dautoplugin.so", | |
| 197 '$ARTIFACTS_DIR/libnpo3dautoplugin.so'), | |
| 198 ("libCg.so", '$ARTIFACTS_DIR/libCg.so'), | |
| 199 ("libCgGL.so", '$ARTIFACTS_DIR/libCgGL.so') | |
| 200 ], | |
| 201 output_dir='$ARTIFACTS_DIR', | |
| 202 force_version=env.get('O3D_PLUGIN_VERSION')) | |
| 203 | |
| 204 else: | |
| 205 print('dpkg-buildpackage not found in PATH; Debian packages will not be ' | |
| 206 'built.'); | |
| 207 | |
| 208 # TODO(tschmelcher): Also build an RPM and a tgz. | |
| OLD | NEW |