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,62 @@
|
|
1
|
+
{
|
2
|
+
"files": [
|
3
|
+
{
|
4
|
+
"source": "brands.json",
|
5
|
+
"target": "../brands.json",
|
6
|
+
"condition": "true"
|
7
|
+
},
|
8
|
+
{
|
9
|
+
"source": "android/assets/",
|
10
|
+
"target": "android/assets/",
|
11
|
+
"condition": "true"
|
12
|
+
},
|
13
|
+
{
|
14
|
+
"source": "android/res/",
|
15
|
+
"target": "android/res/",
|
16
|
+
"condition": "true"
|
17
|
+
},
|
18
|
+
{
|
19
|
+
"source": "android/android_config.json",
|
20
|
+
"target": "android/android_config.json",
|
21
|
+
"condition": "true"
|
22
|
+
},
|
23
|
+
{
|
24
|
+
"source": "android/android_signing.json",
|
25
|
+
"target": "android/android_signing.json",
|
26
|
+
"condition": "true"
|
27
|
+
},
|
28
|
+
{
|
29
|
+
"source": "ios/assets/",
|
30
|
+
"target": "ios/assets/",
|
31
|
+
"condition": "true"
|
32
|
+
},
|
33
|
+
{
|
34
|
+
"source": "ios/ios_config.json",
|
35
|
+
"target": "ios/ios_config.json",
|
36
|
+
"condition": "true"
|
37
|
+
},
|
38
|
+
{
|
39
|
+
"source": "ios/ios_signing.json",
|
40
|
+
"target": "ios/ios_signing.json",
|
41
|
+
"condition": "true"
|
42
|
+
},
|
43
|
+
{
|
44
|
+
"source": "shared/assets/",
|
45
|
+
"target": "shared/assets/",
|
46
|
+
"condition": "true"
|
47
|
+
},
|
48
|
+
{
|
49
|
+
"source": "shared/theme.json",
|
50
|
+
"target": "shared/theme.json",
|
51
|
+
"condition": "true"
|
52
|
+
},
|
53
|
+
{
|
54
|
+
"source": "shared/brand_config.json",
|
55
|
+
"target": "shared/brand_config.json",
|
56
|
+
"condition": "true"
|
57
|
+
}
|
58
|
+
],
|
59
|
+
"variables": {
|
60
|
+
"platform": "flutter"
|
61
|
+
}
|
62
|
+
}
|
@@ -0,0 +1,57 @@
|
|
1
|
+
{
|
2
|
+
"files": [
|
3
|
+
{
|
4
|
+
"source": "brands.json",
|
5
|
+
"target": "../brands.json",
|
6
|
+
"condition": "true"
|
7
|
+
},
|
8
|
+
{
|
9
|
+
"source": "android/assets/",
|
10
|
+
"target": "android/assets/",
|
11
|
+
"condition": "true"
|
12
|
+
},
|
13
|
+
{
|
14
|
+
"source": "android/res/",
|
15
|
+
"target": "android/res/",
|
16
|
+
"condition": "true"
|
17
|
+
},
|
18
|
+
{
|
19
|
+
"source": "android/android_config.json",
|
20
|
+
"target": "android/android_config.json",
|
21
|
+
"condition": "true"
|
22
|
+
},
|
23
|
+
{
|
24
|
+
"source": "android/android_signing.json",
|
25
|
+
"target": "android/android_signing.json",
|
26
|
+
"condition": "true"
|
27
|
+
},
|
28
|
+
{
|
29
|
+
"source": "ios/assets/",
|
30
|
+
"target": "ios/assets/",
|
31
|
+
"condition": "true"
|
32
|
+
},
|
33
|
+
{
|
34
|
+
"source": "ios/ios_config.json",
|
35
|
+
"target": "ios/ios_config.json",
|
36
|
+
"condition": "true"
|
37
|
+
},
|
38
|
+
{
|
39
|
+
"source": "ios/ios_signing.json",
|
40
|
+
"target": "ios/ios_signing.json",
|
41
|
+
"condition": "true"
|
42
|
+
},
|
43
|
+
{
|
44
|
+
"source": "shared/theme.json",
|
45
|
+
"target": "shared/theme.json",
|
46
|
+
"condition": "true"
|
47
|
+
},
|
48
|
+
{
|
49
|
+
"source": "shared/brand_config.json",
|
50
|
+
"target": "shared/brand_config.json",
|
51
|
+
"condition": "true"
|
52
|
+
}
|
53
|
+
],
|
54
|
+
"variables": {
|
55
|
+
"platform": "ios"
|
56
|
+
}
|
57
|
+
}
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
class ProjectTemplateGenerator
|
5
|
+
def initialize(template_dir, target_dir, config_file)
|
6
|
+
@template_dir = template_dir
|
7
|
+
@target_dir = target_dir
|
8
|
+
@config_file = config_file
|
9
|
+
@config = read_config
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_project
|
13
|
+
@config["files"].each do |file|
|
14
|
+
if evaluate_condition(file["condition"], @config["variables"])
|
15
|
+
source_path = File.join(@template_dir, file["source"])
|
16
|
+
target_path = File.join(@target_dir, file["target"])
|
17
|
+
|
18
|
+
copy_content = file.fetch("copy_content", true)
|
19
|
+
copy_item(source_path, target_path, copy_content)
|
20
|
+
replace_variables(target_path, @config["variables"]) if copy_content
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def read_config
|
28
|
+
JSON.parse(File.read(@config_file))
|
29
|
+
end
|
30
|
+
|
31
|
+
def evaluate_condition(condition, variables)
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
def copy_item(source, target, copy_content)
|
36
|
+
if File.directory?(source)
|
37
|
+
FileUtils.mkdir_p(target)
|
38
|
+
Dir.foreach(source) do |item|
|
39
|
+
next if item == '.' || item == '..'
|
40
|
+
copy_item(File.join(source, item), File.join(target, item), copy_content)
|
41
|
+
end
|
42
|
+
else
|
43
|
+
FileUtils.mkdir_p(File.dirname(target))
|
44
|
+
if File.exist?(source) && copy_content
|
45
|
+
FileUtils.cp(source, target)
|
46
|
+
else
|
47
|
+
FileUtils.touch(target)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def replace_variables(file_path, variables)
|
53
|
+
return unless File.exist?(file_path) && File.file?(file_path)
|
54
|
+
|
55
|
+
content = File.read(file_path)
|
56
|
+
|
57
|
+
variables.each do |key, value|
|
58
|
+
content.gsub!(/\{\{#{key}\}\}/, value.to_s)
|
59
|
+
end
|
60
|
+
|
61
|
+
File.write(file_path, content)
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'find'
|
2
|
+
|
3
|
+
class PlatformDetector
|
4
|
+
def initialize
|
5
|
+
@project_path = SolaraSettingsManager.instance.project_root
|
6
|
+
end
|
7
|
+
|
8
|
+
def platform
|
9
|
+
Solara.logger.start_step("Detecting current platform")
|
10
|
+
detected_platform = detect
|
11
|
+
|
12
|
+
if detected_platform != Platform::Unknown
|
13
|
+
Solara.logger.info("👀 Detected platform: #{detected_platform}")
|
14
|
+
else
|
15
|
+
Solara.logger.failure("Unable to detect platfrom")
|
16
|
+
return enter_correct_platform
|
17
|
+
end
|
18
|
+
|
19
|
+
print "Is this #{detected_platform.upcase} project? (y/n): ".yellow
|
20
|
+
|
21
|
+
loop do
|
22
|
+
response = STDIN.gets.chomp.downcase
|
23
|
+
if response == 'y' || response.empty?
|
24
|
+
Solara.logger.end_step("Detecting current platform")
|
25
|
+
return detected_platform
|
26
|
+
elsif response == 'n'
|
27
|
+
return enter_correct_platform
|
28
|
+
else
|
29
|
+
Solara.logger.failure("Invalid input. Please enter 'y' or 'n'.")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def enter_correct_platform
|
37
|
+
loop do
|
38
|
+
print "Enter the platform (#{Platform.all.join(', ')}): ".green
|
39
|
+
user_input = STDIN.gets.chomp.downcase
|
40
|
+
if Platform.all.map(&:downcase).include?(user_input)
|
41
|
+
Solara.logger.end_step("Detecting current platform")
|
42
|
+
return user_input
|
43
|
+
else
|
44
|
+
Solara.logger.failure("Invalid platform. Please enter one of: #{Platform.all.join(', ')}")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def detect
|
50
|
+
if flutter?
|
51
|
+
Platform::Flutter
|
52
|
+
elsif ios?
|
53
|
+
Platform::IOS
|
54
|
+
elsif android?
|
55
|
+
Platform::Android
|
56
|
+
else
|
57
|
+
Platform::Unknown
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def flutter?
|
62
|
+
flutter_config_file = File.join(@project_path, 'pubspec.yaml')
|
63
|
+
flutter_main_file = File.join(@project_path, 'lib', 'main.dart')
|
64
|
+
File.exist?(flutter_config_file) && File.exist?(flutter_main_file)
|
65
|
+
end
|
66
|
+
|
67
|
+
def ios?
|
68
|
+
ios_project_files = []
|
69
|
+
Find.find(@project_path) do |path|
|
70
|
+
if File.directory?(path) && (path.end_with?('.xcodeproj') || path.end_with?('.xcworkspace'))
|
71
|
+
ios_project_files << path
|
72
|
+
Find.prune # Stop searching further in this directory
|
73
|
+
end
|
74
|
+
end
|
75
|
+
!ios_project_files.empty?
|
76
|
+
end
|
77
|
+
|
78
|
+
def android?
|
79
|
+
app_build_gradle = File.join(@project_path, 'app', 'build.gradle')
|
80
|
+
app_build_gradle_kts = File.join(@project_path, 'app', 'build.gradle.kts')
|
81
|
+
gradle_properties = File.join(@project_path, 'gradle.properties')
|
82
|
+
(File.exist?(app_build_gradle) || File.exist?(app_build_gradle_kts)) && File.exist?(gradle_properties)
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,238 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'fileutils'
|
3
|
+
Dir['*.rb'].each { |file| require_relative file }
|
4
|
+
Dir.glob("#{__dir__}/core/scripts/*.rb").each { |file| require file }
|
5
|
+
require 'solara_manager'
|
6
|
+
require 'rubygems'
|
7
|
+
|
8
|
+
module Solara
|
9
|
+
ROOT = Pathname.new(File.expand_path('..', __FILE__))
|
10
|
+
PROJECT_ROOT = Dir.pwd
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_reader :logger
|
14
|
+
attr_reader :verbose
|
15
|
+
|
16
|
+
def verbose=(value)
|
17
|
+
@verbose = value
|
18
|
+
@logger.verbose = value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
@logger = SolaraLogger.new
|
23
|
+
@verbose = false
|
24
|
+
|
25
|
+
class Setup
|
26
|
+
def setup
|
27
|
+
SolaraSettingsManager.instance.root = ROOT
|
28
|
+
SolaraSettingsManager.instance.project_root = PROJECT_ROOT
|
29
|
+
|
30
|
+
Solara.logger.debug("Solara installation at path: #{PROJECT_ROOT}")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class CLI < Thor
|
35
|
+
class_option :verbose, type: :boolean, :aliases => "-v", default: false, desc: 'Run verbosely'
|
36
|
+
|
37
|
+
def initialize(*args)
|
38
|
+
super
|
39
|
+
setup
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.exit_on_failure?
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "init -p YOUR_PLATFORM -k YOUR_BRAND_KEY -n YOUR_BRAND_NAME",
|
47
|
+
"Initialize Solara. Options: #{Platform.all.join(', ')}"
|
48
|
+
method_option :brand_key, :type => :string, :aliases => "-k"
|
49
|
+
method_option :brand_name, :type => :string, :aliases => "-n"
|
50
|
+
method_option :platform, :type => :string, :aliases => "-p"
|
51
|
+
|
52
|
+
def init
|
53
|
+
brand_key = options['brand_key']
|
54
|
+
brand_name = options['brand_name']
|
55
|
+
input_platform = options['platform']
|
56
|
+
|
57
|
+
brand_key = validate_brand_key(brand_key, ignore_brand_check: true)
|
58
|
+
brand_name = validate_brand_name(brand_name)
|
59
|
+
|
60
|
+
platform = if !input_platform.nil?
|
61
|
+
input_platform
|
62
|
+
else
|
63
|
+
PlatformDetector.new.platform
|
64
|
+
end
|
65
|
+
|
66
|
+
platform = platform.to_s.downcase
|
67
|
+
|
68
|
+
SolaraSettingsManager.instance.platform = platform
|
69
|
+
SolaraManager.new.init(platform, brand_key, brand_name)
|
70
|
+
end
|
71
|
+
|
72
|
+
desc "status", "Check the current status of Solara. The results may include information about the brand's current standing, the list of brands, and additional details."
|
73
|
+
|
74
|
+
def status
|
75
|
+
check_project_health
|
76
|
+
SolaraManager.new.status
|
77
|
+
end
|
78
|
+
|
79
|
+
desc "import -configurations CONFIGURATIONS_JSON_FILE --brand_key YOUR_BRAND_KEY", "Import the brand's configurations. If the brand is existing, it will be updated with these configurations, otherwise, a new brand will be onboarded."
|
80
|
+
|
81
|
+
method_option :configurations, :type => :array, :aliases => "-c"
|
82
|
+
def import
|
83
|
+
check_project_health
|
84
|
+
|
85
|
+
configurations = options['configurations']
|
86
|
+
|
87
|
+
SolaraManager.new.import(configurations)
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
desc "export --brand_key YOUR_BRAND_KEY --directory DIRECTORY", "Export the brand's configurations. The brand details will be saved to a JSON file at the specified location."
|
92
|
+
method_option :brand_keys, :type => :array, :aliases => "-k"
|
93
|
+
method_option :directory, :type => :string, :aliases => "-d"
|
94
|
+
def export
|
95
|
+
check_project_health
|
96
|
+
|
97
|
+
brand_keys = options['brand_keys']
|
98
|
+
directory = options['directory']
|
99
|
+
|
100
|
+
|
101
|
+
SolaraManager.new.export(brand_keys, directory)
|
102
|
+
end
|
103
|
+
|
104
|
+
desc "onboard -k YOUR_BRAND_KEY -n YOUR_BRAND_NAME", "Onboard a new brand"
|
105
|
+
method_option :brand_key, :type => :string, :aliases => "-k"
|
106
|
+
method_option :brand_name, :type => :string, :aliases => "-n"
|
107
|
+
method_option :clone, :type => :string, :aliases => "-c"
|
108
|
+
|
109
|
+
def onboard
|
110
|
+
check_project_health
|
111
|
+
|
112
|
+
brand_key = options['brand_key']
|
113
|
+
brand_name = options['brand_name']
|
114
|
+
clone_brand_key = options['clone']
|
115
|
+
|
116
|
+
brand_key = validate_brand_key(brand_key, ignore_brand_check: true)
|
117
|
+
brand_name = validate_brand_name(brand_name)
|
118
|
+
|
119
|
+
unless clone_brand_key.nil? || clone_brand_key.empty?
|
120
|
+
clone_brand_key = validate_brand_key(clone_brand_key, message: "Clone brand key is not existing, please enter correct key: ")
|
121
|
+
end
|
122
|
+
|
123
|
+
SolaraManager.new.onboard(brand_key, brand_name, clone_brand_key: clone_brand_key)
|
124
|
+
end
|
125
|
+
|
126
|
+
desc "offboard -k YOUR_BRAND_KEY", "Offboard a brand by deleting it from brands."
|
127
|
+
method_option :brand_key, :type => :string, :aliases => "-k"
|
128
|
+
|
129
|
+
def offboard
|
130
|
+
check_project_health
|
131
|
+
brand_key = options['brand_key']
|
132
|
+
brand_key = validate_brand_key(brand_key)
|
133
|
+
SolaraManager.new.offboard(brand_key)
|
134
|
+
end
|
135
|
+
|
136
|
+
desc "`switch -k YOUR_BRAND_KEY", "Switch to a brand."
|
137
|
+
method_option :brand_key, :type => :string, :aliases => "-k"
|
138
|
+
|
139
|
+
def switch
|
140
|
+
check_project_health
|
141
|
+
brand_key = options['brand_key']
|
142
|
+
brand_key = validate_brand_key(brand_key)
|
143
|
+
begin
|
144
|
+
SolaraManager.new.switch(brand_key)
|
145
|
+
rescue StandardError => e
|
146
|
+
Solara.logger.fatal("Switching to #{brand_key} failed.")
|
147
|
+
exit 1
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
|
152
|
+
desc "dashboard -k YOUR_OPTIONAL_BRAND_KEY", "Open the dashboard for a brand if brank_key is provided."
|
153
|
+
method_option :brand_key, :type => :string, :aliases => "-k"
|
154
|
+
method_option :port, :type => :numeric, :aliases => "-p"
|
155
|
+
|
156
|
+
def dashboard
|
157
|
+
check_project_health
|
158
|
+
brand_key = options['brand_key']
|
159
|
+
brand_key = validate_brand_key(brand_key, ignore_if_nil: true)
|
160
|
+
SolaraManager.new.dashboard(brand_key, options['port'] || 8000)
|
161
|
+
end
|
162
|
+
|
163
|
+
desc "doctor -k YOUR_BRAND_KEY", "Visit Doctor for a brand if brankd_key provided."
|
164
|
+
method_option :brand_key, :type => :string, :aliases => "-k"
|
165
|
+
|
166
|
+
def doctor
|
167
|
+
check_project_health
|
168
|
+
brand_key = options['brand_key']
|
169
|
+
brand_key = validate_brand_key(brand_key, ignore_if_nil: true)
|
170
|
+
SolaraManager.new.doctor(brand_key)
|
171
|
+
end
|
172
|
+
|
173
|
+
private
|
174
|
+
|
175
|
+
# Ensure the platform is set when Solara is initialized but the platform is not set
|
176
|
+
# This happens in scenarios like cloning the project and running Solara, In this case the
|
177
|
+
# platfrom is not set yet.
|
178
|
+
def ensure_platform
|
179
|
+
brands = FilePath.brands
|
180
|
+
platform = SolaraSettingsManager.instance.platform || ''
|
181
|
+
if File.exist?(brands) && platform.empty?
|
182
|
+
SolaraSettingsManager.instance.platform = PlatformDetector.new.platform
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def check_project_health
|
187
|
+
DoctorManager.new.visit_project!
|
188
|
+
end
|
189
|
+
|
190
|
+
def validate_brand_key(brand_key, ignore_if_nil: false, ignore_brand_check: false, message: nil)
|
191
|
+
if ignore_if_nil && brand_key.nil?
|
192
|
+
return brand_key
|
193
|
+
end
|
194
|
+
|
195
|
+
if brand_key.nil? || brand_key.empty? || (!ignore_brand_check && BrandsManager.instance.find(brand_key).nil?)
|
196
|
+
message = message || (brand_key.nil? || brand_key.empty? ? "Please enter brand key: " : "Please enter existing brand key: ")
|
197
|
+
brand_key = TerminalInputManager.new.get_validated(message) do |input|
|
198
|
+
# Validate that it starts with a letter and contains no spaces
|
199
|
+
unless input.match?(/^[a-zA-Z][\S]*$/)
|
200
|
+
Solara.logger.failure("Invalid brand key. It must start with at least a letter and contain no spaces.")
|
201
|
+
next false # Use `next` to continue the loop
|
202
|
+
end
|
203
|
+
|
204
|
+
# Check if the brand exists in the list
|
205
|
+
if !ignore_brand_check && BrandsManager.instance.find(input).nil?
|
206
|
+
Solara.logger.failure("Brand key does not exist.")
|
207
|
+
next false # Use `next` to continue the loop
|
208
|
+
end
|
209
|
+
|
210
|
+
true # Valid input and brand exists
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# If brand_key is valid and exists, return it
|
215
|
+
brand_key
|
216
|
+
end
|
217
|
+
|
218
|
+
def validate_brand_name(brand_name)
|
219
|
+
if brand_name.nil? || brand_name.empty?
|
220
|
+
message = "Please enter brand name: "
|
221
|
+
return TerminalInputManager.new.get(message)
|
222
|
+
end
|
223
|
+
brand_name
|
224
|
+
end
|
225
|
+
|
226
|
+
|
227
|
+
def setup
|
228
|
+
Solara.logger.verbose = options[:verbose] || false
|
229
|
+
|
230
|
+
ensure_platform
|
231
|
+
|
232
|
+
# Solara version is mandatory because the structure and logic may change in the future and need to migrate.
|
233
|
+
SolaraVersionManager.instance.version = Gem.loaded_specs['solara'].version.to_s
|
234
|
+
end
|
235
|
+
|
236
|
+
end
|
237
|
+
|
238
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
Dir.glob("#{__dir__}/core/scripts/*.rb").each { |file| require file }
|
2
|
+
Dir.glob("#{__dir__}/core/scripts/*.rb").each { |file| require file }
|
3
|
+
Dir.glob("#{__dir__}/core/*.rb").each { |file| require file }
|
4
|
+
Dir.glob("#{__dir__}/core/doctor/*.rb").each { |file| require file }
|
5
|
+
Dir.glob("#{__dir__}/core/aliases/*.rb").each { |file| require file }
|
6
|
+
Dir.glob("#{__dir__}/core/dashboard/*.rb").each { |file| require file }
|
7
|
+
Dir.glob("#{__dir__}/core/brands/*.rb").each { |file| require file }
|
8
|
+
|
9
|
+
require 'json'
|
10
|
+
require 'xcodeproj'
|
11
|
+
|
12
|
+
class SolaraInitializer
|
13
|
+
|
14
|
+
def initialize(brand_key, brand_name)
|
15
|
+
@brand_key = brand_key
|
16
|
+
@brand_name = brand_name
|
17
|
+
@project_root = SolaraSettingsManager.instance.project_root
|
18
|
+
end
|
19
|
+
|
20
|
+
def init
|
21
|
+
Solara.logger.header("Initializing Solara")
|
22
|
+
confirm_init_if_necessary
|
23
|
+
message = "Initialized #{SolaraSettingsManager.instance.platform} successfully."
|
24
|
+
SolaraManager.new.onboard(@brand_key, @brand_name, init: true, success_message: message)
|
25
|
+
end
|
26
|
+
|
27
|
+
def confirm_init_if_necessary
|
28
|
+
brand_path = File.join(FilePath.solara, 'brands')
|
29
|
+
# Check if Solara path exists
|
30
|
+
if Dir.exist?(brand_path)
|
31
|
+
Solara.logger.warn("Solara already initialized! Be aware that reinitializing will delete all current brands!")
|
32
|
+
Solara.logger.warn("Don't say I didn't warn you!")
|
33
|
+
Solara.logger.warn("Do you want to proceed? (y/n)")
|
34
|
+
confirmation = STDIN.gets.chomp.downcase
|
35
|
+
|
36
|
+
unless confirmation == 'y'
|
37
|
+
Solara.logger.info("Solara initialization cancelled.")
|
38
|
+
exit 1
|
39
|
+
end
|
40
|
+
FileUtils.rm_rf(brand_path)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
Dir.glob("#{__dir__}/*.rb").each { |file| require file }
|
2
|
+
Dir.glob("#{__dir__}/core/scripts/*.rb").each { |file| require file }
|
3
|
+
Dir.glob("#{__dir__}/core/scripts/*.rb").each { |file| require file }
|
4
|
+
Dir.glob("#{__dir__}/core/*.rb").each { |file| require file }
|
5
|
+
Dir.glob("#{__dir__}/core/doctor/*.rb").each { |file| require file }
|
6
|
+
Dir.glob("#{__dir__}/core/aliases/*.rb").each { |file| require file }
|
7
|
+
Dir.glob("#{__dir__}/core/dashboard/*.rb").each { |file| require file }
|
8
|
+
Dir.glob("#{__dir__}/core/brands/*.rb").each { |file| require file }
|
9
|
+
|
10
|
+
require 'json'
|
11
|
+
require 'xcodeproj'
|
12
|
+
|
13
|
+
class SolaraManager
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
end
|
17
|
+
|
18
|
+
def init(platform, brand_key, brand_name)
|
19
|
+
SolaraInitializer.new(brand_key, brand_name).init
|
20
|
+
end
|
21
|
+
|
22
|
+
def import(configurations)
|
23
|
+
BrandImporter.new.start(configurations)
|
24
|
+
end
|
25
|
+
|
26
|
+
def export(brand_keys, path)
|
27
|
+
BrandExporter.new.start(brand_keys, path)
|
28
|
+
end
|
29
|
+
|
30
|
+
def status
|
31
|
+
SolaraStatusManager.new.start
|
32
|
+
end
|
33
|
+
|
34
|
+
def onboard(brand_key, brand_name, init: false, clone_brand_key: nil, open_dashboard: true, success_message: nil)
|
35
|
+
Solara.logger.header("Onboarding #{brand_key}")
|
36
|
+
|
37
|
+
if !init && BrandsManager.instance.exists(brand_key)
|
38
|
+
Solara.logger.fatal("Brand with key (#{brand_key}) already added to brands!")
|
39
|
+
return
|
40
|
+
end
|
41
|
+
|
42
|
+
BrandOnboarder.new(brand_key, brand_name, clone_brand_key: clone_brand_key).onboard
|
43
|
+
|
44
|
+
switch(brand_key, ignore_health_check: true)
|
45
|
+
|
46
|
+
clone_message = clone_brand_key.nil? || clone_brand_key.empty? ? '.' : ", cloned from #{clone_brand_key}."
|
47
|
+
message = success_message || "Onboarded #{brand_key} successfully#{clone_message}"
|
48
|
+
Solara.logger.success(message)
|
49
|
+
|
50
|
+
if open_dashboard
|
51
|
+
Solara.logger.success("Openning the dashboard for #{brand_key} to complete its details.")
|
52
|
+
dashboard(brand_key)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def offboard(brand_key, confirm: true)
|
57
|
+
BrandOffboarder.new.offboard(brand_key, confirm: confirm)
|
58
|
+
end
|
59
|
+
|
60
|
+
def switch(brand_key, ignore_health_check: false)
|
61
|
+
BrandSwitcher.new(brand_key, ignore_health_check: ignore_health_check).start
|
62
|
+
end
|
63
|
+
|
64
|
+
def dashboard(brand_key, port = 8000)
|
65
|
+
DashboardManager.new.start(brand_key, port)
|
66
|
+
end
|
67
|
+
|
68
|
+
def doctor(brand_key = nil, print_logs: true)
|
69
|
+
keys = brand_key.nil? || brand_key.empty? ? [] : [brand_key]
|
70
|
+
DoctorManager.new.visit_brands(keys, print_logs: print_logs)
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|