Merge branch 'BS-38'

This commit is contained in:
rzaitov 2013-11-13 18:35:43 +04:00
commit 9fd63b8bfa
19 changed files with 229 additions and 53 deletions

View File

@ -1,3 +1,5 @@
sh echo 'IosSetupSteps.txt'
# restore from backup # восстанавливаем из бэкапа (исходники от сборки предыдущей конфигурации могут быть модифицированными)
# create backup
@ -6,7 +8,7 @@ sh echo '{@sln_config}'
inside 'BuildSample/BuildSample.sln' remove NotCompileApp project
inside 'BuildSample/BuildSample/CoolApp.csproj' set OutputPath to 'Output' for '{@sln_config}'
inside 'BuildSample/BuildSample/CoolApp.csproj' set AssemblyName to 'CoolApp' for ''
inside 'BuildSample/BuildSample/CoolApp.csproj' set AssemblyName to '{@assembly_name}' for ''
inside 'BuildSample/BuildSample/Info.plist' set CFBundleVersion to '{@version}'
inside 'BuildSample/BuildSample/Info.plist' set CFBundleDisplayName to 'CoolApp'

View File

@ -1,3 +1,4 @@
sh echo 'IosSteps.txt'
sh echo '{@builder_path}'
<include 'scripts/{@setup_steps}'>
@ -9,10 +10,10 @@ clean 'BuildSample/BuildSample.sln' for '{@sln_config}'
build 'BuildSample/BuildSample.sln' for '{@sln_config}'
create dirs 'Output/Appstore/Artifacts'
copy 'BuildSample/BuildSample/Output/BuildSample-{@version}.ipa' to 'Output/Appstore/Artifacts'
copy 'BuildSample/BuildSample/Output/{@assembly_name}-{@version}.ipa' to 'Output/Appstore/Artifacts'
sh cp -a BuildSample/BuildSample/Output/ Output/Appstore/
publish 'Output/Appstore/Artifacts/BuildSample-{@version}.ipa' to testflight notes = 'Hello' api_token = '{@tf_api_token}' team_token = '{@tf_team_token}'
publish 'Output/Appstore/Artifacts/{@assembly_name}-{@version}.ipa' to testflight notes = 'Hello' api_token = '{@tf_api_token}' team_token = '{@tf_team_token}'
restore from backup
delete backup
#restore from backup
#delete backup

View File

@ -1,6 +1,9 @@
class CommentRemover:
from Core.LineConveyor.PreprocessorBase import PreprocessorBase
class CommentRemover(PreprocessorBase):
def __init__(self):
pass
PreprocessorBase.__init__(self)
def processText(self, line, conveyorProcessor):
assert line is not None

View File

@ -1,5 +1,10 @@
class MacroResolver:
from Core.LineConveyor.PreprocessorBase import PreprocessorBase
class MacroResolver(PreprocessorBase):
def __init__(self, macroProcessor, valueProvider):
PreprocessorBase.__init__(self)
assert macroProcessor is not None
assert valueProvider is not None

View File

@ -0,0 +1,9 @@
from Core.LineConveyor.PreprocessorBase import PreprocessorBase
class NullPreprocessor(PreprocessorBase):
def __init__(self):
PreprocessorBase.__init__(self)
def processText(self, text, conveyorProcessor):
return text

View File

@ -0,0 +1,12 @@
import abc
class PreprocessorBase:
__metaclass__ = abc.ABCMeta
def __init__(self):
pass
@abc.abstractmethod
def processText(self, line, conveyorProcessor):
pass

View File

@ -1,6 +1,9 @@
class Stripper:
from Core.LineConveyor.PreprocessorBase import PreprocessorBase
class Stripper(PreprocessorBase):
def __init__(self):
pass
PreprocessorBase.__init__(self)
def processText(self, line, conveyorProcessor):
assert line is not None

View File

@ -1,5 +1,9 @@
class TextConveyorPreprocessor:
from Core.LineConveyor.PreprocessorBase import PreprocessorBase
class TextConveyorPreprocessor(PreprocessorBase):
def __init__(self):
PreprocessorBase.__init__(self)
self.processors = []
def addProcessor(self, processor):

View File

