summaryrefslogtreecommitdiffstats
path: root/win
diff options
context:
space:
mode:
authorJames Yonan <james@openvpn.net>2010-04-22 12:53:31 +0000
committerJames Yonan <james@openvpn.net>2010-04-22 12:53:31 +0000
commit059739e9341781d9019e07fc5119367c1630b012 (patch)
tree6839d8071558539505991895ef377baee58e960f /win
parent7a464e32394f2d072fad2d31ad625b332108300f (diff)
downloadopenvpn-059739e9341781d9019e07fc5119367c1630b012.tar.gz
openvpn-059739e9341781d9019e07fc5119367c1630b012.tar.xz
openvpn-059739e9341781d9019e07fc5119367c1630b012.zip
Added Python-based build system for Windows in
win directory. Fixed minor issue in TAP driver DEBUG builds where non-null-terminated unicode strings were being printed incorrectly. Version 2.1.1g git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@5577 e7ae566f-a301-0410-adde-c780ea21d3b5
Diffstat (limited to 'win')
-rw-r--r--win/__init__.py0
-rw-r--r--win/autodefs.h.in31
-rw-r--r--win/build.py15
-rw-r--r--win/build_all.py18
-rw-r--r--win/build_ddk.py50
-rw-r--r--win/config.py17
-rw-r--r--win/config_all.py13
-rw-r--r--win/config_tap.py35
-rw-r--r--win/config_ti.py18
-rw-r--r--win/js.py10
-rw-r--r--win/make_dist.py54
-rw-r--r--win/msvc.mak.in52
-rw-r--r--win/settings.in62
-rw-r--r--win/show.py10
-rw-r--r--win/sign.py19
-rw-r--r--win/wb.py185
16 files changed, 589 insertions, 0 deletions
diff --git a/win/__init__.py b/win/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/win/__init__.py
diff --git a/win/autodefs.h.in b/win/autodefs.h.in
new file mode 100644
index 0000000..2edd9b6
--- /dev/null
+++ b/win/autodefs.h.in
@@ -0,0 +1,31 @@
+#ifndef AUTODEFS_H
+#define AUTODEFS_H
+
+/*
+ * Minimum TAP-Win32 version number expected by userspace
+ *
+ * The TAP-Win32 version number is defined in tap-win32/SOURCES
+ */
+#define TAP_ID "@PRODUCT_TAP_ID@"
+#define TAP_WIN32_MIN_MAJOR @PRODUCT_TAP_WIN32_MIN_MAJOR@
+#define TAP_WIN32_MIN_MINOR @PRODUCT_TAP_WIN32_MIN_MINOR@
+
+/* Friendly name for TAP driver */
+#define PRODUCT_TAP_DEVICE_DESCRIPTION "@PRODUCT_TAP_DEVICE_DESCRIPTION@"
+
+/* Version number of DDK/WDK used to build TAP driver */
+#define DDKVER_MAJOR @DDKVER_MAJOR@
+
+/* Name of package */
+#define PACKAGE "@PRODUCT_UNIX_NAME@"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "@PRODUCT_NAME@"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "@PRODUCT_UNIX_NAME@"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "@PRODUCT_VERSION@"
+
+#endif
diff --git a/win/build.py b/win/build.py
new file mode 100644
index 0000000..f42715b
--- /dev/null
+++ b/win/build.py
@@ -0,0 +1,15 @@
+import os
+from wb import system, config, home_fn, cd_home
+
+os.environ['PATH'] += ";%s\\VC" % (os.path.normpath(config['MSVC']),)
+
+def build_vc(cmd):
+ system('cmd /c "vcvarsall.bat x86 && %s"' % (cmd,))
+
+def main():
+ cd_home()
+ build_vc("nmake /f %s" % (home_fn('msvc.mak'),))
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ main()
diff --git a/win/build_all.py b/win/build_all.py
new file mode 100644
index 0000000..92d2bf4
--- /dev/null
+++ b/win/build_all.py
@@ -0,0 +1,18 @@
+from config_all import main as config_all
+from build import main as build_openvpn
+from build_ddk import main as build_ddk
+from sign import main as sign
+from make_dist import main as make_dist
+
+def main(config):
+ config_all(config)
+ build_openvpn()
+ build_ddk(config, 'tap', 'all')
+ build_ddk(config, 'tapinstall', 'all')
+ sign(config, 'all')
+ make_dist(config)
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ from wb import config
+ main(config)
diff --git a/win/build_ddk.py b/win/build_ddk.py
new file mode 100644
index 0000000..ca68e81
--- /dev/null
+++ b/win/build_ddk.py
@@ -0,0 +1,50 @@
+import os
+from wb import system, home_fn, choose_arch
+
+def build_ddk(config, dir, x64):
+ setenv_bat = os.path.realpath(os.path.join(config['DDK_PATH'], 'bin/setenv.bat'))
+ ddk_major = int(config['DDKVER_MAJOR'])
+ debug = 'PRODUCT_TAP_DEBUG' in config
+ target = 'chk' if debug else 'fre'
+ if x64:
+ target += ' x64'
+ else:
+ target += ' x86'
+ if ddk_major >= 7600:
+ if x64:
+ target += ' wlh' # vista
+ else:
+ target += ' wnet' # server 2003
+ else:
+ if x64:
+ target += ' wnet' # server 2003
+ else:
+ target += ' w2k' # 2000
+
+ system('cmd /c "%s %s %s && cd %s && build -cef"' % (
+ setenv_bat,
+ os.path.realpath(config['DDK_PATH']),
+ target,
+ dir
+ ))
+
+def main(config, proj, arch):
+ if proj == 'tap':
+ dir = home_fn('tap-win32')
+ elif proj == 'tapinstall':
+ dir = home_fn('tapinstall')
+ else:
+ raise ValueError("unknown project: %s" % (proj,))
+
+ for x64 in choose_arch(arch):
+ build_ddk(config, dir, x64)
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ import sys
+ from wb import config
+ if len(sys.argv) >= 3:
+ main(config, sys.argv[1], sys.argv[2])
+ else:
+ print "usage: build <tap|tapinstall> <x64|x86|all>"
+ sys.exit(2)
diff --git a/win/config.py b/win/config.py
new file mode 100644
index 0000000..67c1d82
--- /dev/null
+++ b/win/config.py
@@ -0,0 +1,17 @@
+from wb import preprocess, autogen, mod_fn, home_fn, build_autodefs, make_headers_objs, dict_def
+
+def main(config):
+ build_autodefs(config, mod_fn('autodefs.h.in'), home_fn('autodefs.h'))
+ ho = make_headers_objs(home_fn('Makefile.am'))
+
+ preprocess(dict_def(config, [('HEADERS_OBJS', ho)]),
+ in_fn=mod_fn('msvc.mak.in'),
+ out_fn=home_fn('msvc.mak'),
+ quote_begin='@',
+ quote_end='@',
+ head_comment='# %s\n\n' % autogen)
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ from wb import config
+ main(config)
diff --git a/win/config_all.py b/win/config_all.py
new file mode 100644
index 0000000..2686780
--- /dev/null
+++ b/win/config_all.py
@@ -0,0 +1,13 @@
+from config import main as config_main
+from config_tap import main as config_tap
+from config_ti import main as config_ti
+
+def main(config):
+ config_main(config)
+ config_tap(config)
+ config_ti(config)
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ from wb import config
+ main(config)
diff --git a/win/config_tap.py b/win/config_tap.py
new file mode 100644
index 0000000..e69ee9b
--- /dev/null
+++ b/win/config_tap.py
@@ -0,0 +1,35 @@
+import os
+from wb import preprocess, home_fn, autogen, dict_def
+
+def main(config):
+ preprocess(config,
+ in_fn=home_fn('tap-win32/SOURCES.in'),
+ out_fn=home_fn('tap-win32/SOURCES'),
+ quote_begin='@@',
+ quote_end='@@',
+ head_comment='# %s\n\n' % autogen)
+
+ preprocess(config,
+ in_fn=home_fn('tap-win32/i386/OemWin2k.inf.in'),
+ out_fn=home_fn('tap-win32/i386/OemWin2k.inf'),
+ quote_begin='@@',
+ quote_end='@@',
+ if_prefix='!',
+ head_comment='; %s\n\n' % autogen)
+
+ try:
+ os.mkdir(home_fn('tap-win32/amd64'))
+ except:
+ pass
+ preprocess(dict_def(config, [('AMD64', '1')]),
+ in_fn=home_fn('tap-win32/i386/OemWin2k.inf.in'),
+ out_fn=home_fn('tap-win32/amd64/OemWin2k.inf'),
+ quote_begin='@@',
+ quote_end='@@',
+ if_prefix='!',
+ head_comment='; %s\n\n' % autogen)
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ from wb import config
+ main(config)
diff --git a/win/config_ti.py b/win/config_ti.py
new file mode 100644
index 0000000..4facaff
--- /dev/null
+++ b/win/config_ti.py
@@ -0,0 +1,18 @@
+import os, shutil
+from wb import preprocess, home_fn, autogen
+
+def main(config):
+ src = os.path.join(home_fn(config['TISRC']), config['DDKVER_MAJOR'])
+ dest = home_fn('tapinstall')
+ shutil.rmtree(dest, ignore_errors=True)
+ shutil.copytree(src, dest)
+ preprocess(config,
+ in_fn=os.path.join(dest, 'sources.in'),
+ out_fn=os.path.join(dest, 'sources'),
+ if_prefix='!',
+ head_comment='# %s\n\n' % autogen)
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ from wb import config
+ main(config)
diff --git a/win/js.py b/win/js.py
new file mode 100644
index 0000000..c515824
--- /dev/null
+++ b/win/js.py
@@ -0,0 +1,10 @@
+import json
+
+# usage:
+# print JSON().encode(kv)
+
+class JSON(json.JSONEncoder):
+ def __init__(self, **kwargs):
+ args = dict(sort_keys=True, indent=2)
+ args.update(kwargs)
+ json.JSONEncoder.__init__(self, **args)
diff --git a/win/make_dist.py b/win/make_dist.py
new file mode 100644
index 0000000..3011279
--- /dev/null
+++ b/win/make_dist.py
@@ -0,0 +1,54 @@
+import os
+from wb import home_fn, rm_rf, mkdir, cp_a, cp
+
+def main(config):
+ dist = config['DIST']
+ assert dist
+ dist = home_fn(dist)
+ bin = os.path.join(dist, 'bin')
+ i386 = os.path.join(dist, 'i386')
+ amd64 = os.path.join(dist, 'amd64')
+
+ # build dist and subdirectories
+ rm_rf(dist)
+ mkdir(dist)
+ mkdir(bin)
+ mkdir(i386)
+ mkdir(amd64)
+
+ # copy openvpn.exe and manifest
+ cp(home_fn('openvpn.exe'), bin)
+ cp(home_fn('openvpn.exe.manifest'), bin)
+
+ # copy DLL dependencies
+ cp(home_fn(config['LZO_DIR']+'/bin/lzo2.dll'), bin)
+ cp(home_fn(config['OPENSSL_DIR']+'/bin/libeay32.dll'), bin)
+ cp(home_fn(config['OPENSSL_DIR']+'/bin/ssleay32.dll'), bin)
+
+ # copy MSVC CRT
+ cp_a(home_fn(config['MSVC_CRT']), bin)
+
+ # copy TAP drivers
+ for dir_name, dest in (('amd64', amd64), ('i386', i386)):
+ dir = home_fn(os.path.join('tap-win32', dir_name))
+ for dirpath, dirnames, filenames in os.walk(dir):
+ for f in filenames:
+ root, ext = os.path.splitext(f)
+ if ext in ('.inf', '.cat', '.sys'):
+ cp(os.path.join(dir, f), dest)
+ break
+
+ # copy tapinstall
+ dest = {'amd64' : amd64, 'i386' : i386}
+ for dirpath, dirnames, filenames in os.walk(home_fn('tapinstall')):
+ for f in filenames:
+ if f == 'tapinstall.exe':
+ dir_name = os.path.basename(dirpath)
+ src = os.path.join(dirpath, f)
+ if dir_name in dest:
+ cp(src, dest[dir_name])
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ from wb import config
+ main(config)
diff --git a/win/msvc.mak.in b/win/msvc.mak.in
new file mode 100644
index 0000000..3f8102a
--- /dev/null
+++ b/win/msvc.mak.in
@@ -0,0 +1,52 @@
+# This makefile builds the user-mode component
+# of OpenVPN for Windows in the Visual Studio 2008 environment.
+
+# To build:
+# python win\config.py
+# nmake /f msvc.mak
+
+# Each of the OPENSSL and LZO dirs should have 'lib' and 'include'
+# directories under them.
+
+OPENSSL = @OPENSSL_DIR@
+OPENSSL_DYNAMIC = libeay32.lib ssleay32.lib
+
+LZO = @LZO_DIR@
+LZO_DYNAMIC = lzo2.lib
+
+INCLUDE_DIRS = -I$(OPENSSL)/include -I$(LZO)/include
+
+LIBS = $(OPENSSL_DYNAMIC) $(LZO_DYNAMIC) ws2_32.lib crypt32.lib iphlpapi.lib winmm.lib user32.lib gdi32.lib advapi32.lib wininet.lib
+
+LIB_DIRS = -LIBPATH:$(OPENSSL)\lib -LIBPATH:$(LZO)\lib
+
+EXE = openvpn.exe
+
+CPP=cl.exe
+CPP_ARG_COMMON=/nologo /W3 /O2 -DWIN32 -DWIN32_LEAN_AND_MEAN -D_CONSOLE -D_MBCS -D_CRT_SECURE_NO_DEPRECATE $(INCLUDE_DIRS) /FD /c
+# release:
+CPP_PROJ=$(CPP_ARG_COMMON) /MD -DNDEBUG
+# debug:
+#CPP_PROJ=$(CPP_ARG_COMMON) /MDd /Zi /Od -D_DEBUG
+
+LINK32=link.exe
+# release:
+LINK32_FLAGS=/nologo /subsystem:console /incremental:no /out:"$(EXE)"
+# debug:
+#LINK32_FLAGS=/nologo /subsystem:console /incremental:no /debug /out:"$(EXE)"
+
+# HEADERS and OBJS definitions, automatically generated
+@HEADERS_OBJS@
+
+openvpn : $(OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LIB_DIRS) $(LIBS) $(OBJS)
+<<
+
+clean :
+ del /Q $(OBJS) $(EXE) *.idb *.pdb
+
+.c.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
diff --git a/win/settings.in b/win/settings.in
new file mode 100644
index 0000000..044834a
--- /dev/null
+++ b/win/settings.in
@@ -0,0 +1,62 @@
+# Version numbers, settings, and dependencies
+# for Windows OpenVPN installer.
+
+# Branding
+!define PRODUCT_NAME "OpenVPN"
+!define PRODUCT_UNIX_NAME "openvpn"
+!define PRODUCT_FILE_EXT "ovpn"
+
+# Allow --askpass and --auth-user-pass passwords to be read from a file
+;!define ENABLE_PASSWORD_SAVE
+
+# Include the OpenVPN GUI exe in the installer.
+# May be undefined.
+!define OPENVPN_GUI_DIR "../openvpn-gui"
+!define OPENVPN_GUI "openvpn-gui-1.0.3.exe"
+
+# Prebuilt libraries. DMALLOC is optional.
+!define OPENSSL_DIR "../openssl"
+!define LZO_DIR "../lzo"
+
+# write output files here
+!define DIST "dist"
+
+# tapinstall.exe source code.
+# Not needed if DRVBINSRC is defined
+# (or if using pre-built mode).
+!define TISRC "../tapinstall"
+
+# TAP Adapter parameters. Note that PRODUCT_TAP_ID is
+# defined in version.m4.
+!define PRODUCT_TAP_DEVICE_DESCRIPTION "TAP-Win32 Adapter V9"
+!define PRODUCT_TAP_PROVIDER "TAP-Win32 Provider V9"
+!define PRODUCT_TAP_MAJOR_VER 9
+!define PRODUCT_TAP_MINOR_VER 7
+!define PRODUCT_TAP_RELDATE "04/19/2010"
+
+# TAP adapter icon -- visible=0x81 or hidden=0x89
+!define PRODUCT_TAP_CHARACTERISTICS 0x81
+
+# Build debugging version of TAP driver
+;!define PRODUCT_TAP_DEBUG
+
+# DDK path -- currently Windows 7 WDK
+!define DDK_PATH "c:/winddk/7600.16385.1"
+;!define DDK_PATH "c:/winddk/6001.18002"
+
+# Visual studio path
+!define MSVC "C:/Program Files/Microsoft Visual Studio 9.0"
+
+# Visual studio C run-time library path
+!define MSVC_CRT "../Microsoft.VC90.CRT"
+
+# Code Signing.
+# If undefined, don't sign any files.
+!define SIGNTOOL "../signtool"
+!define PRODUCT_SIGN_CN "openvpn"
+
+; DEBUGGING -- set to something like "-DBG2"
+!define OUTFILE_LABEL ""
+
+; DEBUGGING -- set to something like "DEBUG2"
+!define TITLE_LABEL ""
diff --git a/win/show.py b/win/show.py
new file mode 100644
index 0000000..9558c87
--- /dev/null
+++ b/win/show.py
@@ -0,0 +1,10 @@
+from wb import get_config
+from js import JSON
+
+def main():
+ kv = get_config()
+ print JSON().encode(kv)
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ main()
diff --git a/win/sign.py b/win/sign.py
new file mode 100644
index 0000000..ee4ae72
--- /dev/null
+++ b/win/sign.py
@@ -0,0 +1,19 @@
+import sys
+from wb import config, choose_arch, home_fn
+
+if 'SIGNTOOL' in config:
+ sys.path.append(home_fn(config['SIGNTOOL']))
+
+def main(conf, arch):
+ from signtool import SignTool
+ st = SignTool(conf)
+ for x64 in choose_arch(arch):
+ st.sign_verify(x64=x64)
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ if len(sys.argv) >= 2:
+ main(config, sys.argv[1])
+ else:
+ print "usage: sign <x64|x86|all>"
+ sys.exit(2)
diff --git a/win/wb.py b/win/wb.py
new file mode 100644
index 0000000..7c2c8b9
--- /dev/null
+++ b/win/wb.py
@@ -0,0 +1,185 @@
+# Python module containing general build functions
+# for OpenVPN on Windows
+
+import os, re, shutil
+
+autogen = "Automatically generated by OpenVPN Windows build system"
+
+def get_config():
+ kv = {}
+ parse_version_m4(kv, home_fn('version.m4'))
+ parse_settings_in(kv, mod_fn('settings.in'))
+
+ # config fixups
+ kv['DDKVER'] = os.path.basename(kv['DDK_PATH'])
+ kv['DDKVER_MAJOR'] = re.match(r'^(\d+)\.', kv['DDKVER']).groups()[0]
+
+ if 'VERSION_SUFFIX' in kv:
+ kv['PRODUCT_VERSION'] += kv['VERSION_SUFFIX']
+
+ return kv
+
+def mod_fn(fn, src=__file__, real=True):
+ p = os.path.join(os.path.dirname(src), os.path.normpath(fn))
+ if real:
+ p = os.path.realpath(p)
+ return p
+
+def home_fn(fn, real=True):
+ return mod_fn(os.path.join('..', fn), real=real)
+
+def cd_home():
+ os.chdir(os.path.join(os.path.dirname(__file__), '..'))
+
+def system(cmd):
+ print "RUN:", cmd
+ os.system(cmd)
+
+def parse_version_m4(kv, version_m4):
+ r = re.compile(r'^define\((\w+),\[(.*)\]\)$')
+ f = open(version_m4)
+ for line in f:
+ line = line.rstrip()
+ m = re.match(r, line)
+ if m:
+ g = m.groups()
+ kv[g[0]] = g[1]
+ f.close()
+
+def parse_settings_in(kv, settings_in):
+ r = re.compile(r'^!define\s+(\w+)(?:\s+"?(.*?)"?)?$')
+ f = open(settings_in)
+ for line in f:
+ line = line.rstrip()
+ m = re.match(r, line)
+ if m:
+ g = m.groups()
+ kv[g[0]] = g[1] or ''
+ f.close()
+
+def dict_def(dict, newdefs):
+ ret = dict.copy()
+ ret.update(newdefs)
+ return ret
+
+def build_autodefs(kv, autodefs_in, autodefs_out):
+ preprocess(kv,
+ in_fn=autodefs_in,
+ out_fn=autodefs_out,
+ quote_begin='@',
+ quote_end='@',
+ head_comment='/* %s */\n\n' % autogen)
+
+def preprocess(kv, in_fn, out_fn, quote_begin=None, quote_end=None, if_prefix=None, head_comment=None):
+ def repfn(m):
+ var, = m.groups()
+ return kv.get(var, '')
+
+ re_macro = re_ifdef = None
+
+ if quote_begin and quote_end:
+ re_macro = re.compile(r'%s(\w+)%s' % (re.escape(quote_begin), re.escape(quote_end)))
+
+ if if_prefix:
+ re_ifdef = re.compile(r'^\s*%sifdef\s+(\w+)\b' % (re.escape(if_prefix),))
+ re_else = re.compile(r'^\s*%selse\b' % (re.escape(if_prefix),))
+ re_endif = re.compile(r'^\s*%sendif\b' % (re.escape(if_prefix),))
+
+ if_stack = []
+ fin = open(in_fn)
+ fout = open(out_fn, 'w')
+ if head_comment:
+ fout.write(head_comment)
+ for line in fin:
+ if re_ifdef:
+ m = re.match(re_ifdef, line)
+ if m:
+ var, = m.groups()
+ if_stack.append(int(var in kv))
+ continue
+ elif re.match(re_else, line):
+ if_stack[-1] ^= 1
+ continue
+ elif re.match(re_endif, line):
+ if_stack.pop()
+ continue
+ if not if_stack or min(if_stack):
+ if re_macro:
+ line = re.sub(re_macro, repfn, line)
+ fout.write(line)
+ assert not if_stack
+ fin.close()
+ fout.close()
+
+def print_key_values(kv):
+ for k, v in sorted(kv.items()):
+ print "%s%s%s" % (k, ' '*(32-len(k)), repr(v))
+
+def get_sources(makefile_am):
+ c = set()
+ h = set()
+ f = open(makefile_am)
+ state = False
+ for line in f:
+ line = line.rstrip()
+ if line == 'openvpn_SOURCES = \\':
+ state = True
+ elif not line:
+ state = False
+ elif state:
+ for sf in line.split():
+ if sf.endswith('.c'):
+ c.add(sf[:-2])
+ elif sf.endswith('.h'):
+ h.add(sf[:-2])
+ elif sf == '\\':
+ pass
+ else:
+ print >>sys.stderr, "Unrecognized filename:", sf
+ f.close()
+ return [ sorted(list(s)) for s in (c, h) ]
+
+def output_mak_list(title, srclist, ext):
+ ret = "%s =" % (title,)
+ for x in srclist:
+ ret += " \\\n\t%s.%s" % (x, ext)
+ ret += '\n\n'
+ return ret
+
+def make_headers_objs(makefile_am):
+ c, h = get_sources(makefile_am)
+ ret = output_mak_list('HEADERS', h, 'h')
+ ret += output_mak_list('OBJS', c, 'obj')
+ return ret
+
+def choose_arch(arch_name):
+ if arch_name == 'x64':
+ return (True,)
+ elif arch_name == 'x86':
+ return (False,)
+ elif arch_name == 'all':
+ return (True, False)
+ else:
+ raise ValueError("architecture ('%s') must be x86, x64, or all" % (arch_name,))
+
+def rm_rf(dir):
+ print "REMOVE", dir
+ shutil.rmtree(dir, ignore_errors=True)
+
+def mkdir(dir):
+ print "MKDIR", dir
+ os.mkdir(dir)
+
+def cp_a(src, dest, dest_is_dir=True):
+ if dest_is_dir:
+ dest = os.path.join(dest, os.path.basename(src))
+ print "COPY_DIR %s %s" % (src, dest)
+ shutil.copytree(src, dest)
+
+def cp(src, dest, dest_is_dir=True):
+ if dest_is_dir:
+ dest = os.path.join(dest, os.path.basename(src))
+ print "COPY %s %s" % (src, dest)
+ shutil.copyfile(src, dest)
+
+config = get_config()