aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2014-10-01 17:39:50 -0700
committerMartin Braun <martin.braun@ettus.com>2014-10-06 10:42:14 +0200
commit29a4693b11cbfa3f2a4c3c517d54cbc155018ee8 (patch)
treec92d1f3d533552b9fa63b7aadc26ad7546048d59
parent57e6930fef096b1af0fc23e59a777f57b39bf2aa (diff)
downloaduhd-29a4693b11cbfa3f2a4c3c517d54cbc155018ee8.tar.gz
uhd-29a4693b11cbfa3f2a4c3c517d54cbc155018ee8.tar.bz2
uhd-29a4693b11cbfa3f2a4c3c517d54cbc155018ee8.zip
uhd: Added infrastructure for maintaining images directory
-rw-r--r--host/CMakeLists.txt9
-rw-r--r--images/README.md64
-rwxr-xr-ximages/create_imgs_package.py98
-rwxr-xr-ximages/make_zip.sh17
-rwxr-xr-ximages/populate_images.py61
-rw-r--r--images/uhdimgs.py99
6 files changed, 337 insertions, 11 deletions
diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt
index 97ffbc24a..68f149871 100644
--- a/host/CMakeLists.txt
+++ b/host/CMakeLists.txt
@@ -209,8 +209,12 @@ UHD_INSTALL(FILES
########################################################################
# Images download directory for utils/uhd_images_downloader.py
########################################################################
-SET(UHD_IMAGES_MD5SUM "b1e06e7d6fe3eacf49d16e2acca98275")
-SET(UHD_IMAGES_DOWNLOAD_SRC "http://files.ettus.com/binaries/maint_images/archive/uhd-images_003.007.003-release.zip")
+#{{{IMG_SECTION
+# This section is written automatically by /images/create_imgs_package.py
+# Any manual changes in here will be overwritten.
+SET(UHD_IMAGES_MD5SUM "3f4e836c6dfbc714c512662de4855082")
+SET(UHD_IMAGES_DOWNLOAD_SRC "uhd-images_003.007.002-108-gcf5739da.zip")
+#}}}
########################################################################
# Register top level components
@@ -329,4 +333,3 @@ ENDIF(LIBUHD_PKG)
UHD_PRINT_COMPONENT_SUMMARY()
MESSAGE(STATUS "Building version: ${UHD_VERSION}${PRINT_APPEND}")
MESSAGE(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}")
-MESSAGE(STATUS "Compatible images can be downloaded from: ${UHD_IMAGES_DOWNLOAD_SRC}")
diff --git a/images/README.md b/images/README.md
index b9e3232aa..6c96fde7b 100644
--- a/images/README.md
+++ b/images/README.md
@@ -3,11 +3,16 @@ UHD Firmware and FPGA Images Builder
The images directory contains the following:
* A Makefile for building firmware and FPGA images
-* A CMake file for building an images package
+* Scripts to load all the binaries for this current commit, as
+ well as create a new images package from the images in subdir
+ images/
This provides a clean and organized way to build all of the firmware and FPGA
images, the source code for which is in the `firmware` and `fpga` directories
-one level above this.
+one level above this, and also maintains a linkage between images and git commits.
+
+Building the binaries
+---------------------
The Makefile and build systems for the images are *probably* Unix-specific.
It's best to build the images on a Unix system with standard build tools. The
@@ -18,7 +23,55 @@ __To build the images (unix):__
1. `make clean`
2. `make images`
-__To build the package (unix):__
+__Fedora note:__
+
+The sdcc binaries are prefixed with "sdcc-" which breaks the build.
+However, /usr/libexec/sdcc contains properly named sdcc binaries.
+`export PATH=${PATH}:/usr/libexec/sdcc`
+
+
+Updating binaries
+-----------------
+
+This goes two ways:
+
+1. Loading the correct binaries for this commit
+2. Updating the binary package on this branch
+
+
+### Loading the correct binaries ###
+
+If you check out a branch or commit, you might want to use the exact same
+binaries that were used when this branch or commit was generated.
+To do this, run `populate_images.py`. This will either download the correct
+images package from a web server or from a local directory if
+`UHD_IMAGES_BASE_URL` is set.
+
+### Updating the binaries ###
+
+If you have commited changes to this branch that require new images, you
+should probably update those.
+Simply copy the new image binaries into images/. If necessary, run
+`populate_images.py` before you do any of this, so all the untouched
+images are the correct version. Then, run `create_imgs_package.py --commit "COMMIT MSG"`
+to create a new ZIP file and commit the info.
+If `UHD_IMAGES_BASE_URL` is set and is a local directory, it will move
+the ZIP file to this directory after creating it.
+
+### Updating the binaries ###
+
+Typical workflow:
+
+1. Check out a branch or commit (git checkout FOO)
+2. Update the images/ subdir (`populate_images.py`)
+3. Do some coding, and commit those changes (`git commit`)
+4. Copy new binaries to images/
+5. Commit the new binaries: `create_imgs_package.py --commit "Updated images on branch X"`
+
+### The CPack system ###
+
+Underlying `create_imgs_package.py` is a CPack system, which can be manually
+invoked by:
1. `mkdir build`
2. `cd build`
@@ -28,8 +81,3 @@ __To build the package (unix):__
The package generator types are described here:
http://www.cmake.org/Wiki/CMake:CPackPackageGenerators
-__Fedora note:__
-
-The sdcc binaries are prefixed with "sdcc-" which breaks the build.
-However, /usr/libexec/sdcc contains properly named sdcc binaries.
-`export PATH=${PATH}:/usr/libexec/sdcc`
diff --git a/images/create_imgs_package.py b/images/create_imgs_package.py
new file mode 100755
index 000000000..642edaebb
--- /dev/null
+++ b/images/create_imgs_package.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 Ettus Research LLC
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+"""
+Command-line utility to create a .zip-file with the current image set.
+"""
+
+import re
+import os
+import uhdimgs
+import glob
+import subprocess
+import argparse
+import shutil
+
+def clear_img_dir(img_root_dir):
+ """ Removes non-image files from the images dir """
+ globs = ["*.tag", "LICENSE"]
+ for the_glob in globs:
+ for filename in glob.iglob(os.path.join(img_root_dir, the_glob)):
+ print 'Removing file from images directory: ', filename
+ os.unlink(filename)
+
+def get_zipfilename_from_cpack_output(cpoutput):
+ """ Parses the output of the ZIP-file creating script
+ and scrapes the actual file name. """
+ regex = re.compile("\/build\/(?P<filename>.*\.zip)")
+ results = regex.search(cpoutput)
+ return results.group('filename')
+
+def parse_args():
+ """ Parse args, duh """
+ parser = argparse.ArgumentParser(description='Link the current set of images to this commit.')
+ parser.add_argument('--commit', default=None,
+ help='Supply a commit message to the changes to host/CMakeLists.txt.')
+ parser.add_argument('-r', '--release-mode', default=None,
+ help='Specify UHD_RELEASE_MODE. Typically "release" or "rc1" or similar.')
+ return parser.parse_args()
+
+def move_zip_to_repo(base_url, zipfilename):
+ final_destination = os.path.join(base_url, zipfilename)
+ if os.path.exists(final_destination):
+ print "WARNING: A file with name {} is already in the images repository.".format(zipfilename)
+ print "Overwrite? [y/N]",
+ ans = raw_input()
+ if ans.strip().upper() != 'Y':
+ return
+ os.unlink(final_destination)
+ shutil.move(zipfilename, base_url)
+
+def main():
+ " Go, go, go! "
+ args = parse_args()
+ img_root_dir = os.path.join(uhdimgs.get_images_dir(), 'images')
+ os.chdir(uhdimgs.get_images_dir())
+ print "== Clearing out the images directory..."
+ clear_img_dir(img_root_dir)
+ print "== Creating ZIP file..."
+ cpack_cmd = ["./make_zip.sh",]
+ if args.release_mode is not None:
+ cpack_cmd.append(args.release_mode)
+ try:
+ cpack_output = subprocess.check_output(cpack_cmd)
+ except subprocess.CalledProcessError as e:
+ print e.output
+ raise SystemExit, 1
+ zipfilename = get_zipfilename_from_cpack_output(cpack_output)
+ print "Filename: ", zipfilename
+ print "== Calculating MD5 sum of ZIP archive..."
+ md5 = uhdimgs.md5_checksum(zipfilename)
+ print 'MD5: ', md5
+ base_url = uhdimgs.get_base_url()
+ if uhdimgs.base_url_is_local(base_url) and os.access(base_url, os.W_OK):
+ print "== Moving ZIP file to {}...".format(base_url)
+ move_zip_to_repo(base_url, zipfilename)
+ print "== Updating CMakeLists.txt..."
+ uhdimgs.update_main_cmake_file(md5, zipfilename)
+ if args.commit is not None:
+ print "== Committing changes..."
+ subprocess.check_call(['git', 'commit', '-m', args.commit, uhdimgs.get_cmake_main_file()])
+ print "== Done!"
+
+if __name__ == "__main__":
+ main()
diff --git a/images/make_zip.sh b/images/make_zip.sh
new file mode 100755
index 000000000..6c44324f9
--- /dev/null
+++ b/images/make_zip.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+# Automatically run the make-zip-file process
+if [ ! -e 'make_zip.sh' ]; then
+ echo 'Are you running this from the images/ directory?'
+ exit 1
+fi
+if [ -e 'build' ]; then
+ echo 'Please remove build subdirectory before proceeding.'
+ exit 1
+fi
+mkdir build
+cd build
+cmake .. -DCPACK_GENERATOR=ZIP -DUHD_RELEASE_MODE="$1" ..
+make package
+mv uhd-images*.zip ..
+cd ..
+rm -r build
diff --git a/images/populate_images.py b/images/populate_images.py
new file mode 100755
index 000000000..1ffc9081b
--- /dev/null
+++ b/images/populate_images.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 Ettus Research LLC
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+"""
+Populates the current directory with a valid set of binaries for the
+current commit.
+"""
+
+import os
+import re
+import subprocess
+import uhdimgs
+
+def get_md5_and_zipfilename():
+ """ Return MD5 hash and ZIP filename from the host/CMakeLists.txt file. """
+ cmakef = open(uhdimgs.get_cmake_main_file(), 'r').read()
+ md5_regex = re.compile(r'UHD_IMAGES_MD5SUM\s*"(?P<md5>[0-9a-f]{32})', flags=re.MULTILINE)
+ md5 = md5_regex.search(cmakef).groups('md5')[0]
+ filename_regex = re.compile(r'UHD_IMAGES_DOWNLOAD_SRC\s*"(?P<filename>[^"]*\.zip)', flags=re.MULTILINE)
+ filename = filename_regex.search(cmakef).groups('filename')[0]
+ return (md5, filename)
+
+def main():
+ " Go, go, go! "
+ # Switch to correct dir
+ img_root_dir = os.path.join(uhdimgs.get_images_dir(), 'images')
+ os.chdir(uhdimgs.get_images_dir())
+ # Read out the CMakeLists.txt file, get filename
+ print "== Reading MD5 and ZIP filename for current commit from {}...".format(uhdimgs.get_cmake_main_file())
+ (md5, filename) = get_md5_and_zipfilename()
+ print "== Starting download..."
+ try:
+ downloader_cmd = [
+ 'python',
+ '../host/utils/uhd_images_downloader.py.in',
+ '-i', img_root_dir,
+ '-f', filename,
+ '-c', md5
+ ]
+ subprocess.check_call(downloader_cmd)
+ except (subprocess.CalledProcessError, OSError):
+ print "[ERROR] Failed to run downloader script."
+ exit(1)
+ print "== Done!"
+
+if __name__ == "__main__":
+ main()
diff --git a/images/uhdimgs.py b/images/uhdimgs.py
new file mode 100644
index 000000000..77da36c0d
--- /dev/null
+++ b/images/uhdimgs.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 Ettus Research LLC
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+"""
+Utility module for packaging and handling UHD binary images.
+"""
+
+import re
+import os
+import sys
+import hashlib
+
+_DEFAULT_BASE_URL = "http://files.ettus.com/binaries/images"
+_DEFAULT_BUFFER_SIZE = 8192
+_CMAKE_MAIN_FILE = "../host/CMakeLists.txt"
+_CMAKE_IMG_TPL = """
+# This section is written automatically by /images/create_imgs_package.py
+# Any manual changes in here will be overwritten.
+SET(UHD_IMAGES_MD5SUM "{}")
+SET(UHD_IMAGES_DOWNLOAD_SRC "{}")
+"""
+
+def get_cmake_main_file():
+ """ Returns a path to the CMakeLists.txt file that contains the image info. """
+ return _CMAKE_MAIN_FILE
+
+def get_base_url():
+ """ Returns the base URL """
+ if os.environ.get("UHD_IMAGES_BASE_URL") is not None and os.environ.get("UHD_IMAGES_BASE_URL") != "":
+ return os.environ.get("UHD_IMAGES_BASE_URL")
+ else:
+ return _DEFAULT_BASE_URL
+
+def base_url_is_local(base_url):
+ """ Returns true if the base URL is actually a http URL
+ instead of a local path. """
+ return not (base_url.find('http') == 0)
+
+def get_images_dir():
+ """
+ Returns the absolute position of the images/ subdir
+ in the UHD source tree.
+ """
+ return os.path.dirname(__file__)
+
+def update_main_cmake_file(md5, zipfilename):
+ """
+ Update the section in host/CMakeLists.txt that contains
+ the ZIP filename and the MD5 hash.
+ """
+ cmakef = open(_CMAKE_MAIN_FILE, 'r').read()
+ new_section = _CMAKE_IMG_TPL.format(md5, zipfilename)
+ regex = re.compile("(?<={{{IMG_SECTION)(.*)(?=#}}})", flags=re.MULTILINE|re.DOTALL)
+ cmakef = regex.sub(new_section, cmakef, count=1)
+ open(_CMAKE_MAIN_FILE, 'w').write(cmakef)
+
+def get_total_md5(img_dir):
+ """ Creates an md5sum of everything in the images directory """
+ def _update_md5_for_dir_recursive(dir_root, md5_obj):
+ for (root, dirnames, filenames) in os.walk(dir_root):
+ for filename in filenames:
+ md5_obj.update(open(os.path.join(root, filename), 'rb').read())
+ sys.stdout.write('.')
+ sys.stdout.flus()
+ for dirname in dirnames:
+ _update_md5_for_dir_recursive(os.path.join(root, dirname), md5_obj)
+ md5 = hashlib.md5()
+ _update_md5_for_dir_recursive(img_dir, md5)
+ print ""
+ return md5.hexdigest()
+
+def md5_checksum(filePath):
+ """ Return MD5 checksum of a single file. """
+ try:
+ with open(filePath, 'rb') as fh:
+ m = hashlib.md5()
+ while True:
+ data = fh.read(_DEFAULT_BUFFER_SIZE)
+ if not data:
+ break
+ m.update(data)
+ return m.hexdigest()
+ except Exception, e:
+ print "Failed to calculated MD5 sum of: %s (%s)" % (filePath, e)
+ raise e