@ -1,5 +1,10 @@
class TextInclude:
from Core.LineConveyor.PreprocessorBase import PreprocessorBase
class TextInclude(PreprocessorBase):
def __init__(self, includeProcessor, contentProvider):
PreprocessorBase.__init__(self)
assert includeProcessor is not None
assert contentProvider is not None

View File

@ -8,12 +8,12 @@ class TestCommentRemover(unittest.TestCase):
def test_startsWithComment(self):
line = '# this line is comment'
newLine = self.commentRemover.processText(line, self.commentRemover)
newLine = self.commentRemover.processText(line, None)
self.assertEqual('', newLine)
def test_containsComment(self):
line = 'this line contains # a comment'
newLine = self.commentRemover.processText(line, self.commentRemover)
newLine = self.commentRemover.processText(line, None)
self.assertEqual('this line contains ', newLine)

View File

@ -0,0 +1 @@
__author__ = 'rzaitov'

View File

@ -0,0 +1,111 @@
import unittest
from parsers.SettingsParser.SettingsMerger import SettingsMerger
class TestSettingsMerger(unittest.TestCase):
def setUp(self):
self.merger = SettingsMerger()
self.child1 = {
'sub_key1': 'value3',
'sub_key2': 'value4',
}
self.child2 = {
'sub_key3': 'value5',
'sub_key4': 'value6',
}
self.globalSettings = {
'top_level_key1': 'value1',
'top_level_key2': 'value2',
'child1': self.child1,
'child2': self.child2
}
def test_mergeTopLevelSettings(self):
description = {
'segments': ['top_level_key1'],
'value': 'new_value1'
}
self.merger.merge(self.globalSettings, description)
self.assertEqual('new_value1', self.globalSettings['top_level_key1'])
self.assertEqual('value2', self.globalSettings['top_level_key2'])
def test_mergeSubElement(self):
description = {
'segments': ['child1', 'sub_key1'],
'value': 'new_value3'
}
self.merger.merge(self.globalSettings, description)
self.assertEqual('value1', self.globalSettings['top_level_key1'])
self.assertEqual('value2', self.globalSettings['top_level_key2'])
self.assertEqual('new_value3', self.globalSettings['child1']['sub_key1'])
self.assertEqual('value4', self.globalSettings['child1']['sub_key2'])
def test_getPropertyName(self):
self.checkName(['one', 'two', 'three'], 'three')
self.checkName(['one', 'two'], 'two')
self.checkName(['one'], 'one')
def checkName(self, segments, expectedName):
name = self.merger.getPropertyName(segments)
self.assertEqual(name, expectedName)
def test_checkPath(self):
self.checkPath(['one', 'two', 'three'], ['one', 'two'])
self.checkPath(['one', 'two'], ['one'])
self.checkPath(['one'], [])
def checkPath(self, segments, expectedPath):
path = self.merger.getPath(segments)
self.assertListEqual(expectedPath, path)
def test_mergeNotExistTopLevelSetting(self):
description = {
'segments': ['new_key'],
'value': 'new_value'
}
self.merger.merge(self.globalSettings, description)
self.assertEqual('new_value', self.globalSettings['new_key'])
def test_mergeNotExistSubSetting(self):
description = {
'segments': ['child1', 'new_key'],
'value': 'new_value'
}
self.merger.merge(self.globalSettings, description)
self.assertEqual('new_value', self.globalSettings['child1']['new_key'])
def test_mergeNotExistSub(self):
description = {
'segments': ['child3', 'new_key'],
'value': 'new_value'
}
self.merger.merge(self.globalSettings, description)
self.assertEqual('new_value', self.globalSettings['child3']['new_key'])
def test_getSettingsDictionaryByPath(self):
dictionary1 = self.merger.getSettingsDictByPath(self.globalSettings, [])
self.assertEqual(self.globalSettings, dictionary1)
self.assertTrue(self.globalSettings == dictionary1)
dictionary2 = self.merger.getSettingsDictByPath(self.globalSettings, ['child1'])
self.assertTrue(self.child1 == dictionary2)
dictionary3 = self.merger.getSettingsDictByPath(self.globalSettings, ['child2'])
self.assertTrue(self.child2 == dictionary3)

View File

@ -1,11 +1,14 @@
# -*- coding: utf-8 -*-
import unittest
from Core.LineConveyor.NullPreprocessor import NullPreprocessor
from parsers.SettingsParser.SettingsParser import SettingsParser
class TestSettingsParser(unittest.TestCase):
def setUp(self):
self.parser = SettingsParser()
self.preprocessor = NullPreprocessor()
self.parser = SettingsParser(self.preprocessor)
def test_processLine(self):
line1 = "x.y.name1 = 'value1'"
@ -38,15 +41,16 @@ class TestSettingsParser(unittest.TestCase):
self.assertEqual('value8', self.parser.settings['a']['z']['name2'])
def test_emptyLinesAndComments(self):
class PartialSettingsParser(SettingsParser):
def __init__(self):
SettingsParser.__init__(self)
def __init__(self, textPreprocessor):
SettingsParser.__init__(self, textPreprocessor)
self.processLineCall = 0
def processLine(self, line):
self.processLineCall += 1
self.parser = PartialSettingsParser()
self.parser = PartialSettingsParser(self.preprocessor)
content = """
valid.line.with.setting = 'some value'
# this is comment
@ -56,7 +60,9 @@ valid.line.with.setting = 'some value'
self.parser.parse(content)
self.assertEqual(2, self.parser.processLineCall)
# всего 6 строк, 2 из которых пустые
# NullPreprocessor не уберет комментарии, поэтому будет 4 вызова processLine
self.assertEqual(4, self.parser.processLineCall)

View File

@ -6,12 +6,10 @@ class SettingsMerger:
value = settingDescription['value']
segments = settingDescription['segments']
propPath = segments[0:-1]
propName = segments[-1]
propPath = self.getPath(segments)
propName = self.getPropertyName(segments)
settingsDict = self.getSettingsDictByPath(globalSettings, propPath)
#self.overrideGuard(settingsDict, propName, propPath)
settingsDict[propName] = value
def getSettingsDictByPath(self, globalSettings, pathToSettingsDict):
@ -26,10 +24,10 @@ class SettingsMerger:
return settingsDict
#def overrideGuard(self, dictionary, key, path):
# if key in dictionary:
# pathStr = '.'.join(path)
# msg = 'settings with name {0} by path {1} already exists with value {3}'.format(key, dictionary[key], pathStr)
# raise Exception(msg)
def getPath(self, segments):
assert segments is not None
return segments[0:-1]
def getPropertyName(self, segments):
assert segments is not None
return segments[-1]

View File

@ -3,10 +3,14 @@ from parsers.SettingsParser.SettingsMerger import SettingsMerger
class SettingsParser:
def __init__(self, settings=None):
self.settings = settings
def __init__(self, compositeLineProcessor, settings):
assert compositeLineProcessor is not None
assert settings is None or type(settings) == dict
if not self.settings:
self.compositeLineProcessor = compositeLineProcessor
self.settings = settings
if self.settings is None:
self.settings = {}
def parse(self, content):
@ -14,14 +18,12 @@ class SettingsParser:
lines = content.splitlines()
for line in lines:
stripped = line.strip(' \t\n\r')
processedLine = self.compositeLineProcessor.processText(line, None)
if len(stripped) == 0:
if len(processedLine) == 0:
continue
if stripped.startswith("#"):
continue
self.processLine(stripped)
else:
self.processLine(processedLine)
def processLine(self, line):
assert line is not None

View File

@ -26,17 +26,17 @@ scriptDir = os.path.dirname(scriptFilePath)
class TaskRunner:
def __init__(self, settingsProvider, fileContentProvider, buildConfigProvider):
def __init__(self, settingsProvider, fileContentProvider, buildConfigProvider, linePreprocessor):
assert settingsProvider is not None
assert fileContentProvider is not None
assert buildConfigProvider is not None
assert linePreprocessor is not None
self.settingsProvider = settingsProvider
self.fileContentProvider = fileContentProvider
self.configsProvider = buildConfigProvider
self.linePreprocessor = linePreprocessor
lineStripper = Stripper()
commentRemover = CommentRemover()
macroProcessor = MacroProcessor()
self.valueProvider = ValueProvider()
@ -52,9 +52,6 @@ class TaskRunner:
self.textPreprocessor.addProcessor(macroResolver)
self.textPreprocessor.addProcessor(textInclude)
self.linePreprocessor = TextConveyorPreprocessor()
self.linePreprocessor.addProcessor(commentRemover)
self.linePreprocessor.addProcessor(lineStripper)
def run(self):
rawSettings = self.settingsProvider.fetchSettings()
@ -83,9 +80,17 @@ if __name__ == "__main__":
parser = argparse.ArgumentParser()
overrideArgs = parser.parse_known_args()[1]
# компоную препроцессор для индивидуальной обработки строк (удаление комментариев и ведущих пробельных символов)
lineStripper = Stripper()
commentRemover = CommentRemover()
linePreprocessor = TextConveyorPreprocessor()
linePreprocessor.addProcessor(commentRemover)
linePreprocessor.addProcessor(lineStripper)
# TODO: перенести в корень комапановки
fromFileSettingsProvider = FromFileSettingsProvider()
overrideWithCmdSetProvider = CmdArgsOverriderSettingsProvider(fromFileSettingsProvider, overrideArgs)
settingsPath = 'scripts/settings.txt'
fromFileSettingsProvider = FromFileSettingsProvider(settingsPath, linePreprocessor)
overrideWithCmdSetProvider = CmdArgsOverriderSettingsProvider(fromFileSettingsProvider, overrideArgs, linePreprocessor)
fContentProvider = FileContentProvider()
@ -96,5 +101,5 @@ if __name__ == "__main__":
resolvedBuildConfigProvider = ResolvedBuildConfigProvider(predefineBuildConfigProvider)
runner = TaskRunner(overrideWithCmdSetProvider, fContentProvider, resolvedBuildConfigProvider)
runner = TaskRunner(overrideWithCmdSetProvider, fContentProvider, resolvedBuildConfigProvider, linePreprocessor)
runner.run()

View File

@ -3,12 +3,14 @@ from parsers.SettingsParser.SettingsParser import SettingsParser
class CmdArgsOverriderSettingsProvider(SettingsProviderBase):
def __init__(self, settingsProvider, settingLines):
def __init__(self, settingsProvider, settingLines, compositeLineProcessor):
SettingsProviderBase.__init__(self)
assert settingsProvider is not None
assert compositeLineProcessor is not None
self.inner = settingsProvider
self.overrideSettings = settingLines
self.compositeLineProcessor = compositeLineProcessor
def fetchSettings(self):
settings = self.inner.fetchSettings()
@ -16,7 +18,7 @@ class CmdArgsOverriderSettingsProvider(SettingsProviderBase):
if self.overrideSettings:
for s in self.overrideSettings:
line = self.normalizeLine(s)
settingParser = SettingsParser(settings)
settingParser = SettingsParser(self.compositeLineProcessor, settings)
settingParser.processLine(line)
return settings

View File

@ -3,14 +3,20 @@ from parsers.SettingsParser.SettingsParser import SettingsParser
class FromFileSettingsProvider(SettingsProviderBase):
def __init__(self):
def __init__(self, pathToSettings, compositeLineProcessor):
SettingsProviderBase.__init__(self)
assert pathToSettings is not None
assert compositeLineProcessor is not None
self.pathToSettings = pathToSettings
self.compositeLineProcessor = compositeLineProcessor
def fetchSettings(self):
settingsFile = open('scripts/settings.txt')
settingsFile = open(self.pathToSettings)
content = settingsFile.read()
parser = SettingsParser()
parser = SettingsParser(self.compositeLineProcessor, None)
parser.parse(content)
return parser.settings

View File

@ -1,12 +1,13 @@
# global settings
build_tool = '/Applications/Xamarin\ Studio.app/Contents/MacOS/mdtool'
version = '0.0.0'
version = '0.0.0' # комментарий в тойже строке
configs = 'appstore, staging'
# ios platform settings
ios.sln_config = 'Release|iPhone'
ios.steps = 'scripts/IosSteps.txt'
ios.setup_steps = 'IosSetupSteps.txt'
ios.assembly_name = 'CoolApp'
ios.tf_api_token = '0e6925075d4fc10fed0e7bbf43fa6894_NjQ0OTI2MjAxMi0wOS0yNSAxMTo0MDozNi40OTY5MjU'
ios.tf_team_token = 'c5c3cf7a6dae2bea4382dfbd181a2075_Mjc4ODkwMjAxMy0wOS0yOSAxNDowOTo1OC40Mzg5MTY'