solara 0.1.0
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 +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
|