xcres 0.4.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/.gitignore +33 -0
- data/.travis.yml +18 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +85 -0
- data/LICENSE.txt +22 -0
- data/README.md +181 -0
- data/Rakefile +58 -0
- data/bin/xcres +12 -0
- data/lib/xcres/analyzer/aggregate_analyzer.rb +48 -0
- data/lib/xcres/analyzer/analyzer.rb +141 -0
- data/lib/xcres/analyzer/resources_aggregate_analyzer.rb +27 -0
- data/lib/xcres/analyzer/resources_analyzer/base_resources_analyzer.rb +133 -0
- data/lib/xcres/analyzer/resources_analyzer/bundle_resources_analyzer.rb +68 -0
- data/lib/xcres/analyzer/resources_analyzer/loose_resources_analyzer.rb +39 -0
- data/lib/xcres/analyzer/resources_analyzer/xcassets_analyzer.rb +62 -0
- data/lib/xcres/analyzer/strings_analyzer.rb +255 -0
- data/lib/xcres/builder/file_builder.rb +61 -0
- data/lib/xcres/builder/resources_builder.rb +184 -0
- data/lib/xcres/builder/string_builder.rb +31 -0
- data/lib/xcres/command/build_command.rb +83 -0
- data/lib/xcres/command/command.rb +58 -0
- data/lib/xcres/command/install_command.rb +173 -0
- data/lib/xcres/command/main_command.rb +14 -0
- data/lib/xcres/command/project_command.rb +111 -0
- data/lib/xcres/command/version_command.rb +12 -0
- data/lib/xcres/helper/file_helper.rb +16 -0
- data/lib/xcres/logger.rb +148 -0
- data/lib/xcres/model/section.rb +43 -0
- data/lib/xcres/model/xcassets/bundle.rb +55 -0
- data/lib/xcres/model/xcassets/resource.rb +141 -0
- data/lib/xcres/model/xcassets/resource_image.rb +134 -0
- data/lib/xcres/version.rb +9 -0
- data/lib/xcres.rb +9 -0
- data/spec/fixtures/Example/Example/AppDelegate.h +15 -0
- data/spec/fixtures/Example/Example/AppDelegate.m +49 -0
- data/spec/fixtures/Example/Example/Example-Info.plist +38 -0
- data/spec/fixtures/Example/Example/Example-Prefix.pch +16 -0
- data/spec/fixtures/Example/Example/Images/doge.jpeg +0 -0
- data/spec/fixtures/Example/Example/Images/nyanCat.png +0 -0
- data/spec/fixtures/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
- data/spec/fixtures/Example/Example/Images.xcassets/Doge.imageset/Contents.json +18 -0
- data/spec/fixtures/Example/Example/Images.xcassets/Doge.imageset/doge.png +0 -0
- data/spec/fixtures/Example/Example/Images.xcassets/Doge.imageset/doge@2x.png +0 -0
- data/spec/fixtures/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
- data/spec/fixtures/Example/Example/de.lproj/Localizable.strings +12 -0
- data/spec/fixtures/Example/Example/en.lproj/InfoPlist.strings +2 -0
- data/spec/fixtures/Example/Example/en.lproj/Localizable.strings +15 -0
- data/spec/fixtures/Example/Example/main.m +18 -0
- data/spec/fixtures/Example/Example.xcodeproj/project.pbxproj +449 -0
- data/spec/fixtures/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- data/spec/fixtures/ExampleOSX/ExampleOSX/AppDelegate.h +15 -0
- data/spec/fixtures/ExampleOSX/ExampleOSX/AppDelegate.m +18 -0
- data/spec/fixtures/ExampleOSX/ExampleOSX/Base.lproj/MainMenu.xib +680 -0
- data/spec/fixtures/ExampleOSX/ExampleOSX/ExampleOSX-Info.plist +34 -0
- data/spec/fixtures/ExampleOSX/ExampleOSX/ExampleOSX-Prefix.pch +9 -0
- data/spec/fixtures/ExampleOSX/ExampleOSX/Images.xcassets/AppIcon.appiconset/Contents.json +58 -0
- data/spec/fixtures/ExampleOSX/ExampleOSX/en.lproj/Credits.rtf +29 -0
- data/spec/fixtures/ExampleOSX/ExampleOSX/en.lproj/InfoPlist.strings +2 -0
- data/spec/fixtures/ExampleOSX/ExampleOSX/main.m +14 -0
- data/spec/fixtures/ExampleOSX/ExampleOSX.xcodeproj/project.pbxproj +481 -0
- data/spec/fixtures/ExampleOSX/ExampleOSX.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- data/spec/fixtures/ExampleOSX/ExampleOSXTests/ExampleOSXTests-Info.plist +22 -0
- data/spec/fixtures/ExampleOSX/ExampleOSXTests/ExampleOSXTests.m +34 -0
- data/spec/fixtures/ExampleOSX/ExampleOSXTests/en.lproj/InfoPlist.strings +2 -0
- data/spec/integration/build/after/Example/Example/AppDelegate.h +15 -0
- data/spec/integration/build/after/Example/Example/AppDelegate.m +49 -0
- data/spec/integration/build/after/Example/Example/Example-Info.plist +38 -0
- data/spec/integration/build/after/Example/Example/Example-Prefix.pch +16 -0
- data/spec/integration/build/after/Example/Example/Icons.bundle/tab_bar/tabbar_list.png +0 -0
- data/spec/integration/build/after/Example/Example/Icons.bundle/tab_bar/tabbar_list@2x.png +0 -0
- data/spec/integration/build/after/Example/Example/Icons.bundle/tab_bar/tabbar_map.png +0 -0
- data/spec/integration/build/after/Example/Example/Icons.bundle/tab_bar/tabbar_map@2x.png +0 -0
- data/spec/integration/build/after/Example/Example/Images/doge.jpeg +0 -0
- data/spec/integration/build/after/Example/Example/Images/nyanCat.png +0 -0
- data/spec/integration/build/after/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
- data/spec/integration/build/after/Example/Example/Images.xcassets/Doge.imageset/Contents.json +18 -0
- data/spec/integration/build/after/Example/Example/Images.xcassets/Doge.imageset/doge.png +0 -0
- data/spec/integration/build/after/Example/Example/Images.xcassets/Doge.imageset/doge@2x.png +0 -0
- data/spec/integration/build/after/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
- data/spec/integration/build/after/Example/Example/de.lproj/Localizable.strings +12 -0
- data/spec/integration/build/after/Example/Example/en.lproj/InfoPlist.strings +2 -0
- data/spec/integration/build/after/Example/Example/en.lproj/Localizable.strings +15 -0
- data/spec/integration/build/after/Example/Example/main.m +18 -0
- data/spec/integration/build/after/Example/Example.xcodeproj.yaml +168 -0
- data/spec/integration/build/after/R.h +39 -0
- data/spec/integration/build/after/R.m +29 -0
- data/spec/integration/build/after/execution_output.txt +19 -0
- data/spec/integration/build/before/Example/Example/AppDelegate.h +15 -0
- data/spec/integration/build/before/Example/Example/AppDelegate.m +49 -0
- data/spec/integration/build/before/Example/Example/Example-Info.plist +38 -0
- data/spec/integration/build/before/Example/Example/Example-Prefix.pch +16 -0
- data/spec/integration/build/before/Example/Example/Icons.bundle/tab_bar/tabbar_list.png +0 -0
- data/spec/integration/build/before/Example/Example/Icons.bundle/tab_bar/tabbar_list@2x.png +0 -0
- data/spec/integration/build/before/Example/Example/Icons.bundle/tab_bar/tabbar_map.png +0 -0
- data/spec/integration/build/before/Example/Example/Icons.bundle/tab_bar/tabbar_map@2x.png +0 -0
- data/spec/integration/build/before/Example/Example/Images/doge.jpeg +0 -0
- data/spec/integration/build/before/Example/Example/Images/nyanCat.png +0 -0
- data/spec/integration/build/before/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
- data/spec/integration/build/before/Example/Example/Images.xcassets/Doge.imageset/Contents.json +18 -0
- data/spec/integration/build/before/Example/Example/Images.xcassets/Doge.imageset/doge.png +0 -0
- data/spec/integration/build/before/Example/Example/Images.xcassets/Doge.imageset/doge@2x.png +0 -0
- data/spec/integration/build/before/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
- data/spec/integration/build/before/Example/Example/de.lproj/Localizable.strings +12 -0
- data/spec/integration/build/before/Example/Example/en.lproj/InfoPlist.strings +2 -0
- data/spec/integration/build/before/Example/Example/en.lproj/Localizable.strings +15 -0
- data/spec/integration/build/before/Example/Example/main.m +18 -0
- data/spec/integration/build/before/Example/Example.xcodeproj/project.pbxproj +453 -0
- data/spec/integration/build/before/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- data/spec/integration/build-keyword-clash/after/Example/Example/AppDelegate.h +15 -0
- data/spec/integration/build-keyword-clash/after/Example/Example/AppDelegate.m +49 -0
- data/spec/integration/build-keyword-clash/after/Example/Example/Default-568h@2x.png +0 -0
- data/spec/integration/build-keyword-clash/after/Example/Example/Default.png +0 -0
- data/spec/integration/build-keyword-clash/after/Example/Example/Default@2x.png +0 -0
- data/spec/integration/build-keyword-clash/after/Example/Example/Example-Info.plist +38 -0
- data/spec/integration/build-keyword-clash/after/Example/Example/Example-Prefix.pch +16 -0
- data/spec/integration/build-keyword-clash/after/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
- data/spec/integration/build-keyword-clash/after/Example/Example/en.lproj/InfoPlist.strings +2 -0
- data/spec/integration/build-keyword-clash/after/Example/Example/main.m +18 -0
- data/spec/integration/build-keyword-clash/after/Example/Example.xcodeproj.yaml +160 -0
- data/spec/integration/build-keyword-clash/after/R.h +15 -0
- data/spec/integration/build-keyword-clash/after/R.m +15 -0
- data/spec/integration/build-keyword-clash/after/execution_output.txt +14 -0
- data/spec/integration/build-keyword-clash/before/Example/Example/AppDelegate.h +15 -0
- data/spec/integration/build-keyword-clash/before/Example/Example/AppDelegate.m +49 -0
- data/spec/integration/build-keyword-clash/before/Example/Example/Default-568h@2x.png +0 -0
- data/spec/integration/build-keyword-clash/before/Example/Example/Default.png +0 -0
- data/spec/integration/build-keyword-clash/before/Example/Example/Default@2x.png +0 -0
- data/spec/integration/build-keyword-clash/before/Example/Example/Example-Info.plist +38 -0
- data/spec/integration/build-keyword-clash/before/Example/Example/Example-Prefix.pch +16 -0
- data/spec/integration/build-keyword-clash/before/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
- data/spec/integration/build-keyword-clash/before/Example/Example/en.lproj/InfoPlist.strings +2 -0
- data/spec/integration/build-keyword-clash/before/Example/Example/main.m +18 -0
- data/spec/integration/build-keyword-clash/before/Example/Example.xcodeproj/project.pbxproj +427 -0
- data/spec/integration/build-keyword-clash/before/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- data/spec/integration/build-var-infoplist/after/Example/Example/AppDelegate.h +15 -0
- data/spec/integration/build-var-infoplist/after/Example/Example/AppDelegate.m +49 -0
- data/spec/integration/build-var-infoplist/after/Example/Example/Example-Info.plist +38 -0
- data/spec/integration/build-var-infoplist/after/Example/Example/Example-Prefix.pch +16 -0
- data/spec/integration/build-var-infoplist/after/Example/Example/Icons.bundle/tab_bar/tabbar_list.png +0 -0
- data/spec/integration/build-var-infoplist/after/Example/Example/Icons.bundle/tab_bar/tabbar_list@2x.png +0 -0
- data/spec/integration/build-var-infoplist/after/Example/Example/Icons.bundle/tab_bar/tabbar_map.png +0 -0
- data/spec/integration/build-var-infoplist/after/Example/Example/Icons.bundle/tab_bar/tabbar_map@2x.png +0 -0
- data/spec/integration/build-var-infoplist/after/Example/Example/Images/doge.jpeg +0 -0
- data/spec/integration/build-var-infoplist/after/Example/Example/Images/nyanCat.png +0 -0
- data/spec/integration/build-var-infoplist/after/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
- data/spec/integration/build-var-infoplist/after/Example/Example/Images.xcassets/Doge.imageset/Contents.json +18 -0
- data/spec/integration/build-var-infoplist/after/Example/Example/Images.xcassets/Doge.imageset/doge.png +0 -0
- data/spec/integration/build-var-infoplist/after/Example/Example/Images.xcassets/Doge.imageset/doge@2x.png +0 -0
- data/spec/integration/build-var-infoplist/after/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
- data/spec/integration/build-var-infoplist/after/Example/Example/de.lproj/Localizable.strings +12 -0
- data/spec/integration/build-var-infoplist/after/Example/Example/en.lproj/InfoPlist.strings +2 -0
- data/spec/integration/build-var-infoplist/after/Example/Example/en.lproj/Localizable.strings +15 -0
- data/spec/integration/build-var-infoplist/after/Example/Example/main.m +18 -0
- data/spec/integration/build-var-infoplist/after/Example/Example.xcodeproj.yaml +168 -0
- data/spec/integration/build-var-infoplist/after/R.h +39 -0
- data/spec/integration/build-var-infoplist/after/R.m +29 -0
- data/spec/integration/build-var-infoplist/after/execution_output.txt +19 -0
- data/spec/integration/build-var-infoplist/before/Example/Example/AppDelegate.h +15 -0
- data/spec/integration/build-var-infoplist/before/Example/Example/AppDelegate.m +49 -0
- data/spec/integration/build-var-infoplist/before/Example/Example/Example-Info.plist +38 -0
- data/spec/integration/build-var-infoplist/before/Example/Example/Example-Prefix.pch +16 -0
- data/spec/integration/build-var-infoplist/before/Example/Example/Icons.bundle/tab_bar/tabbar_list.png +0 -0
- data/spec/integration/build-var-infoplist/before/Example/Example/Icons.bundle/tab_bar/tabbar_list@2x.png +0 -0
- data/spec/integration/build-var-infoplist/before/Example/Example/Icons.bundle/tab_bar/tabbar_map.png +0 -0
- data/spec/integration/build-var-infoplist/before/Example/Example/Icons.bundle/tab_bar/tabbar_map@2x.png +0 -0
- data/spec/integration/build-var-infoplist/before/Example/Example/Images/doge.jpeg +0 -0
- data/spec/integration/build-var-infoplist/before/Example/Example/Images/nyanCat.png +0 -0
- data/spec/integration/build-var-infoplist/before/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
- data/spec/integration/build-var-infoplist/before/Example/Example/Images.xcassets/Doge.imageset/Contents.json +18 -0
- data/spec/integration/build-var-infoplist/before/Example/Example/Images.xcassets/Doge.imageset/doge.png +0 -0
- data/spec/integration/build-var-infoplist/before/Example/Example/Images.xcassets/Doge.imageset/doge@2x.png +0 -0
- data/spec/integration/build-var-infoplist/before/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
- data/spec/integration/build-var-infoplist/before/Example/Example/de.lproj/Localizable.strings +12 -0
- data/spec/integration/build-var-infoplist/before/Example/Example/en.lproj/InfoPlist.strings +2 -0
- data/spec/integration/build-var-infoplist/before/Example/Example/en.lproj/Localizable.strings +15 -0
- data/spec/integration/build-var-infoplist/before/Example/Example/main.m +18 -0
- data/spec/integration/build-var-infoplist/before/Example/Example.xcodeproj/project.pbxproj +453 -0
- data/spec/integration/build-var-infoplist/before/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- data/spec/integration/help/after/execution_output.txt +18 -0
- data/spec/integration/help/before/.gitkeep +0 -0
- data/spec/integration/install/after/Example/Example/AppDelegate.h +15 -0
- data/spec/integration/install/after/Example/Example/AppDelegate.m +49 -0
- data/spec/integration/install/after/Example/Example/Example-Info.plist +38 -0
- data/spec/integration/install/after/Example/Example/Example-Prefix.pch +18 -0
- data/spec/integration/install/after/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
- data/spec/integration/install/after/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
- data/spec/integration/install/after/Example/Example/Resources/R.h +19 -0
- data/spec/integration/install/after/Example/Example/Resources/R.m +17 -0
- data/spec/integration/install/after/Example/Example/en.lproj/InfoPlist.strings +2 -0
- data/spec/integration/install/after/Example/Example/main.m +18 -0
- data/spec/integration/install/after/Example/Example.xcodeproj/project.pbxproj +898 -0
- data/spec/integration/install/after/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- data/spec/integration/install/after/Example/Example.xcodeproj.yaml +172 -0
- data/spec/integration/install/after/execution_output.txt +22 -0
- data/spec/integration/install/before/Example/Example/AppDelegate.h +15 -0
- data/spec/integration/install/before/Example/Example/AppDelegate.m +49 -0
- data/spec/integration/install/before/Example/Example/Example-Info.plist +38 -0
- data/spec/integration/install/before/Example/Example/Example-Prefix.pch +16 -0
- data/spec/integration/install/before/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
- data/spec/integration/install/before/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
- data/spec/integration/install/before/Example/Example/en.lproj/InfoPlist.strings +2 -0
- data/spec/integration/install/before/Example/Example/main.m +18 -0
- data/spec/integration/install/before/Example/Example.xcodeproj/project.pbxproj +421 -0
- data/spec/integration/install/before/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- data/spec/integration/install-again/after/Example/Example/AppDelegate.h +15 -0
- data/spec/integration/install-again/after/Example/Example/AppDelegate.m +49 -0
- data/spec/integration/install-again/after/Example/Example/Example-Info.plist +38 -0
- data/spec/integration/install-again/after/Example/Example/Example-Prefix.pch +18 -0
- data/spec/integration/install-again/after/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
- data/spec/integration/install-again/after/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
- data/spec/integration/install-again/after/Example/Example/Resources/R.h +19 -0
- data/spec/integration/install-again/after/Example/Example/Resources/R.m +17 -0
- data/spec/integration/install-again/after/Example/Example/en.lproj/InfoPlist.strings +2 -0
- data/spec/integration/install-again/after/Example/Example/main.m +18 -0
- data/spec/integration/install-again/after/Example/Example.xcodeproj.yaml +172 -0
- data/spec/integration/install-again/after/execution_output.txt +23 -0
- data/spec/integration/install-again/before/Example/Example/AppDelegate.h +15 -0
- data/spec/integration/install-again/before/Example/Example/AppDelegate.m +49 -0
- data/spec/integration/install-again/before/Example/Example/Example-Info.plist +38 -0
- data/spec/integration/install-again/before/Example/Example/Example-Prefix.pch +18 -0
- data/spec/integration/install-again/before/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
- data/spec/integration/install-again/before/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
- data/spec/integration/install-again/before/Example/Example/Resources/R.h +19 -0
- data/spec/integration/install-again/before/Example/Example/Resources/R.m +17 -0
- data/spec/integration/install-again/before/Example/Example/en.lproj/InfoPlist.strings +2 -0
- data/spec/integration/install-again/before/Example/Example/main.m +18 -0
- data/spec/integration/install-again/before/Example/Example.xcodeproj/project.pbxproj +898 -0
- data/spec/integration/install-again/before/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- data/spec/integration/install-moved-supporting-files/after/Example/Example.xcodeproj.yaml +173 -0
- data/spec/integration/install-moved-supporting-files/after/Example/Supporting_Files/Example-Info.plist +38 -0
- data/spec/integration/install-moved-supporting-files/after/Example/Supporting_Files/Example-Prefix.pch +18 -0
- data/spec/integration/install-moved-supporting-files/after/Example/Supporting_Files/Resources/R.h +19 -0
- data/spec/integration/install-moved-supporting-files/after/Example/Supporting_Files/Resources/R.m +17 -0
- data/spec/integration/install-moved-supporting-files/after/Example/Supporting_Files/en.lproj/InfoPlist.strings +2 -0
- data/spec/integration/install-moved-supporting-files/after/Example/Supporting_Files/main.m +18 -0
- data/spec/integration/install-moved-supporting-files/after/Example/res/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
- data/spec/integration/install-moved-supporting-files/after/Example/res/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
- data/spec/integration/install-moved-supporting-files/after/Example/src/AppDelegate.h +15 -0
- data/spec/integration/install-moved-supporting-files/after/Example/src/AppDelegate.m +49 -0
- data/spec/integration/install-moved-supporting-files/after/execution_output.txt +22 -0
- data/spec/integration/install-moved-supporting-files/before/Example/Example.xcodeproj/project.pbxproj +431 -0
- data/spec/integration/install-moved-supporting-files/before/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- data/spec/integration/install-moved-supporting-files/before/Example/Supporting_Files/Example-Info.plist +38 -0
- data/spec/integration/install-moved-supporting-files/before/Example/Supporting_Files/Example-Prefix.pch +16 -0
- data/spec/integration/install-moved-supporting-files/before/Example/Supporting_Files/en.lproj/InfoPlist.strings +2 -0
- data/spec/integration/install-moved-supporting-files/before/Example/Supporting_Files/main.m +18 -0
- data/spec/integration/install-moved-supporting-files/before/Example/res/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
- data/spec/integration/install-moved-supporting-files/before/Example/res/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
- data/spec/integration/install-moved-supporting-files/before/Example/src/AppDelegate.h +15 -0
- data/spec/integration/install-moved-supporting-files/before/Example/src/AppDelegate.m +49 -0
- data/spec/integration/install-no-supporting-files/after/Example/Example.xcodeproj.yaml +173 -0
- data/spec/integration/install-no-supporting-files/after/Example/Resources/R.h +19 -0
- data/spec/integration/install-no-supporting-files/after/Example/Resources/R.m +17 -0
- data/spec/integration/install-no-supporting-files/after/Example/Supporting_Files/Example-Info.plist +38 -0
- data/spec/integration/install-no-supporting-files/after/Example/Supporting_Files/Example-Prefix.pch +18 -0
- data/spec/integration/install-no-supporting-files/after/Example/Supporting_Files/en.lproj/InfoPlist.strings +2 -0
- data/spec/integration/install-no-supporting-files/after/Example/Supporting_Files/main.m +18 -0
- data/spec/integration/install-no-supporting-files/after/Example/res/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
- data/spec/integration/install-no-supporting-files/after/Example/res/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
- data/spec/integration/install-no-supporting-files/after/Example/src/AppDelegate.h +15 -0
- data/spec/integration/install-no-supporting-files/after/Example/src/AppDelegate.m +49 -0
- data/spec/integration/install-no-supporting-files/after/execution_output.txt +23 -0
- data/spec/integration/install-no-supporting-files/before/Example/Example.xcodeproj/project.pbxproj +430 -0
- data/spec/integration/install-no-supporting-files/before/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- data/spec/integration/install-no-supporting-files/before/Example/Supporting_Files/Example-Info.plist +38 -0
- data/spec/integration/install-no-supporting-files/before/Example/Supporting_Files/Example-Prefix.pch +16 -0
- data/spec/integration/install-no-supporting-files/before/Example/Supporting_Files/en.lproj/InfoPlist.strings +2 -0
- data/spec/integration/install-no-supporting-files/before/Example/Supporting_Files/main.m +18 -0
- data/spec/integration/install-no-supporting-files/before/Example/res/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
- data/spec/integration/install-no-supporting-files/before/Example/res/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
- data/spec/integration/install-no-supporting-files/before/Example/src/AppDelegate.h +15 -0
- data/spec/integration/install-no-supporting-files/before/Example/src/AppDelegate.m +49 -0
- data/spec/integration/version/after/execution_output.txt +3 -0
- data/spec/integration/version/before/.gitkeep +0 -0
- data/spec/integration.rb +86 -0
- data/spec/spec_helper/xcodeproj_project_yaml.rb +26 -0
- data/spec/unit/analyzer/aggregate_analyzer_spec.rb +61 -0
- data/spec/unit/analyzer/analyzer_spec.rb +123 -0
- data/spec/unit/analyzer/resources_aggregate_analyzer_spec.rb +46 -0
- data/spec/unit/analyzer/resources_analyzer/base_resources_analyzer_spec.rb +126 -0
- data/spec/unit/analyzer/resources_analyzer/bundle_resources_analyzer_spec.rb +57 -0
- data/spec/unit/analyzer/resources_analyzer/loose_resources_analyzer_spec.rb +22 -0
- data/spec/unit/analyzer/strings_analyzer_spec.rb +99 -0
- data/spec/unit/builder/file_builder_spec.rb +46 -0
- data/spec/unit/builder/resources_builder_spec.rb +50 -0
- data/spec/unit/builder/string_builder_spec.rb +76 -0
- data/spec/unit/command/main_command_spec.rb +5 -0
- data/spec/unit/command/project_command_spec.rb +23 -0
- data/spec/unit/helper/file_helper_spec.rb +24 -0
- data/spec/unit/logger_spec.rb +142 -0
- data/spec/unit/model/section_spec.rb +47 -0
- data/spec/unit/model/xcassets/bundle_spec.rb +154 -0
- data/spec/unit/model/xcassets/resource_image_spec.rb +141 -0
- data/spec/unit/model/xcassets/resource_spec.rb +174 -0
- data/spec/unit/model/xcassets/spec_helper.rb +31 -0
- data/spec/unit/spec_helper.rb +17 -0
- data/xcres.gemspec +42 -0
- metadata +811 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
require 'xcres/analyzer/analyzer'
|
|
2
|
+
require 'set'
|
|
3
|
+
|
|
4
|
+
module XCRes
|
|
5
|
+
module ResourcesAnalyzer
|
|
6
|
+
|
|
7
|
+
# A +BaseResourcesAnalyzer+ scans the project for resources,
|
|
8
|
+
# which should be included in the output file.
|
|
9
|
+
#
|
|
10
|
+
class BaseResourcesAnalyzer < Analyzer
|
|
11
|
+
|
|
12
|
+
FILTER_WORDS = ['icon', 'image']
|
|
13
|
+
|
|
14
|
+
# Get a list of all files in a directory
|
|
15
|
+
#
|
|
16
|
+
# @param [Pathname] dir
|
|
17
|
+
# the directory
|
|
18
|
+
#
|
|
19
|
+
# @return [Array<Pathname>]
|
|
20
|
+
# the file paths relative to the given dir
|
|
21
|
+
#
|
|
22
|
+
def find_files_in_dir dir
|
|
23
|
+
unless dir.exist?
|
|
24
|
+
warn "Can't find files in dir %s as it doesn't exist!",
|
|
25
|
+
dir.relative_path_from(project.path + '..').to_s
|
|
26
|
+
return []
|
|
27
|
+
end
|
|
28
|
+
Dir.chdir dir do
|
|
29
|
+
Dir['**/*'].map { |path| Pathname(path) }
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Build a section for image resources
|
|
34
|
+
#
|
|
35
|
+
# @param [Array<String>] image_files
|
|
36
|
+
#
|
|
37
|
+
# @param [Hash] options
|
|
38
|
+
# see #build_section_data
|
|
39
|
+
#
|
|
40
|
+
# @return [Hash{String => Pathname}]
|
|
41
|
+
#
|
|
42
|
+
def build_images_section_data image_file_paths, options={}
|
|
43
|
+
image_file_paths = filter_exclusions(image_file_paths)
|
|
44
|
+
image_file_paths = filter_device_specific_image_paths(image_file_paths)
|
|
45
|
+
build_section_data(image_file_paths, options)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Filter out device scale and idiom specific images (retina, ipad),
|
|
49
|
+
# but ensure the base exist once
|
|
50
|
+
#
|
|
51
|
+
# @param [Array<Pathname>] file_paths
|
|
52
|
+
# the file paths to filter
|
|
53
|
+
#
|
|
54
|
+
# @return [Array<String>]
|
|
55
|
+
# the filtered file paths
|
|
56
|
+
#
|
|
57
|
+
def filter_device_specific_image_paths file_paths
|
|
58
|
+
file_paths.map do |path|
|
|
59
|
+
path.to_s.gsub /(@2x)?(~(iphone|ipad))?(?=\.\w+$)/, ''
|
|
60
|
+
end.to_set.to_a
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Find image files in a given list of file paths
|
|
64
|
+
#
|
|
65
|
+
# @param [Array<Pathname>] file_paths
|
|
66
|
+
# the list of files
|
|
67
|
+
#
|
|
68
|
+
# @return [Array<Pathname>]
|
|
69
|
+
# the filtered list
|
|
70
|
+
#
|
|
71
|
+
def find_image_files file_paths
|
|
72
|
+
file_paths.select { |path| path.to_s.match /\.(png|jpe?g|gif)$/ }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Build a keys to paths mapping
|
|
76
|
+
#
|
|
77
|
+
# @param [Array<Pathname>] file_paths
|
|
78
|
+
# the file paths, which will be the values of the mapping
|
|
79
|
+
#
|
|
80
|
+
# @param [Hash] options
|
|
81
|
+
# valid options are:
|
|
82
|
+
# * [Bool] :use_basename?
|
|
83
|
+
# if set, it will only use the basename of the path for the key
|
|
84
|
+
#
|
|
85
|
+
# @return [Hash{String => Pathname}]
|
|
86
|
+
#
|
|
87
|
+
def build_section_data file_paths, options={}
|
|
88
|
+
options = { use_basename?: false }.merge options
|
|
89
|
+
|
|
90
|
+
# Transform image file paths to keys
|
|
91
|
+
keys_to_paths = {}
|
|
92
|
+
for path in file_paths
|
|
93
|
+
path = options[:use_basename?] ? File.basename(path) : path.to_s
|
|
94
|
+
key = key_from_path(path)
|
|
95
|
+
keys_to_paths[key] = path
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
keys_to_paths
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Derive a key from a resource path
|
|
102
|
+
#
|
|
103
|
+
# @param [String] path
|
|
104
|
+
# the path to the resource
|
|
105
|
+
#
|
|
106
|
+
# @return [String]
|
|
107
|
+
#
|
|
108
|
+
def key_from_path path
|
|
109
|
+
key = path.to_s
|
|
110
|
+
|
|
111
|
+
# Get rid of the file extension
|
|
112
|
+
key = key.sub /#{File.extname(path)}$/, ''
|
|
113
|
+
|
|
114
|
+
# Graphical assets tend to contain words, which you want to strip.
|
|
115
|
+
# Because we want to list the words to ignore only in one variant,
|
|
116
|
+
# we have to ensure that the icon name is prepared for that, without
|
|
117
|
+
# loosing word separation if camel case was used.
|
|
118
|
+
key = key.underscore.downcase
|
|
119
|
+
|
|
120
|
+
for filter_word in FILTER_WORDS do
|
|
121
|
+
key.gsub! filter_word, ''
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Remove unnecessary underscores
|
|
125
|
+
key = key.gsub(/^_*|_*$|(_)_+/, '\1')
|
|
126
|
+
|
|
127
|
+
return key
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
end
|
|
133
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require 'xcres/analyzer/resources_analyzer/base_resources_analyzer'
|
|
2
|
+
|
|
3
|
+
module XCRes
|
|
4
|
+
module ResourcesAnalyzer
|
|
5
|
+
|
|
6
|
+
# A +BundleResourcesAnalyzer+ scans the project for bundles, whose resources
|
|
7
|
+
# should be included in the output file.
|
|
8
|
+
#
|
|
9
|
+
class BundleResourcesAnalyzer < BaseResourcesAnalyzer
|
|
10
|
+
|
|
11
|
+
def analyze
|
|
12
|
+
@sections = build_sections_for_bundles.compact
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Build a section for each bundle if it contains any resources
|
|
16
|
+
#
|
|
17
|
+
# @return [Array<Section>]
|
|
18
|
+
# the built sections
|
|
19
|
+
#
|
|
20
|
+
def build_sections_for_bundles
|
|
21
|
+
bundle_file_refs = find_bundle_file_refs
|
|
22
|
+
|
|
23
|
+
log "Found #%s resource bundles in project.", bundle_file_refs.count
|
|
24
|
+
|
|
25
|
+
bundle_file_refs.map do |file_ref|
|
|
26
|
+
section = build_section_for_bundle(file_ref)
|
|
27
|
+
log 'Add section for %s with %s elements', section.name, section.items.count unless section.nil?
|
|
28
|
+
section
|
|
29
|
+
end.compact
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Discover all references to resources bundles in project
|
|
33
|
+
#
|
|
34
|
+
# @return [Array<PBXFileReference>]
|
|
35
|
+
#
|
|
36
|
+
def find_bundle_file_refs
|
|
37
|
+
find_file_refs_by_extname '.bundle'
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Build a section for a resources bundle
|
|
41
|
+
#
|
|
42
|
+
# @param [PBXFileReference] bundle_file_ref
|
|
43
|
+
# the file reference to the resources bundle file
|
|
44
|
+
#
|
|
45
|
+
# @return [Section?]
|
|
46
|
+
# a section or nil
|
|
47
|
+
#
|
|
48
|
+
def build_section_for_bundle bundle_file_ref
|
|
49
|
+
bundle_files = find_files_in_dir(bundle_file_ref.real_path)
|
|
50
|
+
image_files = find_image_files(bundle_files)
|
|
51
|
+
|
|
52
|
+
log "Found bundle %s with #%s image files of #%s total files.", bundle_file_ref.path, image_files.count, bundle_files.count
|
|
53
|
+
|
|
54
|
+
return nil if image_files.empty?
|
|
55
|
+
|
|
56
|
+
section_data = build_images_section_data(image_files)
|
|
57
|
+
|
|
58
|
+
return nil if section_data.empty?
|
|
59
|
+
|
|
60
|
+
section_name = basename_without_ext(bundle_file_ref.path)
|
|
61
|
+
|
|
62
|
+
new_section(section_name, section_data)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'xcres/analyzer/resources_analyzer/base_resources_analyzer'
|
|
2
|
+
|
|
3
|
+
module XCRes
|
|
4
|
+
module ResourcesAnalyzer
|
|
5
|
+
|
|
6
|
+
# A +LooseResourcesAnalyzer+ scans the project for resources, which are
|
|
7
|
+
# loosely placed in the project or in a group and should be included in the
|
|
8
|
+
# output file.
|
|
9
|
+
#
|
|
10
|
+
class LooseResourcesAnalyzer < BaseResourcesAnalyzer
|
|
11
|
+
|
|
12
|
+
def analyze
|
|
13
|
+
@sections = [build_section_for_loose_images].compact
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def exclude_file_patterns
|
|
17
|
+
super + ['Default.*', 'Default@2x.*', 'Default-568h@2x.*']
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Build a section for loose image resources in the project
|
|
21
|
+
#
|
|
22
|
+
# @return [Section?]
|
|
23
|
+
#
|
|
24
|
+
def build_section_for_loose_images
|
|
25
|
+
image_files = find_image_files(resources_files.map(&:path))
|
|
26
|
+
|
|
27
|
+
log "Found #%s image files in project.", image_files.count
|
|
28
|
+
|
|
29
|
+
return nil if image_files.empty?
|
|
30
|
+
|
|
31
|
+
data = build_images_section_data(image_files, use_basename?: true)
|
|
32
|
+
|
|
33
|
+
new_section('Images', data)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require 'xcres/analyzer/resources_analyzer/base_resources_analyzer'
|
|
2
|
+
require 'xcres/model/xcassets/bundle'
|
|
3
|
+
|
|
4
|
+
module XCRes
|
|
5
|
+
module ResourcesAnalyzer
|
|
6
|
+
|
|
7
|
+
# A +XCAssetsAnalyzer+ scans the project for asset catalogs,
|
|
8
|
+
# which should be included in the output file.
|
|
9
|
+
#
|
|
10
|
+
class XCAssetsAnalyzer < BaseResourcesAnalyzer
|
|
11
|
+
|
|
12
|
+
def analyze
|
|
13
|
+
sections = []
|
|
14
|
+
sections += build_sections_for_xcassets
|
|
15
|
+
@sections = sections.compact
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Build a section for each asset catalog if it contains any resources
|
|
19
|
+
#
|
|
20
|
+
# @return [Array<Section>]
|
|
21
|
+
# the built sections
|
|
22
|
+
#
|
|
23
|
+
def build_sections_for_xcassets
|
|
24
|
+
file_refs = find_file_refs_by_extname '.xcassets'
|
|
25
|
+
|
|
26
|
+
log "Found #%s asset catalogs in project.", file_refs.count
|
|
27
|
+
|
|
28
|
+
file_refs.map do |file_ref|
|
|
29
|
+
bundle = XCAssets::Bundle.open(file_ref.real_path)
|
|
30
|
+
section = build_section_for_xcassets(bundle)
|
|
31
|
+
log 'Add section for %s with %s elements', section.name, section.items.count unless section.nil?
|
|
32
|
+
section
|
|
33
|
+
end.compact
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Build a section for a asset catalog
|
|
37
|
+
#
|
|
38
|
+
# @param [XCAssets::Bundle] xcassets_bundle
|
|
39
|
+
# the file reference to the resources bundle file
|
|
40
|
+
#
|
|
41
|
+
# @return [Section?]
|
|
42
|
+
# a section or nil
|
|
43
|
+
#
|
|
44
|
+
def build_section_for_xcassets bundle
|
|
45
|
+
log "Found asset catalog %s with #%s image files.",
|
|
46
|
+
bundle.path.basename, bundle.resources.count
|
|
47
|
+
|
|
48
|
+
return nil if bundle.resources.empty?
|
|
49
|
+
|
|
50
|
+
section_data = build_images_section_data(bundle.resources.map(&:name))
|
|
51
|
+
|
|
52
|
+
return nil if section_data.empty?
|
|
53
|
+
|
|
54
|
+
section_name = "#{basename_without_ext(bundle.path)}Assets"
|
|
55
|
+
|
|
56
|
+
new_section(section_name, section_data)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
require 'xcres/analyzer/analyzer'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
module XCRes
|
|
5
|
+
|
|
6
|
+
# A +StringsAnalyzer+ scans the project for resources,
|
|
7
|
+
# which should be included in the output file.
|
|
8
|
+
#
|
|
9
|
+
class StringsAnalyzer < Analyzer
|
|
10
|
+
|
|
11
|
+
# @return [String]
|
|
12
|
+
# optional two-letter language code conforming ISO 639-1
|
|
13
|
+
attr_accessor :default_language
|
|
14
|
+
|
|
15
|
+
# Initialize a new analyzer
|
|
16
|
+
#
|
|
17
|
+
# @param [Xcodeproj::Project] project
|
|
18
|
+
# see #project.
|
|
19
|
+
#
|
|
20
|
+
# @param [Hash] options
|
|
21
|
+
# Possible options:
|
|
22
|
+
# * :default_language => see #default_language.
|
|
23
|
+
#
|
|
24
|
+
def initialize(project=nil, options={})
|
|
25
|
+
super
|
|
26
|
+
self.default_language = options[:default_language]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def analyze
|
|
30
|
+
log 'Strings files in project: %s', strings_file_refs.map(&:path)
|
|
31
|
+
log 'Native development languages: %s', native_dev_languages.to_a
|
|
32
|
+
log 'Used languages for .strings files: %s', used_languages.to_a
|
|
33
|
+
log 'Preferred languages: %s', languages.to_a
|
|
34
|
+
log 'Strings files after language selection: %s', selected_strings_file_refs.map(&:path)
|
|
35
|
+
|
|
36
|
+
@sections = [build_section]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Build the section
|
|
40
|
+
#
|
|
41
|
+
# @return [Section]
|
|
42
|
+
#
|
|
43
|
+
def build_section
|
|
44
|
+
selected_file_refs = selected_strings_file_refs
|
|
45
|
+
|
|
46
|
+
# Apply ignore list
|
|
47
|
+
file_paths = filter_exclusions(selected_file_refs.map(&:path))
|
|
48
|
+
filtered_file_refs = selected_file_refs.select { |file_ref| file_paths.include? file_ref.path }
|
|
49
|
+
rel_file_paths = filtered_file_refs.map { |p| p.real_path.relative_path_from(Pathname.pwd) }
|
|
50
|
+
|
|
51
|
+
log 'Non-ignored .strings files: %s', rel_file_paths.map(&:to_s)
|
|
52
|
+
|
|
53
|
+
keys_by_file = {}
|
|
54
|
+
for path in rel_file_paths
|
|
55
|
+
keys_by_file[path] = keys_by_file(path)
|
|
56
|
+
end
|
|
57
|
+
items = keys_by_file.values.reduce({}, :merge)
|
|
58
|
+
|
|
59
|
+
new_section('Strings', items)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Discover all references to .strings files in project (e.g. Localizable.strings)
|
|
63
|
+
#
|
|
64
|
+
# @return [Array<PBXFileReference>]
|
|
65
|
+
#
|
|
66
|
+
def strings_file_refs
|
|
67
|
+
@strings_file_refs ||= find_file_refs_by_extname '.strings'
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Select strings files by language
|
|
71
|
+
#
|
|
72
|
+
# @return [Array<PBXFileReference>]
|
|
73
|
+
#
|
|
74
|
+
def selected_strings_file_refs
|
|
75
|
+
@selected_strings_file_refs ||= strings_file_refs.select { |file_ref| languages.include? file_ref.name }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Derive the used languages from given strings files
|
|
79
|
+
#
|
|
80
|
+
# @param [Array<PBXFileReference>] strings_file_refs
|
|
81
|
+
#
|
|
82
|
+
# @return [Set<String>]
|
|
83
|
+
#
|
|
84
|
+
def derive_used_languages(strings_file_refs)
|
|
85
|
+
strings_file_refs.map(&:name).to_set
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# All used languages in the project
|
|
89
|
+
#
|
|
90
|
+
# @return [Set<String>]
|
|
91
|
+
#
|
|
92
|
+
def used_languages
|
|
93
|
+
@used_languages ||= derive_used_languages(strings_file_refs)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Find preferred languages, which is:
|
|
97
|
+
# - either only the default_language, if specified
|
|
98
|
+
# - or the intersection of native development and used languages
|
|
99
|
+
# - or all used languages
|
|
100
|
+
#
|
|
101
|
+
# @return [Set<String>]
|
|
102
|
+
#
|
|
103
|
+
def languages
|
|
104
|
+
if default_language != nil
|
|
105
|
+
# Use specified default language as primary language
|
|
106
|
+
[default_language]
|
|
107
|
+
else
|
|
108
|
+
# Calculate the intersection of native development and used languages,
|
|
109
|
+
# fallback to the latter only, if it is empty
|
|
110
|
+
languages = native_dev_languages & used_languages
|
|
111
|
+
if languages.empty?
|
|
112
|
+
used_languages
|
|
113
|
+
else
|
|
114
|
+
languages
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Discover Info.plist files by build settings of the application target
|
|
120
|
+
#
|
|
121
|
+
# @return [Set<Pathname>]
|
|
122
|
+
# the relative paths to the .plist-files
|
|
123
|
+
#
|
|
124
|
+
def info_plist_paths
|
|
125
|
+
@info_plist_paths ||= target.build_configurations.map do |config|
|
|
126
|
+
config.build_settings['INFOPLIST_FILE']
|
|
127
|
+
end.compact.map { |file| Pathname(file) }.flatten.to_set
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Absolute file paths to Info.plist files by build settings.
|
|
131
|
+
# See #info_plist_paths.
|
|
132
|
+
#
|
|
133
|
+
# @return [Set<Pathname>]
|
|
134
|
+
# the absolute paths to the .plist-files
|
|
135
|
+
#
|
|
136
|
+
def absolute_info_plist_paths
|
|
137
|
+
info_plist_paths.map do |path|
|
|
138
|
+
absolute_project_file_path(path)
|
|
139
|
+
end.select do |path|
|
|
140
|
+
if path.to_s.include?('$')
|
|
141
|
+
warn "Couldn't resolve all placeholders in INFOPLIST_FILE %s.", path.to_s
|
|
142
|
+
false
|
|
143
|
+
else
|
|
144
|
+
true
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Find the native development languages by trying to use the
|
|
150
|
+
# "Localization native development region" from Info.plist
|
|
151
|
+
#
|
|
152
|
+
# @return [Set<String>]
|
|
153
|
+
#
|
|
154
|
+
def native_dev_languages
|
|
155
|
+
@native_dev_languages ||= absolute_info_plist_paths.map do |path|
|
|
156
|
+
read_plist_key(path, :CFBundleDevelopmentRegion)
|
|
157
|
+
end.to_set
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Extracts a given key from a plist file given as a path
|
|
161
|
+
#
|
|
162
|
+
# @param [Pathname] path
|
|
163
|
+
# the path of the plist file
|
|
164
|
+
#
|
|
165
|
+
# @param [String] key
|
|
166
|
+
# the key, whose value should been extracted
|
|
167
|
+
#
|
|
168
|
+
# @return [String]
|
|
169
|
+
#
|
|
170
|
+
def read_plist_key(path, key)
|
|
171
|
+
raise ArgumentError, 'Path is required, but nil' if path.nil?
|
|
172
|
+
raise ArgumentError, 'Key is required, but nil' if key.nil?
|
|
173
|
+
out = `/usr/libexec/PlistBuddy -c "Print :#{key}" #{path}`.chomp
|
|
174
|
+
raise ArgumentError, out unless $?.success?
|
|
175
|
+
out
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Read a .strings file given as a path
|
|
179
|
+
#
|
|
180
|
+
# @param [Pathname] path
|
|
181
|
+
# the path of the strings file
|
|
182
|
+
#
|
|
183
|
+
# @return [Hash]
|
|
184
|
+
#
|
|
185
|
+
def read_strings_file(path)
|
|
186
|
+
raise ArgumentError, "File '#{path}' doesn't exist" unless path.exist?
|
|
187
|
+
raise ArgumentError, "File '#{path}' is not a file" unless path.file?
|
|
188
|
+
error = `plutil -lint -s "#{path}"`
|
|
189
|
+
return warn "File %s is malformed:\n#{error}", path.to_s unless $?.success?
|
|
190
|
+
json_or_error = `plutil -convert json "#{path}" -o -`.chomp
|
|
191
|
+
return warn "File %s couldn't be converted to JSON.\n#{json_or_error}", path.to_s unless $?.success?
|
|
192
|
+
JSON.parse(json_or_error.force_encoding('UTF-8'))
|
|
193
|
+
rescue EncodingError => e
|
|
194
|
+
raise StandardError, "Encoding error in #{path}: #{e}"
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Calculate the absolute path for a file path given relative to the
|
|
198
|
+
# project / its `$SRCROOT`.
|
|
199
|
+
#
|
|
200
|
+
# We need either absolute paths or relative paths to our current location.
|
|
201
|
+
# Xcodeproj provides this for +PBXFileReference+, but this doesn't work
|
|
202
|
+
# for file references in build settings.
|
|
203
|
+
#
|
|
204
|
+
# @param [String|Pathname] file_path
|
|
205
|
+
# the path relative to the project.
|
|
206
|
+
#
|
|
207
|
+
# @return [Pathname]
|
|
208
|
+
#
|
|
209
|
+
def absolute_project_file_path(file_path)
|
|
210
|
+
source_root = (project.path + '..').realpath
|
|
211
|
+
if file_path.to_s.include?('$')
|
|
212
|
+
Pathname(file_path.to_s.gsub(/\$[({]?SRCROOT[)}]?/, source_root.to_s))
|
|
213
|
+
else
|
|
214
|
+
source_root + file_path
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Get relative file paths
|
|
219
|
+
#
|
|
220
|
+
# @return [Array<Pathname>]
|
|
221
|
+
#
|
|
222
|
+
def strings_file_paths
|
|
223
|
+
project_dir = project.path + '..'
|
|
224
|
+
project_dir_realpath = project_dir.realpath
|
|
225
|
+
strings_file_refs.map(&:real_path).map do |path|
|
|
226
|
+
project_dir + path.relative_path_from(project_dir_realpath) rescue path
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# Read a file and collect all its keys
|
|
231
|
+
#
|
|
232
|
+
# @param [Pathname] path
|
|
233
|
+
# the path to the .strings file to read
|
|
234
|
+
#
|
|
235
|
+
# @return [Hash{String => Hash}]
|
|
236
|
+
#
|
|
237
|
+
def keys_by_file(path)
|
|
238
|
+
begin
|
|
239
|
+
# Load strings file contents
|
|
240
|
+
strings = read_strings_file(path)
|
|
241
|
+
|
|
242
|
+
keys = Hash[strings.map do |key, value|
|
|
243
|
+
[key, { value: key, comment: value.gsub(/[\r\n]/, ' ') }]
|
|
244
|
+
end]
|
|
245
|
+
|
|
246
|
+
log 'Found %s keys in file %s', keys.count, path
|
|
247
|
+
|
|
248
|
+
keys
|
|
249
|
+
rescue ArgumentError => error
|
|
250
|
+
raise ArgumentError, 'Error while reading %s: %s' % [path, error]
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
end
|
|
255
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require 'colored'
|
|
2
|
+
require 'xcres/builder/string_builder'
|
|
3
|
+
|
|
4
|
+
class XCRes::FileBuilder
|
|
5
|
+
|
|
6
|
+
attr_accessor :output_path
|
|
7
|
+
attr_accessor :logger
|
|
8
|
+
|
|
9
|
+
def prepare_output_path!
|
|
10
|
+
# Ensure that the given directory exists
|
|
11
|
+
output_dir = File.dirname output_path
|
|
12
|
+
unless Dir.exist? output_dir
|
|
13
|
+
logger.success 'Directory did not exist. Will been created.'
|
|
14
|
+
Dir.mkdir output_dir
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Replace an already existing file, by deleting it and rebuilding from scratch
|
|
18
|
+
if File.exist? output_path
|
|
19
|
+
raise ArgumentError.new 'Output path is a directory!' if Dir.exist? output_path
|
|
20
|
+
logger.warn "Output path already exists. Will be replaced."
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def build
|
|
25
|
+
prepare_output_path!
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def build_contents &block
|
|
29
|
+
# Pass a new string builder to given block
|
|
30
|
+
builder = XCRes::StringBuilder.new
|
|
31
|
+
block.call builder
|
|
32
|
+
builder.result
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def write_file_eventually file_path, contents
|
|
36
|
+
# Check if the file already exists and touch it only if the contents changed
|
|
37
|
+
if File.exist? file_path
|
|
38
|
+
tmp_dir_path = `/usr/bin/mktemp -d -t xcres`
|
|
39
|
+
tmp_file_path = tmp_dir_path + File.basename(file_path)
|
|
40
|
+
|
|
41
|
+
# Write temp file
|
|
42
|
+
write_file tmp_file_path, contents
|
|
43
|
+
|
|
44
|
+
# Diff current version and temporary file
|
|
45
|
+
if FileUtils.compare_file(tmp_file_path, file_path)
|
|
46
|
+
logger.success "Existing file is up-to-date. Don't touch."
|
|
47
|
+
return
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
write_file file_path, contents
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def write_file file_path, contents
|
|
55
|
+
# Write file
|
|
56
|
+
File.open file_path, 'w' do |file|
|
|
57
|
+
file.write contents
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|