=== modified file 'setup.py' --- setup.py 2008-03-16 00:28:48 +0000 +++ setup.py 2008-07-07 11:41:58 +0000 @@ -318,9 +318,28 @@ import warnings warnings.warn('Unknown Python version.\n' 'Please check setup.py script for compatibility.') + + # Although we currently can't enforce it, we consider it an error for + # py2exe to report any files are "missing". Such modules we know aren't + # used should be listed here. + excludes = """Tkinter psyco ElementPath r_hmac + ImaginaryModule cElementTree elementtree.ElementTree + Crypto.PublicKey._fastmath + medusa medusa.filesys medusa.ftp_server + tools tools.doc_generate + resource validate""".split() + # email package from std python library use lazy import, # so we need to explicitly add all package additional_packages.add('email') + # And it uses funky mappings to conver to 'Oldname' to 'newname'. As + # a result, packages like 'email.Parser' show as missing. Tell py2exe + # to exclude them. + import email + for oldname in getattr(email, '_LOWERNAMES', []): + excludes.append("email." + oldname) + for oldname in getattr(email, '_MIMENAMES', []): + excludes.append("email.MIME" + oldname) # text files for help topis text_topics = glob.glob('bzrlib/help_topics/en/*.txt') @@ -346,16 +365,97 @@ packs, mods = mf.get_result() additional_packages.update(packs) + console_targets = [target, + 'tools/win32/bzr_postinstall.py', + ] + gui_targets = [] + com_targets = [] + + if "TBZR" in os.environ: + # Eg: via SVN: http://tortoisesvn.tigris.org/svn/tortoisesvn/TortoiseOverlays/version-1.0.4/bin/TortoiseOverlays-1.0.4.11886-win32.msi + if not os.path.isfile(os.environ.get('TOVMSI_WIN32', '')): + raise RuntimeError, "Please set TOVMSI_WIN32 to the location of " \ + "the TortoiseOverlays .msi installerfile" + + # ModuleFinder can't handle runtime changes to __path__, but + # win32com uses them. Hook this in so win32com.shell is found. + import modulefinder + import win32com + for p in win32com.__path__[1:]: + modulefinder.AddPackagePath("win32com", p) + for extra in ["win32com.shell"]: + __import__(extra) + m = sys.modules[extra] + for p in m.__path__[1:]: + modulefinder.AddPackagePath(extra, p) + + # TBZR points to the TBZR directory + tbzr_root = os.environ["TBZR"] + + # Ensure tbzrlib itself is on sys.path + sys.path.append(tbzr_root) + + # Ensure our COM "entry-point" is on sys.path + sys.path.append(os.path.join(tbzr_root, "shellext", "python")) + + packages.append("tbzrlib") + excludes.extend("""pywin pywin.dialogs pywin.dialogs.list + win32ui crawler.Crawler""".split()) + + tbzr = dict( + modules=["tbzr"], + create_exe = False, # we only want a .dll + ) + com_targets.append(tbzr) + + # tbzrcache executables - a "console" version for debugging and a + # GUI version that is generally used. + tbzrcache = dict( + script = os.path.join(tbzr_root, "Scripts", "tbzrcache.py"), + icon_resources = [(0,'bzr.ico')], + ) + console_targets.append(tbzrcache) + + # Make a windows version which is the same except for the base name. + tbzrcachew = tbzrcache.copy() + tbzrcachew["dest_base"]="tbzrcachew" + gui_targets.append(tbzrcachew) + + # tbzr tests + tbzrtest = dict( + script = os.path.join(tbzr_root, "Scripts", "tbzrtest.py"), + ) + console_targets.append(tbzrtest) + + # A utility to see python output from the shell extension - this will + # die when we get a c++ extension + # any .py file from pywin32's win32 lib will do (other than + # win32traceutil itself that is) + import winerror + win32_lib_dir = os.path.dirname(winerror.__file__) + tracer = dict(script = os.path.join(win32_lib_dir, "win32traceutil.py"), + dest_base="tbzr_tracer") + console_targets.append(tracer) + + else: + # print this warning to stderr as output is redirected, so it is seen + # at build time. Also to stdout so it appears in the log + for f in (sys.stderr, sys.stdout): + print >> f, \ + "Skipping TBZR binaries - please set TBZR to a directory to enable" + options_list = {"py2exe": {"packages": packages + list(additional_packages), "includes": includes + mods, - "excludes": ["Tkinter", "medusa", "tools"], + "excludes": excludes, "dist_dir": "win32_bzr.exe", + "optimize": 1, }, } + setup(options=options_list, - console=[target, - 'tools/win32/bzr_postinstall.py', - ], + console=console_targets, + windows=gui_targets, + com_server=com_targets, zipfile='lib/library.zip', data_files=topics_files + plugins_files, ) === modified file 'tools/win32/bzr.iss.cog' --- tools/win32/bzr.iss.cog 2008-02-06 15:33:12 +0000 +++ tools/win32/bzr.iss.cog 2008-07-05 05:06:44 +0000 @@ -45,8 +45,8 @@ InfoAfterFile="..\tools\win32\survey.txt" VersionInfoCompany="Canonical Ltd." -VersionInfoCopyright="Canonical Ltd., 2005-2007" -VersionInfoDescription="Installer for stand-alone bzr.exe" +VersionInfoCopyright="Canonical Ltd., 2005-2008" +VersionInfoDescription="Windows installer for Bazaar" ; [[[cog ; import bzrlib ; version_number = [] @@ -79,14 +79,40 @@ ; [[[end]]] ChangesEnvironment=yes -PrivilegesRequired=none - +; MARKH: PrivilegesRequired=none means it can't be installed by a non-admin +; user - but sadly we still need admin - eg, tortoise overlays, installing +; into "\Program Files", installing COM objects etc all must be done by an +; admin. +PrivilegesRequired=admin [Files] -Source: "*.*"; DestDir: "{app}"; Flags: ignoreversion; -Source: "lib\*.*"; DestDir: "{app}\lib"; Flags: createallsubdirs ignoreversion recursesubdirs; +; Tortoise files - these are at the top as we use 'ExtractTemporaryFile' on +; the TortoiseOverlays MSI, and inno documents such files should be at the +; start for best performance. +; [[[cog +; if "TBZR" in os.environ: # we need a more formal way of controlling this... +; tovmsi = os.environ["TOVMSI_WIN32"] # point at TortoiseOverlays .msi +; cog.outl('Source: "%s"; Flags: dontcopy ignoreversion ; Components: tortoise' % tovmsi) +; cog.outl('Source: "tbzrcache.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: tortoise') +; cog.outl('Source: "tbzrcachew.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: tortoise') +; cog.outl('Source: "tbzr_tracer.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: debug') +; # Note 'regserver' here appears to run regsvr32 without elevation, which +; # is no good for us - so we have a [run] entry below. +; cog.outl('Source: "tbzr.dll"; DestDir: "{app}"; Flags: ignoreversion regserver restartreplace; Components: tortoise') +; +; cog.outl('Source: "%s\\doc\\index.html"; DestDir: "{app}\\doc\\tbzr"; Flags: ignoreversion; Components: tortoise' % os.environ['TBZR']) +; ]]] +; [[[end]]] + +; We can't say '*.*' due to optional components. +Source: "*.bat"; DestDir: "{app}"; Flags: ignoreversion; +Source: "*.url"; DestDir: "{app}"; Flags: ignoreversion; +Source: "msvc*.dll"; DestDir: "{app}"; Flags: ignoreversion restartreplace; +Source: "bz*.exe"; DestDir: "{app}"; Flags: ignoreversion; +Source: "Python*.dll"; DestDir: "{app}"; Flags: ignoreversion restartreplace; +Source: "lib\*.*"; DestDir: "{app}\lib"; Flags: createallsubdirs ignoreversion recursesubdirs restartreplace; Source: "doc\*.*"; DestDir: "{app}\doc"; Flags: createallsubdirs ignoreversion recursesubdirs; -Source: "plugins\*.*"; DestDir: "{app}\plugins"; Components: plugins; Flags: createallsubdirs ignoreversion recursesubdirs; +Source: "plugins\*.*"; DestDir: "{app}\plugins"; Components: plugins; Flags: createallsubdirs ignoreversion recursesubdirs restartreplace; ; [[[cog ; try: ; import pycurl @@ -105,19 +131,27 @@ ; ]]] ; [[[end]]] +[Types] +Name: "typical"; Description: "A typical installation" +Name: "full"; Description: "Full Installation (typical installation plus test utilities)" +Name: "compact"; Description: "Compact installation" +Name: "custom"; Description: "Custom installation"; Flags: iscustom [Components] -Name: "main"; Description: "Main Files"; Types: full compact custom; Flags: fixed -Name: "plugins"; Description: "Default plugins"; Types: full custom; +Name: "main"; Description: "Main Files"; Types: full typical compact custom; Flags: fixed +Name: "plugins"; Description: "Default plugins"; Types: full typical custom; ; [[[cog ; if ca_path: ; cog.outl('Name: "cabundle"; ' ; 'Description: "CA certificates for SSL support"; ' -; 'Types: full custom') +; 'Types: full typical custom') +; if "TBZR" in os.environ: # we need a more formal way of controlling this... +; cog.out1('Name: "tortoise"; Description: "Windows Shell Extensions (TortoiseBZR) - EXPERIMENTAL"; Types: full typical custom;') +; cog.out1('Name: "debug"; Description: "Test, diagnostic and debugging utilities"; Types: full custom;') +; ; ]]] ; [[[end]]] - [Dirs] Name: "{userappdata}\bazaar\2.0" Name: "{app}\plugins"; Flags: uninsalwaysuninstall @@ -127,12 +161,25 @@ Name: "{group}\Documentation index"; Filename: "{app}\doc\index.html"; WorkingDir: "{app}\doc"; Name: "{group}\Bazaar Home Page"; Filename: "{app}\bazaar.url"; Comment: "http://www.bazaar-vcs.org"; Name: "{group}\Start Bzr in cmd shell"; Filename: "{cmd}"; Parameters: "/K start_bzr.bat"; WorkingDir: "{app}"; IconFilename: "{app}\bzr.exe"; Comment: "Open new Bzr session"; -Name: "{group}\Uninstall Bazaar"; Filename: "{uninstallexe}"; IconFileName: "{sys}\shell32.dll"; IconIndex: 101; Comment: "Remove Bzr completely"; +; NOTE: Intent is to change the log file location - the line below will need to change to reflect that. +Name: "{group}\Open Bzr log file"; Filename: "notepad.exe"; Parameters: "{userdocs}\.bzr.log"; Comment: "Launch notepad to view the bzr log file"; + +; [[[cog +; if "TBZR" in os.environ: +; cog.out1('Name: "{group}\TortoiseBZR documentation"; Filename: "{app}\doc\tbzr\index.html"; Comment: "Launch TortoiseBZR documentation";') +; ]]] +; [[[end]]] +; No Uninstall here - Control Panel will do [Tasks] -Name: Path; Description: "Add {app} directory to PATH environment variable"; +Name: Path; Description: "Add {app} directory to PATH environment variable" Name: Shell; Description: "Add Bzr context menu to shell"; Flags: unchecked +; [[[cog +; if "TBZR" in os.environ: +; cog.out1('Name: TBZRReadme; Description: "View the TortoiseBZR Readme"; Components: tortoise') +; ]]] +; [[[end]]] [Registry] @@ -148,6 +195,8 @@ [Run] Filename: "{app}\bzr_postinstall.exe"; Parameters: "--start-bzr"; Flags: skipifdoesntexist runhidden; ; [[[cog +; # NOTE: A patch has been submitted to Paramika that will avoid use +; # of the MFC DLL. See http://www.lag.net/pipermail/paramiko/2008-June/000732.html ; import os ; if os.path.isfile('win32_bzr.exe/lib/win32ui.pyd'): # pywin32 mfc wrapper ; cog.outl('Filename: "{app}\bzr_postinstall.exe"; ' @@ -157,11 +206,77 @@ ; [[[end]]] Filename: "{app}\bzr_postinstall.exe"; Parameters: "--add-path"; Tasks: Path; Flags: skipifdoesntexist skipifsilent runhidden; Filename: "{app}\bzr_postinstall.exe"; Parameters: "--add-shell-menu"; Tasks: Shell; Flags: skipifdoesntexist skipifsilent runhidden; +; [[[cog +; if "TBZR" in os.environ: +; cog.out1('Filename: "regsvr32.exe"; Parameters: "/s tbzr.dll"; WorkingDir: "{app}"; Components: tortoise; Description: "Register TBZR"; StatusMsg: "Registering TBZR"') +; cog.out1('Filename: "{app}\doc\tbzr\index.html"; Tasks: TBZRReadme; Flags: shellexec') +; ]]] +; [[[end]]] [UninstallRun] -Filename: "{app}\bzr_postinstall.exe"; Parameters: "--delete-path --delete-shell-menu --silent"; Flags: skipifdoesntexist runhidden; +; [[[cog +; if "TBZR" in os.environ: +; cog.out1('Filename: "regsvr32.exe"; Parameters: "/u /s tbzr.dll"; WorkingDir: "{app}"; Components: tortoise; StatusMsg: "Unregistering TBZR"; Flags: skipifdoesntexist') +; ]]] +; [[[end]]] [UninstallDelete] Type: filesandordirs; Name: "{app}\plugins\*" + +[Code] +const + SHCNF_IDLIST = $0000; + SHCNE_ASSOCCHANGED = $08000000; + WM_QUIT = 18; + +procedure SHChangeNotify(wEventId, uFlags, dwItem1, dwItem2: Integer); + external 'SHChangeNotify@shell32.dll stdcall'; + +procedure CurStepChanged(CurStep: TSetupStep); +var + S, tovmsi, fqtovmsi, params: String; + ErrorCode: Integer; + hwnd: HWND; +begin + if CurStep=ssInstall then begin +// [[[cog +// if "TBZR" not in os.environ: +// cog.outl(' Exit; // No TSVN set - exit this procedure.') +// ]]] +// [[[end]]] + // ask the cache process to shut-down. + hwnd := FindWindowByClassName('TBZRCache_Taskbar'); + if hwnd <> 0 then + PostMessage(hwnd, WM_QUIT, 1, 0); + end; + + if CurStep=ssPostInstall then begin + // a couple of post-install tasks + if IsComponentSelected('tortoise') then begin + // Need to execute: + // msiexec /i TortoiseOverlays-1.X.X.XXXX-win32.msi /qn /norestart +// [[[cog +// if "TBZR" in os.environ: +// import os +// cog.outl("tovmsi := '%s';" % os.path.basename(os.environ["TOVMSI_WIN32"])) +// else: +// cog.outl("tovmsi := '';") +// ]]] +// [[[end]]] + ExtractTemporaryFile(tovmsi); + fqtovmsi := AddBackslash(ExpandConstant('{tmp}')) + tovmsi; + params := '/i "' + fqtovmsi + '" /qn /norestart'; + if not ShellExec('', 'msiexec.exe', params, '', SW_HIDE, + ewWaitUntilTerminated, ErrorCode) then + MsgBox('Failed to install TortoiseOverlays: ' + SysErrorMessage(ErrorCode), + mbInformation, MB_OK); + // Ideally we could be bzr_postinstall.exe this way too, but + // its needed at uninstall time. + end; + // cause explorer to re-fetch handlers. + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0); + end; +end; +