Skip to content

Instantly share code, notes, and snippets.

@ViteFalcon
Last active August 29, 2015 13:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ViteFalcon/a77c1c135304f5afce53 to your computer and use it in GitHub Desktop.
Save ViteFalcon/a77c1c135304f5afce53 to your computer and use it in GitHub Desktop.
#!/usr/bin/python
from RunCmd import RunCmd
class CMakeError(BaseException):pass
from Utils import Done, Fail, Pause, GetKeyValue
from os import getcwd, path
from Platform import IsWindows
from GenCache import GenCache
class CMakeError(BaseException):pass
DEFAULT_WORKING_DIR = path.dirname(path.dirname(__file__))
if IsWindows():
CMAKE_COMPILERS = {
'borland' : 'Borland Makefiles',
'msys' : 'MSYS Makefiles',
'mingw' : 'MinGW Makefiles',
'nmake' : 'NMake Makefiles',
'nmakejom' : 'NMake Makefiles JOM',
'vs11' : 'Visual Studio 11',
'vs11x64' : 'Visual Studio 11 Win64',
'vs10' : 'Visual Studio 10',
'vs10x64' : 'Visual Studio 10 Win64',
'vs6' : 'Visual Studio 6',
'vs7_2002' : 'Visual Studio 7',
'vs7_2003' : 'Visual Studio 7 .NET 2003',
'vs8' : 'Visual Studio 8 2005',
'vs8x64' : 'Visual Studio 8 2005 Win64',
'vs9' : 'Visual Studio 9 2008',
'vs9x64' : 'Visual Studio 9 2008 Win64',
'watcom' : 'Watcom WMake',
'cb_mingw' : 'CodeBlocks - MinGW Makefiles',
'cb_nmake' : 'CodeBlocks - NMake Makefiles',
'eclipse_mingw' : 'Eclipse CDT4 - MinGW Makefiles',
'eclipse_nmake' : 'Eclipse CDT4 - NMake Makefiles',
'eclipse_unix' : 'Eclipse CDT4 - Unix Makefiles'
}
else:
CMAKE_COMPILERS = {
'kde3' : 'KDevelop3',
'kde3_make' : 'KDevelop3 - Unix Makefiles',
'eclipse_unix' : 'Eclipse CDT4 - Unix Makefiles',
'makefiles' : 'Unix Makefiles'
}
class CMake(object):
# Class that interfaces with CMake
@classmethod
def Generators(cls):
return CMAKE_COMPILERS.keys()
@classmethod
def GenerateProject(cls, projectType, settings, isUnityBuild = None):
# Generate options
options = []
if isUnityBuild:
options.append('%s=ON'%settings.unityBuildVar)
elif isUnityBuild is False:
options.append('%s=OFF'%settings.unityBuildVar)
else:
with GenCache(settings.projectRoot) as gencache:
if gencache.isUnityBuild:
options.append('%s=ON'%settings.unityBuildVar)
else:
options.append('%s=OFF'%settings.unityBuildVar)
# Record options
with GenCache(settings.projectRoot) as gencache:
gencache.setIsUnityBuild(isUnityBuild)
if not projectType in CMAKE_COMPILERS:
raise Exception("Unrecognized project type '%s'!"%projectType)
cmake = CMake(settings)
cmake.generate(projectType, options)
@classmethod
def GenerateFileList(cls, settings, headers, sources, tests):
from Templates.CMake import GenerateCMakeFileList
GenerateCMakeFileList(settings, headers, sources, tests)
@classmethod
def AddSubParser(cls, subparser):
from lib.argparse import ArgumentGroup
genparser = subparser.add_parser('generate')
genparser.add_argument(
'-p',
type=CMake.GenerateProject,
action='store',
choices=CMAKE_COMPILERS.keys())
def __init__(self, settings):
# Constructor
self._settings = settings
self._dir = settings.projectRoot
if not path.isdir(path.join(self._dir, 'CMake')):
raise Exception('Could not find CMake folder inside working directory (%s)'%self._dir)
retval, output = RunCmd('cmake --version')
if not 0 == retval:
raise Exception('CMake is NOT installed or is not in the your PATH environment variable')
self._version = output[-2].split()[-1]
Done('Found CMake Version %s'%self._version)
@property
def version(self):
# The version of CMake being used
return self._version
@property
def workingDir(self):
# Gets the working directory
return self._dir
def generate(self, generator, options):
project_dir = path.join(
self._settings.absBuildDirectory,
generator
)
definitions = ''
if options:
for option in options:
definitions += '-D%s '%option
from Utils import ScopedChdir
with ScopedChdir(project_dir, True) as build_dir:
from RunCmd import RunCmd
(result,output) = RunCmd('cmake -G "%s" %s %s'%
(
CMAKE_COMPILERS[generator],
self._settings.projectRoot,
definitions
),
True
)
if 0 != result:
raise CMakeError('Failed to generate the project files!')
from GenCache import GenCache
gencache = GenCache(self._settings.projectRoot)
gencache.load()
gencache.setProjectType(generator)
gencache.setProjectDir(self._settings.projectRoot)
gencache.save()
Done('Build files successfully generated for %s'%(CMAKE_COMPILERS[generator]))
from os import path, getcwd
import json
CACHE_FILE = '.gencache'
PROJECT_TYPE = 'project_type'
PROJECT_DIR = 'project_dir'
PROJECTS = 'projects'
UNITY_BUILD = 'unit_build'
class GenCache(object):
def __init__(self,rootPath=None):
if not rootPath or not path.isdir(rootPath):
rootPath = getcwd()
self._filePath = path.join(rootPath, CACHE_FILE)
def __enter__(self):
self.load()
return self
def __exit__(self, type, value, traceback):
self.save()
def load(self):
if path.isfile(self._filePath):
with open(self._filePath, 'r+') as cachefile:
self._config = json.loads(
reduce(lambda x, y: x + y, cachefile.readlines()))
else:
self._config = {}
def empty(self):
return 0 == len(self._config)
def save(self):
with open(self._filePath, 'w') as cachefile:
cachefile.writelines(json.dumps(self._config, indent=4))
def setProjectType(self, proj_type):
self._config[PROJECT_TYPE] = proj_type
@property
def hasProjectType(self):
return self._config.has_key(PROJECT_TYPE)
def getProjectType(self):
return self._config[PROJECT_TYPE]
def setProjectDir(self, proj_dir):
self._config[PROJECT_DIR] = proj_dir
def hasProjectDir(self):
return self._config.has_key(PROJECT_DIR)
def getProjectDir(self):
return self._config[PROJECT_DIR]
@property
def hasIsUnityBuild(self):
return self._config.has_key(UNITY_BUILD)
@property
def isUnityBuild(self):
return self.hasIsUnityBuild and self._config[UNITY_BUILD]
def setIsUnityBuild(self, isUnityBuild):
self._config[UNITY_BUILD] = isUnityBuild
from os import name as osname
from platform import system as psystem, release as prelease
def IsPosix():
return osname == 'posix'
def System():
return psystem()
def IsWindows():
return System() == 'Windows'
def IsLinux():
return System() == 'Linux'
def OsRelease():
return prelease()
# -*- coding: utf-8 *-*
from dulwich.repo import Repo
from os import path
def GetRepo(settings):
if GitRepo.IsMyType(settings.projectRoot):
return GitRepo(settings.projectRoot)
return None
def GetTrackedTestFiles(settings):
repo = GetRepo(settings)
if not repo:
return []
return GetTestFilesFromRepo(repo, settings)
def GetTestFilesFromRepo(repo, settings):
regex_expr = '^%s\/.*\.(h|(c(pp)?))$'%(
settings.testsHeaderDirectoryFromRoot)
return repo.grepTrackedFiles(regex_expr)
def GetTrackedHeaderFiles(settings):
repo = GetRepo(settings)
if not repo:
return []
return GetHeaderFilesFromRepo(repo, settings)
def GetHeaderFilesFromRepo(repo, settings):
regex_expr = '^%s\/.*\.h(pp)?$'%(settings.headerDirectory)
return repo.grepTrackedFiles(regex_expr)
def IsFileTracked(filePath, settings):
repo = GetRepo(settings)
if not repo:
return False
return repo.isFileTracked(filePath)
def GetTrackedSourceFiles(settings):
repo = GetRepo(settings)
if not repo:
return []
return GetSourceFilesFromRepo(repo, settings)
def GetSourceFilesFromRepo(repo, settings):
regex_expr = '^%s\/.*\.c(pp)?$'%(settings.sourceDirectory)
return repo.grepTrackedFiles(regex_expr)
class GitRepo(object):
@classmethod
def IsMyType(cls, root):
return path.isdir(path.join(root,'.git'))
def __init__(self, root):
self._git = Repo(root)
@property
def workingDir(self):
return self._git.path
def addFiles(self, files):
filesToStage = []
trackedFiles = self.trackedFiles
for filePath in files:
if not filePath in trackedFiles:
filesToStage.append(filePath)
self._git.stage(filesToStage)
def commit(self, message):
return self._git.do_commit(message)
@property
def trackedFiles(self):
git_index = self._git.open_index()
tracked_files = []
for path in git_index:
tracked_files.append(path)
return tracked_files
def isFileTracked(self, filePath):
return filePath in self.trackedFiles
def grepTrackedFiles(self, regexExpr):
import re
regex = re.compile(regexExpr)
tracked_files = self.trackedFiles
return filter(lambda x: regex.search(x), tracked_files)
from subprocess import call, Popen, PIPE, STDOUT
from sys import stdout
from shlex import split as shsplit
from Platform import IsWindows, IsLinux
def RunShellCmd(cmd):
call(cmd,shell=True)
#===============================================================================
def RunCmd(cmd,displayOutput=False):
"""
Runs a command and returns a tuple of (return_value, output) where output
is a list of output lines generated.
"""
runAsShell = IsWindows()
if IsLinux():
if isinstance(cmd, str) or isinstance(cmd,unicode):
cmd = shsplit(cmd)
proc = Popen(cmd, stdout=PIPE, stderr=STDOUT,shell=runAsShell)
output = ''
while True:
retval = proc.poll()
readstr = proc.stdout.read(1)
output += readstr
if readstr == '' and None is not retval:
break
elif displayOutput and readstr != '':
stdout.write(readstr)
output = output.split('\n')
return (retval, output)
from RunCmd import RunShellCmd
from os import path, makedirs, getcwd, chdir
from shutil import copy2
from clint.textui import colored
from Platform import IsWindows
#==============================================================================
DONE = colored.green
#===============================================================================
ERROR = colored.yellow
#===============================================================================
FAIL = colored.red
#===============================================================================
QUERY = colored.cyan
#===============================================================================
def ParseBool(val, default):
val = val.lower()
true_vals = ['y','yes','true','t','1']
false_vals = ['n','no','false','f','0']
if val in true_vals:
return True
elif val in false_vals:
return False
return default
#==============================================================================
def Error(msg):
"""
Displays an error message
"""
print ERROR(msg)
#===============================================================================
def Query(msg,color=QUERY,default=''):
"""
Queries the user about something and receives their input as a string
"""
if default:
msg = '%s (default=%s): '%(msg,default)
else:
msg = '%s: '%msg
response = raw_input(color(msg))
if not response:
return default
return response
#===============================================================================
def QueryYesNo(msg,color=QUERY,default=None):
"""
Queries the user for a yes/no answer
"""
def BoolQuery():
return ParseBool(Query(msg,color),default)
response = BoolQuery()
while None is response:
Error('Please enter a valid yes/no value (Yes/Y/True/T/No/N/False/F')
response = BoolQuery()
return response
#===============================================================================
def Done(msg):
"""
Prints the message that something is done
"""
print DONE(msg)
#===============================================================================
def Fail(msg):
"""
Prints the message that something failed
"""
print FAIL(msg)
#===============================================================================
def HandleException(e, msg=None):
if msg:
Fail('%s: %s'%(msg, e))
else:
Fail('%s'%e)
raise
#===============================================================================
def CiStartsWith(string, chkstr):
string = string.lower()
chkstr = chkstr.lower()
return string.startswith(chkstr)
#===============================================================================
def GetKeyValue(settings, setting_name, default_value):
if settings.has_key(setting_name):
return settings[setting_name]
return default_value
#===============================================================================
def Pause():
if IsWindows():
RunShellCmd('pause')
else:
RunShellCmd('read -n1 -r -p "(Press any key to continue...)"')
#===============================================================================
class ScopedChdir(object):
def __init__(self,directory,createIfNotExists=False):
self._create = createIfNotExists
self._dir = directory
def __enter__(self):
if not path.isdir(self._dir):
if not self._create:
msg = "The path '%s' does not exist!"%(self._dir)
print colored.red(msg)
raise Exception(msg)
makedirs(self._dir)
self._prevDir = getcwd()
chdir(self._dir)
def __exit__(self,type,value,traceback):
chdir(self._prevDir)
#===============================================================================
class TaskCopyFile(object):
def __init__(self, src, dst, msg=None):
self._src = src
self._dst = dst
self._run = False
self._traceback = None
self.msg(msg)
#---------------------------------------------------------------------------
def run(self):
self._run = True
try:
copy2(self._src, self._dst)
except Exception:
self._traceback = exc_info()
#---------------------------------------------------------------------------
def msg(self, strMsg):
if None is strMsg:
cwd = getcwd()
self._msg = "Copying file '%s' to '%s'... "%(
path.relpath(self._src, cwd),
path.relpath(self._dst, cwd)
)
else:
self._msg = '%s... '%(strMsg)
#--------------------------------------------------------------------------
def echo(self, msg=None):
if msg:
self.msg(msg)
if not self._run:
print Fail('This task was not run!')
return
print self._msg,
if not self._traceback:
Done('DONE')
else:
Fail('FAILED')
traceback.print_exception(self._traceback[0], self._traceback[1], self._traceback[2], limit=3)
Fail('<End of stack-trace>')
#--------------------------------------------------------------------------
def __enter__(self):
self.run()
return self
#--------------------------------------------------------------------------
def __exit__(self,type,value,traceback):
pass
#==============================================================================
def ZipDir(directory,target_file=None):
"""
Zips a directory and returns a tuple of (success, zip-file-path)
@param directory: The directory to be zipped
@return: A tuple in the format (success, zip-file-path)
"""
directory = path.abspath(path.join(MEDIA_SRC_DIR, directory))
if not path.isdir(directory):
Fail("%s isn't a valid directory"%(directory))
return (False,None)
if not target_file:
zfName = '%s.zip'%(path.basename(directory))
else:
zfName = target_file
from zipfile import ZipFile
zf = ZipFile(zfName, mode='w')
with ScopedChdir(directory):
dirList = listdir('.')
for filename in dirList:
if not filename.lower() in IGNORE_LIST:
zf.write(filename)
zf.close()
return (True, path.abspath(zfName))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment