solara 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/solara/lib/core/.DS_Store +0 -0
- data/solara/lib/core/aliases/alias_generator.rb +1 -0
- data/solara/lib/core/aliases/alias_generator_manager.rb +2 -1
- data/solara/lib/core/aliases/solara_terminal_setup.rb +1 -1
- data/solara/lib/core/brands/brand_font_switcher.rb +154 -0
- data/solara/lib/core/brands/brand_onboarder.rb +8 -6
- data/solara/lib/core/brands/brand_switcher.rb +232 -166
- data/solara/lib/core/brands/brands_manager.rb +15 -39
- data/solara/lib/core/dashboard/brand/BrandDetail.js +19 -0
- data/solara/lib/core/dashboard/brand/BrandDetailController.js +50 -8
- data/solara/lib/core/dashboard/brand/BrandDetailModel.js +9 -30
- data/solara/lib/core/dashboard/brand/BrandDetailView.js +49 -3
- data/solara/lib/core/dashboard/brand/InfoPlistStringCatalogManager.js +19 -0
- data/solara/lib/core/dashboard/brand/brand.html +209 -62
- data/solara/lib/core/dashboard/brand/source/BrandLocalSource.js +1 -1
- data/solara/lib/core/dashboard/brand/source/BrandRemoteSource.js +38 -53
- data/solara/lib/core/dashboard/brands/BrandsController.js +6 -5
- data/solara/lib/core/dashboard/brands/BrandsModel.js +2 -2
- data/solara/lib/core/dashboard/brands/BrandsView.js +2 -2
- data/solara/lib/core/dashboard/brands/brands.html +3 -1
- data/solara/lib/core/dashboard/component/AliasesBottomSheet.js +7 -5
- data/solara/lib/core/dashboard/dashboard_manager.rb +2 -0
- data/solara/lib/core/dashboard/dashboard_server.rb +13 -8
- data/solara/lib/core/dashboard/handler/brand_alisases_handler.rb +4 -11
- data/solara/lib/core/dashboard/handler/brand_configurations_manager.rb +11 -11
- data/solara/lib/core/dashboard/handler/{brand_configurations_handler.rb → brand_details_handler.rb} +4 -4
- data/solara/lib/core/dashboard/handler/brands_handler.rb +1 -1
- data/solara/lib/core/dashboard/handler/edit_section_handler.rb +8 -8
- data/solara/lib/core/doctor/brand_doctor.rb +31 -31
- data/solara/lib/core/doctor/doctor_manager.rb +0 -1
- data/solara/lib/core/doctor/project_doctor.rb +0 -1
- data/solara/lib/core/doctor/schema/platform/android/android_config.json +0 -4
- data/solara/lib/core/doctor/schema/platform/ios/InfoPlist.xcstrings +15 -0
- data/solara/lib/core/doctor/schema/platform/ios/ios_config.json +0 -5
- data/solara/lib/core/doctor/schema/platform/shared/brand_config.json +9 -0
- data/solara/lib/core/doctor/schema/platform/shared/theme.json +94 -9
- data/solara/lib/core/doctor/validator/brand_settings_validator.rb +6 -0
- data/solara/lib/core/doctor/validator/brand_settings_validator_manager.rb +9 -21
- data/solara/lib/core/doctor/validator/template/android_template_validation_config.yml +22 -4
- data/solara/lib/core/doctor/validator/template/flutter_template_validation_config.yml +22 -6
- data/solara/lib/core/doctor/validator/template/ios_template_validation_config.yml +22 -4
- data/solara/lib/core/scripts/brand_config_generator.rb +1 -0
- data/solara/lib/core/scripts/brand_config_manager.rb +2 -4
- data/solara/lib/core/scripts/brand_exporter.rb +1 -1
- data/solara/lib/core/scripts/brand_importer.rb +2 -3
- data/solara/lib/core/scripts/brand_offboarder.rb +5 -0
- data/solara/lib/core/scripts/brand_resources_manager.rb +127 -54
- data/solara/lib/core/scripts/directory_creator.rb +2 -2
- data/solara/lib/core/scripts/file_manager.rb +53 -19
- data/solara/lib/core/scripts/file_path.rb +175 -30
- data/solara/lib/core/scripts/folder_copier.rb +3 -7
- data/solara/lib/core/scripts/gitignore_manager.rb +21 -10
- data/solara/lib/core/scripts/interactive_file_system_validator.rb +8 -2
- data/solara/lib/core/scripts/platform/android/android_manifest_switcher.rb +3 -3
- data/solara/lib/core/scripts/platform/android/android_strings_switcher.rb +26 -24
- data/solara/lib/core/scripts/platform/android/gradle_switcher.rb +7 -6
- data/solara/lib/core/scripts/platform/ios/infoplist_string_catalog_manager.rb +123 -0
- data/solara/lib/core/scripts/platform/ios/infoplist_switcher.rb +59 -0
- data/solara/lib/core/scripts/platform/ios/ios_plist_manager.rb +11 -20
- data/solara/lib/core/scripts/platform/ios/plist_font_manager.rb +33 -0
- data/solara/lib/core/scripts/platform/ios/xcconfig_generator.rb +15 -3
- data/solara/lib/core/scripts/platform/ios/xcode_asset_manager.rb +2 -3
- data/solara/lib/core/scripts/platform/ios/xcode_project_manager.rb +80 -1
- data/solara/lib/core/scripts/platform/ios/xcode_project_switcher.rb +15 -34
- data/solara/lib/core/scripts/solara_logger.rb +10 -0
- data/solara/lib/core/scripts/solara_settings_manager.rb +26 -1
- data/solara/lib/core/scripts/strings_xml_manager.rb +17 -2
- data/solara/lib/core/scripts/theme_generator.rb +133 -130
- data/solara/lib/core/scripts/yaml_manager.rb +23 -0
- data/solara/lib/core/solara_configurator.rb +1 -1
- data/solara/lib/core/template/brands/android/android_config.json +0 -1
- data/solara/lib/core/template/brands/android/res/values/strings.xml +4 -0
- data/solara/lib/core/template/brands/ios/InfoPlist.xcstrings +30 -0
- data/solara/lib/core/template/brands/ios/ios_config.json +1 -2
- data/solara/lib/core/template/brands/shared/brand_config.json +1 -0
- data/solara/lib/core/template/brands/shared/theme.json +3 -3
- data/solara/lib/core/template/config/android_template_config.json +11 -1
- data/solara/lib/core/template/config/flutter_template_config.json +12 -2
- data/solara/lib/core/template/config/ios_template_config.json +11 -1
- data/solara/lib/core/template/project_template_generator.rb +8 -3
- data/solara/lib/solara/version.rb +1 -1
- data/solara/lib/solara.rb +8 -4
- data/solara/lib/solara_initializer.rb +5 -2
- data/solara/lib/solara_manager.rb +1 -1
- metadata +62 -43
- data/solara/lib/core/dashboard/handler/brand_section_handler.rb +0 -20
- data/solara/lib/core/doctor/validator/directory_structure_validator.rb +0 -38
- data/solara/lib/core/doctor/validator/file_structure_validator.rb +0 -37
- data/solara/lib/core/scripts/platform/ios/ios_file_path_manager.rb +0 -109
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/.DS_Store +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/100.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/102.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/1024.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/114.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/120.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/128.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/144.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/152.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/16.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/167.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/172.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/180.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/196.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/20.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/216.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/256.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/29.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/32.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/40.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/48.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/50.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/512.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/55.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/57.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/58.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/60.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/64.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/66.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/72.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/76.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/80.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/87.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/88.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/92.png +0 -0
- /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/Contents.json +0 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
$LOAD_PATH.unshift(File.expand_path(__dir__))
|
|
2
|
+
|
|
3
|
+
class InfoPlistSwitcher
|
|
4
|
+
def initialize(project_path, brand_key)
|
|
5
|
+
@project_path = project_path
|
|
6
|
+
@brand_key = brand_key
|
|
7
|
+
@project = Xcodeproj::Project.open(@project_path)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def switch
|
|
11
|
+
copy_string_catalog
|
|
12
|
+
update_info_plist
|
|
13
|
+
@project.save
|
|
14
|
+
Solara.logger.debug("Switched #{FilePath.info_plist} successfully.")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def copy_string_catalog
|
|
20
|
+
# Remove from project before copying
|
|
21
|
+
project_infoplist_string_catalog = FilePath.project_infoplist_string_catalog
|
|
22
|
+
if File.exist?(project_infoplist_string_catalog)
|
|
23
|
+
FileManager.delete_if_exists(project_infoplist_string_catalog)
|
|
24
|
+
Solara.logger.debug("Deleted #{project_infoplist_string_catalog} successfully.")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
source = FilePath.brand_infoplist_string_catalog(@brand_key)
|
|
28
|
+
destination = FilePath.project_info_plist_directory
|
|
29
|
+
FolderCopier.new(source, destination).copy
|
|
30
|
+
|
|
31
|
+
# Add reference to XcodeProject
|
|
32
|
+
XcodeProjectManager.add_file_near_info_plist(@project, project_infoplist_string_catalog)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def update_info_plist
|
|
36
|
+
info_plist_path = FilePath.info_plist
|
|
37
|
+
manager = IOSPlistManager.new(@project, info_plist_path)
|
|
38
|
+
manager.set_info_plist_in_build_settings
|
|
39
|
+
|
|
40
|
+
xcconfig_values = {
|
|
41
|
+
'CFBUNDLE_DISPLAY_NAME' => "$(CFBUNDLE_DISPLAY_NAME)",
|
|
42
|
+
'CFBUNDLE_NAME' => "$(CFBUNDLE_NAME)",
|
|
43
|
+
'PRODUCT_NAME' => "$(PRODUCT_NAME)",
|
|
44
|
+
'PRODUCT_BUNDLE_IDENTIFIER' => "$(PRODUCT_BUNDLE_IDENTIFIER)",
|
|
45
|
+
'MARKETING_VERSION' => "$(MARKETING_VERSION)",
|
|
46
|
+
'BUNDLE_VERSION' => "$(BUNDLE_VERSION)"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
info_plist = Xcodeproj::Plist.read_from_path(info_plist_path)
|
|
50
|
+
info_plist[InfoPListKey::BUNDLE_DISPLAY_NAME] = xcconfig_values['CFBUNDLE_DISPLAY_NAME']
|
|
51
|
+
info_plist[InfoPListKey::BUNDLE_NAME] = xcconfig_values['CFBUNDLE_NAME']
|
|
52
|
+
info_plist['CFBundleIdentifier'] = xcconfig_values['PRODUCT_BUNDLE_IDENTIFIER']
|
|
53
|
+
info_plist['CFBundleShortVersionString'] = xcconfig_values['MARKETING_VERSION']
|
|
54
|
+
info_plist['CFBundleVersion'] = xcconfig_values['BUNDLE_VERSION']
|
|
55
|
+
|
|
56
|
+
Xcodeproj::Plist.write_to_path(info_plist, info_plist_path)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'xcodeproj'
|
|
2
|
+
require 'plist'
|
|
2
3
|
|
|
3
4
|
class IOSPlistManager
|
|
4
5
|
def initialize(project, info_plist_path)
|
|
@@ -6,31 +7,20 @@ class IOSPlistManager
|
|
|
6
7
|
@info_plist_path = info_plist_path
|
|
7
8
|
end
|
|
8
9
|
|
|
9
|
-
def create_and_add_info_plist
|
|
10
|
-
# add_info_plist_to_project
|
|
11
|
-
set_info_plist_in_build_settings
|
|
12
|
-
save_project
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
private
|
|
16
|
-
|
|
17
|
-
def add_info_plist_to_project
|
|
18
|
-
file_ref = @project.files.select { |f| f.path == @info_plist_path }.first
|
|
19
|
-
if file_ref
|
|
20
|
-
Solara.logger.debug("Info.plist file reference already exists in the project. Skipping this step.")
|
|
21
|
-
else
|
|
22
|
-
file_ref = XcodeProjectManager.new.add_single_file_to_group(@project, @project.main_group, @info_plist_path)
|
|
23
|
-
Solara.logger.debug("Info.plist file created. file_ref = #{file_ref}")
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
10
|
def set_info_plist_in_build_settings
|
|
28
|
-
path = FileManager.get_relative_path(
|
|
11
|
+
path = FileManager.get_relative_path(FilePath.xcode_project_directory, @info_plist_path)
|
|
29
12
|
main_target.build_configurations.each do |config|
|
|
30
13
|
config.build_settings['INFOPLIST_FILE'] = path
|
|
31
14
|
end
|
|
32
15
|
end
|
|
33
16
|
|
|
17
|
+
def add_fonts(font_names)
|
|
18
|
+
font_manager = PlistFontManager.new(FilePath.info_plist)
|
|
19
|
+
font_manager.add_fonts(font_names)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
34
24
|
def save_project
|
|
35
25
|
@project.save
|
|
36
26
|
end
|
|
@@ -39,4 +29,5 @@ class IOSPlistManager
|
|
|
39
29
|
@project.targets.first
|
|
40
30
|
end
|
|
41
31
|
|
|
42
|
-
end
|
|
32
|
+
end
|
|
33
|
+
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
class PlistFontManager
|
|
2
|
+
def initialize(plist_path)
|
|
3
|
+
@plist_path = plist_path
|
|
4
|
+
load_plist
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def load_plist
|
|
8
|
+
@plist = Plist.parse_xml(@plist_path)
|
|
9
|
+
@plist['UIAppFonts'] ||= []
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def add_fonts(font_names)
|
|
13
|
+
font_names.each do |font_name|
|
|
14
|
+
add_font(font_name)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def add_font(font_name)
|
|
19
|
+
unless @plist['UIAppFonts'].include?(font_name)
|
|
20
|
+
@plist['UIAppFonts'] << font_name
|
|
21
|
+
save_plist
|
|
22
|
+
Solara.logger.debug("#{font_name} added to UIAppFonts.")
|
|
23
|
+
else
|
|
24
|
+
Solara.logger.debug("#{font_name} already exists in UIAppFonts.")
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def save_plist
|
|
29
|
+
File.open(@plist_path, 'w') do |file|
|
|
30
|
+
file.write(Plist::Emit.dump(@plist))
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -6,10 +6,10 @@ class XcconfigGenerator
|
|
|
6
6
|
|
|
7
7
|
def generate
|
|
8
8
|
Solara.logger.start_step("Generate Brand.xcconfig for iOS")
|
|
9
|
-
destination =
|
|
9
|
+
destination = FilePath.brand_xcconfig
|
|
10
10
|
content = generate_xcconfig_content
|
|
11
11
|
File.write(destination, content)
|
|
12
|
-
Solara.logger.debug("🎉 Generated #{
|
|
12
|
+
Solara.logger.debug("🎉 Generated #{FilePath.brand_xcconfig}. Content below ⬇️")
|
|
13
13
|
Solara.logger.debug("--------------\n#{content}--------------")
|
|
14
14
|
Solara.logger.end_step("Generate Brand.xcconfig for iOS")
|
|
15
15
|
end
|
|
@@ -18,7 +18,10 @@ class XcconfigGenerator
|
|
|
18
18
|
|
|
19
19
|
def generate_xcconfig_content
|
|
20
20
|
content = <<~XCCONFIG
|
|
21
|
-
|
|
21
|
+
APPICON_NAME = AppIcon
|
|
22
|
+
PRODUCT_NAME = #{get_value_of(InfoPListKey::BUNDLE_DISPLAY_NAME)}
|
|
23
|
+
CFBUNDLE_DISPLAY_NAME = #{get_value_of(InfoPListKey::BUNDLE_DISPLAY_NAME)}
|
|
24
|
+
CFBUNDLE_NAME = #{get_value_of(InfoPListKey::BUNDLE_NAME)}
|
|
22
25
|
#{load_config.map { |key, value| "#{key.upcase} = #{value}" }.join("\n")}
|
|
23
26
|
XCCONFIG
|
|
24
27
|
|
|
@@ -37,6 +40,15 @@ class XcconfigGenerator
|
|
|
37
40
|
end
|
|
38
41
|
end
|
|
39
42
|
|
|
43
|
+
def get_value_of(key)
|
|
44
|
+
infoplist_value = InfoPListStringCatalogManager.new(FilePath.brand_infoplist_string_catalog(@brand_key)).get(key)
|
|
45
|
+
return infoplist_value if !infoplist_value && !infoplist_value.empty?
|
|
46
|
+
|
|
47
|
+
brand_config_path = FilePath.brand_config(@brand_key)
|
|
48
|
+
brand_config = JSON.parse(File.read(brand_config_path))
|
|
49
|
+
brand_config['brandName']
|
|
50
|
+
end
|
|
51
|
+
|
|
40
52
|
def load_config
|
|
41
53
|
config_path = FilePath.ios_config(@brand_key)
|
|
42
54
|
JSON.parse(File.read(config_path))
|
|
@@ -6,11 +6,10 @@ class XcodeAssetManager
|
|
|
6
6
|
@asset_catalog_path = asset_catalog_path
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
|
|
10
9
|
def add(source)
|
|
11
10
|
# Fetches only files in the specified source directory
|
|
12
11
|
Dir.glob(File.join(source, '*.{png,jpg,jpeg,svg,heic,pdf}')).each do |file_path|
|
|
13
|
-
|
|
12
|
+
if File.file?(file_path) # Ensure it's a file and not a directory
|
|
14
13
|
filename_without_extension = File.basename(file_path, File.extname(file_path))
|
|
15
14
|
add_image(filename_without_extension, file_path, '1x')
|
|
16
15
|
end
|
|
@@ -51,6 +50,6 @@ class XcodeAssetManager
|
|
|
51
50
|
# Write the updated Contents.json
|
|
52
51
|
File.write(contents_json_path, JSON.pretty_generate(contents))
|
|
53
52
|
|
|
54
|
-
|
|
53
|
+
Solara.logger.debug("XcodeAssetManager: Image '#{image_name}' added successfully at scale #{scale}.")
|
|
55
54
|
end
|
|
56
55
|
end
|
|
@@ -64,7 +64,6 @@ class XcodeProjectManager
|
|
|
64
64
|
|
|
65
65
|
Solara.logger.debug("Base XCConfig files have been set for all build configurations.")
|
|
66
66
|
end
|
|
67
|
-
|
|
68
67
|
def self.set_xcconfig(project, config, xcconfig)
|
|
69
68
|
# Find the existing file reference or create a new one if it doesn't exist
|
|
70
69
|
file_reference = project.reference_for_path(xcconfig[:path])
|
|
@@ -79,4 +78,84 @@ class XcodeProjectManager
|
|
|
79
78
|
end
|
|
80
79
|
end
|
|
81
80
|
|
|
81
|
+
def add_file_to_root(project, file_path)
|
|
82
|
+
Solara.logger.debug("Adding file to root: #{file_path}")
|
|
83
|
+
|
|
84
|
+
root_group = project.main_group
|
|
85
|
+
file_name = File.basename(file_path, File.extname(file_path))
|
|
86
|
+
|
|
87
|
+
existing_file = root_group.files.find { |f| File.basename(f.path, File.extname(f.path))&.downcase == file_name.downcase }
|
|
88
|
+
|
|
89
|
+
if existing_file
|
|
90
|
+
Solara.logger.debug("Ignoring file: #{file_path} (Existing file reference: #{existing_file.path})")
|
|
91
|
+
return nil
|
|
92
|
+
else
|
|
93
|
+
file_reference = root_group.new_file(file_path)
|
|
94
|
+
Solara.logger.debug("Added new file to root: #{file_path} (File reference: #{file_reference.uuid})")
|
|
95
|
+
|
|
96
|
+
# Add the file to the project's main target if it's a source file
|
|
97
|
+
if %w[.swift .m .mm .c .cpp].include?(File.extname(file_path).downcase)
|
|
98
|
+
target = project.targets.first
|
|
99
|
+
target.add_file_references([file_reference])
|
|
100
|
+
Solara.logger.debug(" Added to target: #{target.name}")
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
file_reference
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def self.add_file_near_info_plist(project, file_path)
|
|
108
|
+
Solara.logger.debug("Adding file near Info.plist: #{file_path}")
|
|
109
|
+
|
|
110
|
+
# Find the Info.plist file path
|
|
111
|
+
info_plist_path = project.targets.first.build_configurations.first.build_settings['INFOPLIST_FILE']
|
|
112
|
+
return Solara.logger.warn("No Info.plist file found for the target") unless info_plist_path
|
|
113
|
+
|
|
114
|
+
# Get the directory of the Info.plist file
|
|
115
|
+
info_plist_dir = File.dirname(info_plist_path)
|
|
116
|
+
|
|
117
|
+
target_file_path = File.basename(file_path)
|
|
118
|
+
infoplist_group = info_plist_dir === '.' ? project.main_group : find_group_by_path(project, [info_plist_dir])
|
|
119
|
+
|
|
120
|
+
# Check if a file with the same name already exists in the target directory
|
|
121
|
+
existing_file = infoplist_group.files.find { |f| f.path == target_file_path }
|
|
122
|
+
|
|
123
|
+
if existing_file
|
|
124
|
+
Solara.logger.debug("Ignoring file: #{file_path} (Existing file reference: #{existing_file.path})")
|
|
125
|
+
return nil
|
|
126
|
+
else
|
|
127
|
+
# Add the file to the main group, which corresponds to the directory of Info.plist
|
|
128
|
+
file_reference = infoplist_group.new_file(target_file_path)
|
|
129
|
+
Solara.logger.debug("Added new file near Info.plist: #{file_path} (File reference: #{file_reference.uuid})")
|
|
130
|
+
|
|
131
|
+
# Add the file to the project's main target as a resource
|
|
132
|
+
target = project.targets.first
|
|
133
|
+
|
|
134
|
+
# Create a new build file
|
|
135
|
+
build_file = project.new(Xcodeproj::Project::Object::PBXBuildFile)
|
|
136
|
+
build_file.file_ref = file_reference
|
|
137
|
+
|
|
138
|
+
# Add the build file to the target's resources build phase
|
|
139
|
+
resources_build_phase = target.resources_build_phase
|
|
140
|
+
resources_build_phase.add_file_reference(file_reference)
|
|
141
|
+
|
|
142
|
+
Solara.logger.debug(" Added to target: #{target.name}")
|
|
143
|
+
Solara.logger.debug(" Added to PBXBuildFile section as a resource")
|
|
144
|
+
|
|
145
|
+
file_reference
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
def self.find_group_by_path(project, paths)
|
|
149
|
+
current_group = project.main_group
|
|
150
|
+
|
|
151
|
+
paths.each do |path|
|
|
152
|
+
current_group = current_group.children.find { |child|
|
|
153
|
+
child.is_a?(Xcodeproj::Project::Object::PBXGroup) && child.path == path
|
|
154
|
+
}
|
|
155
|
+
return nil unless current_group
|
|
156
|
+
end
|
|
157
|
+
current_group
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
|
|
82
161
|
end
|
|
@@ -11,11 +11,10 @@ class XcodeProjectSwitcher
|
|
|
11
11
|
|
|
12
12
|
def switch
|
|
13
13
|
update_xcode_target_settings
|
|
14
|
-
update_info_plist
|
|
15
14
|
add_artifacts_group
|
|
16
15
|
update_debug_and_release_xcconfig
|
|
17
16
|
@project.save
|
|
18
|
-
Solara.logger.debug("
|
|
17
|
+
Solara.logger.debug("Switched #{@project_path} Successfully.")
|
|
19
18
|
end
|
|
20
19
|
|
|
21
20
|
private
|
|
@@ -23,8 +22,9 @@ class XcodeProjectSwitcher
|
|
|
23
22
|
def update_xcode_target_settings
|
|
24
23
|
@target.build_configurations.each do |config|
|
|
25
24
|
config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = '$(PRODUCT_BUNDLE_IDENTIFIER)'
|
|
26
|
-
config.build_settings['PRODUCT_NAME'] = '$(PRODUCT_NAME)'
|
|
27
25
|
config.build_settings['MARKETING_VERSION'] = '$(MARKETING_VERSION)'
|
|
26
|
+
config.build_settings['ASSETCATALOG_COMPILER_APPICON_NAME'] = '$(APPICON_NAME)'
|
|
27
|
+
config.build_settings['PRODUCT_NAME'] = '$(PRODUCT_NAME)'
|
|
28
28
|
|
|
29
29
|
# We need to apply code signing only if the user has provided its config
|
|
30
30
|
path = FilePath.brand_signing(@brand_key, Platform::IOS)
|
|
@@ -47,30 +47,9 @@ class XcodeProjectSwitcher
|
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
def update_info_plist
|
|
51
|
-
info_plist_path = IOSFilePathManager.instance.info_plist
|
|
52
|
-
manager = IOSPlistManager.new(@project, info_plist_path)
|
|
53
|
-
manager.create_and_add_info_plist
|
|
54
|
-
|
|
55
|
-
xcconfig_values = {
|
|
56
|
-
'PRODUCT_NAME' => "$(PRODUCT_NAME)",
|
|
57
|
-
'PRODUCT_BUNDLE_IDENTIFIER' => "$(PRODUCT_BUNDLE_IDENTIFIER)",
|
|
58
|
-
'MARKETING_VERSION' => "$(MARKETING_VERSION)",
|
|
59
|
-
'BUNDLE_VERSION' => "$(BUNDLE_VERSION)"
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
info_plist = Xcodeproj::Plist.read_from_path(info_plist_path)
|
|
63
|
-
info_plist['CFBundleDisplayName'] = xcconfig_values['PRODUCT_NAME']
|
|
64
|
-
info_plist['CFBundleIdentifier'] = xcconfig_values['PRODUCT_BUNDLE_IDENTIFIER']
|
|
65
|
-
info_plist['CFBundleShortVersionString'] = xcconfig_values['MARKETING_VERSION']
|
|
66
|
-
info_plist['CFBundleVersion'] = xcconfig_values['BUNDLE_VERSION']
|
|
67
|
-
|
|
68
|
-
Xcodeproj::Plist.write_to_path(info_plist, info_plist_path)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
50
|
def update_debug_and_release_xcconfig
|
|
72
|
-
debug_xcconfig_path =
|
|
73
|
-
release_xcconfig_path =
|
|
51
|
+
debug_xcconfig_path = FilePath.app_xcconfig('Debug.xcconfig')
|
|
52
|
+
release_xcconfig_path = FilePath.app_xcconfig('Release.xcconfig')
|
|
74
53
|
|
|
75
54
|
create_xcconfigs_and_add_to_project(debug_xcconfig_path, release_xcconfig_path)
|
|
76
55
|
set_base_xcconfigs(debug_xcconfig_path, release_xcconfig_path)
|
|
@@ -78,7 +57,7 @@ class XcodeProjectSwitcher
|
|
|
78
57
|
|
|
79
58
|
def create_xcconfigs_and_add_to_project(debug_xcconfig_path, release_xcconfig_path)
|
|
80
59
|
FileManager.create_files_if_not_exist([debug_xcconfig_path, release_xcconfig_path])
|
|
81
|
-
base_xcconfig_name =
|
|
60
|
+
base_xcconfig_name = "#{FilePath.artifacts_dir_name_ios}/Brand.xcconfig"
|
|
82
61
|
|
|
83
62
|
case @platform
|
|
84
63
|
when Platform::Flutter
|
|
@@ -87,7 +66,7 @@ class XcodeProjectSwitcher
|
|
|
87
66
|
group_name = 'XCConfig'
|
|
88
67
|
config_group = @project.groups.find { |group| group.name == group_name }
|
|
89
68
|
config_group = @project.new_group(group_name) if config_group.nil?
|
|
90
|
-
add_files_to_group(config_group,
|
|
69
|
+
add_files_to_group(config_group, FilePath.app_xcconfig_directory)
|
|
91
70
|
else
|
|
92
71
|
raise ArgumentError, "Invalid platform: #{@platform}"
|
|
93
72
|
end
|
|
@@ -108,16 +87,18 @@ class XcodeProjectSwitcher
|
|
|
108
87
|
end
|
|
109
88
|
|
|
110
89
|
def add_artifacts_group
|
|
90
|
+
artifacts_dir_name = FilePath.artifacts_dir_name_ios
|
|
91
|
+
|
|
111
92
|
case @platform
|
|
112
93
|
when Platform::Flutter
|
|
113
94
|
flutter_group = @project.groups.find { |group| group.name == 'Flutter' }
|
|
114
|
-
artifacts_group = flutter_group.groups.find { |group| group.name ==
|
|
115
|
-
artifacts_group = flutter_group.new_group(
|
|
116
|
-
add_files_to_group(artifacts_group,
|
|
95
|
+
artifacts_group = flutter_group.groups.find { |group| group.name == artifacts_dir_name }
|
|
96
|
+
artifacts_group = flutter_group.new_group(artifacts_dir_name) if artifacts_group.nil?
|
|
97
|
+
add_files_to_group(artifacts_group, FilePath.ios_project_root_artifacts)
|
|
117
98
|
when Platform::IOS
|
|
118
|
-
artifacts_group = @project.groups.find { |group| group.name ==
|
|
119
|
-
artifacts_group = @project.new_group(
|
|
120
|
-
add_files_to_group(artifacts_group,
|
|
99
|
+
artifacts_group = @project.groups.find { |group| group.name == artifacts_dir_name }
|
|
100
|
+
artifacts_group = @project.new_group(artifacts_dir_name) if artifacts_group.nil?
|
|
101
|
+
add_files_to_group(artifacts_group, FilePath.ios_project_root_artifacts)
|
|
121
102
|
else
|
|
122
103
|
raise ArgumentError, "Invalid platform: #{@platform}"
|
|
123
104
|
end
|
|
@@ -24,6 +24,10 @@ class SolaraLogger
|
|
|
24
24
|
set_default_format
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
def reset_steps
|
|
28
|
+
@step_count = 0
|
|
29
|
+
end
|
|
30
|
+
|
|
27
31
|
def verbose=(value)
|
|
28
32
|
@verbose = value
|
|
29
33
|
@logger.level = @verbose ? Logger::DEBUG : Logger::INFO
|
|
@@ -43,6 +47,12 @@ class SolaraLogger
|
|
|
43
47
|
line
|
|
44
48
|
end
|
|
45
49
|
|
|
50
|
+
def log_step(step_name)
|
|
51
|
+
start_step(step_name)
|
|
52
|
+
yield
|
|
53
|
+
end_step(step_name)
|
|
54
|
+
end
|
|
55
|
+
|
|
46
56
|
def title(message)
|
|
47
57
|
@logger.info(message.green)
|
|
48
58
|
line
|
|
@@ -6,7 +6,11 @@ require 'json'
|
|
|
6
6
|
class SolaraSettingsManager
|
|
7
7
|
include Singleton
|
|
8
8
|
|
|
9
|
-
attr_accessor :root, :project_root
|
|
9
|
+
attr_accessor :root, :project_root, :environment
|
|
10
|
+
|
|
11
|
+
def initialize
|
|
12
|
+
@environment = SolaraEnvironment::Production
|
|
13
|
+
end
|
|
10
14
|
|
|
11
15
|
def platform
|
|
12
16
|
settings['platform']
|
|
@@ -28,6 +32,10 @@ class SolaraSettingsManager
|
|
|
28
32
|
save(json)
|
|
29
33
|
end
|
|
30
34
|
|
|
35
|
+
def is_test_environment
|
|
36
|
+
@environment === 'test'
|
|
37
|
+
end
|
|
38
|
+
|
|
31
39
|
private
|
|
32
40
|
|
|
33
41
|
def settings
|
|
@@ -70,4 +78,21 @@ def init(platform)
|
|
|
70
78
|
unless Platform.all.include?(platform)
|
|
71
79
|
raise ArgumentError, "Invalid platform. Please use one of: #{Platform.all.join(', ')}"
|
|
72
80
|
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
module SolaraEnvironment
|
|
84
|
+
Production = 'production'
|
|
85
|
+
Test = 'test'
|
|
86
|
+
|
|
87
|
+
def self.all
|
|
88
|
+
[Production, Test]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def self.is_production
|
|
92
|
+
SolaraSettingsManager.instance.environment.downcase == Production.downcase
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def self.is_test
|
|
96
|
+
SolaraSettingsManager.instance.environment.downcase == Test.downcase
|
|
97
|
+
end
|
|
73
98
|
end
|
|
@@ -3,7 +3,7 @@ require 'rexml/document'
|
|
|
3
3
|
class StringsXmlManager
|
|
4
4
|
def initialize(file_path)
|
|
5
5
|
@file_path = file_path
|
|
6
|
-
@xml_content = File.read(@file_path)
|
|
6
|
+
@xml_content = File.read(@file_path, encoding: 'UTF-8')
|
|
7
7
|
@doc = REXML::Document.new(@xml_content)
|
|
8
8
|
end
|
|
9
9
|
|
|
@@ -11,7 +11,22 @@ class StringsXmlManager
|
|
|
11
11
|
app_name_element = @doc.elements['resources/string[@name="app_name"]']
|
|
12
12
|
app_name_element.remove if app_name_element
|
|
13
13
|
save_changes
|
|
14
|
-
Solara.logger.debug("Removed app_name from #{@file_path} to avoid duplication with
|
|
14
|
+
Solara.logger.debug("Removed app_name from #{@file_path} to avoid duplication with #{FilePath.artifacts_dir_name}/strings.xml.")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def update_string_value(string_name, new_value)
|
|
18
|
+
string_element = @doc.elements["resources/string[@name=\"#{string_name}\"]"]
|
|
19
|
+
if string_element
|
|
20
|
+
string_element.text = new_value
|
|
21
|
+
save_changes
|
|
22
|
+
Solara.logger.debug("Updated string '#{string_name}' to '#{new_value}' in #{@file_path}.")
|
|
23
|
+
else
|
|
24
|
+
Solara.logger.warn("String '#{string_name}' not found in #{@file_path}. Update failed.")
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def get_value(string_name)
|
|
29
|
+
@doc.elements["resources/string[@name=\"#{string_name}\"]"].text
|
|
15
30
|
end
|
|
16
31
|
|
|
17
32
|
private
|