solara 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/solara +18 -0
- data/solara/lib/.DS_Store +0 -0
- data/solara/lib/core/.DS_Store +0 -0
- data/solara/lib/core/aliases/alias_generator.rb +128 -0
- data/solara/lib/core/aliases/alias_generator_manager.rb +28 -0
- data/solara/lib/core/aliases/solara_terminal_setup.rb +103 -0
- data/solara/lib/core/brands/brand_onboarder.rb +46 -0
- data/solara/lib/core/brands/brand_switcher.rb +204 -0
- data/solara/lib/core/brands/brands_manager.rb +154 -0
- data/solara/lib/core/dashboard/.DS_Store +0 -0
- data/solara/lib/core/dashboard/brand/.DS_Store +0 -0
- data/solara/lib/core/dashboard/brand/BrandDetail.js +11 -0
- data/solara/lib/core/dashboard/brand/BrandDetailController.js +361 -0
- data/solara/lib/core/dashboard/brand/BrandDetailModel.js +155 -0
- data/solara/lib/core/dashboard/brand/BrandDetailView.js +245 -0
- data/solara/lib/core/dashboard/brand/brand.html +477 -0
- data/solara/lib/core/dashboard/brand/source/BrandLocalSource.js +123 -0
- data/solara/lib/core/dashboard/brand/source/BrandRemoteSource.js +260 -0
- data/solara/lib/core/dashboard/brands/Brands.js +10 -0
- data/solara/lib/core/dashboard/brands/BrandsController.js +155 -0
- data/solara/lib/core/dashboard/brands/BrandsModel.js +136 -0
- data/solara/lib/core/dashboard/brands/BrandsView.js +136 -0
- data/solara/lib/core/dashboard/brands/brands.html +345 -0
- data/solara/lib/core/dashboard/component/AddFieldSheet.js +212 -0
- data/solara/lib/core/dashboard/component/AliasesBottomSheet.js +128 -0
- data/solara/lib/core/dashboard/component/BrandOptionsBottomSheet.js +130 -0
- data/solara/lib/core/dashboard/component/ConfirmationDialog.js +103 -0
- data/solara/lib/core/dashboard/component/MessageBottomSheet.js +80 -0
- data/solara/lib/core/dashboard/component/OnboardBrandBottomSheet.js +214 -0
- data/solara/lib/core/dashboard/dashboard_manager.rb +19 -0
- data/solara/lib/core/dashboard/dashboard_server.rb +132 -0
- data/solara/lib/core/dashboard/handler/base_handler.rb +25 -0
- data/solara/lib/core/dashboard/handler/brand_alisases_handler.rb +33 -0
- data/solara/lib/core/dashboard/handler/brand_configurations_handler.rb +18 -0
- data/solara/lib/core/dashboard/handler/brand_configurations_manager.rb +73 -0
- data/solara/lib/core/dashboard/handler/brand_icon_handler.rb +20 -0
- data/solara/lib/core/dashboard/handler/brand_section_handler.rb +20 -0
- data/solara/lib/core/dashboard/handler/brands_handler.rb +14 -0
- data/solara/lib/core/dashboard/handler/current_brand_handler.rb +18 -0
- data/solara/lib/core/dashboard/handler/doctor_handler.rb +39 -0
- data/solara/lib/core/dashboard/handler/edit_section_handler.rb +55 -0
- data/solara/lib/core/dashboard/handler/offboard_brand_handler.rb +34 -0
- data/solara/lib/core/dashboard/handler/onboard_brand_handler.rb +53 -0
- data/solara/lib/core/dashboard/handler/redirect_handler.rb +12 -0
- data/solara/lib/core/dashboard/handler/switch_handler.rb +25 -0
- data/solara/lib/core/dashboard/index.html +36 -0
- data/solara/lib/core/dashboard/local.html +41 -0
- data/solara/lib/core/dashboard/res/favicon/android-chrome-192x192.png +0 -0
- data/solara/lib/core/dashboard/res/favicon/android-chrome-512x512.png +0 -0
- data/solara/lib/core/dashboard/res/favicon/apple-touch-icon.png +0 -0
- data/solara/lib/core/dashboard/res/favicon/favicon-16x16.png +0 -0
- data/solara/lib/core/dashboard/res/favicon/favicon-32x32.png +0 -0
- data/solara/lib/core/dashboard/res/favicon/favicon.ico +0 -0
- data/solara/lib/core/dashboard/res/favicon/site.webmanifest +1 -0
- data/solara/lib/core/dashboard/solara.png +0 -0
- data/solara/lib/core/doctor/brand_doctor.rb +94 -0
- data/solara/lib/core/doctor/doctor_manager.rb +35 -0
- data/solara/lib/core/doctor/project_doctor.rb +8 -0
- data/solara/lib/core/doctor/schema/brand_configurations.json +60 -0
- data/solara/lib/core/doctor/schema/platform/android/android_config.json +23 -0
- data/solara/lib/core/doctor/schema/platform/android/android_signing.json +23 -0
- data/solara/lib/core/doctor/schema/platform/ios/ios_config.json +27 -0
- data/solara/lib/core/doctor/schema/platform/ios/ios_signing.json +27 -0
- data/solara/lib/core/doctor/schema/platform/shared/theme.json +48 -0
- data/solara/lib/core/doctor/validator/brand_settings_validator.rb +55 -0
- data/solara/lib/core/doctor/validator/brand_settings_validator_manager.rb +82 -0
- data/solara/lib/core/doctor/validator/directory_structure_validator.rb +38 -0
- data/solara/lib/core/doctor/validator/file_structure_validator.rb +37 -0
- data/solara/lib/core/doctor/validator/json_file_validator.rb +21 -0
- data/solara/lib/core/doctor/validator/json_schema_validator.rb +32 -0
- data/solara/lib/core/doctor/validator/project_filesystem_validator.rb +70 -0
- data/solara/lib/core/doctor/validator/template/android_template_validation_config.yml +51 -0
- data/solara/lib/core/doctor/validator/template/flutter_template_validation_config.yml +53 -0
- data/solara/lib/core/doctor/validator/template/ios_template_validation_config.yml +51 -0
- data/solara/lib/core/doctor/validator/template/template_validator.rb +108 -0
- data/solara/lib/core/doctor/validator/validation_strategy.rb +7 -0
- data/solara/lib/core/scripts/brand_config_generator.rb +245 -0
- data/solara/lib/core/scripts/brand_config_manager.rb +90 -0
- data/solara/lib/core/scripts/brand_exporter.rb +38 -0
- data/solara/lib/core/scripts/brand_importer.rb +84 -0
- data/solara/lib/core/scripts/brand_offboarder.rb +19 -0
- data/solara/lib/core/scripts/brand_resources_manager.rb +77 -0
- data/solara/lib/core/scripts/directory_creator.rb +22 -0
- data/solara/lib/core/scripts/file_manager.rb +90 -0
- data/solara/lib/core/scripts/file_path.rb +327 -0
- data/solara/lib/core/scripts/folder_copier.rb +41 -0
- data/solara/lib/core/scripts/gitignore_manager.rb +54 -0
- data/solara/lib/core/scripts/interactive_file_system_validator.rb +110 -0
- data/solara/lib/core/scripts/platform/android/android_manifest_switcher.rb +24 -0
- data/solara/lib/core/scripts/platform/android/android_strings_switcher.rb +39 -0
- data/solara/lib/core/scripts/platform/android/gradle_switcher.rb +233 -0
- data/solara/lib/core/scripts/platform/android/properties_generator.rb +31 -0
- data/solara/lib/core/scripts/platform/ios/ios_file_path_manager.rb +109 -0
- data/solara/lib/core/scripts/platform/ios/ios_plist_manager.rb +42 -0
- data/solara/lib/core/scripts/platform/ios/xcconfig_generator.rb +44 -0
- data/solara/lib/core/scripts/platform/ios/xcode_asset_manager.rb +56 -0
- data/solara/lib/core/scripts/platform/ios/xcode_project_manager.rb +82 -0
- data/solara/lib/core/scripts/platform/ios/xcode_project_switcher.rb +130 -0
- data/solara/lib/core/scripts/project_settings_manager.rb +39 -0
- data/solara/lib/core/scripts/solara_logger.rb +103 -0
- data/solara/lib/core/scripts/solara_settings_manager.rb +73 -0
- data/solara/lib/core/scripts/solara_status_manager.rb +55 -0
- data/solara/lib/core/scripts/solara_version_manager.rb +42 -0
- data/solara/lib/core/scripts/strings_xml_manager.rb +22 -0
- data/solara/lib/core/scripts/terminal_input_manager.rb +22 -0
- data/solara/lib/core/scripts/theme_generator.rb +250 -0
- data/solara/lib/core/scripts/yaml_manager.rb +72 -0
- data/solara/lib/core/solara_configurator.rb +15 -0
- data/solara/lib/core/template/brands/android/android_config.json +8 -0
- data/solara/lib/core/template/brands/android/android_signing.json +6 -0
- data/solara/lib/core/template/brands/android/res/.DS_Store +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-hdpi/ic_launcher.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-mdpi/ic_launcher.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-xhdpi/ic_launcher.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- data/solara/lib/core/template/brands/brands.json +4 -0
- data/solara/lib/core/template/brands/ios/assets/.DS_Store +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/100.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/102.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/1024.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/114.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/120.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/128.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/144.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/152.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/16.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/167.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/172.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/180.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/196.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/20.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/216.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/256.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/29.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/32.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/40.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/48.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/50.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/512.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/55.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/57.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/58.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/60.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/64.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/66.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/72.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/76.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/80.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/87.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/88.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/92.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/Contents.json +1 -0
- data/solara/lib/core/template/brands/ios/ios_config.json +7 -0
- data/solara/lib/core/template/brands/ios/ios_signing.json +7 -0
- data/solara/lib/core/template/brands/shared/.DS_Store +0 -0
- data/solara/lib/core/template/brands/shared/brand_config.json +2 -0
- data/solara/lib/core/template/brands/shared/theme.json +46 -0
- data/solara/lib/core/template/config/android_template_config.json +57 -0
- data/solara/lib/core/template/config/flutter_template_config.json +62 -0
- data/solara/lib/core/template/config/ios_template_config.json +57 -0
- data/solara/lib/core/template/project_template_generator.rb +63 -0
- data/solara/lib/platform_detector.rb +84 -0
- data/solara/lib/solara/cli.rb +5 -0
- data/solara/lib/solara/version.rb +3 -0
- data/solara/lib/solara.rb +238 -0
- data/solara/lib/solara_initializer.rb +44 -0
- data/solara/lib/solara_manager.rb +73 -0
- metadata +346 -0
@@ -0,0 +1,82 @@
|
|
1
|
+
class XcodeProjectManager
|
2
|
+
def initialize
|
3
|
+
end
|
4
|
+
|
5
|
+
def add_files_to_group(project, group, directory_path)
|
6
|
+
Dir.foreach(directory_path) do |entry|
|
7
|
+
next if entry == '.' || entry == '..' || entry == '.DS_Store'
|
8
|
+
|
9
|
+
file_path = File.join(directory_path, entry)
|
10
|
+
if File.directory?(file_path)
|
11
|
+
Solara.logger.debug("Processing directory: #{file_path}")
|
12
|
+
subgroup = group.groups.find { |g| g.name == entry } || group.new_group(entry)
|
13
|
+
add_files_to_group(project, subgroup, file_path)
|
14
|
+
else
|
15
|
+
add_single_file_to_group(project, group, file_path)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_single_file_to_group(project, group, file_path)
|
21
|
+
Solara.logger.debug("Adding new file: #{file_path}")
|
22
|
+
file_name = File.basename(file_path, File.extname(file_path))
|
23
|
+
|
24
|
+
existing_file = group.files.find { |f| File.basename(f.path, File.extname(f.path))&.downcase == file_name.downcase }
|
25
|
+
existing_group = group.groups.find { |g| g.name&.downcase == file_name.downcase }
|
26
|
+
existing_reference = existing_file || existing_group
|
27
|
+
|
28
|
+
if existing_reference
|
29
|
+
if existing_reference.is_a?(Xcodeproj::Project::Object::PBXFileReference)
|
30
|
+
Solara.logger.debug("Ignoring file: #{file_path} (Existing file reference: #{existing_reference.path})")
|
31
|
+
else
|
32
|
+
Solara.logger.debug("Ignoring file: #{file_path} (Existing group with same name: #{existing_reference.name})")
|
33
|
+
end
|
34
|
+
return nil
|
35
|
+
else
|
36
|
+
file_reference = group.new_file(file_path)
|
37
|
+
Solara.logger.debug("Adding new file: #{file_path} (File reference: #{file_reference.uuid})")
|
38
|
+
|
39
|
+
# Add the file to the project's main target if it's a source file
|
40
|
+
if %w[.swift .m .mm .c .cpp].include?(File.extname(file_path).downcase)
|
41
|
+
target = project.targets.first
|
42
|
+
target.add_file_references([file_reference])
|
43
|
+
Solara.logger.debug(" Added to target: #{target.name}")
|
44
|
+
end
|
45
|
+
|
46
|
+
file_reference
|
47
|
+
end
|
48
|
+
end
|
49
|
+
def self.set_base_xcconfigs(project, xcconfigs)
|
50
|
+
# Iterate through all build configurations in the target
|
51
|
+
project.targets.first.build_configurations.each do |config|
|
52
|
+
# Find the matching XCConfig from the array
|
53
|
+
matching_xcconfig = xcconfigs.find { |xc| config.name.downcase.include?(xc[:type].downcase) }
|
54
|
+
|
55
|
+
# If no matching XCConfig found, use debug as base
|
56
|
+
matching_xcconfig ||= xcconfigs.find { |xc| xc[:type].downcase == 'debug' }
|
57
|
+
|
58
|
+
if matching_xcconfig
|
59
|
+
set_xcconfig(project, config, matching_xcconfig)
|
60
|
+
else
|
61
|
+
Solara.logger.warn("Warning: No matching XCConfig found for #{config.name} configuration, and no Debug XCConfig available")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
Solara.logger.debug("Base XCConfig files have been set for all build configurations.")
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.set_xcconfig(project, config, xcconfig)
|
69
|
+
# Find the existing file reference or create a new one if it doesn't exist
|
70
|
+
file_reference = project.reference_for_path(xcconfig[:path])
|
71
|
+
if file_reference
|
72
|
+
config.base_configuration_reference = file_reference
|
73
|
+
Solara.logger.debug("Set #{xcconfig[:type]} XCConfig for #{config.name} configuration")
|
74
|
+
else
|
75
|
+
# If the file reference doesn't exist, create a new one
|
76
|
+
new_file_reference = project.new_file(xcconfig[:path])
|
77
|
+
config.base_configuration_reference = new_file_reference
|
78
|
+
Solara.logger.debug("Created and set new #{xcconfig[:type]} XCConfig for #{config.name} configuration")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.expand_path(__dir__))
|
2
|
+
|
3
|
+
class XcodeProjectSwitcher
|
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
|
+
@target = @project.targets.first
|
9
|
+
@platform = SolaraSettingsManager.instance.platform
|
10
|
+
end
|
11
|
+
|
12
|
+
def switch
|
13
|
+
update_xcode_target_settings
|
14
|
+
update_info_plist
|
15
|
+
add_artifacts_group
|
16
|
+
update_debug_and_release_xcconfig
|
17
|
+
@project.save
|
18
|
+
Solara.logger.debug("Updated #{@project_path} to use the values of #{IOSFilePathManager.instance.brand_xcconfig}")
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def update_xcode_target_settings
|
24
|
+
@target.build_configurations.each do |config|
|
25
|
+
config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = '$(PRODUCT_BUNDLE_IDENTIFIER)'
|
26
|
+
config.build_settings['PRODUCT_NAME'] = '$(PRODUCT_NAME)'
|
27
|
+
config.build_settings['MARKETING_VERSION'] = '$(MARKETING_VERSION)'
|
28
|
+
|
29
|
+
# We need to apply code signing only if the user has provided its config
|
30
|
+
path = FilePath.brand_signing(@brand_key, Platform::IOS)
|
31
|
+
signing = JSON.parse(File.read(path))
|
32
|
+
unless signing['PROVISIONING_PROFILE_SPECIFIER'].empty?
|
33
|
+
config.build_settings['CODE_SIGN_IDENTITY'] = '$(CODE_SIGN_IDENTITY)'
|
34
|
+
config.build_settings['DEVELOPMENT_TEAM'] = '$(DEVELOPMENT_TEAM)'
|
35
|
+
config.build_settings['PROVISIONING_PROFILE_SPECIFIER'] = '$(PROVISIONING_PROFILE_SPECIFIER)'
|
36
|
+
config.build_settings['CODE_SIGN_STYLE'] = '$(CODE_SIGN_STYLE)'
|
37
|
+
config.build_settings['CODE_SIGN_ENTITLEMENTS'] = '$(CODE_SIGN_ENTITLEMENTS)'
|
38
|
+
end
|
39
|
+
|
40
|
+
# We need to apply APL_MRCH_ID only if the user has provided its config
|
41
|
+
path = FilePath.ios_config(@brand_key)
|
42
|
+
ios_config = JSON.parse(File.read(path))
|
43
|
+
merchant_id = ios_config['APL_MRCH_ID']
|
44
|
+
unless merchant_id.nil? || merchant_id.empty?
|
45
|
+
config.build_settings['APL_MRCH_ID'] = '$(APL_MRCH_ID)'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
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
|
+
def update_debug_and_release_xcconfig
|
72
|
+
debug_xcconfig_path = IOSFilePathManager.instance.app_xcconfig('Debug.xcconfig')
|
73
|
+
release_xcconfig_path = IOSFilePathManager.instance.app_xcconfig('Release.xcconfig')
|
74
|
+
|
75
|
+
create_xcconfigs_and_add_to_project(debug_xcconfig_path, release_xcconfig_path)
|
76
|
+
set_base_xcconfigs(debug_xcconfig_path, release_xcconfig_path)
|
77
|
+
end
|
78
|
+
|
79
|
+
def create_xcconfigs_and_add_to_project(debug_xcconfig_path, release_xcconfig_path)
|
80
|
+
FileManager.create_files_if_not_exist([debug_xcconfig_path, release_xcconfig_path])
|
81
|
+
base_xcconfig_name = 'Artifacts/Brand.xcconfig'
|
82
|
+
|
83
|
+
case @platform
|
84
|
+
when Platform::Flutter
|
85
|
+
# Nothing
|
86
|
+
when Platform::IOS
|
87
|
+
group_name = 'XCConfig'
|
88
|
+
config_group = @project.groups.find { |group| group.name == group_name }
|
89
|
+
config_group = @project.new_group(group_name) if config_group.nil?
|
90
|
+
add_files_to_group(config_group, IOSFilePathManager.instance.app_xcconfig_directory)
|
91
|
+
else
|
92
|
+
raise ArgumentError, "Invalid platform: #{@platform}"
|
93
|
+
end
|
94
|
+
|
95
|
+
File.open(debug_xcconfig_path, "w") { |file| file.write("#include \"#{base_xcconfig_name}\"\n") }
|
96
|
+
File.open(release_xcconfig_path, "w") { |file| file.write("#include \"#{base_xcconfig_name}\"\n") }
|
97
|
+
end
|
98
|
+
|
99
|
+
def set_base_xcconfigs(debug_xcconfig_path, release_xcconfig_path)
|
100
|
+
xcconfigs = [
|
101
|
+
{ type: 'Debug', path: debug_xcconfig_path },
|
102
|
+
{ type: 'Release', path: release_xcconfig_path },
|
103
|
+
]
|
104
|
+
XcodeProjectManager.set_base_xcconfigs(
|
105
|
+
@project,
|
106
|
+
xcconfigs
|
107
|
+
)
|
108
|
+
end
|
109
|
+
|
110
|
+
def add_artifacts_group
|
111
|
+
case @platform
|
112
|
+
when Platform::Flutter
|
113
|
+
flutter_group = @project.groups.find { |group| group.name == 'Flutter' }
|
114
|
+
artifacts_group = flutter_group.groups.find { |group| group.name == 'Artifacts' }
|
115
|
+
artifacts_group = flutter_group.new_group("Artifacts") if artifacts_group.nil?
|
116
|
+
add_files_to_group(artifacts_group, IOSFilePathManager.instance.artifacts)
|
117
|
+
when Platform::IOS
|
118
|
+
artifacts_group = @project.groups.find { |group| group.name == 'Artifacts' }
|
119
|
+
artifacts_group = @project.new_group("Artifacts") if artifacts_group.nil?
|
120
|
+
add_files_to_group(artifacts_group, IOSFilePathManager.instance.artifacts)
|
121
|
+
else
|
122
|
+
raise ArgumentError, "Invalid platform: #{@platform}"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def add_files_to_group(group, directory_path)
|
127
|
+
XcodeProjectManager.new.add_files_to_group(@project, group, directory_path)
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
require 'singleton'
|
7
|
+
require 'json'
|
8
|
+
|
9
|
+
class ProjectSettingsManager
|
10
|
+
include Singleton
|
11
|
+
|
12
|
+
attr_accessor :root, :project_root
|
13
|
+
|
14
|
+
def value(key, platform)
|
15
|
+
settings.dig(platform.to_s, key)
|
16
|
+
end
|
17
|
+
|
18
|
+
def add(key, value, platform)
|
19
|
+
json = settings
|
20
|
+
json[platform.to_s] ||= {}
|
21
|
+
json[platform.to_s][key] = value
|
22
|
+
save(json)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def settings
|
28
|
+
path = FilePath.project_settings
|
29
|
+
FileManager.create_file_if_not_exist(path)
|
30
|
+
JSON.parse(File.read(path))
|
31
|
+
rescue JSON::ParserError => e
|
32
|
+
{}
|
33
|
+
end
|
34
|
+
|
35
|
+
def save(json)
|
36
|
+
path = FilePath.project_settings
|
37
|
+
File.write(path, JSON.pretty_generate(json))
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.expand_path(__dir__))
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
|
5
|
+
require 'logger'
|
6
|
+
require 'colorize'
|
7
|
+
|
8
|
+
class SolaraLogger
|
9
|
+
LEVELS = %i[debug info warn error fatal]
|
10
|
+
EMOJIS = {
|
11
|
+
debug: "",
|
12
|
+
info: "",
|
13
|
+
warn: "⚠️",
|
14
|
+
error: "❌ ",
|
15
|
+
fatal: "💀"
|
16
|
+
}
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@logger = Logger.new(STDOUT)
|
20
|
+
# Set the default to INFO until we override it later.
|
21
|
+
@logger.level = Logger::INFO
|
22
|
+
@verbose = false
|
23
|
+
@step_count = 0
|
24
|
+
set_default_format
|
25
|
+
end
|
26
|
+
|
27
|
+
def verbose=(value)
|
28
|
+
@verbose = value
|
29
|
+
@logger.level = @verbose ? Logger::DEBUG : Logger::INFO
|
30
|
+
end
|
31
|
+
|
32
|
+
LEVELS.each do |level|
|
33
|
+
define_method(level) do |message|
|
34
|
+
emoji = EMOJIS[level]
|
35
|
+
@logger.send(level, colorize("#{emoji.empty? ? '' : emoji + "\s"}#{message}", level))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def start_step(message)
|
40
|
+
return unless @verbose
|
41
|
+
@step_count += 1
|
42
|
+
@logger.debug("Step #{@step_count}: #{message}".green)
|
43
|
+
line
|
44
|
+
end
|
45
|
+
|
46
|
+
def title(message)
|
47
|
+
@logger.info(message.green)
|
48
|
+
line
|
49
|
+
end
|
50
|
+
|
51
|
+
def end_step(message = "Step completed")
|
52
|
+
return unless @verbose
|
53
|
+
@logger.debug("FINISHED Step #{@step_count}: #{message}".green)
|
54
|
+
line
|
55
|
+
info("") # Empty line for better readability
|
56
|
+
end
|
57
|
+
|
58
|
+
def line(char: '-', length: 50)
|
59
|
+
message = char * length
|
60
|
+
@logger.info(message.green)
|
61
|
+
end
|
62
|
+
|
63
|
+
def header(message)
|
64
|
+
return unless @verbose
|
65
|
+
|
66
|
+
line(char: '=')
|
67
|
+
@logger.info(message.upcase.green)
|
68
|
+
line(char: '=')
|
69
|
+
info("") # Empty line for better readability
|
70
|
+
end
|
71
|
+
|
72
|
+
def success(message)
|
73
|
+
@logger.info("🎉 #{message.green}")
|
74
|
+
end
|
75
|
+
|
76
|
+
def failure(message)
|
77
|
+
error(message)
|
78
|
+
end
|
79
|
+
|
80
|
+
def passed(message)
|
81
|
+
@logger.debug("✅ #{message.green}")
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def set_default_format
|
88
|
+
@logger.formatter = proc do |severity, datetime, progname, msg|
|
89
|
+
"#{msg}\n"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def colorize(message, level)
|
94
|
+
case level
|
95
|
+
when :debug then message
|
96
|
+
when :info then message
|
97
|
+
when :warn then message.yellow
|
98
|
+
when :error then message.red
|
99
|
+
when :fatal then message.red.bold
|
100
|
+
else message
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
class SolaraSettingsManager
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
attr_accessor :root, :project_root
|
10
|
+
|
11
|
+
def platform
|
12
|
+
settings['platform']
|
13
|
+
end
|
14
|
+
|
15
|
+
def platform=(new_platform)
|
16
|
+
json = settings
|
17
|
+
json['platform'] = new_platform
|
18
|
+
save(json)
|
19
|
+
end
|
20
|
+
|
21
|
+
def value(key)
|
22
|
+
settings[key]
|
23
|
+
end
|
24
|
+
|
25
|
+
def add(key, value)
|
26
|
+
json = settings
|
27
|
+
json[key] = value
|
28
|
+
save(json)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def settings
|
34
|
+
path = FilePath.solara_settings
|
35
|
+
FileManager.create_file_if_not_exist(path)
|
36
|
+
JSON.parse(File.read(path))
|
37
|
+
rescue JSON::ParserError => e
|
38
|
+
{}
|
39
|
+
end
|
40
|
+
|
41
|
+
def save(json)
|
42
|
+
File.write(FilePath.solara_settings, JSON.pretty_generate(json))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
module Platform
|
47
|
+
Flutter = 'flutter'
|
48
|
+
Android = 'android'
|
49
|
+
IOS = 'ios'
|
50
|
+
Unknown = 'unknown'
|
51
|
+
|
52
|
+
def self.all
|
53
|
+
[Flutter, Android, IOS]
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.is_ios
|
57
|
+
SolaraSettingsManager.instance.platform.downcase == IOS.downcase
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.is_android
|
61
|
+
SolaraSettingsManager.instance.platform.downcase == Android.downcase
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.is_flutter
|
65
|
+
SolaraSettingsManager.instance.platform.downcase == Flutter.downcase
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def init(platform)
|
70
|
+
unless Platform.all.include?(platform)
|
71
|
+
raise ArgumentError, "Invalid platform. Please use one of: #{Platform.all.join(', ')}"
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class SolaraStatusManager
|
2
|
+
|
3
|
+
def start
|
4
|
+
current_brand_draft
|
5
|
+
puts
|
6
|
+
brands_list
|
7
|
+
doctor
|
8
|
+
end
|
9
|
+
|
10
|
+
def current_brand_draft
|
11
|
+
current_brand = BrandsManager.instance.current_brand
|
12
|
+
unless current_brand
|
13
|
+
return
|
14
|
+
end
|
15
|
+
|
16
|
+
Solara.logger.title("Current Brand Status")
|
17
|
+
|
18
|
+
content_changed = current_brand['content_changed']
|
19
|
+
|
20
|
+
unless content_changed
|
21
|
+
Solara.logger.info("Current brand configurations are up-to-date")
|
22
|
+
return
|
23
|
+
end
|
24
|
+
|
25
|
+
Solara.logger.warn("Changes for the current brand have been drafted!")
|
26
|
+
Solara.logger.info("To apply these changes, please use one of the following methods:")
|
27
|
+
message = <<-MESSAGE
|
28
|
+
1. Run this command in your terminal:
|
29
|
+
|
30
|
+
solara switch -k #{current_brand['key']}
|
31
|
+
|
32
|
+
2. Alternatively, open the dashboard by executing this command in your terminal:
|
33
|
+
|
34
|
+
solara dashboard -k #{current_brand['key']}
|
35
|
+
|
36
|
+
Then, click the "Apply Changes" button.
|
37
|
+
MESSAGE
|
38
|
+
Solara.logger.info(message)
|
39
|
+
end
|
40
|
+
|
41
|
+
def brands_list
|
42
|
+
Solara.logger.title("Brands List")
|
43
|
+
|
44
|
+
brands_list = BrandsManager.instance.brands_list.each_with_index.map { |brand, index|
|
45
|
+
"#{index + 1}. Key: #{brand['key']}\n Name: #{brand['name']}\n"
|
46
|
+
}
|
47
|
+
brands_list.each do |brand|
|
48
|
+
Solara.logger.info(brand)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def doctor
|
53
|
+
SolaraManager.new.doctor
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
class SolaraVersionManager
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
def sversion
|
10
|
+
json['solaraVersion']
|
11
|
+
end
|
12
|
+
|
13
|
+
def version=(value)
|
14
|
+
new_json = json
|
15
|
+
new_json['solaraVersion'] = value
|
16
|
+
save(new_json)
|
17
|
+
end
|
18
|
+
|
19
|
+
def value(key)
|
20
|
+
json[key]
|
21
|
+
end
|
22
|
+
|
23
|
+
def add(key, value)
|
24
|
+
new_json = json
|
25
|
+
new_json[key] = value
|
26
|
+
save(new_json)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def json
|
32
|
+
path = FilePath.solara_version
|
33
|
+
FileManager.create_file_if_not_exist(path)
|
34
|
+
JSON.parse(File.read(path))
|
35
|
+
rescue JSON::ParserError => e
|
36
|
+
{}
|
37
|
+
end
|
38
|
+
|
39
|
+
def save(json)
|
40
|
+
File.write(FilePath.solara_version, JSON.pretty_generate(json))
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
|
3
|
+
class StringsXmlManager
|
4
|
+
def initialize(file_path)
|
5
|
+
@file_path = file_path
|
6
|
+
@xml_content = File.read(@file_path)
|
7
|
+
@doc = REXML::Document.new(@xml_content)
|
8
|
+
end
|
9
|
+
|
10
|
+
def delete_app_name
|
11
|
+
app_name_element = @doc.elements['resources/string[@name="app_name"]']
|
12
|
+
app_name_element.remove if app_name_element
|
13
|
+
save_changes
|
14
|
+
Solara.logger.debug("Removed app_name from #{@file_path} to avoid duplication with artifacts/strings.xml.")
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def save_changes
|
20
|
+
File.write(@file_path, @doc.to_s)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class TerminalInputManager
|
2
|
+
|
3
|
+
def get_validated(message)
|
4
|
+
loop do
|
5
|
+
print message.green
|
6
|
+
user_input = STDIN.gets.chomp
|
7
|
+
|
8
|
+
if yield(user_input)
|
9
|
+
return user_input
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def get(message)
|
15
|
+
loop do
|
16
|
+
print message.green
|
17
|
+
user_input = STDIN.gets.chomp
|
18
|
+
return user_input unless user_input.nil? || user_input.empty?
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|