[tor-commits] [tor-browser-build/master] Bug 22499: build obfsproxy and fteproxy for Windows

boklm at torproject.org boklm at torproject.org
Thu Aug 3 16:58:29 UTC 2017


commit 6221fac747287361a0e4432c3ebf6590461bbbcf
Author: Nicolas Vigier <boklm at torproject.org>
Date:   Thu Aug 3 17:56:39 2017 +0200

    Bug 22499: build obfsproxy and fteproxy for Windows
    
    Also finish including the Linux build of obfsproxy and fteproxy.
    
    Based on gitian/descriptors/windows/gitian-pluggable-transports.yml
    from tor-browser-bundle.git.
---
 keyring/winpython.gpg                        | Bin 0 -> 1167 bytes
 projects/argparse/build                      |  20 +++++++---
 projects/argparse/config                     |   7 ++++
 projects/fteproxy/build                      |  21 +++++++++-
 projects/fteproxy/config                     |   9 +++++
 projects/libfte/build                        |  23 +++++++++--
 projects/libfte/config                       |   8 ++++
 projects/obfsproxy/build                     |  32 ++++++++++++++--
 projects/obfsproxy/config                    |  25 +++++++++++-
 projects/parsley/build                       |  21 +++++++---
 projects/parsley/config                      |   7 ++++
 projects/pycrypto/build                      |  29 +++++++++++---
 projects/pycrypto/config                     |   7 ++++
 projects/pyptlib/build                       |  21 +++++++---
 projects/pyptlib/config                      |   7 ++++
 projects/pyyaml/build                        |  21 +++++++---
 projects/pyyaml/config                       |   7 ++++
 projects/tor-browser/build                   |   4 ++
 projects/tor-browser/config                  |   3 ++
 projects/twisted/build                       |  32 +++++++++++++---
 projects/twisted/config                      |  10 +++++
 projects/txsocksx/build                      |  21 +++++++---
 projects/txsocksx/config                     |   7 ++++
 projects/winpython/build                     |  36 ++++++++++++++++++
 projects/winpython/config                    |  55 +++++++++++++++++++++++++++
 projects/winpython/pyc-timestamp.sh          |  18 +++++++++
 projects/winpython/wine-wrappers/common.py   |  27 +++++++++++++
 projects/winpython/wine-wrappers/dllwrap.py  |  36 ++++++++++++++++++
 projects/winpython/wine-wrappers/g++.py      |  39 +++++++++++++++++++
 projects/winpython/wine-wrappers/gcc.py      |  36 ++++++++++++++++++
 projects/winpython/wine-wrappers/settings.py |   2 +
 projects/winpython/wine-wrappers/setup.py    |   7 ++++
 projects/zope.interface/build                |  27 ++++++++++---
 projects/zope.interface/config               |   9 +++++
 rbm.conf                                     |  29 ++++++++++++++
 35 files changed, 612 insertions(+), 51 deletions(-)

diff --git a/keyring/winpython.gpg b/keyring/winpython.gpg
new file mode 100644
index 0000000..97abdc1
Binary files /dev/null and b/keyring/winpython.gpg differ
diff --git a/projects/argparse/build b/projects/argparse/build
index 938c5e9..29e4221 100644
--- a/projects/argparse/build
+++ b/projects/argparse/build
@@ -1,14 +1,24 @@
 #!/bin/bash
 [% c("var/set_default_env") -%]
 distdir="/var/tmp/dist/[% project %]"
-[% c("var/set_PTDIR_DOCSDIR") -%]
-mkdir -p $PTDIR
+[% IF c("var/windows") -%]
+  [% pc(c('var/compiler'), 'var/setup', { compiler_tarfile => c('input_files_by_name/' _ c('var/compiler')) }) %]
+[% ELSE -%]
+  [% c("var/set_PTDIR_DOCSDIR") -%]
+  mkdir -p $PTDIR
+[% END -%]
 mkdir -p /var/tmp/build
 tar -C /var/tmp/build -xf $rootdir/[% project %]-[% c('version') %].tar.gz
 cd /var/tmp/build/[% project %]-[% c('version') %]
