#!/usr/bin/env ruby # # Copyright 2005-2007 Helsinki Institute for Information Technology # (HIIT) and the authors. All rights reserved. # # Authors: Tero Hasu # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. $as_script = (File.basename($0) == File.basename(__FILE__)) if $as_script $usage = %{Python for S60 SDK installer. Last revised: 4 Apr 2007 Installs a Python for S60 SDK on top of a GnuPoc-style Symbian C++ SDK installation. (Tested with GnuPoc patch archive 1.01, and Python v1.3.20 SDKs.) Usage: #{$0} e.g.: #{$0} /tmp/PythonForS60_SDK_1stEd_1_3_1.zip ~/symbian/s60_12 To apply the Pyrex (BAD_STATIC_FORWARD) patch to pyconfig.h, pass the -p switch. The "unzip" program is required. On Debian, install with "apt-get install unzip". } module Kernel alias orig_warn warn def warn *args end end require 'parsearg' module Kernel alias warn orig_warn end $USAGE = "print $usage" parseArgs(2, nil, 'pqs') $pyrex = $OPT_p $simulate = $OPT_s $quiet = $OPT_q end require 'fileutils' if $simulate fumod = FileUtils::DryRun elsif $quiet fumod = FileUtils else fumod = FileUtils::Verbose end include fumod @fileutils_output = $stdout require 'tmpdir' def entries(dir, root = nil) if dir and root file = File.join(root, dir) elsif dir file = dir elsif root file = root else raise end list = Dir.entries(file) list.delete('.') list.delete('..') list.collect! {|x| dir ? File.join(dir, x) : x} list end def install_tree(src, dest) f = proc do |path| if path.nil? srcfile = src destfile = dest else srcfile = File.join(src, path) destfile = File.join(dest, path) end if File.file? srcfile cp srcfile, destfile elsif File.directory? srcfile mkdir_p destfile for entry in entries(path, src) f.call(entry) end else raise srcfile end end f.call(nil) end def fui_split_op aargs op = {} args = [] for arg in aargs if arg.respond_to? :to_hash op.update(arg.to_hash) else args.push(arg) end end [args, op] end SHELL_SPECIAL_CHARS = '()|&<> \'"\\$*' SHELL_ESC_RE = Regexp.new('([' + Regexp.escape(SHELL_SPECIAL_CHARS) + '])') def to_shell_string(array) Array(array).map do |elem| elem.to_str.gsub(SHELL_ESC_RE, '\\\\' + '\1') end.join(" ") end def exec_command_to_string *args args.map do |arg| to_shell_string arg end.join(" ") end def sh(*args) args, op = fui_split_op(args) string = exec_command_to_string(*args) puts string unless $quiet unless $simulate unless system(*args) errormsg = "command failed: " + string raise errormsg unless op[:failok] end end end class UnknownSdk < StandardError def message %{ Error: The Python SDK archive does not appear to have expected structure, so it is probably of an unsupported version. This script probably needs to be updated to support it. Please send a patch. } end end def each_zip_entry zipfile IO.popen("unzip -l " + zipfile) do |input| for line in input line =~ /\s(\S*)$/ or raise yield $1 end end end def zip_has_paths zipfile, paths paths = paths.dup each_zip_entry zipfile do |path| paths.delete(path) return true if paths.empty? end paths.empty? end def zip_find_path zipfile, pathre each_zip_entry zipfile do |path| if path =~ pathre return path end end end def traverse(root, &block) if File.directory? root for entry in entries(root) traverse(entry, &block) end block.call(root) elsif File.file? root block.call(root) else raise root end end # everything but these lowercased, including directories PRESERVE = %w{cStringIO.h Python.h Python_appui.h CSPyInterpreter.h StringIO.py UserDict.py UserList.py UserString.py} def fix_set(root) traverse(root) do |file| path, basename = File.split(file) if basename =~ /^(.*)\{[0-9a-f]+\}(.dso)$/i cp file, File.join(path, ($1 + $2).downcase) end end end def fix_names(root) traverse(root) do |file| path, basename = File.split(file) if basename =~ /[A-Z]/ and !PRESERVE.include?(basename) mv file, File.join(path, basename.downcase) end end end def fix_contents(root) traverse(root) do |file| next unless File.file?(file) if file =~ /\.h$/ data = File.read(file) newdata = data.gsub(/\r\n/, "\n") if newdata != data File.open(file, "w") do |out| out.write(newdata) end end end end end def apply_pyrex_patch(root) traverse(root) do |file| basename = File.basename(file) next unless basename == "pyconfig.h" data = File.read(file) newdata = data.gsub(/^#undef\s+BAD_STATIC_FORWARD/, "#define BAD_STATIC_FORWARD") if newdata != data File.open(file, "w") do |out| out.write(newdata) end end end end def unzip_selected(zipfile, targetdir, entrypath) entrypaths = Array(entrypath) for path in entrypaths sh("unzip", "-q", zipfile, path, "-d", targetdir) end end def unzip_all(zipfile, targetdir) sh("unzip", "-q", zipfile, "-d", targetdir) end def install_sdk zipfile, sdkhome e32home = File.join(sdkhome, 'epoc32') unless File.directory?(e32home) raise %{ Unrecognized SDK directory structure at #{sdkhome}. Either there is no GnuPoc-style SDK installed at #{sdkhome}, or it is of an unsupported version. } end tmphome = File.join(Dir::tmpdir, 'tmp.' + File.basename(__FILE__)) rm_rf tmphome # The .zip contains an entry named Pythonsomething/sdk_files.zip. fileszippath = zip_find_path zipfile, /.*sdk_files\.zip$/i unless fileszippath raise UnknownSdk end unzip_selected(zipfile, tmphome, fileszippath) # Let us also unpack sdk_files.zip. # It should contain epoc32 at its root. zipfile = File.join(tmphome, fileszippath) unzip_all(zipfile, tmphome) e32tree = File.join(tmphome, 'epoc32') unless File.directory?(e32tree) raise UnknownSdk end for dir in [e32tree] fix_set(dir) fix_names(dir) fix_contents(dir) apply_pyrex_patch(dir) if $pyrex end ## Up till this point we have not touched the SDK tree; we shall do ## so now that it looks like we have all the files we require. install_tree(e32tree, e32home) end if $as_script zipfile = ARGV[0] sdkhome = ARGV[1] unless File.file? zipfile raise "no such file: #{zipfile}" end unless File.directory? sdkhome raise "no such directory: #{sdkhome}" end install_sdk(zipfile, sdkhome) end