Merge branch 'BS-38'
This commit is contained in:
commit
9fd63b8bfa
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import abc
|
||||
|
||||
|
||||
class PreprocessorBase:
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def processText(self, line, conveyorProcessor):
|
||||
pass
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -0,0 +1 @@
|
|||
__author__ = 'rzaitov'
|
||||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
Loading…
Reference in New Issue