-export PYTHON=python2
-$PYTHON setup.py build --build-lib build
-cp -a build/argparse.py $PTDIR/
+[% IF c("var/windows") -%]
+  pydir="$distdir/python"
+  mkdir -p $pydir/Lib/site-packages
+  export PYTHONPATH="$(winepath -w $pydir)\\Lib\\site-packages"
+  $PYTHON setup.py install --prefix=$(winepath -w $pydir)
+[% ELSE -%]
+  python2 setup.py build --build-lib build
+  cp -a build/argparse.py $PTDIR/
+[% END -%]
 cd $distdir
 [% c('tar', {
         tar_src => [ '.' ],
diff --git a/projects/argparse/config b/projects/argparse/config
index 87f80b0..c4d9dec 100644
--- a/projects/argparse/config
+++ b/projects/argparse/config
@@ -12,8 +12,15 @@ targets:
       arch_deps:
         - python-setuptools
         - python-dev
+  windows-i686:
+    var:
+      compiler: winpython
+      post_pkginst: '[% c("var/install_wine_ppa") %]'
 
 input_files:
   - project: container-image
   - URL: 'https://pypi.python.org/packages/source/a/argparse/argparse-[% c("version") %].tar.gz'
     sha256sum: ddaf4b0a618335a32b6664d4ae038a1de8fbada3b25033f9021510ed2b3941a4
+  - name: '[% c("var/compiler") %]'
+    project: '[% c("var/compiler") %]'
+    enable: '[% c("var/windows") %]'
diff --git a/projects/fteproxy/build b/projects/fteproxy/build
index b33c3a5..0d9baf1 100644
--- a/projects/fteproxy/build
+++ b/projects/fteproxy/build
@@ -3,11 +3,28 @@
 distdir="/var/tmp/dist/[% project %]"
 [% c("var/set_PTDIR_DOCSDIR") -%]
 mkdir -p $PTDIR $DOCSDIR
+[% IF c("var/windows") -%]
+  [% pc(c('var/compiler'), 'var/setup', { compiler_tarfile => c('input_files_by_name/' _ c('var/compiler')) }) %]
+[% END -%]
+tar -C $distdir -xf $rootdir/[% c('input_files_by_name/libfte') %]
 mkdir -p /var/tmp/build
 tar -C /var/tmp/build -xf $rootdir/[% project %]-[% c('version') %].tar.gz
 cd /var/tmp/build/[% project %]-[% c('version') %]
-cp -a bin/fteproxy $PTDIR/fteproxy.bin
-cp -ra fteproxy $PTDIR/
+[% IF c("var/windows") -%]
+  pydir="$distdir/python"
+  export PYTHONPATH="$(winepath -w $pydir)\\Lib\\site-packages"
+  $PYTHON setup_tbb.py py2exe
+  py2exe_zip_timestomp dist/fteproxy.zip
+  cp -an dist/{*.pyd,*.exe,*.zip} $PTDIR/
+  mkdir -p $PTDIR/fteproxy
+  cp -a fteproxy/VERSION $PTDIR/fteproxy
+  mkdir -p $PTDIR/fteproxy/defs
+  cp -a fteproxy/defs/*.json $PTDIR/fteproxy/defs
+  rm -Rf $pydir
+[% ELSE -%]
+  cp -a bin/fteproxy $PTDIR/fteproxy.bin
+  cp -ra fteproxy $PTDIR/
+[% END -%]
 cp -a {COPYING,README.md} $DOCSDIR/
 cd $distdir
 [% c('tar', {
diff --git a/projects/fteproxy/config b/projects/fteproxy/config
index 059381b..6a13e0d 100644
--- a/projects/fteproxy/config
+++ b/projects/fteproxy/config
@@ -15,6 +15,15 @@ targets:
       arch_deps:
         - python-setuptools
         - python-dev
+  windows-i686:
+    var:
+      compiler: winpython
+      post_pkginst: '[% c("var/install_wine_ppa") %]'
 
 input_files:
   - project: container-image
+  - project: libfte
+    name: libfte
+  - name: '[% c("var/compiler") %]'
+    project: '[% c("var/compiler") %]'
+    enable: '[% c("var/windows") %]'
diff --git a/projects/libfte/build b/projects/libfte/build
index fc7b9f6..62c8fce 100644
--- a/projects/libfte/build
+++ b/projects/libfte/build
@@ -10,9 +10,26 @@ tar -C /var/tmp/build -xf $rootdir/[% project %]-[% c('version') %].tar.gz
 cd /var/tmp/build/[% project %]-[% c('version') %]
 tar -C /var/tmp/dist -xf $rootdir/[% c('input_files_by_name/gmp') %]
 ln -s /var/tmp/dist/gmp thirdparty/gmp
-export PYTHON=python2
-make
-cp -ra fte $PTDIR/
+mkdir -p $distdir
+tar -C $distdir -xf $rootdir/[% c('input_files_by_name/obfsproxy') %]
+[% IF c("var/windows") -%]
+  pydir=$distdir/python
+  export FAKETIME="[% USE date; GET date.format(c('timestamp'), format = '%Y-%m-%d %H:%M:%S') %]"
+  export LD_PRELOAD=
+  export PYTHONPATH="$(winepath -w $pydir)\\Lib\\site-packages"
+  # FTE only needs libgmp-10.dll and no libgmpxx anymore.
+  cp -a /var/tmp/dist/gmp/bin/libgmp-10.dll .
+  cp -a /var/tmp/dist/gmp/bin/libgmp-10.dll $distdir/TorBrowser/Tor/
+  WINDOWS_BUILD=1 CROSS_COMPILE=1 make
+  $PYTHON setup.py install --prefix=$(winepath -w "$pydir")
+  $PYTHON setup.py install
+[% ELSE -%]
+  export PYTHON=python2
+  make
+  cp -ra fte $PTDIR/
+  mkdir -p $distdir/TorBrowser/Tor
+  cp /var/tmp/dist/gmp/lib/libgmp.so.10 $distdir/TorBrowser/Tor/
+[% END -%]
 cp -a {LICENSE,README.md} $DOCSDIR/
 cp -a thirdparty/re2/LICENSE $DOCSDIR/LICENSE.re2
 cd $distdir
diff --git a/projects/libfte/config b/projects/libfte/config
index e2219a7..4c34116 100644
--- a/projects/libfte/config
+++ b/projects/libfte/config
@@ -14,6 +14,12 @@ targets:
       arch_deps:
         - python-setuptools
         - python-dev
+  windows-i686:
+    var:
+      compiler: winpython
+      post_pkginst: '[% c("var/install_wine_ppa") %]'
+      arch_deps:
+        - faketime
 
 input_files:
   - project: container-image
@@ -21,3 +27,5 @@ input_files:
     project: '[% c("var/compiler") %]'
   - project: gmp
     name: gmp
+  - project: obfsproxy
+    name: obfsproxy
diff --git a/projects/obfsproxy/build b/projects/obfsproxy/build
index 841c608..9d64aa9 100644
--- a/projects/obfsproxy/build
+++ b/projects/obfsproxy/build
@@ -3,13 +3,37 @@
 distdir="/var/tmp/dist/[% project %]"
 [% c("var/set_PTDIR_DOCSDIR") -%]
 mkdir -p $PTDIR $DOCSDIR
+[% IF c("var/windows") -%]
+  [% pc(c('var/compiler'), 'var/setup', { compiler_tarfile => c('input_files_by_name/' _ c('var/compiler')) }) %]
+[% ELSE -%]
+[% END -%]
+mkdir -p $distdir
+tar -C $distdir -xf $rootdir/[% c('input_files_by_name/pycrypto') %]
+tar -C $distdir -xf $rootdir/[% c('input_files_by_name/twisted') %]
+tar -C $distdir -xf $rootdir/[% c('input_files_by_name/argparse') %]
+tar -C $distdir -xf $rootdir/[% c('input_files_by_name/parsley') %]
+tar -C $distdir -xf $rootdir/[% c('input_files_by_name/pyptlib') %]
+tar -C $distdir -xf $rootdir/[% c('input_files_by_name/pyyaml') %]
+tar -C $distdir -xf $rootdir/[% c('input_files_by_name/txsocksx') %]
+tar -C $distdir -xf $rootdir/[% c('input_files_by_name/zope.interface') %]
 mkdir -p /var/tmp/build
 tar -C /var/tmp/build -xf $rootdir/[% project %]-[% c('version') %].tar.gz
 cd /var/tmp/build/[% project %]-[% c('version') %]
-export PYTHON=python2
-$PYTHON setup.py build --build-lib build
-cp -a build/obfsproxy $PTDIR/
-cp -a bin/obfsproxy $PTDIR/obfsproxy.bin
+[% IF c("var/windows") -%]
+  pydir="$distdir/python"
+  export PYTHONPATH="$(winepath -w $pydir)\\Lib\\site-packages"
+  $PYTHON setup_py2exe.py py2exe
+  $PYTHON setup.py install --prefix=$(winepath -w $pydir)
+  py2exe_zip_timestomp py2exe_bundle/dist/obfsproxy.zip
+  cp -an py2exe_bundle/dist/{*.pyd,*.exe,*.zip} $PTDIR/
+  # http://bugs.winehq.org/show_bug.cgi?id=3591
+  cp -a /var/tmp/dist/winpython/python27.dll $PTDIR
+[% ELSE -%]
+  export PYTHON=python2
+  $PYTHON setup.py build --build-lib build
+  cp -a build/obfsproxy $PTDIR/
+  cp -a bin/obfsproxy $PTDIR/obfsproxy.bin
+[% END -%]
 cp -a {LICENSE,README} $DOCSDIR
 cd $distdir
 [% c('tar', {
diff --git a/projects/obfsproxy/config b/projects/obfsproxy/config
index ad436dd..9134de1 100644
--- a/projects/obfsproxy/config
+++ b/projects/obfsproxy/config
@@ -7,7 +7,7 @@ gpg_keyring: obfsproxy.gpg
 filename: '[% project %]-[% c("version") %]-[% c("var/osname") %]-[% c("var/build_id") %].tar.gz'
 
 var:
-  DOCSDIR_project: Obsfproxy
+  DOCSDIR_project: Obfsproxy
   container:
     use_container: 1
 
@@ -17,6 +17,29 @@ targets:
       arch_deps:
         - python-setuptools
         - python-dev
+  windows-i686:
+    var:
+      compiler: winpython
+      post_pkginst: '[% c("var/install_wine_ppa") %]'
 
 input_files:
   - project: container-image
+  - project: pycrypto
+    name: pycrypto
+  - project: twisted
+    name: twisted
+  - project: argparse
+    name: argparse
+  - project: parsley
+    name: parsley
+  - project: pyptlib
+    name: pyptlib
+  - project: pyyaml
+    name: pyyaml
+  - project: txsocksx
+    name: txsocksx
+  - project: zope.interface
+    name: zope.interface
+  - name: '[% c("var/compiler") %]'
+    project: '[% c("var/compiler") %]'
+    enable: '[% c("var/windows") %]'
diff --git a/projects/parsley/build b/projects/parsley/build
index ea5f19a..1d52f9a 100644
--- a/projects/parsley/build
+++ b/projects/parsley/build
@@ -1,14 +1,25 @@
 #!/bin/bash
 [% c("var/set_default_env") -%]
 distdir="/var/tmp/dist/[% project %]"
-[% c("var/set_PTDIR_DOCSDIR") -%]
-mkdir -p $PTDIR
+[% IF c("var/windows") -%]
+  [% pc(c('var/compiler'), 'var/setup', { compiler_tarfile => c('input_files_by_name/' _ c('var/compiler')) }) %]
+[% ELSE -%]
+  [% c("var/set_PTDIR_DOCSDIR") -%]
+  mkdir -p $PTDIR
+[% END -%]
 mkdir -p /var/tmp/build
 tar -C /var/tmp/build -xf $rootdir/Parsley-[% c('version') %].tar.gz
 cd /var/tmp/build/Parsley-[% c('version') %]
-export PYTHON=python2
-$PYTHON setup.py build --build-lib build
-cp -a build/parsley.py build/ometa build/terml $PTDIR/
+[% IF c("var/windows") -%]
+  pydir="$distdir/python"
+  mkdir -p $pydir/Lib/site-packages
+  export PYTHONPATH="$(winepath -w $pydir)\\Lib\\site-packages"
+  $PYTHON setup.py install --prefix=$(winepath -w $pydir)
+[% ELSE -%]
+  PYTHON=python2
+  $PYTHON setup.py build --build-lib build
+  cp -a build/parsley.py build/ometa build/terml $PTDIR/
+[% END -%]
 cd $distdir
 [% c('tar', {
         tar_src => [ '.' ],
diff --git a/projects/parsley/config b/projects/parsley/config
index 72d5bfc..b788899 100644
--- a/projects/parsley/config
+++ b/projects/parsley/config
@@ -12,8 +12,15 @@ targets:
       arch_deps:
         - python-setuptools
         - python-dev
+  windows-i686:
+    var:
+      compiler: winpython
+      post_pkginst: '[% c("var/install_wine_ppa") %]'
 
 input_files:
   - project: container-image
   - URL: 'https://pypi.python.org/packages/source/P/Parsley/Parsley-[% c("version") %].tar.gz'
     sha256sum: 50d30cee70770fd44db7cea421cb2fb75af247c3a1cd54885c06b30a7c85dd23
+  - name: '[% c("var/compiler") %]'
+    project: '[% c("var/compiler") %]'
+    enable: '[% c("var/windows") %]'
diff --git a/projects/pycrypto/build b/projects/pycrypto/build
index 9b005ab..51ec5ce 100644
--- a/projects/pycrypto/build
+++ b/projects/pycrypto/build
@@ -1,22 +1,39 @@
 #!/bin/bash
+set -e
 [% c("var/set_default_env") -%]
 [% c("var/setarch") -%]
 [% pc(c('var/compiler'), 'var/setup', { compiler_tarfile => c('input_files_by_name/' _ c('var/compiler')) }) %]
 distdir="/var/tmp/dist/[% project %]"
-[% c("var/set_PTDIR_DOCSDIR") -%]
-mkdir -p $PTDIR
+[% IF c("var/linux") -%]
+  [% c("var/set_PTDIR_DOCSDIR") -%]
+  mkdir -p $PTDIR
+[% END -%]
 mkdir -p /var/tmp/build
 tar -C /var/tmp/build -xf $rootdir/[% project %]-[% c('version') %].tar.gz
 cd /var/tmp/build/[% project %]-[% c('version') %]
-export PYTHON=python2
 [% IF c("var/linux-i686") -%]
   export CFLAGS=-m32
   export CXXFLAGS=-m32
   export LDFLAGS=-m32
 [% END -%]
-./configure --build=i686-linux-gnu [% c("var/configure_opt") %]
-$PYTHON setup.py build --build-lib build
-cp -a build/Crypto $PTDIR/
+[% IF c("var/windows") -%]
+  pydir="$distdir/python"
+  mkdir -p "$pydir"
+  export FAKETIME="[% USE date; GET date.format(c('timestamp'), format = '%Y-%m-%d %H:%M:%S') %]"
+  export LD_PRELOAD=[% c("var/faketime_path") %]
+  # This is bogus, that we run the configure script in the build environment,
+  # but it seems to work. https://bugs.launchpad.net/pycrypto/+bug/1096207 for
+  # ac_cv_func_malloc_0_nonnull.
+  ac_cv_func_malloc_0_nonnull=yes sh configure --host=i686-w64-mingw32
+  export LD_PRELOAD=
+  $PYTHON setup.py build_ext -c mingw32
+  $PYTHON setup.py install --prefix=$(winepath -w $pydir)
+[% ELSE -%]
+  export PYTHON=python2
+  ./configure --build=i686-linux-gnu [% c("var/configure_opt") %]
+  python2 setup.py build --build-lib build
+  cp -a build/Crypto $PTDIR/
+[% END -%]
 cd $distdir
 [% c('tar', {
         tar_src => [ '.' ],
diff --git a/projects/pycrypto/config b/projects/pycrypto/config
index 3a9f24b..ca314c8 100644
--- a/projects/pycrypto/config
+++ b/projects/pycrypto/config
@@ -12,6 +12,13 @@ targets:
         - python-dev
         - python-setuptools
 
+  windows-i686:
+    var:
+      compiler: winpython
+      post_pkginst: '[% c("var/install_wine_ppa") %]'
+      arch_deps:
+        - faketime
+
 input_files:
   - project: container-image
   - name: '[% c("var/compiler") %]'
diff --git a/projects/pyptlib/build b/projects/pyptlib/build
index 1dc0c07..de70c5b 100644
--- a/projects/pyptlib/build
+++ b/projects/pyptlib/build
@@ -1,14 +1,25 @@
 #!/bin/bash
 [% c("var/set_default_env") -%]
 distdir="/var/tmp/dist/[% project %]"
-[% c("var/set_PTDIR_DOCSDIR") -%]
-mkdir -p $PTDIR
+[% IF c("var/linux") -%]
+  [% c("var/set_PTDIR_DOCSDIR") -%]
+  mkdir -p $PTDIR
+[% END -%]
+[% IF c("var/windows") -%]
+  [% pc(c('var/compiler'), 'var/setup', { compiler_tarfile => c('input_files_by_name/' _ c('var/compiler')) }) %]
+[% END -%]
 mkdir -p /var/tmp/build
 tar -C /var/tmp/build -xf $rootdir/[% project %]-[% c('version') %].tar.gz
 cd /var/tmp/build/[% project %]-[% c('version') %]
-export PYTHON=python2
-$PYTHON setup.py build --build-lib build
-cp -a build/pyptlib $PTDIR/
+[% IF c("var/windows") -%]
+  pydir="$distdir/python"
+  mkdir -p "$pydir"
+  $PYTHON setup.py install --single-version-externally-managed --record /dev/null --prefix=$(winepath -w $pydir)
+[% ELSE -%]
+  export PYTHON=python2
+  $PYTHON setup.py build --build-lib build
+  cp -a build/pyptlib $PTDIR/
+[% END -%]
 cd $distdir
 [% c('tar', {
         tar_src => [ '.' ],
diff --git a/projects/pyptlib/config b/projects/pyptlib/config
index e8ca100..7ae1d68 100644
--- a/projects/pyptlib/config
+++ b/projects/pyptlib/config
@@ -16,6 +16,13 @@ targets:
       arch_deps:
         - python-setuptools
         - python-dev
+  windows-i686:
+    var:
+      compiler: winpython
+      post_pkginst: '[% c("var/install_wine_ppa") %]'
 
 input_files:
   - project: container-image
+  - name: '[% c("var/compiler") %]'
+    project: '[% c("var/compiler") %]'
+    enable: '[% c("var/windows") %]'
diff --git a/projects/pyyaml/build b/projects/pyyaml/build
index c10855c..d3d60d7 100644
--- a/projects/pyyaml/build
+++ b/projects/pyyaml/build
@@ -1,14 +1,25 @@
 #!/bin/bash
 [% c("var/set_default_env") -%]
 distdir="/var/tmp/dist/[% project %]"
-[% c("var/set_PTDIR_DOCSDIR") -%]
-mkdir -p $PTDIR
+[% IF c("var/windows") -%]
+  [% pc(c('var/compiler'), 'var/setup', { compiler_tarfile => c('input_files_by_name/' _ c('var/compiler')) }) %]
+[% ELSE -%]
+  [% c("var/set_PTDIR_DOCSDIR") -%]
+  mkdir -p $PTDIR
+[% END -%]
 mkdir -p /var/tmp/build
 tar -C /var/tmp/build -xf $rootdir/PyYAML-[% c('version') %].tar.gz
 cd /var/tmp/build/PyYAML-[% c('version') %]
-export PYTHON=python2
-$PYTHON setup.py build --build-lib build
-cp -a build/yaml $PTDIR/
+[% IF c("var/windows") -%]
+  pydir="$distdir/python"
+  mkdir -p $pydir/Lib/site-packages
+  export PYTHONPATH="$(winepath -w $pydir)\\Lib\\site-packages"
+  $PYTHON setup.py install --prefix=$(winepath -w $pydir)
+[% ELSE -%]
+  export PYTHON=python2
+  $PYTHON setup.py build --build-lib build
+  cp -a build/yaml $PTDIR/
+[% END -%]
 cd $distdir
 [% c('tar', {
         tar_src => [ '.' ],
diff --git a/projects/pyyaml/config b/projects/pyyaml/config
index 5324c10..8d43bf6 100644
--- a/projects/pyyaml/config
+++ b/projects/pyyaml/config
@@ -12,8 +12,15 @@ targets:
       arch_deps:
         - python-setuptools
         - python-dev
+  windows-i686:
+    var:
+      compiler: winpython
+      post_pkginst: '[% c("var/install_wine_ppa") %]'
 
 input_files:
   - project: container-image
   - URL: 'https://pypi.python.org/packages/source/P/PyYAML/PyYAML-[% c("version") %].tar.gz'
     sha256sum: c36c938a872e5ff494938b33b14aaa156cb439ec67548fcab3535bb78b0846e8
+  - name: '[% c("var/compiler") %]'
+    project: '[% c("var/compiler") %]'
+    enable: '[% c("var/windows") %]'
diff --git a/projects/tor-browser/build b/projects/tor-browser/build
index b9537a3..77a02ea 100644
--- a/projects/tor-browser/build
+++ b/projects/tor-browser/build
@@ -56,6 +56,10 @@ mv $TBDIR/meek-http-helper at bamsoftware.com.xpi $TBDIR/$MEEKPROFILEPATH/extension
   tar -C $TBDIR -xf [% c('input_files_by_name/snowflake') -%]
 [% END -%]
 
+[% IF c("var/fteproxy") -%]
+  tar -C $TBDIR -xf [% c('input_files_by_name/fteproxy') %]
+[% END -%]
+
 tar -C $TBDIR[% IF c("var/osx") %]/Contents/Resources[% END %] -xf [% c('input_files_by_name/fonts') %]
 
 [% IF c("var/linux") %]
diff --git a/projects/tor-browser/config b/projects/tor-browser/config
index fef279b..4f708bc 100644
--- a/projects/tor-browser/config
+++ b/projects/tor-browser/config
@@ -50,6 +50,9 @@ input_files:
     name: meek
   - project: obfs4
     name: obfs4
+  - project: fteproxy
+    name: fteproxy
+    enable: '[% c("var/fteproxy") %]'
   - project: snowflake
     name: snowflake
     enable: '[% c("var/snowflake") %]'
diff --git a/projects/twisted/build b/projects/twisted/build
index acc5c9d..0d9154f 100644
--- a/projects/twisted/build
+++ b/projects/twisted/build
@@ -1,14 +1,36 @@
 #!/bin/bash
 [% c("var/set_default_env") -%]
 distdir="/var/tmp/dist/[% project %]"
-[% c("var/set_PTDIR_DOCSDIR") -%]
-mkdir -p $PTDIR
+[% IF c("var/windows") -%]
+  [% pc(c('var/compiler'), 'var/setup', { compiler_tarfile => c('input_files_by_name/' _ c('var/compiler')) }) %]
+[% ELSE -%]
+  [% c("var/set_PTDIR_DOCSDIR") -%]
+  mkdir -p $PTDIR
+[% END -%]
 mkdir -p /var/tmp/build
 tar -C /var/tmp/build -xf $rootdir/Twisted-[% c('version') %].tar.bz2
 cd /var/tmp/build/Twisted-[% c('version') %]
-export PYTHON=python2
-$PYTHON setup.py build --build-lib build
-cp -a build/twisted $PTDIR/
+[% IF c("var/windows") -%]
+  pydir="$distdir/python"
+  export FAKETIME="[% USE date; GET date.format(c('timestamp'), format = '%Y-%m-%d %H:%M:%S') %]"
+  export LD_PRELOAD=[% c("var/faketime_path") %]
+  # twisted/internet/iocpreactor/iocpsupport/iocpsupport.c includes "python.h"
+  # rather than "Python.h".
+  ln -sf Python.h /var/tmp/dist/winpython/include/python.h
+  # We need to set the "mingw32" compiler to avoid an error in build_ext, but
+  # Twisted's "install" command calls build_ext unconditionally, whether the
+  # extensions have been built already or not, so we can't just call build_ext
+  # separately as with other packages. The "install" command doesn't recognize
+  # the -c option, so we set the compiler in a configuration file.
+  echo $'[build_ext]\ncompiler=mingw32' > setup.cfg
+  mkdir -p $pydir/Lib/site-packages
+  export PYTHONPATH="$(winepath -w $pydir)\\Lib\\site-packages"
+  LD_PRELOAD= $PYTHON setup.py install --single-version-externally-managed --record /dev/null --prefix=$(winepath -w $pydir)
+[% ELSE -%]
+  export PYTHON=python2
+  $PYTHON setup.py build --build-lib build
+  cp -a build/twisted $PTDIR/
+[% END -%]
 cd $distdir
 [% c('tar', {
         tar_src => [ '.' ],
diff --git a/projects/twisted/config b/projects/twisted/config
index f2f7de8..2f35166 100644
--- a/projects/twisted/config
+++ b/projects/twisted/config
@@ -12,8 +12,18 @@ targets:
       arch_deps:
         - python-setuptools
         - python-dev
+  windows-i686:
+    var:
+      compiler: winpython
+      post_pkginst: '[% c("var/install_wine_ppa") %]'
+      arch_deps:
+        - p7zip-full
+        - faketime
 
 input_files:
   - project: container-image
   - URL: 'https://pypi.python.org/packages/source/T/Twisted/Twisted-[% c("version") %].tar.bz2'
     sha256sum: 095175638c019ac7c0604f4c291724a16ff1acd062e181b01293bf4dcbc62cf3
+  - name: '[% c("var/compiler") %]'
+    project: '[% c("var/compiler") %]'
+    enable: '[% c("var/windows") %]'
diff --git a/projects/txsocksx/build b/projects/txsocksx/build
index 3491a26..31d7b18 100644
--- a/projects/txsocksx/build
+++ b/projects/txsocksx/build
@@ -1,8 +1,12 @@
 #!/bin/bash
 [% c("var/set_default_env") -%]
 distdir="/var/tmp/dist/[% project %]"
-[% c("var/set_PTDIR_DOCSDIR") -%]
-mkdir -p $PTDIR
+[% IF c("var/windows") -%]
+  [% pc(c('var/compiler'), 'var/setup', { compiler_tarfile => c('input_files_by_name/' _ c('var/compiler')) }) %]
+[% ELSE -%]
+  [% c("var/set_PTDIR_DOCSDIR") -%]
+  mkdir -p $PTDIR
+[% END -%]
 mkdir -p /var/tmp/build
 tar -C /var/tmp/build -xf $rootdir/[% project %]-[% c('version') %].tar.gz
 cd /var/tmp/build/[% project %]-[% c('version') %]
@@ -11,9 +15,16 @@ cd /var/tmp/build/[% project %]-[% c('version') %]
 # dependency should be fine here as txsocksx catches the exception due to
 # missing __version__ and __sha__ .
 mkdir vcversioner-1.14.1.1-py2.7.egg
-export PYTHON=python2
-$PYTHON setup.py build --build-lib build
-cp -a build/txsocksx $PTDIR/
+[% IF c("var/windows") -%]
+  pydir="$distdir/python"
+  mkdir -p $pydir/Lib/site-packages
+  export PYTHONPATH="$(winepath -w $pydir)\\Lib\\site-packages"
+  $PYTHON setup.py install_lib --install-dir=$(winepath -w "$pydir/Lib/site-packages")
+[% ELSE -%]
+  export PYTHON=python2
+  $PYTHON setup.py build --build-lib build
+  cp -a build/txsocksx $PTDIR/
+[% END -%]
 cd $distdir
 [% c('tar', {
         tar_src => [ '.' ],
diff --git a/projects/txsocksx/config b/projects/txsocksx/config
index 6142943..18fc4a8 100644
--- a/projects/txsocksx/config
+++ b/projects/txsocksx/config
@@ -14,6 +14,13 @@ targets:
       arch_deps:
         - python-setuptools
         - python-dev
+  windows-i686:
+    var:
+      compiler: winpython
+      post_pkginst: '[% c("var/install_wine_ppa") %]'
 
 input_files:
   - project: container-image
+  - name: '[% c("var/compiler") %]'
+    project: '[% c("var/compiler") %]'
+    enable: '[% c("var/windows") %]'
diff --git a/projects/winpython/build b/projects/winpython/build
new file mode 100644
index 0000000..2a30acc
--- /dev/null
+++ b/projects/winpython/build
@@ -0,0 +1,36 @@
+#!/bin/bash
+set -e
+[% c("var/set_default_env") -%]
+[% pc(c('var/compiler'), 'var/setup', { compiler_tarfile => c('input_files_by_name/' _ c('var/compiler')) }) %]
+distdir="/var/tmp/dist/[% project %]"
+mkdir -p $distdir
+WINEROOT=$HOME/.wine/drive_c
+wineboot -i
+msiexec /qn /i python-[% c("version") %].msi TARGETDIR=$distdir
+sed -i 's/self.dll_libraries = get_msvcr()/pass#self.dll_libraries = get_msvcr()/g' $distdir/Lib/distutils/cygwinccompiler.py
+tar xf setuptools-*.tar.gz
+rm setuptools-*.tar.gz
+cd setuptools-*
+wine $distdir/python.exe setup.py install
+cd $rootdir
+7z x $rootdir/py2exe-*.exe
+cp -a PLATLIB/* $distdir/Lib/site-packages/
+export FAKETIME="[% USE date; GET date.format(c('timestamp'), format = '%Y-%m-%d %H:%M:%S') %]"
+export LD_PRELOAD=[% c("var/faketime_path") %]
+cd wine-wrappers
+# Push our config into wine-wrappers.
+> settings.py
+echo "LD_PRELOAD = \"$LD_PRELOAD\"" >> settings.py
+echo "FAKETIME = \"$FAKETIME\"" >> settings.py
+# Must pre-copy python27.dll into the build directory, or else py2exe can't find it.
+mkdir -p build/bdist.win32/winexe/bundle-2.7/
+cp -a $distdir/python27.dll build/bdist.win32/winexe/bundle-2.7/
+LD_PRELOAD= $distdir/python.exe setup.py py2exe
+mkdir -p $distdir/wineroot/windows/
+cp -a dist/gcc.exe dist/g++.exe dist/dllwrap.exe $distdir/wineroot/windows/
+cp $rootdir/pyc-timestamp.sh $distdir/
+cd $distdir/..
+[% c('tar', {
+        tar_src => [ project, 'mingw-w64' ],
+        tar_args => '-czf ' _ dest_dir _ '/' _ c('filename'),
+    }) %]
diff --git a/projects/winpython/config b/projects/winpython/config
new file mode 100644
index 0000000..dcd21f6
--- /dev/null
+++ b/projects/winpython/config
@@ -0,0 +1,55 @@
+# vim: filetype=yaml sw=2
+version: 2.7.5
+filename: '[% project %]-[% c("version") %]-[% c("var/build_id") %].tar.gz'
+
+var:
+  compiler: mingw-w64
+  post_pkginst: '[% c("var/install_wine_ppa") %]'
+  arch_deps:
+    - p7zip-full
+    - faketime
+  container:
+    use_container: 1
+  setup: |
+    [% pc('mingw-w64', 'var/setup') %]
+    # wine path ($HOME/.wine) gets included in some binaries, so set HOME
+    # to a fixed path.
+    export HOME=/var/tmp/home
+    mkdir -p $HOME
+    WINEROOT=$HOME/.wine/drive_c
+    wineboot -i
+    cp -a /var/tmp/dist/winpython/wineroot/windows/* $WINEROOT/windows/
+    export PYTHON="wine /var/tmp/dist/winpython/python.exe"
+
+    # Set the timestamp on every .pyc file in a zip file, and re-dzip the zip file.
+    function py2exe_zip_timestomp {
+      ZIPFILE="$1"
+      local tmpdir="$(mktemp -d)"
+      local tmpzip="$(mktemp -u)"
+      unzip -d "$tmpdir" "$ZIPFILE"
+      cd "$tmpdir"
+      find . -name '*.pyc' -print0 | xargs -0 /var/tmp/dist/winpython/pyc-timestamp.sh "2000-01-01 00:00:00"
+      [% c('zip', {
+        zip_src => [ '.' ],
+        zip_args => '$tmpzip',
+        }) %]
+      cd -
+      mv -f "$tmpzip" "$ZIPFILE"
+      rm -rf "$tmpdir"
+    }
+
+
+input_files:
+  - project: container-image
+  - URL: 'https://www.python.org/ftp/python/[% c("version") %]/python-[% c("version") %].msi'
+    file_gpg_id: 1
+    sig_ext: asc
+    gpg_keyring: winpython.gpg
+  - URL: https://pypi.python.org/packages/source/s/setuptools/setuptools-1.4.tar.gz
+    sha256sum: 75d288687066ed124311d6ca5f40ffa92a0e81adcd7fff318c6e84082713cf39
+  - URL: http://downloads.sourceforge.net/py2exe/0.6.9/py2exe-0.6.9.win32-py2.7.exe
+    sha256sum: 610a8800de3d973ed5ed4ac505ab42ad058add18a68609ac09e6cf3598ef056c
+  - name: '[% c("var/compiler") %]'
+    project: '[% c("var/compiler") %]'
+  - filename: wine-wrappers
+  - filename: pyc-timestamp.sh
diff --git a/projects/winpython/pyc-timestamp.sh b/projects/winpython/pyc-timestamp.sh
new file mode 100755
index 0000000..e092268
--- /dev/null
+++ b/projects/winpython/pyc-timestamp.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+# Usage: pyc-timestamp.sh "2001-01-01" FILENAMES...
+# Overwrite (in place) the timestamp in .pyc Python bytecode files.
+#
+# http://hg.python.org/cpython/file/2.7/Lib/py_compile.py#l123
+# http://nedbatchelder.com/blog/200804/the_structure_of_pyc_files.html
+# http://benno.id.au/blog/2013/01/15/python-determinism
+
+TIMESPEC="$1"
+shift
+
+hex=$(printf 0x%08x $(date +%s --date="$TIMESPEC"))
+# Write little-endian.
+esc=$(printf "\\\\x%02x\\\\x%02x\\\\x%02x\\\\x%02x" $(($hex&0xff)) $((($hex>>8)&0xff)) $((($hex>>16)&0xff)) $((($hex>>24)&0xff)))
+for filename in "$@"; do
+	echo $filename
+	echo -n -e "$esc" | dd of="$filename" bs=1 seek=4 conv=notrunc
+done
diff --git a/projects/winpython/wine-wrappers/common.py b/projects/winpython/wine-wrappers/common.py
new file mode 100644
index 0000000..19e994b
--- /dev/null
+++ b/projects/winpython/wine-wrappers/common.py
@@ -0,0 +1,27 @@
+import os
+import subprocess
+
+import settings
+
+def winepath(windowspath):
+    """Convert a Windows path to a Unix path."""
+    return subprocess.check_output(["winepath", "-u", windowspath])[:-1]
+
+def search_startswith(a, elems):
+    """Search for the first element of the array a that startswith any of the
+    members of elems, and return it. Return None if no match was found."""
+    for e in elems:
+        if a.startswith(e):
+            return e
+    return None
+
+def popen_faketime(*args, **kwargs):
+    """Does subprocess.Popen after setting faketime environment variables."""
+    ld_preload = os.getenv("LD_PRELOAD")
+    if ld_preload:
+        # ld.so(8): "The items of [LD_PRELOAD] can be separated by spaces or colons."
+        ld_preload += ":"
+    ld_preload += settings.LD_PRELOAD
+    os.putenv("LD_PRELOAD", ld_preload)
+    os.putenv("FAKETIME", settings.FAKETIME)
+    return subprocess.Popen(*args, **kwargs)
diff --git a/projects/winpython/wine-wrappers/dllwrap.py b/projects/winpython/wine-wrappers/dllwrap.py
new file mode 100755
index 0000000..300a3bd
--- /dev/null
+++ b/projects/winpython/wine-wrappers/dllwrap.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+# A wrapper for i686-w64-mingw32-dllwrap that removes -mno-cygwin and converts
+# Windows paths to Unix paths, so that the w64-mingw32 dllwrap can be called by
+# Python distutils.
+
+import os
+import subprocess
+import sys
+
+import common
+
+args = ["/var/tmp/dist/mingw-w64/bin/i686-w64-mingw32-dllwrap"]
+sys.argv.pop(0)
+while sys.argv:
+    a = sys.argv.pop(0)
+    if not a.startswith("-"):
+        args.append(common.winepath(a))
+        continue
+    if a == "-mno-cygwin":
+        continue
+    if a in ("-I", "-L", "-s", "--def", "--output-lib"):
+        args.append(a)
+        args.append(common.winepath(sys.argv.pop(0)))
+        continue
+    o = common.search_startswith(a, ("-I", "-L", "--def=", "--output-lib="))
+    if o is not None:
+        path = a[len(o):]
+        args.append("%s%s" % (o, common.winepath(path)))
+        continue
+    args.append(a)
+p = common.popen_faketime(args, stderr=subprocess.PIPE)
+stderr = p.stderr.read()
+sys.stderr.write(stderr)
+if " error: " in stderr:
+    sys.exit(1)
diff --git a/projects/winpython/wine-wrappers/g++.py b/projects/winpython/wine-wrappers/g++.py
new file mode 100755
index 0000000..a71c4e3
--- /dev/null
+++ b/projects/winpython/wine-wrappers/g++.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+
+# A wrapper for i686-w64-mingw32-g++ that removes -mno-cygwin and converts
+# Windows paths to Unix paths, so that the w64-mingw32 g++ can be called by
+# Python distutils.
+
+import os
+import subprocess
+import sys
+
+import common
+
+args = ["/var/tmp/dist/mingw-w64/bin/i686-w64-mingw32-g++"]
+sys.argv.pop(0)
+while sys.argv:
+    a = sys.argv.pop(0)
+    if not a.startswith("-"):
+        args.append(common.winepath(a))
+        continue
+    if a == "-mno-cygwin":
+        continue
+    if a == "--output-lib":
+        o = sys.argv.pop(0)
+        a = "-out-implib="+o
+    if a in ("-I", "-L"):
+        args.append(a)
+        args.append(common.winepath(sys.argv.pop(0)))
+        continue
+    o = common.search_startswith(a, ("-I", "-L"))
+    if o is not None:
+        path = a[len(o):]
+        args.append("%s%s" % (o, common.winepath(path)))
+        continue
+    args.append(a)
+p = common.popen_faketime(args, stderr=subprocess.PIPE)
+stderr = p.stderr.read()
+sys.stderr.write(stderr)
+if " error: " in stderr:
+    sys.exit(1)
diff --git a/projects/winpython/wine-wrappers/gcc.py b/projects/winpython/wine-wrappers/gcc.py
new file mode 100755
index 0000000..3db89b4
--- /dev/null
+++ b/projects/winpython/wine-wrappers/gcc.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+# A wrapper for i686-w64-mingw32-gcc that removes -mno-cygwin and converts
+# Windows paths to Unix paths, so that the w64-mingw32 gcc can be called by
+# Python distutils.
+
+import os
+import subprocess
+import sys
+
+import common
+
+args = ["/var/tmp/dist/mingw-w64/bin/i686-w64-mingw32-gcc"]
+sys.argv.pop(0)
+while sys.argv:
+    a = sys.argv.pop(0)
+    if not a.startswith("-"):
+        args.append(common.winepath(a))
+        continue
+    if a == "-mno-cygwin":
+        continue
+    if a in ("-I", "-L"):
+        args.append(a)
+        args.append(common.winepath(sys.argv.pop(0)))
+        continue
+    o = common.search_startswith(a, ("-I", "-L"))
+    if o is not None:
+        path = a[len(o):]
+        args.append("%s%s" % (o, common.winepath(path)))
+        continue
+    args.append(a)
+p = common.popen_faketime(args, stderr=subprocess.PIPE)
+stderr = p.stderr.read()
+sys.stderr.write(stderr)
+if " error: " in stderr:
+    sys.exit(1)
diff --git a/projects/winpython/wine-wrappers/settings.py b/projects/winpython/wine-wrappers/settings.py
new file mode 100644
index 0000000..f395433
--- /dev/null
+++ b/projects/winpython/wine-wrappers/settings.py
@@ -0,0 +1,2 @@
+LD_PRELOAD = "/usr/lib/faketime/libfaketime.so.1"
+FAKETIME = "2000-01-01 00:00:00"
diff --git a/projects/winpython/wine-wrappers/setup.py b/projects/winpython/wine-wrappers/setup.py
new file mode 100644
index 0000000..f80f2c0
--- /dev/null
+++ b/projects/winpython/wine-wrappers/setup.py
@@ -0,0 +1,7 @@
+from distutils.core import setup
+import py2exe
+setup(
+    console=["gcc.py", "g++.py", "dllwrap.py"],
+    zipfile=None,
+    options={"py2exe": {"bundle_files": 1, "compressed": True}}
+)
diff --git a/projects/zope.interface/build b/projects/zope.interface/build
index 23501a3..29406fb 100644
--- a/projects/zope.interface/build
+++ b/projects/zope.interface/build
@@ -1,14 +1,31 @@
 #!/bin/bash
 [% c("var/set_default_env") -%]
 distdir="/var/tmp/dist/[% project %]"
-[% c("var/set_PTDIR_DOCSDIR") -%]
-mkdir -p $PTDIR
+[% IF c("var/linux") -%]
+  [% c("var/set_PTDIR_DOCSDIR") -%]
+  mkdir -p $PTDIR
+[% END -%]
+[% IF c("var/windows") -%]
+  [% pc(c('var/compiler'), 'var/setup', { compiler_tarfile => c('input_files_by_name/' _ c('var/compiler')) }) %]
+[% END -%]
 mkdir -p /var/tmp/build
 unzip -d /var/tmp/build $rootdir/[% project %]-[% c('version') %].zip
 cd /var/tmp/build/[% project %]-[% c('version') %]
-export PYTHON=python2
-$PYTHON setup.py build --build-lib build
-cp -a build/zope $PTDIR/
+[% IF c("var/windows") -%]
+  find -type f -print0 | xargs -0 [% c("var/touch") %]
+  pydir="$distdir/python"
+  mkdir -p $pydir/Lib/site-packages
+  export PYTHONPATH="$(winepath -w $pydir)\\Lib\\site-packages"
+  export FAKETIME="[% USE date; GET date.format(c('timestamp'), format = '%Y-%m-%d %H:%M:%S') %]"
+  LD_PRELOAD= $PYTHON setup.py build_ext -c mingw32
+  $PYTHON setup.py install --single-version-externally-managed --record /dev/null --prefix=$(winepath -w $pydir)
+  # Must create this file in order for py2exe to find the package.
+  touch $pydir/Lib/site-packages/zope/__init__.py
+[% ELSE -%]
+  export PYTHON=python2
+  $PYTHON setup.py build --build-lib build
+  cp -a build/zope $PTDIR/
+[% END -%]
 cd $distdir
 [% c('tar', {
         tar_src => [ '.' ],
diff --git a/projects/zope.interface/config b/projects/zope.interface/config
index 9743b79..4ae3cff 100644
--- a/projects/zope.interface/config
+++ b/projects/zope.interface/config
@@ -12,8 +12,17 @@ targets:
       arch_deps:
         - python-setuptools
         - python-dev
+  windows-i686:
+    var:
+      compiler: winpython
+      post_pkginst: '[% c("var/install_wine_ppa") %]'
+      arch_deps:
+        - faketime
 
 input_files:
   - project: container-image
   - URL: 'https://pypi.python.org/packages/source/z/zope.interface/zope.interface-[% c("version") %].zip'
     sha256sum: 1a7c84716bbd9981915b64a81d8a3f076a5934a8c8df4224655469b3564940cc
+  - name: '[% c("var/compiler") %]'
+    project: '[% c("var/compiler") %]'
+    enable: '[% c("var/windows") %]'
diff --git a/rbm.conf b/rbm.conf
index ae8c5b2..c93019e 100644
--- a/rbm.conf
+++ b/rbm.conf
@@ -144,6 +144,7 @@ targets:
       compiler: gcc
       # We only build snowflake on linux and osx for now
       snowflake: 1
+      fteproxy: 1
       container:
         suite: wheezy
       deps:
@@ -186,6 +187,34 @@ targets:
            export RBM_SETARCH=1
            exec setarch i686 ./build
         fi
+      fteproxy: 1
+      install_wine_ppa: |
+        # Install a Wine new enough to have a fix for
+        # http://bugs.winehq.org/show_bug.cgi?id=29764; otherwise Python run under
+        # Wine constantly crashes in _PyVerify_fd, which is called by such common
+        # operations as io.open and os.fstat (anything involving a file descriptor
+        # number). Ubuntu's main repository only has wine1.4, and the issue was fixed
+        # in 1.5.29.
+        echo 'deb http://ppa.launchpad.net/ubuntu-wine/ppa/ubuntu precise main' >> /etc/apt/sources.list
+        # This key is from https://launchpad.net/~ubuntu-wine/+archive/ppa and
+        # http://keyserver.ubuntu.com:11371/pks/lookup?op=get&search=0x5A9A06AEF9CB8DB0.
+        apt-key add - << EOF
+        -----BEGIN PGP PUBLIC KEY BLOCK-----
+        Version: GnuPG v1
+        
+        mI0ESXVzlQEEAN1BxiR961SiFrJ7tacrAImCmDdxs4OSifgpBAp8q0fe0iLcSeAo
+        WdS7H+7Y4T+/2t3XEw7+3cD831WBu8c/Pv0ldx5TyDyOQmEtUBlMqy33WdKVxsci
+        rnag8ShrNM9PtG/vAQU/JtfQl68dXfD3BsCtrXVrjqcO2AxNYBSvd9hpABEBAAG0
+        IkxhdW5jaHBhZCBQUEEgZm9yIFVidW50dSBXaW5lIFRlYW2ItgQTAQIAIAUCSXVz
+        lQIbAwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEFqaBq75y42wflcD/jLMihWM
+        zRCO60S/a7SqD0QNqV/nAYEOsma/Y2C/uhQ44j0np+iOB6+PDRbyJ8GVgIjpaIbt
+        l4sReXcf7bS9Dhhn5Gbe/n6VQr7xoMr1Io0PrXdmWpmsOfCuebWU4bV1w+YBvHFF
+        qTu5QF2Y0Fj9bRxQdQ1M2HcnXOiLq82hKlb+
+        =Z9DY
+        -----END PGP PUBLIC KEY BLOCK-----
+        EOF
+        apt-get update
+        apt-get --no-install-recommends -y install wine
 
   torbrowser-osx-x86_64:
     - osx-x86_64



More information about the tor-commits mailing list