From 93fff46485ad4036f510a8f2d740a294f28d9106 Mon Sep 17 00:00:00 2001 From: Rustam Zaitov Date: Thu, 3 Oct 2013 14:31:21 +0400 Subject: [PATCH] =?UTF-8?q?=D0=9D=D0=B0=D0=B2=D0=B5=D0=BB=20=D0=BF=D0=BE?= =?UTF-8?q?=D1=80=D1=8F=D0=B4=D0=BE=D0=BA=20=D1=81=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D1=80=D0=B0=D0=BD=D1=81=D1=82=D0=B2=D0=B0=D0=BC?= =?UTF-8?q?=D0=B8=20=D0=B8=D0=BC=D0=B5=D0=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../remove_project_sections_from_test.py | 10 +-- scripts/{ => commands}/build_command.py | 0 scripts/commands/patch_infoplist_command.py | 64 +++++++++++++++++++ scripts/commands/testflight_command.py | 29 +-------- scripts/instruments.py | 4 +- scripts/patch.py | 5 +- scripts/plist_patch.py | 49 -------------- scripts/testflight.py | 36 ----------- scripts/utils/PathConverter/__init__.py | 1 + scripts/utils/PathConverter/converter_base.py | 6 ++ scripts/utils/PathConverter/path_converter.py | 10 +++ scripts/utils/__init__.py | 1 + scripts/utils/infoplist/__init__.py | 1 + scripts/utils/infoplist/patcher.py | 57 +++++++++++++++++ scripts/utils/sln/__init__.py | 1 + scripts/{ => utils/sln}/sln_toolkit.py | 11 +--- scripts/utils/sln/sln_toolkit_base.py | 11 ++++ scripts/utils/testflight/__init__.py | 1 + .../utils/testflight/testflight_publisher.py | 22 +++++++ .../testflight/testflight_publisher_base.py | 17 +++++ 20 files changed, 205 insertions(+), 131 deletions(-) rename scripts/{ => commands}/build_command.py (100%) create mode 100644 scripts/commands/patch_infoplist_command.py delete mode 100644 scripts/plist_patch.py delete mode 100644 scripts/testflight.py create mode 100644 scripts/utils/PathConverter/__init__.py create mode 100644 scripts/utils/PathConverter/converter_base.py create mode 100644 scripts/utils/PathConverter/path_converter.py create mode 100644 scripts/utils/__init__.py create mode 100644 scripts/utils/infoplist/__init__.py create mode 100644 scripts/utils/infoplist/patcher.py create mode 100644 scripts/utils/sln/__init__.py rename scripts/{ => utils/sln}/sln_toolkit.py (63%) create mode 100644 scripts/utils/sln/sln_toolkit_base.py create mode 100644 scripts/utils/testflight/__init__.py create mode 100644 scripts/utils/testflight/testflight_publisher.py create mode 100644 scripts/utils/testflight/testflight_publisher_base.py diff --git a/scripts/UnitTests/SolutionToolkit/remove_project_sections_from_test.py b/scripts/UnitTests/SolutionToolkit/remove_project_sections_from_test.py index f0e8bfb..3a3cc14 100644 --- a/scripts/UnitTests/SolutionToolkit/remove_project_sections_from_test.py +++ b/scripts/UnitTests/SolutionToolkit/remove_project_sections_from_test.py @@ -1,7 +1,6 @@ import unittest -import sys -sys.path.append('../../') -import sln_toolkit as sln +from utils.sln import sln_toolkit_base as sln + class TestRemoveProjectSections(unittest.TestCase): @@ -42,7 +41,4 @@ Global Debug|iPhone = Debug|iPhone Release|iPhone = Release|iPhone EndGlobalSection -""" - -if __name__ == '__main__': - unittest.main() \ No newline at end of file +""" \ No newline at end of file diff --git a/scripts/build_command.py b/scripts/commands/build_command.py similarity index 100% rename from scripts/build_command.py rename to scripts/commands/build_command.py diff --git a/scripts/commands/patch_infoplist_command.py b/scripts/commands/patch_infoplist_command.py new file mode 100644 index 0000000..bf3d248 --- /dev/null +++ b/scripts/commands/patch_infoplist_command.py @@ -0,0 +1,64 @@ +import commands.build_command as bcmd +import utils.PathConverter.path_converter as pc +import utils.infoplist.patcher as plist + + +class PatchInfoPlist(bcmd.BuildCommand): + _command_prefix = 'info_plist_' + _cmd_prefix_len = len(_command_prefix) + + def __init__(self, config): + self._config = config + self._info_plist_rel_path = None + self._plist_dict = {} + + self.ParseConfig() + + def ParseConfig(self): + self.FetchInfoPlistPath() + self.FetchAllParams() + + def FetchInfoPlistPath(self): + self._info_plist_rel_path = self._config['info_plist_rel_path'] + + def FetchAllParams(self): + all_conf_keys = self.FetchAllConfigKeys() + + for k in all_conf_keys: + self.AddValueFor(k) + + def FetchAllConfigKeys(self): + all_keys = [] + for k in self._config.keys(): + if k.startswith(PatchInfoPlist._command_prefix) and not k.endswith('rel_path'): + all_keys.append(k) + + return all_keys + + def AddValueFor(self, conf_key): + value_token = self._config[conf_key] + value = self.ParseValueToken(value_token) + + k = self.ParsePlistKeyFrom(conf_key) + self._plist_dict[k] = value + + def ParseValueToken(self, value_token): + value = value_token + + if value_token.startswith('@'): + key = value_token[1:] + value = self._config[key] + + return value + + def ParsePlistKeyFrom(self, config_key): + return config_key[PatchInfoPlist._cmd_prefix_len:] + + def Execute(self): + sln_path = self._config['sln_path'] + pConverter = pc.PathConverter(sln_path) + + info_plist_abs_path = pConverter.Convert(self._info_plist_rel_path) + patcher = plist.Patcher(info_plist_abs_path) + + patcher.AddOrReplace(self._plist_dict) diff --git a/scripts/commands/testflight_command.py b/scripts/commands/testflight_command.py index 9a279b8..dd4c40d 100644 --- a/scripts/commands/testflight_command.py +++ b/scripts/commands/testflight_command.py @@ -1,33 +1,10 @@ -import os -import inspect -cur_abs_dir_path = os.path.abspath(os.path.split(inspect.getfile(inspect.currentframe()))[0]) -print('testflight_command', cur_abs_dir_path) +import commands.build_command as bcmd +import utils.testflight.testflight_publisher as tf -import sys -parent = os.path.split(cur_abs_dir_path)[0] -if parent not in sys.path: - sys.path.append(parent) - -import build_command as bcmd -import testflight as tf class PublishToTestFlightCommand(bcmd.BuildCommand): def __init__(self, api_token, team_token, notes): self._publisher = tf.TestFlightPublisherBase(api_token, team_token, notes) def Execute(self): - self._publisher.Publish() - -if __name__ == '__main__': - import argparse - - parser = argparse.ArgumentParser() - parser.add_argument('path') - parser.add_argument('-at', '--api_token', required=True, help='api token') - parser.add_argument('-tt', '--team_token', required=True, help='team token') - parser.add_argument('-n', '--notes', default=tf.TestFlightPublisherBase.DefaultNotes, help='upload notes') - - args = parser.parse_args() - - cmd = PublishToTestFlightCommand(args.api_token, args.team_token, args.notes) - cmd.Execute() \ No newline at end of file + self._publisher.Publish() \ No newline at end of file diff --git a/scripts/instruments.py b/scripts/instruments.py index 632de4c..a3df072 100644 --- a/scripts/instruments.py +++ b/scripts/instruments.py @@ -1,8 +1,8 @@ from subprocess import call import shutil import os -import re -import sln_toolkit as sln +from utils.sln import sln_toolkit as sln + def MapToBackupName(origin_path): diff --git a/scripts/patch.py b/scripts/patch.py index 38d9016..07e5465 100644 --- a/scripts/patch.py +++ b/scripts/patch.py @@ -1,6 +1,6 @@ import re import os -import plist_patch as plist +import utils.infoplist.patcher as plist def RewriteFile(file_to_rewrite, content): file_to_rewrite.seek(0) @@ -26,7 +26,8 @@ def PatchInfoPlist(build_config): abs_info_plist_path = os.path.join(sln_dir, build_config['info_plist_rel_path']) key_values = {'CFBundleVersion' : build_config['version']} - plist.AppendOrReplace(key_values, abs_info_plist_path) + patcher = plist.Patcher(abs_info_plist_path) + patcher.AddOrReplace(key_values) def PathcIos(build_config): diff --git a/scripts/plist_patch.py b/scripts/plist_patch.py deleted file mode 100644 index b034937..0000000 --- a/scripts/plist_patch.py +++ /dev/null @@ -1,49 +0,0 @@ -import xml.etree.ElementTree as ET - -def AppendKeyValue(key_name, value, dict_element): - key_element = ET.Element('key') - key_element.text = key_name - - value_element = ET.Element('string') - value_element.text = value - - dict_element.append(key_element) - dict_element.append(value_element) - -def ReplaceValueByKeyIndex(key_element_index, value, dict_element): - value_index = key_element_index + 1 - value_element = dict_element[value_index] - value_element.text = value - -def FindIndexByKey(key_name, dict_element): - all_keys_elements = dict_element.findall('key') - - is_exists = False - index = 0 - - for e in all_keys_elements: - if e.text == key_name: - is_exists = True - break - index += 1 - - element_index = index * 2 - return element_index if is_exists else -1 - -def AppendOrReplaceValueByKey(key_name, value, dict_element): - key_index = FindIndexByKey(key_name, dict_element) - element_exists = key_index >= 0 - - if element_exists: - ReplaceValueByKeyIndex(key_index, value, dict_element) - else: - AppendKeyValue(key_name, value, dict_element) - -def AppendOrReplace(key_value_dict, abs_plist_path): - tree = ET.parse(abs_plist_path) - plist_dict = tree.getroot().find('dict') - - for key_name in key_value_dict: - AppendOrReplaceValueByKey(key_name, key_value_dict[key_name], plist_dict) - - tree.write(abs_plist_path) \ No newline at end of file diff --git a/scripts/testflight.py b/scripts/testflight.py deleted file mode 100644 index 980f960..0000000 --- a/scripts/testflight.py +++ /dev/null @@ -1,36 +0,0 @@ -from subprocess import call -import os - -class TestFlightPublisherBase: - DefaultNotes = 'This build was uploaded via the upload API' - - def __init__(self, api_token, team_token, notes=DefaultNotes): - self._api_token = api_token - self._team_token = team_token - self._notes = notes - - def Publish(self, pathToFile): - cmd_text_pattern = "curl http://testflightapp.com/api/builds.json -F file=@'{0}' -F api_token='{1}' -F team_token='{2}' -F notes='{3}'" - cmd_text = cmd_text_pattern.format(pathToFile, self._api_token, self._team_token, self._notes) - - ret_code = call(cmd_text, shell=True) - return ret_code - -class TestFlightPublisher(TestFlightPublisherBase): - def __init__(self, config): - self._config = config - - api_token = config['tf_api_token'] - team_token = config['tf_team_token'] - notes = config.get('ft_notes', None) - - TestFlightPublisherBase.__init__(self, api_token, team_token, notes) - - def Publish(self): - sln_path = self._config['sln_path'] - sln_dir = os.path.dirname(sln_path) - - ipa_rel_path = 'BuildSample/bin/iPhone/Release/BuildSample-{0}.ipa'.format(self._config['version']) - ipa_abs_path = os.path.join(sln_dir, ipa_rel_path) - - return TestFlightPublisherBase.Publish(self, ipa_abs_path) \ No newline at end of file diff --git a/scripts/utils/PathConverter/__init__.py b/scripts/utils/PathConverter/__init__.py new file mode 100644 index 0000000..cc31abc --- /dev/null +++ b/scripts/utils/PathConverter/__init__.py @@ -0,0 +1 @@ +__author__ = 'rzaitov' diff --git a/scripts/utils/PathConverter/converter_base.py b/scripts/utils/PathConverter/converter_base.py new file mode 100644 index 0000000..f070b93 --- /dev/null +++ b/scripts/utils/PathConverter/converter_base.py @@ -0,0 +1,6 @@ + + +class ConverterBase: + + def Convert(self, rel_path): + return None diff --git a/scripts/utils/PathConverter/path_converter.py b/scripts/utils/PathConverter/path_converter.py new file mode 100644 index 0000000..d7397cd --- /dev/null +++ b/scripts/utils/PathConverter/path_converter.py @@ -0,0 +1,10 @@ +import utils.PathConverter.converter_base as cB +import os + + +class PathConverter(cB.ConverterBase): + def __init__(self, sln_path): + self._sln_dir = os.path.dirname(sln_path) + + def Convert(self, rel_path): + return os.path.join(self._sln_dir, rel_path) \ No newline at end of file diff --git a/scripts/utils/__init__.py b/scripts/utils/__init__.py new file mode 100644 index 0000000..cc31abc --- /dev/null +++ b/scripts/utils/__init__.py @@ -0,0 +1 @@ +__author__ = 'rzaitov' diff --git a/scripts/utils/infoplist/__init__.py b/scripts/utils/infoplist/__init__.py new file mode 100644 index 0000000..cc31abc --- /dev/null +++ b/scripts/utils/infoplist/__init__.py @@ -0,0 +1 @@ +__author__ = 'rzaitov' diff --git a/scripts/utils/infoplist/patcher.py b/scripts/utils/infoplist/patcher.py new file mode 100644 index 0000000..a216d2a --- /dev/null +++ b/scripts/utils/infoplist/patcher.py @@ -0,0 +1,57 @@ +import xml.etree.ElementTree as eT + + +class Patcher(): + def __init__(self, abs_plist_path): + self._abs_plist_path = abs_plist_path + + def AddOrReplace(self, key_value_dict): + tree = eT.parse(self._abs_plist_path) + plist_dict = tree.getroot().find('dict') + + for key_name in key_value_dict: + self.AppendOrReplaceValueByKey(key_name, key_value_dict[key_name], plist_dict) + + tree.write(self._abs_plist_path) + + def AppendOrReplaceValueByKey(self, key_name, value, dict_element): + key_index = self.FindIndexByKey(key_name, dict_element) + element_exists = key_index >= 0 + + if element_exists: + self.ReplaceValueByKeyIndex(key_index, value, dict_element) + else: + self.AppendKeyValue(key_name, value, dict_element) + + def FindIndexByKey(self, key_name, dict_element): + all_keys_elements = dict_element.findall('key') + + is_exists = False + index = 0 + + for e in all_keys_elements: + if e.text == key_name: + is_exists = True + break + index += 1 + + element_index = index * 2 + return element_index if is_exists else -1 + + def ReplaceValueByKeyIndex(self, key_element_index, value, dict_element): + value_index = key_element_index + 1 + value_element = dict_element[value_index] + value_element.text = value + + def AppendKeyValue(self, key_name, value, dict_element): + key_element = eT.Element('key') + key_element.text = key_name + + value_element = eT.Element('string') + value_element.text = value + + dict_element.append(key_element) + dict_element.append(value_element) + + + diff --git a/scripts/utils/sln/__init__.py b/scripts/utils/sln/__init__.py new file mode 100644 index 0000000..cc31abc --- /dev/null +++ b/scripts/utils/sln/__init__.py @@ -0,0 +1 @@ +__author__ = 'rzaitov' diff --git a/scripts/sln_toolkit.py b/scripts/utils/sln/sln_toolkit.py similarity index 63% rename from scripts/sln_toolkit.py rename to scripts/utils/sln/sln_toolkit.py index 9aa121f..65d30ac 100644 --- a/scripts/sln_toolkit.py +++ b/scripts/utils/sln/sln_toolkit.py @@ -1,14 +1,7 @@ -import re +import utils.sln.sln_toolkit_base as sln -class SolutionToolkitBase: - def RemoveProjectSectionsFrom(self, sln_file_content, project_names): - for pn in project_names: - reg_pattern = r'\n*Project.*?"{0}".*?\n*EndProject'.format(pn) - sln_file_content = re.sub(reg_pattern, "", sln_file_content) - return sln_file_content - -class SolutionToolkit(SolutionToolkitBase): +class SolutionToolkit(sln.SolutionToolkitBase): def __init__(self, pathToSlnFile): self._sln_path = pathToSlnFile self._sln_file = None diff --git a/scripts/utils/sln/sln_toolkit_base.py b/scripts/utils/sln/sln_toolkit_base.py new file mode 100644 index 0000000..abfeab6 --- /dev/null +++ b/scripts/utils/sln/sln_toolkit_base.py @@ -0,0 +1,11 @@ +import re + + +class SolutionToolkitBase: + def RemoveProjectSectionsFrom(self, sln_file_content, project_names): + for pn in project_names: + reg_pattern = r'\n*Project.*?"{0}".*?\n*EndProject'.format(pn) + sln_file_content = re.sub(reg_pattern, "", sln_file_content) + + return sln_file_content + diff --git a/scripts/utils/testflight/__init__.py b/scripts/utils/testflight/__init__.py new file mode 100644 index 0000000..cc31abc --- /dev/null +++ b/scripts/utils/testflight/__init__.py @@ -0,0 +1 @@ +__author__ = 'rzaitov' diff --git a/scripts/utils/testflight/testflight_publisher.py b/scripts/utils/testflight/testflight_publisher.py new file mode 100644 index 0000000..0e5ac12 --- /dev/null +++ b/scripts/utils/testflight/testflight_publisher.py @@ -0,0 +1,22 @@ +import os +from utils import testflight as tf + + +class TestFlightPublisher(tf.TestFlightPublisherBase): + def __init__(self, config): + self._config = config + + api_token = config['tf_api_token'] + team_token = config['tf_team_token'] + notes = config.get('ft_notes', None) + + tf.TestFlightPublisherBase.__init__(self, api_token, team_token, notes) + + def Publish(self): + sln_path = self._config['sln_path'] + sln_dir = os.path.dirname(sln_path) + + ipa_rel_path = 'BuildSample/bin/iPhone/Release/BuildSample-{0}.ipa'.format(self._config['version']) + ipa_abs_path = os.path.join(sln_dir, ipa_rel_path) + + return tf.TestFlightPublisherBase.Publish(self, ipa_abs_path) \ No newline at end of file diff --git a/scripts/utils/testflight/testflight_publisher_base.py b/scripts/utils/testflight/testflight_publisher_base.py new file mode 100644 index 0000000..7a74568 --- /dev/null +++ b/scripts/utils/testflight/testflight_publisher_base.py @@ -0,0 +1,17 @@ +from subprocess import call + + +class TestFlightPublisherBase: + DefaultNotes = 'This build was uploaded via the upload API' + + def __init__(self, api_token, team_token, notes=DefaultNotes): + self._api_token = api_token + self._team_token = team_token + self._notes = notes + + def Publish(self, pathToFile): + cmd_text_pattern = "curl http://testflightapp.com/api/builds.json -F file=@'{0}' -F api_token='{1}' -F team_token='{2}' -F notes='{3}'" + cmd_text = cmd_text_pattern.format(pathToFile, self._api_token, self._team_token, self._notes) + + ret_code = call(cmd_text, shell=True) + return ret_code \ No newline at end of file