Upgrade pip dependencies as well
[bitmask_bundler.git] / bundler / actions.py
1 import datetime
2 import hashlib
3 import os
4 import stat
5 import sys
6 import subprocess
7 import zipfile
8 import urllib
9
10 from abc import ABCMeta, abstractmethod
11 from contextlib import contextmanager
12 from distutils import file_util, dir_util
13
14 from utils import IS_MAC, IS_WIN
15
16 if IS_MAC:
17     from sh import SetFile, hdiutil, codesign
18     from darwin_dyliber import fix_all_dylibs
19 if IS_WIN:
20     import pbs
21     from pbs import cd, glob
22     git = pbs.Command("C:\\Program Files\\Git\\bin\\git.exe")
23     python = pbs.Command("C:\\Python27\\python.exe")
24     pip = pbs.Command("C:\\Python27\\scripts\\pip.exe")
25     mkdir = pbs.Command("C:\\Program Files\\Git\\bin\\mkdir.exe")
26     make = pbs.Command("C:\\MinGW\\bin\\mingw32-make.exe")
27     cp = pbs.Command("C:\\Program Files\\Git\\bin\\cp.exe")
28     rm = pbs.Command("C:\\Program Files\\Git\\bin\\rm.exe")
29     find = pbs.Command("C:\\Program Files\\Git\\bin\\find.exe")
30     ln = pbs.Command("C:\\Program Files\\Git\\bin\\ln.exe")
31     tar = pbs.Command("C:\\Program Files\\Git\\bin\\tar.exe")
32     mv = pbs.Command("C:\\Program Files\\Git\\bin\\mv.exe")
33 else:
34     from sh import git, cd, python, mkdir, make, cp, glob, pip, rm
35     from sh import find, ln, tar, mv, strip
36
37 from depcollector import collect_deps
38
39
40 class Action(object):
41     __metaclass__ = ABCMeta
42
43     def __init__(self, name, basedir, skip=[], do=[]):
44         self._name = name
45         self._basedir = basedir
46         self._skip = skip
47         self._do = do
48
49     @property
50     def name(self):
51         return self._name
52
53     @property
54     def skip(self):
55         return self._name in self._skip
56
57     @property
58     def do(self):
59         if len(self._do) > 0:
60             return self._name in self._do
61         return True
62
63     @abstractmethod
64     def run(self, *args, **kwargs):
65         pass
66
67
68 def skippable(func):
69     def skip_func(self, *args, **kwargs):
70         if self.skip:
71             print "Skipping...", self.name
72             return
73         if not self.do:
74             print "Skipping...", self.name
75             return
76         return func(self, *args, **kwargs)
77     return skip_func
78
79
80 def platform_dir(basedir, *args):
81     dir = os.path.join(basedir,
82                        "Bitmask",
83                        *args)
84     if IS_MAC:
85         dir = os.path.join(basedir,
86                            "Bitmask",
87                            "Bitmask.app",
88                            "Contents",
89                            "MacOS",
90                            *args)
91     return dir
92
93
94 @contextmanager
95 def push_pop(*directories):
96     cd(os.path.join(*directories))
97     yield
98     cd(os.path.join(*(("..",)*len(directories))))
99
100
101 def get_version(repos, nightly):
102     if not nightly:
103         version = "unknown"
104         with push_pop("bitmask_client"):
105             version = git("describe", "--tags").strip()
106         return version
107
108     m = hashlib.sha256()
109     for repo in repos:
110         version = "unknown"
111         with push_pop(repo):
112             try:
113                 version = git("describe").strip()
114             except:
115                 pass
116         m.update(version)
117
118     return "{0}-{1}".format(str(datetime.date.today()),
119                             m.hexdigest()[:8])
120
121
122 class GitCloneAll(Action):
123     def __init__(self, basedir, skip, do):
124         Action.__init__(self, "gitclone", basedir, skip, do)
125
126     def _repo_url(self, repo_name):
127         if repo_name == "leap_assets":
128             return "git://leap.se/leap_assets"
129         return "git://github.com/leapcode/{0}".format(repo_name)
130
131     @skippable
132     def run(self, sorted_repos, nightly):
133         print "Cloning repositories..."
134         cd(self._basedir)
135         for repo in sorted_repos:
136             print "Cloning", repo
137             rm("-rf", repo)
138             git.clone(self._repo_url(repo), repo)
139             with push_pop(repo):
140                 # Thandy is a special case regarding branches, we'll just use
141                 # develop
142                 if repo in ["leap_assets"]:
143                     continue
144                 if not nightly:
145                     git.checkout("master")
146                     git.pull("--ff-only", "origin", "master")
147                     git.fetch()
148                     git.reset("--hard", "origin/master")
149                     latest_tag = git.describe("--abbrev=0").strip()
150                     git.checkout("--quiet", latest_tag)
151                 else:
152                     git.checkout("develop")
153
154         print "Done cloning repos..."
155
156
157 class PythonSetupAll(Action):
158     def __init__(self, basedir, skip, do):
159         Action.__init__(self, "pythonsetup", basedir, skip, do)
160
161     @skippable
162     def run(self, sorted_repos, binaries_path):
163         cd(self._basedir)
164         for repo in sorted_repos:
165             print "Setting up", repo
166             if repo == "soledad":
167                 for subrepo in ["common", "client"]:
168                     with push_pop(repo, subrepo):
169                         pip("install", "-r", "pkg/requirements.pip", "--upgrade")
170                         python("setup.py", "develop")
171                         sys.path.append(os.path.join(self._basedir,
172                                                      repo, subrepo, "src"))
173             elif repo in ["bitmask_launcher", "leap_assets"]:
174                 print "Skipping launcher..."
175                 continue
176             else:
177                 with push_pop(repo):
178                     if repo != "thandy":
179                         pip("install", "-r", "pkg/requirements.pip", "--upgrade")
180                     else:
181                         # Thandy is a special kid at this point in
182                         # terms of packaging. So we install
183                         # dependencies ourselves for the time being
184                         pip("install", "pycrypto", "--upgrade")
185                     if repo == "bitmask_client":
186                         print "Running make on the client..."
187                         make()
188                         print "Running build to get correct version..."
189                         python("setup.py", "build")
190                         print "Updating hashes"
191                         os.environ["OPENVPN_BIN"] = os.path.join(
192                             binaries_path, "openvpn.files", "leap-openvpn")
193                         os.environ["BITMASK_ROOT"] = os.path.join(
194                             self._basedir, repo, "pkg", "linux", "bitmask-root")
195                         python("setup.py", "hash_binaries")
196                     python("setup.py", "develop")
197                     sys.path.append(os.path.join(self._basedir, repo, "src"))
198
199
200 def _convert_path_for_win(path):
201     npath = path
202     if IS_WIN:
203         npath = path.replace("\\", "/")
204     return npath
205
206
207 class CreateDirStructure(Action):
208     def __init__(self, basedir, skip, do):
209         Action.__init__(self, "createdirs", basedir, skip, do)
210
211     @skippable
212     def run(self):
213         print "Creating directory structure..."
214         if IS_MAC:
215             self._darwin_create_dir_structure()
216             self._create_dir_structure(os.path.join(self._basedir,
217                                                     "Bitmask.app",
218                                                     "Contents", "MacOS"))
219         else:
220             self._create_dir_structure(self._basedir)
221         print "Done"
222
223     def _create_dir_structure(self, basedir):
224         mkdirp = mkdir.bake("-p")
225         apps = os.path.join(basedir, "apps")
226         mkdirp(_convert_path_for_win(apps))
227         if IS_WIN:
228             mkdirp(_convert_path_for_win(os.path.join(apps, "eip")))
229         else:
230             mkdirp(_convert_path_for_win(os.path.join(apps, "eip", "files")))
231         mkdirp(_convert_path_for_win(os.path.join(apps, "mail")))
232         mkdirp(_convert_path_for_win(os.path.join(basedir, "lib")))
233
234     def _darwin_create_dir_structure(self):
235         mkdirp = mkdir.bake("-p")
236         app_path = os.path.join(self._basedir, "Bitmask.app")
237         mkdirp(app_path)
238         mkdirp(os.path.join(app_path, "Contents", "MacOS"))
239         mkdirp(os.path.join(app_path, "Contents", "Resources"))
240         mkdirp(os.path.join(app_path, "Contents", "PlugIns"))
241         mkdirp(os.path.join(app_path, "Contents", "StartupItems"))
242         ln("-s", "/Applications", os.path.join(self._basedir, "Applications"))
243
244
245 class CollectAllDeps(Action):
246     def __init__(self, basedir, skip, do):
247         Action.__init__(self, "collectdeps", basedir, skip, do)
248
249     def _remove_unneeded(self, lib_dir):
250         print "Removing unneeded files..."
251         files = find(lib_dir).strip().splitlines()
252         keep = ["QtCore.so",
253                 "QtGui.so",
254                 "__init__.py",
255                 "_utils.py",
256                 "PySide",
257                 ""]  # empty means the whole pyside dir
258         if IS_WIN:
259             keep = ["QtCore4.dll",
260                     "QtGui4.dll",
261                     "__init__.py",
262                     "_utils.py",
263                     "PySide",
264                     "QtGui.pyd",
265                     "QtCore.pyd",
266                     ""]  # empty means the whole pyside dir
267         for f in files:
268             if f.find("PySide") > 0:
269                 if os.path.split(f)[1] not in keep:
270                     rm("-rf", f)
271                     pass
272         print "Done"
273
274     @skippable
275     def run(self, path_file):
276         print "Collecting dependencies..."
277         app_py = os.path.join(self._basedir,
278                               "bitmask_client",
279                               "src",
280                               "leap",
281                               "bitmask",
282                               "app.py")
283         dest_lib_dir = platform_dir(self._basedir, "lib")
284         collect_deps(app_py, dest_lib_dir, path_file)
285
286         self._remove_unneeded(dest_lib_dir)
287         print "Done"
288
289
290 class CopyBinaries(Action):
291     def __init__(self, basedir, skip, do):
292         Action.__init__(self, "copybinaries", basedir, skip, do)
293
294     @skippable
295     def run(self, binaries_path):
296         print "Copying binaries..."
297         dest_lib_dir = platform_dir(self._basedir, "lib")
298
299         if IS_MAC:
300             cp(glob(os.path.join(binaries_path, "Qt*")), dest_lib_dir)
301             cp(glob(os.path.join(binaries_path, "*.dylib")), dest_lib_dir)
302             cp(glob(os.path.join(binaries_path, "Python")), dest_lib_dir)
303             resources_dir = os.path.join(self._basedir,
304                                          "Bitmask",
305                                          "Bitmask.app",
306                                          "Contents",
307                                          "Resources")
308             cp(glob(os.path.join(binaries_path, "openvpn.leap*")),
309                resources_dir)
310
311             mkdir("-p", os.path.join(resources_dir, "openvpn"))
312             cp("-r", glob(os.path.join(binaries_path, "openvpn.files", "*")),
313                os.path.join(resources_dir, "openvpn"))
314
315             cp(os.path.join(binaries_path, "cocoasudo"), resources_dir)
316
317             cp("-r", os.path.join(binaries_path, "qt_menu.nib"), resources_dir)
318             cp("-r", os.path.join(binaries_path, "tuntap-installer.app"),
319                resources_dir)
320             cp(os.path.join(binaries_path, "Bitmask"),
321                platform_dir(self._basedir))
322         elif IS_WIN:
323             root = _convert_path_for_win(
324                 os.path.join(self._basedir, "Bitmask"))
325             for i in glob(os.path.join(binaries_path, "*.dll")):
326                 cp(_convert_path_for_win(i),
327                    root)
328             import win32com
329             win32comext_path = os.path.split(win32com.__file__)[0] + "ext"
330             shell_path = os.path.join(win32comext_path, "shell")
331             cp("-r",
332                _convert_path_for_win(shell_path),
333                _convert_path_for_win(os.path.join(dest_lib_dir, "win32com")))
334             cp(_convert_path_for_win(
335                 os.path.join(binaries_path, "bitmask.exe")),
336                root)
337             cp(_convert_path_for_win(
338                 os.path.join(binaries_path, "Microsoft.VC90.CRT.manifest")),
339                root)
340             cp(_convert_path_for_win(
341                 os.path.join(binaries_path, "openvpn_leap.exe")),
342                _convert_path_for_win(
343                    os.path.join(root, "apps", "eip")))
344             cp(_convert_path_for_win(
345                 os.path.join(binaries_path, "openvpn_leap.exe.manifest")),
346                _convert_path_for_win(
347                    os.path.join(root, "apps", "eip")))
348             cp("-r",
349                _convert_path_for_win(
350                    os.path.join(binaries_path, "tap_driver")),
351                _convert_path_for_win(
352                    os.path.join(root, "apps", "eip")))
353         else:
354             cp(glob(os.path.join(binaries_path, "*.so*")), dest_lib_dir)
355
356             eip_dir = platform_dir(self._basedir, "apps", "eip")
357             #cp(os.path.join(binaries_path, "openvpn"), eip_dir)
358
359             cp("-r", glob(os.path.join(binaries_path, "openvpn.files", "*")),
360                os.path.join(eip_dir, "files"))
361             cp(os.path.join(binaries_path, "bitmask"),
362                platform_dir(self._basedir))
363
364         mail_dir = platform_dir(self._basedir, "apps", "mail")
365         cp(_convert_path_for_win(os.path.join(binaries_path, "gpg")),
366            _convert_path_for_win(mail_dir))
367         print "Done"
368
369
370 class PLister(Action):
371     plist = """<?xml version="1.0" encoding="UTF-8"?>
372 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
373 <plist version="1.0">
374 <dict>
375         <key>CFBundleDisplayName</key>
376         <string>Bitmask</string>
377         <key>CFBundleExecutable</key>
378         <string>MacOS/bitmask-launcher</string>
379         <key>CFBundleIconFile</key>
380         <string>bitmask.icns</string>
381         <key>CFBundleInfoDictionaryVersion</key>
382         <string>6.0</string>
383         <key>CFBundleName</key>
384         <string>Bitmask</string>
385         <key>CFBundlePackageType</key>
386         <string>APPL</string>
387         <key>CFBundleShortVersionString</key>
388         <string>1</string>
389         <key>LSBackgroundOnly</key>
390         <false/>
391         <key>CFBundleIdentifier</key>
392         <string>se.leap.bitmask</string>
393 </dict>
394 </plist>""".split("\n")
395
396     qtconf = """[Paths]
397 Plugins = PlugIns"""
398
399     def __init__(self, basedir, skip, do):
400         Action.__init__(self, "plister", basedir, skip, do)
401
402     @skippable
403     def run(self):
404         print "Generating Info.plist file..."
405         file_util.write_file(os.path.join(self._basedir,
406                                           "Bitmask",
407                                           "Bitmask.app",
408                                           "Contents",
409                                           "Info.plist"),
410                              self.plist)
411         print "Generating qt.conf file..."
412         file_util.write_file(os.path.join(self._basedir,
413                                           "Bitmask",
414                                           "Bitmask.app",
415                                           "Contents",
416                                           "Resources",
417                                           "qt.conf"),
418                              self.qtconf)
419         print "Done"
420
421
422 class SeededConfig(Action):
423     def __init__(self, basedir, skip, do):
424         Action.__init__(self, "seededconfig", basedir, skip, do)
425
426     @skippable
427     def run(self, seeded_config):
428         print "Copying seeded config..."
429         dir_util.copy_tree(seeded_config,
430                            platform_dir(self._basedir, "config"))
431         print "Done"
432
433
434 class DarwinLauncher(Action):
435     launcher = """#!/bin/bash
436 #
437 # Launcher for the LEAP Client under OSX
438 #
439 DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)"
440 export DYLD_LIBRARY_PATH=$DIR/lib
441 export PATH=$DIR/../Resources/:$PATH
442 # ---------------------------
443 # DEBUG Info -- enable this if you
444 # are having problems with dynamic libraries loading
445
446 cd "${DIR}" && ./Bitmask $1 $2 $3 $4 $5""".split("\n")
447
448     def __init__(self, basedir, skip, do):
449         Action.__init__(self, "darwinlauncher", basedir, skip, do)
450
451     @skippable
452     def run(self):
453         print "Generating launcher script for OSX..."
454         launcher_path = os.path.join(self._basedir,
455                                      "Bitmask",
456                                      "Bitmask.app",
457                                      "Contents",
458                                      "MacOS",
459                                      "bitmask-launcher")
460         file_util.write_file(launcher_path, self.launcher)
461         os.chmod(launcher_path, stat.S_IRGRP | stat.S_IROTH | stat.S_IRUSR
462                  | stat.S_IWGRP | stat.S_IWOTH | stat.S_IWUSR
463                  | stat.S_IXGRP | stat.S_IXOTH | stat.S_IXUSR)
464         print "Done"
465
466
467 class CopyAssets(Action):
468     def __init__(self, basedir, skip, do):
469         Action.__init__(self, "copyassets", basedir, skip, do)
470
471     @skippable
472     def run(self):
473         print "Copying assets..."
474         resources_dir = os.path.join(self._basedir,
475                                      "Bitmask",
476                                      "Bitmask.app",
477                                      "Contents",
478                                      "Resources")
479         cp(os.path.join(self._basedir, "leap_assets", "mac", "bitmask.icns"),
480            resources_dir)
481         cp(os.path.join(self._basedir, "leap_assets", "mac", "bitmask.tiff"),
482            resources_dir)
483         print "Done"
484
485
486 class CopyMisc(Action):
487     TUF_CONFIG="""[General]
488 updater_delay = 60
489
490 [Mirror.localhost]
491 url_prefix = http://dl.bitmask.net/tuf"""
492
493     def __init__(self, basedir, skip, do):
494         Action.__init__(self, "copymisc", basedir, skip, do)
495
496     @skippable
497     def run(self, binary_path):
498         print "Downloading thunderbird extension..."
499         ext_path = platform_dir(self._basedir, "apps",
500                                 "bitmask-thunderbird-latest.xpi")
501         urllib.urlretrieve(
502             "https://downloads.leap.se/thunderbird_extension/"
503             "bitmask-thunderbird-latest.xpi",
504             ext_path)
505         print "Done"
506         print "Copying misc files..."
507         apps_dir = _convert_path_for_win(platform_dir(self._basedir, "apps"))
508         cp(_convert_path_for_win(
509             os.path.join(self._basedir, "bitmask_launcher", "src",
510                          "launcher.py")),
511            apps_dir)
512         cp("-r",
513            _convert_path_for_win(os.path.join(self._basedir, "bitmask_client",
514                                               "src", "leap")),
515            apps_dir)
516         lib_dir = _convert_path_for_win(platform_dir(self._basedir, "lib"))
517         cp(_convert_path_for_win(
518             os.path.join(self._basedir,
519                          "leap_pycommon",
520                          "src", "leap", "common", "cacert.pem")),
521            _convert_path_for_win(os.path.join(lib_dir, "leap", "common")))
522         cp(_convert_path_for_win(glob(os.path.join(self._basedir,
523                                                    "bitmask_client", "build",
524                                                    "lib*", "leap", "bitmask",
525                                                    "_version.py"))[0]),
526            os.path.join(apps_dir, "leap", "bitmask"))
527
528         cp(_convert_path_for_win(
529             os.path.join(self._basedir,
530                          "bitmask_client", "relnotes.txt")),
531            _convert_path_for_win(os.path.join(self._basedir, "Bitmask")))
532         with open(os.path.join(self._basedir, "Bitmask", "launcher.conf"), "w") as f:
533             f.write(self.TUF_CONFIG)
534         mkdir("-p", os.path.join(self._basedir, "Bitmask", "repo", "metadata", "current"))
535         mkdir("-p", os.path.join(self._basedir, "Bitmask", "repo", "metadata", "previous"))
536         cp(os.path.join(binary_path, "root.json"),
537            os.path.join(self._basedir, "Bitmask", "repo", "metadata", "current"))
538         print "Done"
539
540
541 class FixDylibs(Action):
542     def __init__(self, basedir, skip, do):
543         Action.__init__(self, "fixdylibs", basedir, skip, do)
544
545     @skippable
546     def run(self):
547         fix_all_dylibs(platform_dir(self._basedir))
548
549
550 class DmgIt(Action):
551     def __init__(self, basedir, skip, do):
552         Action.__init__(self, "dmgit", basedir, skip, do)
553
554     @skippable
555     def run(self, repos, nightly):
556         print "Dmg'ing it..."
557         cd(self._basedir)
558         version = get_version(repos, nightly)
559         dmg_dir = os.path.join(self._basedir, "dmg")
560         template_dir = os.path.join(self._basedir, "Bitmask")
561         mkdir("-p", dmg_dir)
562         cp("-R", os.path.join(template_dir, "Applications"), dmg_dir)
563         cp("-R", os.path.join(template_dir, "relnotes.txt"), dmg_dir)
564         cp("-R", os.path.join(template_dir, "Bitmask.app"), dmg_dir)
565         cp(os.path.join(self._basedir,
566                         "leap_assets",
567                         "mac", "bitmask.icns"),
568            os.path.join(dmg_dir, ".VolumeIcon.icns"))
569         SetFile("-c", "icnC", os.path.join(dmg_dir, ".VolumeIcon.icns"))
570
571         vol_name = "Bitmask"
572         dmg_name = "Bitmask-OSX-{0}.dmg".format(version)
573         raw_dmg_path = os.path.join(self._basedir, "raw-{0}".format(dmg_name))
574         dmg_path = os.path.join(self._basedir, dmg_name)
575
576         hdiutil("create", "-srcfolder", dmg_dir, "-volname", vol_name,
577                 "-fsargs", "-c c=64,a=16,e=16", "-fs", "HFS+",
578                 "-format", "UDRW", "-ov", "-size", "500000k",
579                 raw_dmg_path)
580         rm("-rf", dmg_dir)
581         mkdir(dmg_dir)
582         hdiutil("attach", raw_dmg_path, "-mountpoint", dmg_dir)
583         SetFile("-a", "C", dmg_dir)
584         hdiutil("detach", dmg_dir)
585
586         rm("-rf", dmg_dir)
587         hdiutil("convert", raw_dmg_path, "-format", "UDZO",
588                 "-imagekey", "zlib-level=9", "-o",
589                 dmg_path)
590         rm("-f", raw_dmg_path)
591         print "Done"
592
593
594 class TarballIt(Action):
595     def __init__(self, basedir, skip, do):
596         Action.__init__(self, "tarballit", basedir, skip, do)
597
598     @skippable
599     def run(self, repos, nightly):
600         print "Tarballing it..."
601         cd(self._basedir)
602         version = get_version(repos, nightly)
603         import platform
604         bits = platform.architecture()[0][:2]
605         bundle_name = "Bitmask-linux%s-%s" % (bits, version)
606         mv("Bitmask", bundle_name)
607         tar("cjf", bundle_name+".tar.bz2", bundle_name)
608         print "Done"
609
610
611 class PycRemover(Action):
612     def __init__(self, basedir, skip, do):
613         Action.__init__(self, "removepyc", basedir, skip, do)
614
615     @skippable
616     def run(self):
617         print "Removing .pyc files..."
618         files = find(self._basedir, "-name", "*.pyc").strip().splitlines()
619         for f in files:
620             rm(f)
621         files = find(self._basedir, "-name", "*\\.so*").strip().splitlines()
622         for f in files:
623             print "Stripping", f
624             try:
625                 strip(f)
626             except:
627                 pass
628         print "Done"
629
630
631 class MtEmAll(Action):
632     def __init__(self, basedir, skip, do):
633         Action.__init__(self, "mtemall", basedir, skip, do)
634
635     @skippable
636     def run(self):
637         print "Mt'ing all the files..."
638         cd(os.path.join(self._basedir, "Bitmask"))
639         subprocess.check_call(
640             ["C:\\Program Files\\Windows Kits\\8.0\\bin\\x86\\mt.exe",
641              "-nologo", "-manifest", "Microsoft.VC90.CRT.manifest",
642              "-outputresource:bitmask.exe;#1"])
643         cd(os.path.join("apps", "eip"))
644         subprocess.check_call(
645             ["C:\\Program Files\\Windows Kits\\8.0\\bin\\x86\\mt.exe",
646              "-nologo", "-manifest", "openvpn_leap.exe.manifest",
647              "-outputresource:openvpn_leap.exe;#1"])
648         print "Done"
649
650
651 class ZipIt(Action):
652     def __init__(self, basedir, skip, do):
653         Action.__init__(self, "zipit", basedir, skip, do)
654
655     def _zipdir(self, path, zf):
656         for root, dirs, files in os.walk(path):
657             for f in files:
658                 zf.write(os.path.join(root, f))
659
660     @skippable
661     def run(self, repos, nightly):
662         print "Ziping it..."
663         cd(self._basedir)
664         version = get_version(repos, nightly)
665         name = "Bitmask-win32-{0}".format(version)
666         mv(_convert_path_for_win(os.path.join(self._basedir, "Bitmask")),
667            _convert_path_for_win(os.path.join(self._basedir, name)))
668         zf = zipfile.ZipFile("{0}.zip".format(name), "w", zipfile.ZIP_DEFLATED)
669         self._zipdir(name, zf)
670         zf.close()
671         print "Done"
672
673
674 class SignIt(Action):
675     def __init__(self, basedir, skip, do):
676         Action.__init__(self, "signit", basedir, skip, do)
677
678     @skippable
679     def run(self, identity):
680         print "Signing tuntap kext..."
681         kext = os.path.join(self._basedir,
682                             "Bitmask",
683                             "Bitmask.app",
684                             "Contents",
685                             "Resources",
686                             "tuntap-installer.app",
687                             "Contents",
688                             "Extensions",
689                             "tun.kext")
690         codesign("-s", identity, "--deep", kext)
691         print "Done"
692         print "Signing tuntap installer..."
693         tuntap_app = os.path.join(self._basedir,
694                                   "Bitmask",
695                                   "Bitmask.app",
696                                   "Contents",
697                                   "Resources",
698                                   "tuntap-installer.app")
699         codesign("-s", identity, "--deep", tuntap_app)
700         print "Done"
701         print "Signing main structure, this will take a while..."
702         main_app = os.path.join(self._basedir,
703                                 "Bitmask",
704                                 "Bitmask.app")
705         print codesign("-s", identity, "--force", "--deep", "--verbose", main_app)
706         print "Done"
707
708
709
710 class RemoveUnused(Action):
711     def __init__(self, basedir, skip, do):
712         Action.__init__(self, "rmunused", basedir, skip, do)
713
714     @skippable
715     def run(self):
716         print "Removing unused python code..."
717         test_dirs = find(self._basedir, "-name", "*test*").strip().splitlines()
718         for td in test_dirs:
719             rm("-rf", os.path.join(self._basedir, td))
720
721         twisted_used = ["aplication", "conch", "cred", "version", "internet", "mail"]
722         # twisted_files = find(self._basedir, "-name", "t
723         print "Done"
724