├── Gemfile
├── docs
└── scheme-selection.png
├── AdditionalAssets.xcassets
├── Contents.json
├── CustomLoopIcon_orig.appiconset
│ ├── Icon.png
│ ├── icon_20pt.png
│ ├── icon_29pt.png
│ ├── icon_40pt.png
│ ├── icon_76pt.png
│ ├── icon_20pt@2x.png
│ ├── icon_20pt@3x.png
│ ├── icon_29pt@2x.png
│ ├── icon_29pt@3x.png
│ ├── icon_40pt@2x.png
│ ├── icon_40pt@3x.png
│ ├── icon_60pt@2x.png
│ ├── icon_60pt@3x.png
│ ├── icon_76pt@2x.png
│ ├── icon_83.5@2x.png
│ ├── icon_20pt@2x-1.png
│ ├── icon_29pt@2x-1.png
│ ├── icon_40pt@2x-1.png
│ └── Contents.json
└── CustomLoopIcon.appiconset
│ ├── ipad_app76x76.png
│ ├── ipad_app76x76@2x.png
│ ├── ipad_settings29x29.png
│ ├── ipad_spotlight40x40.png
│ ├── iphone_app60x60@2x.png
│ ├── iphone_app60x60@3x.png
│ ├── ios_marketing1024x1024.png
│ ├── ipad_notification20x20.png
│ ├── ipad_settings29x29@2x.png
│ ├── ipad_spotlight40x40@2x.png
│ ├── ipad_pro_app83.5x83.5@2x.png
│ ├── iphone_settings29x29@2x.png
│ ├── iphone_settings29x29@3x.png
│ ├── iphone_spotlight40x40@2x.png
│ ├── iphone_spotlight40x40@3x.png
│ ├── ipad_notification20x20@2x.png
│ ├── iphone_notification20x20@2x.png
│ ├── iphone_notification20x20@3x.png
│ └── Contents.json
├── AdditionalWatchAssets.xcassets
├── Contents.json
├── CustomLoopIcon_orig.appiconset
│ ├── Icon.png
│ ├── icon_24pt@2x.png
│ ├── icon_29pt@2x.png
│ ├── icon_29pt@3x.png
│ ├── icon_40pt@2x.png
│ ├── icon_44pt@2x.png
│ ├── icon_50pt@2x.png
│ ├── icon_86pt@2x.png
│ ├── icon_98pt@2x.png
│ ├── icon_108pt@2x.png
│ ├── icon_27.5pt@2x.png
│ └── Contents.json
└── CustomLoopIcon.appiconset
│ ├── watch_home40x40@2x.png
│ ├── watch_home44x44@2x.png
│ ├── watch_home50x50@2x.png
│ ├── watch_appstore1024x1024.png
│ ├── watch_short_look86x86@2x.png
│ ├── watch_short_look98x98@2x.png
│ ├── watch_short_look108x108@2x.png
│ ├── watch_companion_settings29x29@2x.png
│ ├── watch_companion_settings29x29@3x.png
│ ├── watch_notification_center24x24@2x.png
│ ├── watch_notification_center27.5x27.5@2x.png
│ └── Contents.json
├── fastlane
├── swift
│ ├── FastlaneSwiftRunner
│ │ ├── FastlaneSwiftRunner.xcodeproj
│ │ │ ├── project.xcworkspace
│ │ │ │ ├── contents.xcworkspacedata
│ │ │ │ └── xcshareddata
│ │ │ │ │ └── IDEWorkspaceChecks.plist
│ │ │ ├── xcshareddata
│ │ │ │ └── xcschemes
│ │ │ │ │ └── FastlaneRunner.xcscheme
│ │ │ └── project.pbxproj
│ │ └── README.txt
│ ├── Fastfile.swift
│ ├── Actions.swift
│ ├── Plugins.swift
│ ├── RunnerArgument.swift
│ ├── Gymfile.swift
│ ├── Scanfile.swift
│ ├── Matchfile.swift
│ ├── Deliverfile.swift
│ ├── Precheckfile.swift
│ ├── Snapshotfile.swift
│ ├── SocketClientDelegateProtocol.swift
│ ├── upgrade_manifest.json
│ ├── Screengrabfile.swift
│ ├── Appfile.swift
│ ├── RubyCommandable.swift
│ ├── PrecheckfileProtocol.swift
│ ├── main.swift
│ ├── ControlCommand.swift
│ ├── SocketResponse.swift
│ ├── ArgumentProcessor.swift
│ ├── ScreengrabfileProtocol.swift
│ ├── LaneFileProtocol.swift
│ ├── RubyCommand.swift
│ ├── MatchfileProtocol.swift
│ ├── SnapshotfileProtocol.swift
│ ├── GymfileProtocol.swift
│ ├── Runner.swift
│ ├── DeliverfileProtocol.swift
│ ├── ScanfileProtocol.swift
│ └── SocketClient.swift
├── Appfile.swift
└── Fastfile.swift
├── Loop.xcworkspace
├── xcshareddata
│ ├── IDEWorkspaceChecks.plist
│ ├── WorkspaceSettings.xcsettings
│ └── xcschemes
│ │ ├── Learn (Workspace).xcscheme
│ │ └── Loop (Workspace).xcscheme
└── contents.xcworkspacedata
├── .travis.yml
├── README.md
├── LoopConfigOverride.xcconfig
├── .gitignore
└── .gitmodules
/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "fastlane"
4 |
--------------------------------------------------------------------------------
/docs/scheme-selection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/docs/scheme-selection.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/Icon.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/ipad_app76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/ipad_app76x76.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_20pt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_20pt.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_29pt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_29pt.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_40pt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_40pt.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_76pt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_76pt.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/Icon.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/ipad_app76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/ipad_app76x76@2x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_20pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_20pt@2x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_20pt@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_20pt@3x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_29pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_29pt@2x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_29pt@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_29pt@3x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_40pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_40pt@2x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_40pt@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_40pt@3x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_60pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_60pt@2x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_60pt@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_60pt@3x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_76pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_76pt@2x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_83.5@2x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/ipad_settings29x29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/ipad_settings29x29.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/ipad_spotlight40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/ipad_spotlight40x40.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/iphone_app60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/iphone_app60x60@2x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/iphone_app60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/iphone_app60x60@3x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_20pt@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_20pt@2x-1.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_29pt@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_29pt@2x-1.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_40pt@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_40pt@2x-1.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/ios_marketing1024x1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/ios_marketing1024x1024.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/ipad_notification20x20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/ipad_notification20x20.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/ipad_settings29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/ipad_settings29x29@2x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/ipad_spotlight40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/ipad_spotlight40x40@2x.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_24pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_24pt@2x.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_29pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_29pt@2x.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_29pt@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_29pt@3x.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_40pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_40pt@2x.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_44pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_44pt@2x.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_50pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_50pt@2x.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_86pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_86pt@2x.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_98pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_98pt@2x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/ipad_pro_app83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/ipad_pro_app83.5x83.5@2x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/iphone_settings29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/iphone_settings29x29@2x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/iphone_settings29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/iphone_settings29x29@3x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/iphone_spotlight40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/iphone_spotlight40x40@2x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/iphone_spotlight40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/iphone_spotlight40x40@3x.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_home40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_home40x40@2x.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_home44x44@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_home44x44@2x.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_home50x50@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_home50x50@2x.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_108pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_108pt@2x.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_27.5pt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/icon_27.5pt@2x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/ipad_notification20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/ipad_notification20x20@2x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/iphone_notification20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/iphone_notification20x20@2x.png
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/iphone_notification20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/iphone_notification20x20@3x.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_appstore1024x1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_appstore1024x1024.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_short_look86x86@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_short_look86x86@2x.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_short_look98x98@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_short_look98x98@2x.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_short_look108x108@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_short_look108x108@2x.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_companion_settings29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_companion_settings29x29@2x.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_companion_settings29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_companion_settings29x29@3x.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_notification_center24x24@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_notification_center24x24@2x.png
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_notification_center27.5x27.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivalkou/LoopWorkspace/HEAD/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/watch_notification_center27.5x27.5@2x.png
--------------------------------------------------------------------------------
/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Loop.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Loop.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded
6 |
7 | PreviewsEnabled
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/fastlane/swift/FastlaneSwiftRunner/README.txt:
--------------------------------------------------------------------------------
1 | Don't modify the structure of this group including but not limited to:
2 | - renaming this group
3 | - adding sub groups
4 | - removing sub groups
5 | - adding new files
6 | - removing files
7 |
8 | If you modify anything in this folder, future fastlane upgrades may not be able to be applied automatically.
9 |
10 | If you need to add new groups, please add them at the root of the "Fastlane Runner" group.
11 |
--------------------------------------------------------------------------------
/fastlane/Appfile.swift:
--------------------------------------------------------------------------------
1 | var appIdentifier: String { return "com.BA7ZHP4963.loopkit.Loop" } // The bundle identifier of your app
2 | var appleID: String { return "ivalkou@gmail.com" } // Your Apple email address
3 |
4 | var itcTeam: String? { return "2082062" } // App Store Connect Team ID
5 | var teamID: String { return "BA7ZHP4963" } // Apple Developer Portal Team ID
6 |
7 |
8 | // For more information about the Appfile, see:
9 | // https://docs.fastlane.tools/advanced/#appfile
10 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: objective-c
2 |
3 | osx_image: xcode10.2
4 |
5 | script:
6 | - set -o pipefail && time xcodebuild -workspace Loop.xcworkspace -scheme 'Loop (Workspace)' -destination 'name=iPhone SE' build | xcpretty
7 | - set -o pipefail && time xcodebuild -workspace Loop.xcworkspace -scheme 'Learn (Workspace)' -destination 'name=iPhone SE' build | xcpretty
8 | - set -o pipefail && time xcodebuild -workspace Loop.xcworkspace -scheme 'Loop (Workspace)' -destination 'name=iPhone SE' test | xcpretty
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Attention please!
2 |
3 | Dear friends! The FreeAPS project is frozen. All the forces of our team are aimed at developing a new project [FreeAPS X](https://github.com/ivalkou/freeaps) based on OpenAPS reference design. If you would like to continue developing FreeAPS/Loop project, please fork.
4 |
5 | # Loop and learn fork
6 |
7 | [Loop and Learn](https://www.loopandlearn.org) community continued to develop FreeAPS/Loop. [We recommend using their fork](https://github.com/loopnlearn/LoopWorkspace).
8 |
--------------------------------------------------------------------------------
/LoopConfigOverride.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 |
3 | // Override this if you don't want the default com.${DEVELOPMENT_TEAM}.loopkit that loop uses
4 | // MAIN_APP_BUNDLE_IDENTIFIER = com.myname.loop
5 |
6 | // Customize this to change the app name displayed
7 | MAIN_APP_DISPLAY_NAME = FreeAPS
8 |
9 | MAIN_APP_PRODUCT_NAME = FreeAPS
10 |
11 | // Features
12 | // SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) FEATURE_OVERRIDES_DISABLED
13 |
14 | // Assets
15 | INCLUDED_SOURCE_FILE_NAMES = AdditionalAssets.xcassets
16 |
17 | APPICON_NAME = CustomLoopIcon
18 |
--------------------------------------------------------------------------------
/fastlane/swift/Fastfile.swift:
--------------------------------------------------------------------------------
1 | // This class is automatically included in FastlaneRunner during build
2 | // If you have a custom Fastfile.swift, this file will be replaced by it
3 | // Don't modify this file unless you are familiar with how fastlane's swift code generation works
4 | // *** This file will be overwritten or replaced during build time ***
5 |
6 | import Foundation
7 |
8 | class Fastfile: LaneFile { }
9 |
10 | // Please don't remove the lines below
11 | // They are used to detect outdated files
12 | // FastlaneRunnerAPIVersion [0.9.1]
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Build
2 | DerivedData/
3 |
4 | ## Settings
5 | *.pbxuser
6 | !default.pbxuser
7 | *.mode1v3
8 | !default.mode1v3
9 | *.mode2v3
10 | !default.mode2v3
11 | *.perspectivev3
12 | !default.perspectivev3
13 | xcuserdata/
14 |
15 | ## Other
16 | *.moved-aside
17 | *.xccheckout
18 | *.xcscmblueprint
19 | *.xcuserstate
20 | .DS_Store
21 |
22 | ## Obj-C/Swift specific
23 | *.hmap
24 | *.ipa
25 |
26 | ## Playgrounds
27 | *.playground
28 | playground.xcworkspace
29 | timeline.xctimeline
30 |
31 | ## fastlane temporary profiling data
32 | fastlane/report.xml
33 |
--------------------------------------------------------------------------------
/fastlane/swift/Actions.swift:
--------------------------------------------------------------------------------
1 | // This class is automatically included in FastlaneRunner during build
2 |
3 | // This autogenerated file will be overwritten or replaced when running "fastlane generate_swift"
4 | //
5 | // ** NOTE **
6 | // This file is provided by fastlane and WILL be overwritten in future updates
7 | // If you want to add extra functionality to this project, create a new file in a
8 | // new group so that it won't be marked for upgrade
9 | //
10 |
11 | import Foundation
12 |
13 | // Please don't remove the lines below
14 | // They are used to detect outdated files
15 | // FastlaneRunnerAPIVersion [0.9.56]
16 |
--------------------------------------------------------------------------------
/fastlane/swift/Plugins.swift:
--------------------------------------------------------------------------------
1 | // This class is automatically included in FastlaneRunner during build
2 |
3 | // This autogenerated file will be overwritten or replaced when installing/updating plugins or running "fastlane generate_swift"
4 | //
5 | // ** NOTE **
6 | // This file is provided by fastlane and WILL be overwritten in future updates
7 | // If you want to add extra functionality to this project, create a new file in a
8 | // new group so that it won't be marked for upgrade
9 | //
10 |
11 | import Foundation
12 |
13 | // Please don't remove the lines below
14 | // They are used to detect outdated files
15 | // FastlaneRunnerAPIVersion [0.9.56]
16 |
--------------------------------------------------------------------------------
/fastlane/swift/RunnerArgument.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RunnerArgument.swift
3 | // FastlaneSwiftRunner
4 | //
5 | // Created by Joshua Liebowitz on 9/1/17.
6 | //
7 |
8 | //
9 | // ** NOTE **
10 | // This file is provided by fastlane and WILL be overwritten in future updates
11 | // If you want to add extra functionality to this project, create a new file in a
12 | // new group so that it won't be marked for upgrade
13 | //
14 |
15 | import Foundation
16 |
17 | struct RunnerArgument {
18 | let name: String
19 | let value: String
20 | }
21 |
22 | // Please don't remove the lines below
23 | // They are used to detect outdated files
24 | // FastlaneRunnerAPIVersion [0.9.2]
25 |
--------------------------------------------------------------------------------
/fastlane/Fastfile.swift:
--------------------------------------------------------------------------------
1 | // This file contains the fastlane.tools configuration
2 | // You can find the documentation at https://docs.fastlane.tools
3 | //
4 | // For a list of all available actions, check out
5 | //
6 | // https://docs.fastlane.tools/actions
7 | //
8 |
9 | import Foundation
10 |
11 | class Fastfile: LaneFile {
12 | func archiveLane() {
13 | desc("Archive")
14 |
15 | let project = "Loop/Loop.xcodeproj"
16 | let scheme = "Loop (Workspace)"
17 | let version = "2.1"
18 | let buildNumber = numberOfCommits()
19 |
20 | incrementVersionNumber(versionNumber: version, xcodeproj: project)
21 | incrementBuildNumber(buildNumber: buildNumber, xcodeproj: project)
22 | buildApp(scheme: scheme, clean: true, skipPackageIpa: true)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/fastlane/swift/Gymfile.swift:
--------------------------------------------------------------------------------
1 | // This class is automatically included in FastlaneRunner during build
2 |
3 | // This autogenerated file will be overwritten or replaced during build time, or when you initialize `gym`
4 | //
5 | // ** NOTE **
6 | // This file is provided by fastlane and WILL be overwritten in future updates
7 | // If you want to add extra functionality to this project, create a new file in a
8 | // new group so that it won't be marked for upgrade
9 | //
10 |
11 | class Gymfile: GymfileProtocol {
12 | // If you want to enable `gym`, run `fastlane gym init`
13 | // After, this file will be replaced with a custom implementation that contains values you supplied
14 | // during the `init` process, and you won't see this message
15 | }
16 |
17 |
18 |
19 |
20 |
21 | // Generated with fastlane 2.135.2
22 |
--------------------------------------------------------------------------------
/fastlane/swift/Scanfile.swift:
--------------------------------------------------------------------------------
1 | // This class is automatically included in FastlaneRunner during build
2 |
3 | // This autogenerated file will be overwritten or replaced during build time, or when you initialize `scan`
4 | //
5 | // ** NOTE **
6 | // This file is provided by fastlane and WILL be overwritten in future updates
7 | // If you want to add extra functionality to this project, create a new file in a
8 | // new group so that it won't be marked for upgrade
9 | //
10 |
11 | class Scanfile: ScanfileProtocol {
12 | // If you want to enable `scan`, run `fastlane scan init`
13 | // After, this file will be replaced with a custom implementation that contains values you supplied
14 | // during the `init` process, and you won't see this message
15 | }
16 |
17 |
18 |
19 |
20 |
21 | // Generated with fastlane 2.135.2
22 |
--------------------------------------------------------------------------------
/fastlane/swift/Matchfile.swift:
--------------------------------------------------------------------------------
1 | // This class is automatically included in FastlaneRunner during build
2 |
3 | // This autogenerated file will be overwritten or replaced during build time, or when you initialize `match`
4 | //
5 | // ** NOTE **
6 | // This file is provided by fastlane and WILL be overwritten in future updates
7 | // If you want to add extra functionality to this project, create a new file in a
8 | // new group so that it won't be marked for upgrade
9 | //
10 |
11 | class Matchfile: MatchfileProtocol {
12 | // If you want to enable `match`, run `fastlane match init`
13 | // After, this file will be replaced with a custom implementation that contains values you supplied
14 | // during the `init` process, and you won't see this message
15 | }
16 |
17 |
18 |
19 |
20 |
21 | // Generated with fastlane 2.135.2
22 |
--------------------------------------------------------------------------------
/fastlane/swift/Deliverfile.swift:
--------------------------------------------------------------------------------
1 | // This class is automatically included in FastlaneRunner during build
2 |
3 | // This autogenerated file will be overwritten or replaced during build time, or when you initialize `deliver`
4 | //
5 | // ** NOTE **
6 | // This file is provided by fastlane and WILL be overwritten in future updates
7 | // If you want to add extra functionality to this project, create a new file in a
8 | // new group so that it won't be marked for upgrade
9 | //
10 |
11 | class Deliverfile: DeliverfileProtocol {
12 | // If you want to enable `deliver`, run `fastlane deliver init`
13 | // After, this file will be replaced with a custom implementation that contains values you supplied
14 | // during the `init` process, and you won't see this message
15 | }
16 |
17 |
18 |
19 |
20 |
21 | // Generated with fastlane 2.135.2
22 |
--------------------------------------------------------------------------------
/fastlane/swift/Precheckfile.swift:
--------------------------------------------------------------------------------
1 | // This class is automatically included in FastlaneRunner during build
2 |
3 | // This autogenerated file will be overwritten or replaced during build time, or when you initialize `precheck`
4 | //
5 | // ** NOTE **
6 | // This file is provided by fastlane and WILL be overwritten in future updates
7 | // If you want to add extra functionality to this project, create a new file in a
8 | // new group so that it won't be marked for upgrade
9 | //
10 |
11 | class Precheckfile: PrecheckfileProtocol {
12 | // If you want to enable `precheck`, run `fastlane precheck init`
13 | // After, this file will be replaced with a custom implementation that contains values you supplied
14 | // during the `init` process, and you won't see this message
15 | }
16 |
17 |
18 |
19 |
20 |
21 | // Generated with fastlane 2.135.2
22 |
--------------------------------------------------------------------------------
/fastlane/swift/Snapshotfile.swift:
--------------------------------------------------------------------------------
1 | // This class is automatically included in FastlaneRunner during build
2 |
3 | // This autogenerated file will be overwritten or replaced during build time, or when you initialize `snapshot`
4 | //
5 | // ** NOTE **
6 | // This file is provided by fastlane and WILL be overwritten in future updates
7 | // If you want to add extra functionality to this project, create a new file in a
8 | // new group so that it won't be marked for upgrade
9 | //
10 |
11 | class Snapshotfile: SnapshotfileProtocol {
12 | // If you want to enable `snapshot`, run `fastlane snapshot init`
13 | // After, this file will be replaced with a custom implementation that contains values you supplied
14 | // during the `init` process, and you won't see this message
15 | }
16 |
17 |
18 |
19 |
20 |
21 | // Generated with fastlane 2.135.2
22 |
--------------------------------------------------------------------------------
/fastlane/swift/SocketClientDelegateProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SocketClientDelegateProtocol.swift
3 | // FastlaneSwiftRunner
4 | //
5 | // Created by Joshua Liebowitz on 8/12/17.
6 | //
7 |
8 | //
9 | // ** NOTE **
10 | // This file is provided by fastlane and WILL be overwritten in future updates
11 | // If you want to add extra functionality to this project, create a new file in a
12 | // new group so that it won't be marked for upgrade
13 | //
14 |
15 | import Foundation
16 |
17 | protocol SocketClientDelegateProtocol: class {
18 | func connectionsOpened()
19 | func connectionsClosed()
20 | func commandExecuted(serverResponse: SocketClientResponse, completion: (SocketClient) -> Void)
21 | }
22 |
23 | // Please don't remove the lines below
24 | // They are used to detect outdated files
25 | // FastlaneRunnerAPIVersion [0.9.2]
26 |
--------------------------------------------------------------------------------
/fastlane/swift/upgrade_manifest.json:
--------------------------------------------------------------------------------
1 | {"Actions.swift":"Autogenerated API","Fastlane.swift":"Autogenerated API","DeliverfileProtocol.swift":"Autogenerated API","GymfileProtocol.swift":"Autogenerated API","MatchfileProtocol.swift":"Autogenerated API","Plugins.swift":"Autogenerated API","PrecheckfileProtocol.swift":"Autogenerated API","ScanfileProtocol.swift":"Autogenerated API","ScreengrabfileProtocol.swift":"Autogenerated API","SnapshotfileProtocol.swift":"Autogenerated API","LaneFileProtocol.swift":"Fastfile Components","ControlCommand.swift":"Networking","RubyCommand.swift":"Networking","RubyCommandable.swift":"Networking","Runner.swift":"Networking","SocketClient.swift":"Networking","SocketClientDelegateProtocol.swift":"Networking","SocketResponse.swift":"Networking","ArgumentProcessor.swift":"Runner Code","main.swift":"Runner Code","RunnerArgument.swift":"Runner Code"}
--------------------------------------------------------------------------------
/fastlane/swift/Screengrabfile.swift:
--------------------------------------------------------------------------------
1 | // This class is automatically included in FastlaneRunner during build
2 |
3 | // This autogenerated file will be overwritten or replaced during build time, or when you initialize `screengrab`
4 | //
5 | // ** NOTE **
6 | // This file is provided by fastlane and WILL be overwritten in future updates
7 | // If you want to add extra functionality to this project, create a new file in a
8 | // new group so that it won't be marked for upgrade
9 | //
10 |
11 | class Screengrabfile: ScreengrabfileProtocol {
12 | // If you want to enable `screengrab`, run `fastlane screengrab init`
13 | // After, this file will be replaced with a custom implementation that contains values you supplied
14 | // during the `init` process, and you won't see this message
15 | }
16 |
17 |
18 |
19 |
20 |
21 | // Generated with fastlane 2.135.2
22 |
--------------------------------------------------------------------------------
/fastlane/swift/Appfile.swift:
--------------------------------------------------------------------------------
1 | // This class is automatically included in FastlaneRunner during build
2 | // If you have a custom Appfile.swift, this file will be replaced by it
3 | // Don't modify this file unless you are familiar with how fastlane's swift code generation works
4 | // *** This file will be overwritten or replaced during build time ***
5 |
6 | var appIdentifier: String { return "" } // The bundle identifier of your app
7 | var appleID: String { return "" } // Your Apple email address
8 |
9 | var teamID: String { return "" } // Developer Portal Team ID
10 | var itcTeam: String? { return nil } // App Store Connect Team ID (may be nil if no team)
11 |
12 | // you can even provide different app identifiers, Apple IDs and team names per lane:
13 | // More information: https://docs.fastlane.tools/advanced/#appfile
14 |
15 | // Please don't remove the lines below
16 | // They are used to detect outdated files
17 | // FastlaneRunnerAPIVersion [0.9.1]
18 |
--------------------------------------------------------------------------------
/fastlane/swift/RubyCommandable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RubyCommandable.swift
3 | // FastlaneRunner
4 | //
5 | // Created by Joshua Liebowitz on 1/4/18.
6 | //
7 |
8 | //
9 | // ** NOTE **
10 | // This file is provided by fastlane and WILL be overwritten in future updates
11 | // If you want to add extra functionality to this project, create a new file in a
12 | // new group so that it won't be marked for upgrade
13 | //
14 |
15 | import Foundation
16 |
17 | enum CommandType {
18 | case action
19 | case control
20 |
21 | var token: String {
22 | switch self {
23 | case .action:
24 | return "action"
25 | case .control:
26 | return "control"
27 | }
28 | }
29 | }
30 |
31 | protocol RubyCommandable {
32 | var type: CommandType { get }
33 | var commandJson: String { get }
34 | var id: String { get }
35 | }
36 |
37 | extension RubyCommandable {
38 | var json: String {
39 | return """
40 | { "commandType": "\(type.token)", "command": \(commandJson) }
41 | """
42 | }
43 | }
44 |
45 | // Please don't remove the lines below
46 | // They are used to detect outdated files
47 | // FastlaneRunnerAPIVersion [0.9.2]
48 |
--------------------------------------------------------------------------------
/fastlane/swift/PrecheckfileProtocol.swift:
--------------------------------------------------------------------------------
1 | protocol PrecheckfileProtocol: class {
2 | /// The bundle identifier of your app
3 | var appIdentifier: String { get }
4 |
5 | /// Your Apple ID Username
6 | var username: String { get }
7 |
8 | /// The ID of your App Store Connect team if you're in multiple teams
9 | var teamId: String? { get }
10 |
11 | /// The name of your App Store Connect team if you're in multiple teams
12 | var teamName: String? { get }
13 |
14 | /// The default rule level unless otherwise configured
15 | var defaultRuleLevel: String { get }
16 |
17 | /// Should check in-app purchases?
18 | var includeInAppPurchases: Bool { get }
19 |
20 | /// using text indicating that your IAP is free
21 | var freeStuffInIap: String? { get }
22 | }
23 |
24 | extension PrecheckfileProtocol {
25 | var appIdentifier: String { return "" }
26 | var username: String { return "" }
27 | var teamId: String? { return nil }
28 | var teamName: String? { return nil }
29 | var defaultRuleLevel: String { return "error" }
30 | var includeInAppPurchases: Bool { return true }
31 | var freeStuffInIap: String? { return nil }
32 | }
33 |
34 | // Please don't remove the lines below
35 | // They are used to detect outdated files
36 | // FastlaneRunnerAPIVersion [0.9.21]
37 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "Loop"]
2 | path = Loop
3 | url=https://github.com/ivalkou/Loop.git
4 | branch = freeaps
5 | [submodule "LoopKit"]
6 | path = LoopKit
7 | url = https://github.com/LoopKit/LoopKit.git
8 | branch = dev
9 | [submodule "CGMBLEKit"]
10 | path = CGMBLEKit
11 | url = https://github.com/LoopKit/CGMBLEKit.git
12 | branch = dev
13 | [submodule "SwiftCharts"]
14 | path = SwiftCharts
15 | url = https://github.com/i-schuetz/SwiftCharts.git
16 | [submodule "dexcom-share-client-swift"]
17 | path = dexcom-share-client-swift
18 | url = https://github.com/LoopKit/dexcom-share-client-swift.git
19 | branch = dev
20 | [submodule "G4ShareSpy"]
21 | path = G4ShareSpy
22 | url = https://github.com/LoopKit/G4ShareSpy.git
23 | branch = dev
24 | [submodule "rileylink_ios"]
25 | path = rileylink_ios
26 | url = https://github.com/ps2/rileylink_ios.git
27 | branch = carthage-pin
28 | [submodule "Amplitude-iOS"]
29 | path = Amplitude-iOS
30 | url = https://github.com/LoopKit/Amplitude-iOS.git
31 | branch = decreepify
32 | [submodule "MKRingProgressView"]
33 | path = MKRingProgressView
34 | url = https://github.com/LoopKit/MKRingProgressView.git
35 | [submodule "NightscoutAPIClient"]
36 | path = NightscoutAPIClient
37 | url = https://github.com/ivalkou/NightscoutAPIClient.git
38 | [submodule "bubble-client-swift"]
39 | path = bubble-client-swift
40 | url = https://github.com/bubbledevteam/bubble-client-swift
41 |
--------------------------------------------------------------------------------
/Loop.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
12 |
13 |
15 |
16 |
18 |
19 |
21 |
22 |
24 |
25 |
27 |
28 |
30 |
31 |
33 |
34 |
36 |
37 |
39 |
40 |
42 |
43 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/fastlane/swift/main.swift:
--------------------------------------------------------------------------------
1 | //
2 | // main.swift
3 | // FastlaneSwiftRunner
4 | //
5 | // Created by Joshua Liebowitz on 8/26/17.
6 | //
7 |
8 | //
9 | // ** NOTE **
10 | // This file is provided by fastlane and WILL be overwritten in future updates
11 | // If you want to add extra functionality to this project, create a new file in a
12 | // new group so that it won't be marked for upgrade
13 | //
14 |
15 | import Foundation
16 |
17 | let argumentProcessor = ArgumentProcessor(args: CommandLine.arguments)
18 | let timeout = argumentProcessor.commandTimeout
19 |
20 | class MainProcess {
21 | var doneRunningLane = false
22 | var thread: Thread!
23 |
24 | @objc func connectToFastlaneAndRunLane() {
25 | runner.startSocketThread(port: argumentProcessor.port)
26 |
27 | let completedRun = Fastfile.runLane(named: argumentProcessor.currentLane, parameters: argumentProcessor.laneParameters())
28 | if completedRun {
29 | runner.disconnectFromFastlaneProcess()
30 | }
31 |
32 | doneRunningLane = true
33 | }
34 |
35 | func startFastlaneThread() {
36 | thread = Thread(target: self, selector: #selector(connectToFastlaneAndRunLane), object: nil)
37 | thread.name = "worker thread"
38 | thread.start()
39 | }
40 | }
41 |
42 | let process: MainProcess = MainProcess()
43 | process.startFastlaneThread()
44 |
45 | while !process.doneRunningLane, RunLoop.current.run(mode: RunLoopMode.defaultRunLoopMode, before: Date(timeIntervalSinceNow: 2)) {
46 | // no op
47 | }
48 |
49 | // Please don't remove the lines below
50 | // They are used to detect outdated files
51 | // FastlaneRunnerAPIVersion [0.9.2]
52 |
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon_orig.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "24x24",
5 | "idiom" : "watch",
6 | "filename" : "icon_24pt@2x.png",
7 | "scale" : "2x",
8 | "role" : "notificationCenter",
9 | "subtype" : "38mm"
10 | },
11 | {
12 | "size" : "27.5x27.5",
13 | "idiom" : "watch",
14 | "filename" : "icon_27.5pt@2x.png",
15 | "scale" : "2x",
16 | "role" : "notificationCenter",
17 | "subtype" : "42mm"
18 | },
19 | {
20 | "size" : "29x29",
21 | "idiom" : "watch",
22 | "filename" : "icon_29pt@2x.png",
23 | "role" : "companionSettings",
24 | "scale" : "2x"
25 | },
26 | {
27 | "size" : "29x29",
28 | "idiom" : "watch",
29 | "filename" : "icon_29pt@3x.png",
30 | "role" : "companionSettings",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "watch",
36 | "filename" : "icon_40pt@2x.png",
37 | "scale" : "2x",
38 | "role" : "appLauncher",
39 | "subtype" : "38mm"
40 | },
41 | {
42 | "size" : "44x44",
43 | "idiom" : "watch",
44 | "filename" : "icon_44pt@2x.png",
45 | "scale" : "2x",
46 | "role" : "appLauncher",
47 | "subtype" : "40mm"
48 | },
49 | {
50 | "size" : "50x50",
51 | "idiom" : "watch",
52 | "filename" : "icon_50pt@2x.png",
53 | "scale" : "2x",
54 | "role" : "appLauncher",
55 | "subtype" : "44mm"
56 | },
57 | {
58 | "size" : "86x86",
59 | "idiom" : "watch",
60 | "filename" : "icon_86pt@2x.png",
61 | "scale" : "2x",
62 | "role" : "quickLook",
63 | "subtype" : "38mm"
64 | },
65 | {
66 | "size" : "98x98",
67 | "idiom" : "watch",
68 | "filename" : "icon_98pt@2x.png",
69 | "scale" : "2x",
70 | "role" : "quickLook",
71 | "subtype" : "42mm"
72 | },
73 | {
74 | "size" : "108x108",
75 | "idiom" : "watch",
76 | "filename" : "icon_108pt@2x.png",
77 | "scale" : "2x",
78 | "role" : "quickLook",
79 | "subtype" : "44mm"
80 | },
81 | {
82 | "size" : "1024x1024",
83 | "idiom" : "watch-marketing",
84 | "filename" : "Icon.png",
85 | "scale" : "1x"
86 | }
87 | ],
88 | "info" : {
89 | "version" : 1,
90 | "author" : "xcode"
91 | }
92 | }
--------------------------------------------------------------------------------
/AdditionalWatchAssets.xcassets/CustomLoopIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "24x24",
5 | "idiom" : "watch",
6 | "filename" : "watch_notification_center24x24@2x.png",
7 | "scale" : "2x",
8 | "role" : "notificationCenter",
9 | "subtype" : "38mm"
10 | },
11 | {
12 | "size" : "27.5x27.5",
13 | "idiom" : "watch",
14 | "filename" : "watch_notification_center27.5x27.5@2x.png",
15 | "scale" : "2x",
16 | "role" : "notificationCenter",
17 | "subtype" : "42mm"
18 | },
19 | {
20 | "size" : "29x29",
21 | "idiom" : "watch",
22 | "filename" : "watch_companion_settings29x29@2x.png",
23 | "role" : "companionSettings",
24 | "scale" : "2x"
25 | },
26 | {
27 | "size" : "29x29",
28 | "idiom" : "watch",
29 | "filename" : "watch_companion_settings29x29@3x.png",
30 | "role" : "companionSettings",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "watch",
36 | "filename" : "watch_home40x40@2x.png",
37 | "scale" : "2x",
38 | "role" : "appLauncher",
39 | "subtype" : "38mm"
40 | },
41 | {
42 | "size" : "44x44",
43 | "idiom" : "watch",
44 | "filename" : "watch_home44x44@2x.png",
45 | "scale" : "2x",
46 | "role" : "appLauncher",
47 | "subtype" : "40mm"
48 | },
49 | {
50 | "size" : "50x50",
51 | "idiom" : "watch",
52 | "filename" : "watch_home50x50@2x.png",
53 | "scale" : "2x",
54 | "role" : "appLauncher",
55 | "subtype" : "44mm"
56 | },
57 | {
58 | "size" : "86x86",
59 | "idiom" : "watch",
60 | "filename" : "watch_short_look86x86@2x.png",
61 | "scale" : "2x",
62 | "role" : "quickLook",
63 | "subtype" : "38mm"
64 | },
65 | {
66 | "size" : "98x98",
67 | "idiom" : "watch",
68 | "filename" : "watch_short_look98x98@2x.png",
69 | "scale" : "2x",
70 | "role" : "quickLook",
71 | "subtype" : "42mm"
72 | },
73 | {
74 | "size" : "108x108",
75 | "idiom" : "watch",
76 | "filename" : "watch_short_look108x108@2x.png",
77 | "scale" : "2x",
78 | "role" : "quickLook",
79 | "subtype" : "44mm"
80 | },
81 | {
82 | "size" : "1024x1024",
83 | "idiom" : "watch-marketing",
84 | "filename" : "watch_appstore1024x1024.png",
85 | "scale" : "1x"
86 | }
87 | ],
88 | "info" : {
89 | "version" : 1,
90 | "author" : "xcode"
91 | }
92 | }
--------------------------------------------------------------------------------
/fastlane/swift/ControlCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ControlCommand.swift
3 | // FastlaneRunner
4 | //
5 | // Created by Joshua Liebowitz on 1/3/18.
6 |
7 | //
8 | // ** NOTE **
9 | // This file is provided by fastlane and WILL be overwritten in future updates
10 | // If you want to add extra functionality to this project, create a new file in a
11 | // new group so that it won't be marked for upgrade
12 | //
13 |
14 | import Foundation
15 |
16 | struct ControlCommand: RubyCommandable {
17 | static let commandKey = "command"
18 | var type: CommandType { return .control }
19 |
20 | enum ShutdownCommandType {
21 | static let userMessageKey: String = "userMessage"
22 |
23 | enum CancelReason {
24 | static let reasonKey: String = "reason"
25 | case clientError
26 | case serverError
27 |
28 | var reasonText: String {
29 | switch self {
30 | case .clientError:
31 | return "clientError"
32 | case .serverError:
33 | return "serverError"
34 | }
35 | }
36 | }
37 |
38 | case done
39 | case cancel(cancelReason: CancelReason)
40 |
41 | var token: String {
42 | switch self {
43 | case .done:
44 | return "done"
45 | case .cancel:
46 | return "cancelFastlaneRun"
47 | }
48 | }
49 | }
50 |
51 | let message: String?
52 | let id: String = UUID().uuidString
53 | let shutdownCommandType: ShutdownCommandType
54 | var commandJson: String {
55 | var jsonDictionary: [String: Any] = [ControlCommand.commandKey: shutdownCommandType.token]
56 |
57 | if let message = message {
58 | jsonDictionary[ShutdownCommandType.userMessageKey] = message
59 | }
60 | if case let .cancel(reason) = shutdownCommandType {
61 | jsonDictionary[ShutdownCommandType.CancelReason.reasonKey] = reason.reasonText
62 | }
63 |
64 | let jsonData = try! JSONSerialization.data(withJSONObject: jsonDictionary, options: [])
65 | let jsonString = String(data: jsonData, encoding: .utf8)!
66 | return jsonString
67 | }
68 |
69 | init(commandType: ShutdownCommandType, message: String? = nil) {
70 | shutdownCommandType = commandType
71 | self.message = message
72 | }
73 | }
74 |
75 | // Please don't remove the lines below
76 | // They are used to detect outdated files
77 | // FastlaneRunnerAPIVersion [0.9.2]
78 |
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon_orig.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "icon_20pt@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "icon_20pt@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "icon_29pt@2x.png",
19 | "scale" : "2x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "icon_29pt@3x.png",
25 | "scale" : "3x"
26 | },
27 | {
28 | "size" : "40x40",
29 | "idiom" : "iphone",
30 | "filename" : "icon_40pt@2x.png",
31 | "scale" : "2x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "icon_40pt@3x.png",
37 | "scale" : "3x"
38 | },
39 | {
40 | "size" : "60x60",
41 | "idiom" : "iphone",
42 | "filename" : "icon_60pt@2x.png",
43 | "scale" : "2x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "icon_60pt@3x.png",
49 | "scale" : "3x"
50 | },
51 | {
52 | "size" : "20x20",
53 | "idiom" : "ipad",
54 | "filename" : "icon_20pt.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "icon_20pt@2x-1.png",
61 | "scale" : "2x"
62 | },
63 | {
64 | "size" : "29x29",
65 | "idiom" : "ipad",
66 | "filename" : "icon_29pt.png",
67 | "scale" : "1x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "icon_29pt@2x-1.png",
73 | "scale" : "2x"
74 | },
75 | {
76 | "size" : "40x40",
77 | "idiom" : "ipad",
78 | "filename" : "icon_40pt.png",
79 | "scale" : "1x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "icon_40pt@2x-1.png",
85 | "scale" : "2x"
86 | },
87 | {
88 | "size" : "76x76",
89 | "idiom" : "ipad",
90 | "filename" : "icon_76pt.png",
91 | "scale" : "1x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "icon_76pt@2x.png",
97 | "scale" : "2x"
98 | },
99 | {
100 | "size" : "83.5x83.5",
101 | "idiom" : "ipad",
102 | "filename" : "icon_83.5@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "1024x1024",
107 | "idiom" : "ios-marketing",
108 | "filename" : "Icon.png",
109 | "scale" : "1x"
110 | }
111 | ],
112 | "info" : {
113 | "version" : 1,
114 | "author" : "xcode"
115 | }
116 | }
--------------------------------------------------------------------------------
/AdditionalAssets.xcassets/CustomLoopIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "iphone_notification20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "iphone_notification20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "iphone_settings29x29@2x.png",
19 | "scale" : "2x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "iphone_settings29x29@3x.png",
25 | "scale" : "3x"
26 | },
27 | {
28 | "size" : "40x40",
29 | "idiom" : "iphone",
30 | "filename" : "iphone_spotlight40x40@2x.png",
31 | "scale" : "2x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "iphone_spotlight40x40@3x.png",
37 | "scale" : "3x"
38 | },
39 | {
40 | "size" : "60x60",
41 | "idiom" : "iphone",
42 | "filename" : "iphone_app60x60@2x.png",
43 | "scale" : "2x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "iphone_app60x60@3x.png",
49 | "scale" : "3x"
50 | },
51 | {
52 | "size" : "20x20",
53 | "idiom" : "ipad",
54 | "filename" : "ipad_notification20x20.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "ipad_notification20x20@2x.png",
61 | "scale" : "2x"
62 | },
63 | {
64 | "size" : "29x29",
65 | "idiom" : "ipad",
66 | "filename" : "ipad_settings29x29.png",
67 | "scale" : "1x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "ipad_settings29x29@2x.png",
73 | "scale" : "2x"
74 | },
75 | {
76 | "size" : "40x40",
77 | "idiom" : "ipad",
78 | "filename" : "ipad_spotlight40x40.png",
79 | "scale" : "1x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "ipad_spotlight40x40@2x.png",
85 | "scale" : "2x"
86 | },
87 | {
88 | "size" : "76x76",
89 | "idiom" : "ipad",
90 | "filename" : "ipad_app76x76.png",
91 | "scale" : "1x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "ipad_app76x76@2x.png",
97 | "scale" : "2x"
98 | },
99 | {
100 | "size" : "83.5x83.5",
101 | "idiom" : "ipad",
102 | "filename" : "ipad_pro_app83.5x83.5@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "1024x1024",
107 | "idiom" : "ios-marketing",
108 | "filename" : "ios_marketing1024x1024.png",
109 | "scale" : "1x"
110 | }
111 | ],
112 | "info" : {
113 | "version" : 1,
114 | "author" : "xcode"
115 | }
116 | }
--------------------------------------------------------------------------------
/fastlane/swift/SocketResponse.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SocketResponse.swift
3 | // FastlaneSwiftRunner
4 | //
5 | // Created by Joshua Liebowitz on 7/30/17.
6 | //
7 |
8 | //
9 | // ** NOTE **
10 | // This file is provided by fastlane and WILL be overwritten in future updates
11 | // If you want to add extra functionality to this project, create a new file in a
12 | // new group so that it won't be marked for upgrade
13 | //
14 |
15 | import Foundation
16 |
17 | struct SocketResponse {
18 | enum ResponseType {
19 | case parseFailure(failureInformation: [String])
20 | case failure(failureInformation: [String])
21 | case readyForNext(returnedObject: String?, closureArgumentValue: String?)
22 | case clientInitiatedCancel
23 |
24 | init(statusDictionary: [String: Any]) {
25 | guard let status = statusDictionary["status"] as? String else {
26 | self = .parseFailure(failureInformation: ["Message failed to parse from Ruby server"])
27 | return
28 | }
29 |
30 | if status == "ready_for_next" {
31 | verbose(message: "ready for next")
32 | let returnedObject = statusDictionary["return_object"] as? String
33 | let closureArgumentValue = statusDictionary["closure_argument_value"] as? String
34 | self = .readyForNext(returnedObject: returnedObject, closureArgumentValue: closureArgumentValue)
35 | return
36 |
37 | } else if status == "cancelled" {
38 | self = .clientInitiatedCancel
39 | return
40 |
41 | } else if status == "failure" {
42 | guard let failureInformation = statusDictionary["failure_information"] as? [String] else {
43 | self = .parseFailure(failureInformation: ["Ruby server indicated failure but Swift couldn't receive it"])
44 | return
45 | }
46 |
47 | self = .failure(failureInformation: failureInformation)
48 | return
49 | }
50 | self = .parseFailure(failureInformation: ["Message status: \(status) not a supported status"])
51 | }
52 | }
53 |
54 | let responseType: ResponseType
55 |
56 | init(payload: String) {
57 | guard let data = SocketResponse.convertToDictionary(text: payload) else {
58 | responseType = .parseFailure(failureInformation: ["Unable to parse message from Ruby server"])
59 | return
60 | }
61 |
62 | guard case let statusDictionary? = data["payload"] as? [String: Any] else {
63 | responseType = .parseFailure(failureInformation: ["Payload missing from Ruby server response"])
64 | return
65 | }
66 |
67 | responseType = ResponseType(statusDictionary: statusDictionary)
68 | }
69 | }
70 |
71 | extension SocketResponse {
72 | static func convertToDictionary(text: String) -> [String: Any]? {
73 | if let data = text.data(using: .utf8) {
74 | do {
75 | return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
76 | } catch {
77 | log(message: error.localizedDescription)
78 | }
79 | }
80 | return nil
81 | }
82 | }
83 |
84 | // Please don't remove the lines below
85 | // They are used to detect outdated files
86 | // FastlaneRunnerAPIVersion [0.9.2]
87 |
--------------------------------------------------------------------------------
/fastlane/swift/ArgumentProcessor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ArgumentProcessor.swift
3 | // FastlaneRunner
4 | //
5 | // Created by Joshua Liebowitz on 9/28/17.
6 | //
7 |
8 | //
9 | // ** NOTE **
10 | // This file is provided by fastlane and WILL be overwritten in future updates
11 | // If you want to add extra functionality to this project, create a new file in a
12 | // new group so that it won't be marked for upgrade
13 | //
14 |
15 | import Foundation
16 |
17 | struct ArgumentProcessor {
18 | let args: [RunnerArgument]
19 | let currentLane: String
20 | let commandTimeout: Int
21 | let port: UInt32
22 |
23 | init(args: [String]) {
24 | // Dump the first arg which is the program name
25 | let fastlaneArgs = stride(from: 1, to: args.count - 1, by: 2).map {
26 | RunnerArgument(name: args[$0], value: args[$0 + 1])
27 | }
28 | self.args = fastlaneArgs
29 |
30 | let fastlaneArgsMinusLanes = fastlaneArgs.filter { arg in
31 | arg.name.lowercased() != "lane"
32 | }
33 |
34 | let potentialLogMode = fastlaneArgsMinusLanes.filter { arg in
35 | arg.name.lowercased() == "logmode"
36 | }
37 |
38 | port = UInt32(fastlaneArgsMinusLanes.first(where: { $0.name == "swiftServerPort" })?.value ?? "") ?? 2000
39 |
40 | // Configure logMode since we might need to use it before we finish parsing
41 | if let logModeArg = potentialLogMode.first {
42 | let logModeString = logModeArg.value
43 | Logger.logMode = Logger.LogMode(logMode: logModeString)
44 | }
45 |
46 | let lanes = self.args.filter { arg in
47 | arg.name.lowercased() == "lane"
48 | }
49 | verbose(message: lanes.description)
50 |
51 | guard lanes.count == 1 else {
52 | let message = "You must have exactly one lane specified as an arg, here's what I got: \(lanes)"
53 | log(message: message)
54 | fatalError(message)
55 | }
56 |
57 | let lane = lanes.first!
58 | currentLane = lane.value
59 |
60 | // User might have configured a timeout for the socket connection
61 | let potentialTimeout = fastlaneArgsMinusLanes.filter { arg in
62 | arg.name.lowercased() == "timeoutseconds"
63 | }
64 |
65 | if let logModeArg = potentialLogMode.first {
66 | let logModeString = logModeArg.value
67 | Logger.logMode = Logger.LogMode(logMode: logModeString)
68 | }
69 |
70 | if let timeoutArg = potentialTimeout.first {
71 | let timeoutString = timeoutArg.value
72 | commandTimeout = (timeoutString as NSString).integerValue
73 | } else {
74 | commandTimeout = SocketClient.defaultCommandTimeoutSeconds
75 | }
76 | }
77 |
78 | func laneParameters() -> [String: String] {
79 | let laneParametersArgs = args.filter { arg in
80 | let lowercasedName = arg.name.lowercased()
81 | return lowercasedName != "timeoutseconds" && lowercasedName != "lane" && lowercasedName != "logmode"
82 | }
83 | var laneParameters = [String: String]()
84 | for arg in laneParametersArgs {
85 | laneParameters[arg.name] = arg.value
86 | }
87 | return laneParameters
88 | }
89 | }
90 |
91 | // Please don't remove the lines below
92 | // They are used to detect outdated files
93 | // FastlaneRunnerAPIVersion [0.9.2]
94 |
--------------------------------------------------------------------------------
/fastlane/swift/ScreengrabfileProtocol.swift:
--------------------------------------------------------------------------------
1 | protocol ScreengrabfileProtocol: class {
2 | /// Path to the root of your Android SDK installation, e.g. ~/tools/android-sdk-macosx
3 | var androidHome: String? { get }
4 |
5 | /// The Android build tools version to use, e.g. '23.0.2'
6 | var buildToolsVersion: String? { get }
7 |
8 | /// A list of locales which should be used
9 | var locales: [String] { get }
10 |
11 | /// Enabling this option will automatically clear previously generated screenshots before running screengrab
12 | var clearPreviousScreenshots: Bool { get }
13 |
14 | /// The directory where to store the screenshots
15 | var outputDirectory: String { get }
16 |
17 | /// Don't open the summary after running _screengrab_
18 | var skipOpenSummary: Bool { get }
19 |
20 | /// The package name of the app under test (e.g. com.yourcompany.yourapp)
21 | var appPackageName: String { get }
22 |
23 | /// The package name of the tests bundle (e.g. com.yourcompany.yourapp.test)
24 | var testsPackageName: String? { get }
25 |
26 | /// Only run tests in these Java packages
27 | var useTestsInPackages: [String]? { get }
28 |
29 | /// Only run tests in these Java classes
30 | var useTestsInClasses: [String]? { get }
31 |
32 | /// Additional launch arguments
33 | var launchArguments: [String]? { get }
34 |
35 | /// The fully qualified class name of your test instrumentation runner
36 | var testInstrumentationRunner: String { get }
37 |
38 | /// Return the device to this locale after running tests
39 | var endingLocale: String { get }
40 |
41 | /// Restarts the adb daemon using `adb root` to allow access to screenshots directories on device. Use if getting 'Permission denied' errors
42 | var useAdbRoot: Bool { get }
43 |
44 | /// The path to the APK for the app under test
45 | var appApkPath: String? { get }
46 |
47 | /// The path to the APK for the the tests bundle
48 | var testsApkPath: String? { get }
49 |
50 | /// Use the device or emulator with the given serial number or qualifier
51 | var specificDevice: String? { get }
52 |
53 | /// Type of device used for screenshots. Matches Google Play Types (phone, sevenInch, tenInch, tv, wear)
54 | var deviceType: String { get }
55 |
56 | /// Whether or not to exit Screengrab on test failure. Exiting on failure will not copy sceenshots to local machine nor open sceenshots summary
57 | var exitOnTestFailure: Bool { get }
58 |
59 | /// Enabling this option will automatically uninstall the application before running it
60 | var reinstallApp: Bool { get }
61 |
62 | /// Add timestamp suffix to screenshot filename
63 | var useTimestampSuffix: Bool { get }
64 |
65 | /// Configure the host used by adb to connect, allows running on remote devices farm
66 | var adbHost: String? { get }
67 | }
68 |
69 | extension ScreengrabfileProtocol {
70 | var androidHome: String? { return nil }
71 | var buildToolsVersion: String? { return nil }
72 | var locales: [String] { return ["en-US"] }
73 | var clearPreviousScreenshots: Bool { return false }
74 | var outputDirectory: String { return "fastlane/metadata/android" }
75 | var skipOpenSummary: Bool { return false }
76 | var appPackageName: String { return "" }
77 | var testsPackageName: String? { return nil }
78 | var useTestsInPackages: [String]? { return nil }
79 | var useTestsInClasses: [String]? { return nil }
80 | var launchArguments: [String]? { return nil }
81 | var testInstrumentationRunner: String { return "androidx.test.runner.AndroidJUnitRunner" }
82 | var endingLocale: String { return "en-US" }
83 | var useAdbRoot: Bool { return false }
84 | var appApkPath: String? { return nil }
85 | var testsApkPath: String? { return nil }
86 | var specificDevice: String? { return nil }
87 | var deviceType: String { return "phone" }
88 | var exitOnTestFailure: Bool { return true }
89 | var reinstallApp: Bool { return false }
90 | var useTimestampSuffix: Bool { return true }
91 | var adbHost: String? { return nil }
92 | }
93 |
94 | // Please don't remove the lines below
95 | // They are used to detect outdated files
96 | // FastlaneRunnerAPIVersion [0.9.23]
97 |
--------------------------------------------------------------------------------
/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/xcshareddata/xcschemes/FastlaneRunner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
40 |
41 |
42 |
43 |
44 |
45 |
56 |
58 |
64 |
65 |
66 |
67 |
70 |
71 |
74 |
75 |
76 |
77 |
78 |
79 |
85 |
87 |
93 |
94 |
95 |
96 |
98 |
99 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/fastlane/swift/LaneFileProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LaneFileProtocol.swift
3 | // FastlaneSwiftRunner
4 | //
5 | // Created by Joshua Liebowitz on 8/4/17.
6 | //
7 |
8 | //
9 | // ** NOTE **
10 | // This file is provided by fastlane and WILL be overwritten in future updates
11 | // If you want to add extra functionality to this project, create a new file in a
12 | // new group so that it won't be marked for upgrade
13 | //
14 |
15 | import Foundation
16 |
17 | public protocol LaneFileProtocol: class {
18 | var fastlaneVersion: String { get }
19 | static func runLane(named: String, parameters: [String: String]) -> Bool
20 |
21 | func recordLaneDescriptions()
22 | func beforeAll()
23 | func afterAll(currentLane: String)
24 | func onError(currentLane: String, errorInfo: String)
25 | }
26 |
27 | public extension LaneFileProtocol {
28 | var fastlaneVersion: String { return "" } // default "" because that means any is fine
29 | func beforeAll() {} // no op by default
30 | func afterAll(currentLane _: String) {} // no op by default
31 | func onError(currentLane _: String, errorInfo _: String) {} // no op by default
32 | func recordLaneDescriptions() {} // no op by default
33 | }
34 |
35 | @objcMembers
36 | public class LaneFile: NSObject, LaneFileProtocol {
37 | private(set) static var fastfileInstance: Fastfile?
38 |
39 | // Called before any lane is executed.
40 | private func setupAllTheThings() {
41 | LaneFile.fastfileInstance!.beforeAll()
42 | }
43 |
44 | private static func trimLaneFromName(laneName: String) -> String {
45 | return String(laneName.prefix(laneName.count - 4))
46 | }
47 |
48 | private static func trimLaneWithOptionsFromName(laneName: String) -> String {
49 | return String(laneName.prefix(laneName.count - 12))
50 | }
51 |
52 | private static var laneFunctionNames: [String] {
53 | var lanes: [String] = []
54 | var methodCount: UInt32 = 0
55 | let methodList = class_copyMethodList(self, &methodCount)
56 | for i in 0 ..< Int(methodCount) {
57 | let selName = sel_getName(method_getName(methodList![i]))
58 | let name = String(cString: selName)
59 | let lowercasedName = name.lowercased()
60 | if lowercasedName.hasSuffix("lane") || lowercasedName.hasSuffix("lanewithoptions:") {
61 | lanes.append(name)
62 | }
63 | }
64 | return lanes
65 | }
66 |
67 | public static var lanes: [String: String] {
68 | var laneToMethodName: [String: String] = [:]
69 | laneFunctionNames.forEach { name in
70 | let lowercasedName = name.lowercased()
71 | if lowercasedName.hasSuffix("lane") {
72 | laneToMethodName[lowercasedName] = name
73 | let lowercasedNameNoLane = trimLaneFromName(laneName: lowercasedName)
74 | laneToMethodName[lowercasedNameNoLane] = name
75 | } else if lowercasedName.hasSuffix("lanewithoptions:") {
76 | let lowercasedNameNoOptions = trimLaneWithOptionsFromName(laneName: lowercasedName)
77 | laneToMethodName[lowercasedNameNoOptions] = name
78 | let lowercasedNameNoLane = trimLaneFromName(laneName: lowercasedNameNoOptions)
79 | laneToMethodName[lowercasedNameNoLane] = name
80 | }
81 | }
82 |
83 | return laneToMethodName
84 | }
85 |
86 | public static func loadFastfile() {
87 | if fastfileInstance == nil {
88 | let fastfileType: AnyObject.Type = NSClassFromString(className())!
89 | let fastfileAsNSObjectType: NSObject.Type = fastfileType as! NSObject.Type
90 | let currentFastfileInstance: Fastfile? = fastfileAsNSObjectType.init() as? Fastfile
91 | fastfileInstance = currentFastfileInstance
92 | }
93 | }
94 |
95 | public static func runLane(named: String, parameters: [String: String]) -> Bool {
96 | log(message: "Running lane: \(named)")
97 | loadFastfile()
98 |
99 | guard let fastfileInstance: Fastfile = self.fastfileInstance else {
100 | let message = "Unable to instantiate class named: \(className())"
101 | log(message: message)
102 | fatalError(message)
103 | }
104 |
105 | let currentLanes = lanes
106 | let lowerCasedLaneRequested = named.lowercased()
107 |
108 | guard let laneMethod = currentLanes[lowerCasedLaneRequested] else {
109 | let laneNames = laneFunctionNames.map { laneFuctionName in
110 | if laneFuctionName.hasSuffix("lanewithoptions:") {
111 | return trimLaneWithOptionsFromName(laneName: laneFuctionName)
112 | } else {
113 | return trimLaneFromName(laneName: laneFuctionName)
114 | }
115 | }.joined(separator: ", ")
116 |
117 | let message = "[!] Could not find lane '\(named)'. Available lanes: \(laneNames)"
118 | log(message: message)
119 |
120 | let shutdownCommand = ControlCommand(commandType: .cancel(cancelReason: .clientError), message: message)
121 | _ = runner.executeCommand(shutdownCommand)
122 | return false
123 | }
124 |
125 | // call all methods that need to be called before we start calling lanes
126 | fastfileInstance.setupAllTheThings()
127 |
128 | // We need to catch all possible errors here and display a nice message
129 | _ = fastfileInstance.perform(NSSelectorFromString(laneMethod), with: parameters)
130 |
131 | // only call on success
132 | fastfileInstance.afterAll(currentLane: named)
133 | log(message: "Done running lane: \(named) 🚀")
134 | return true
135 | }
136 | }
137 |
138 | // Please don't remove the lines below
139 | // They are used to detect outdated files
140 | // FastlaneRunnerAPIVersion [0.9.2]
141 |
--------------------------------------------------------------------------------
/fastlane/swift/RubyCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RubyCommand.swift
3 | // FastlaneSwiftRunner
4 | //
5 | // Created by Joshua Liebowitz on 8/4/17.
6 | //
7 |
8 | //
9 | // ** NOTE **
10 | // This file is provided by fastlane and WILL be overwritten in future updates
11 | // If you want to add extra functionality to this project, create a new file in a
12 | // new group so that it won't be marked for upgrade
13 | //
14 |
15 | import Foundation
16 |
17 | struct RubyCommand: RubyCommandable {
18 | var type: CommandType { return .action }
19 |
20 | struct Argument {
21 | enum ArgType {
22 | case stringClosure
23 |
24 | var typeString: String {
25 | switch self {
26 | case .stringClosure:
27 | return "string_closure" // this should match when is in ruby's SocketServerActionCommandExecutor
28 | }
29 | }
30 | }
31 |
32 | let name: String
33 | let value: Any?
34 | let type: ArgType?
35 |
36 | init(name: String, value: Any?, type: ArgType? = nil) {
37 | self.name = name
38 | self.value = value
39 | self.type = type
40 | }
41 |
42 | var hasValue: Bool {
43 | return value != nil
44 | }
45 |
46 | var json: String {
47 | if let someValue = value {
48 | let typeJson: String
49 | if let type = type {
50 | typeJson = ", \"value_type\" : \"\(type.typeString)\""
51 | } else {
52 | typeJson = ""
53 | }
54 |
55 | if type == .stringClosure {
56 | return "{\"name\" : \"\(name)\", \"value\" : \"ignored_for_closure\"\(typeJson)}"
57 | } else if let array = someValue as? [String] {
58 | return "{\"name\" : \"\(name)\", \"value\" : \"\(array.joined(separator: ","))\"\(typeJson)}"
59 | } else if let hash = someValue as? [String: Any] {
60 | let jsonData = try! JSONSerialization.data(withJSONObject: hash, options: [])
61 | let jsonString = String(data: jsonData, encoding: .utf8)!
62 | return "{\"name\" : \"\(name)\", \"value\" : \(jsonString)\(typeJson)}"
63 | } else {
64 | let dictionary = [
65 | "name": name,
66 | "value": someValue,
67 | ]
68 | let jsonData = try! JSONSerialization.data(withJSONObject: dictionary, options: [])
69 | let jsonString = String(data: jsonData, encoding: .utf8)!
70 | return jsonString
71 | }
72 | } else {
73 | // Just exclude this arg if it doesn't have a value
74 | return ""
75 | }
76 | }
77 | }
78 |
79 | let commandID: String
80 | let methodName: String
81 | let className: String?
82 | let args: [Argument]
83 | let id: String = UUID().uuidString
84 |
85 | var closure: ((String) -> Void)? {
86 | let callbacks = args.filter { ($0.type != nil) && $0.type == .stringClosure }
87 | guard let callback = callbacks.first else {
88 | return nil
89 | }
90 |
91 | guard let callbackArgValue = callback.value else {
92 | return nil
93 | }
94 |
95 | guard let callbackClosure = callbackArgValue as? ((String) -> Void) else {
96 | return nil
97 | }
98 | return callbackClosure
99 | }
100 |
101 | func callbackClosure(_ callbackArg: String) -> ((String) -> Void)? {
102 | // WARNING: This will perform the first callback it receives
103 | let callbacks = args.filter { ($0.type != nil) && $0.type == .stringClosure }
104 | guard let callback = callbacks.first else {
105 | verbose(message: "received call to performCallback with \(callbackArg), but no callback available to perform")
106 | return nil
107 | }
108 |
109 | guard let callbackArgValue = callback.value else {
110 | verbose(message: "received call to performCallback with \(callbackArg), but callback is nil")
111 | return nil
112 | }
113 |
114 | guard let callbackClosure = callbackArgValue as? ((String) -> Void) else {
115 | verbose(message: "received call to performCallback with \(callbackArg), but callback type is unknown \(callbackArgValue.self)")
116 | return nil
117 | }
118 | return callbackClosure
119 | }
120 |
121 | func performCallback(callbackArg: String, socket: SocketClient, completion: @escaping () -> Void) {
122 | verbose(message: "Performing callback with: \(callbackArg)")
123 | socket.leave()
124 | callbackClosure(callbackArg)?(callbackArg)
125 | completion()
126 | }
127 |
128 | var commandJson: String {
129 | let argsArrayJson = args
130 | .map { $0.json }
131 | .filter { $0 != "" }
132 |
133 | let argsJson: String?
134 | if !argsArrayJson.isEmpty {
135 | argsJson = "\"args\" : [\(argsArrayJson.joined(separator: ","))]"
136 | } else {
137 | argsJson = nil
138 | }
139 |
140 | let commandIDJson = "\"commandID\" : \"\(commandID)\""
141 | let methodNameJson = "\"methodName\" : \"\(methodName)\""
142 |
143 | var jsonParts = [commandIDJson, methodNameJson]
144 | if let argsJson = argsJson {
145 | jsonParts.append(argsJson)
146 | }
147 |
148 | if let className = className {
149 | let classNameJson = "\"className\" : \"\(className)\""
150 | jsonParts.append(classNameJson)
151 | }
152 |
153 | let commandJsonString = "{\(jsonParts.joined(separator: ","))}"
154 |
155 | return commandJsonString
156 | }
157 | }
158 |
159 | // Please don't remove the lines below
160 | // They are used to detect outdated files
161 | // FastlaneRunnerAPIVersion [0.9.2]
162 |
--------------------------------------------------------------------------------
/Loop.xcworkspace/xcshareddata/xcschemes/Learn (Workspace).xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
43 |
49 |
50 |
51 |
57 |
63 |
64 |
65 |
71 |
77 |
78 |
79 |
85 |
91 |
92 |
93 |
94 |
95 |
100 |
101 |
107 |
108 |
109 |
110 |
111 |
112 |
122 |
124 |
130 |
131 |
132 |
133 |
139 |
140 |
146 |
147 |
148 |
149 |
151 |
152 |
155 |
156 |
157 |
--------------------------------------------------------------------------------
/fastlane/swift/MatchfileProtocol.swift:
--------------------------------------------------------------------------------
1 | protocol MatchfileProtocol: class {
2 | /// Define the profile type, can be appstore, adhoc, development, enterprise, developer_id
3 | var type: String { get }
4 |
5 | /// Create additional cert types needed for macOS installers (valid values: mac_installer_distribution, developer_id_installer)
6 | var additionalCertTypes: [String]? { get }
7 |
8 | /// Only fetch existing certificates and profiles, don't generate new ones
9 | var readonly: Bool { get }
10 |
11 | /// Create a certificate type for Xcode 11 and later (Apple Development or Apple Distribution)
12 | var generateAppleCerts: Bool { get }
13 |
14 | /// Skip syncing provisioning profiles
15 | var skipProvisioningProfiles: Bool { get }
16 |
17 | /// The bundle identifier(s) of your app (comma-separated)
18 | var appIdentifier: [String] { get }
19 |
20 | /// Your Apple ID Username
21 | var username: String { get }
22 |
23 | /// The ID of your Developer Portal team if you're in multiple teams
24 | var teamId: String? { get }
25 |
26 | /// The name of your Developer Portal team if you're in multiple teams
27 | var teamName: String? { get }
28 |
29 | /// Define where you want to store your certificates
30 | var storageMode: String { get }
31 |
32 | /// URL to the git repo containing all the certificates
33 | var gitUrl: String { get }
34 |
35 | /// Specific git branch to use
36 | var gitBranch: String { get }
37 |
38 | /// git user full name to commit
39 | var gitFullName: String? { get }
40 |
41 | /// git user email to commit
42 | var gitUserEmail: String? { get }
43 |
44 | /// Make a shallow clone of the repository (truncate the history to 1 revision)
45 | var shallowClone: Bool { get }
46 |
47 | /// Clone just the branch specified, instead of the whole repo. This requires that the branch already exists. Otherwise the command will fail
48 | var cloneBranchDirectly: Bool { get }
49 |
50 | /// Use a basic authorization header to access the git repo (e.g.: access via HTTPS, GitHub Actions, etc), usually a string in Base64
51 | var gitBasicAuthorization: String? { get }
52 |
53 | /// Use a bearer authorization header to access the git repo (e.g.: access to an Azure Devops repository), usually a string in Base64
54 | var gitBearerAuthorization: String? { get }
55 |
56 | /// Name of the Google Cloud Storage bucket to use
57 | var googleCloudBucketName: String? { get }
58 |
59 | /// Path to the gc_keys.json file
60 | var googleCloudKeysFile: String? { get }
61 |
62 | /// ID of the Google Cloud project to use for authentication
63 | var googleCloudProjectId: String? { get }
64 |
65 | /// Name of the S3 region
66 | var s3Region: String? { get }
67 |
68 | /// S3 access key
69 | var s3AccessKey: String? { get }
70 |
71 | /// S3 secret access key
72 | var s3SecretAccessKey: String? { get }
73 |
74 | /// Name of the S3 bucket
75 | var s3Bucket: String? { get }
76 |
77 | /// Prefix to be used on all objects uploaded to S3
78 | var s3ObjectPrefix: String? { get }
79 |
80 | /// Keychain the items should be imported to
81 | var keychainName: String { get }
82 |
83 | /// This might be required the first time you access certificates on a new mac. For the login/default keychain this is your account password
84 | var keychainPassword: String? { get }
85 |
86 | /// Renew the provisioning profiles every time you run match
87 | var force: Bool { get }
88 |
89 | /// Renew the provisioning profiles if the device count on the developer portal has changed. Ignored for profile type 'appstore'
90 | var forceForNewDevices: Bool { get }
91 |
92 | /// Disables confirmation prompts during nuke, answering them with yes
93 | var skipConfirmation: Bool { get }
94 |
95 | /// Skip generation of a README.md for the created git repository
96 | var skipDocs: Bool { get }
97 |
98 | /// Set the provisioning profile's platform to work with (i.e. ios, tvos, macos)
99 | var platform: String { get }
100 |
101 | /// The name of provisioning profile template. If the developer account has provisioning profile templates (aka: custom entitlements), the template name can be found by inspecting the Entitlements drop-down while creating/editing a provisioning profile (e.g. "Apple Pay Pass Suppression Development")
102 | var templateName: String? { get }
103 |
104 | /// A custom name for the provisioning profile. This will replace the default provisioning profile name if specified
105 | var profileName: String? { get }
106 |
107 | /// Should the command fail if it was about to create a duplicate of an existing provisioning profile. It can happen due to issues on Apple Developer Portal, when profile to be recreated was not properly deleted first
108 | var failOnNameTaken: Bool { get }
109 |
110 | /// Path in which to export certificates, key and profile
111 | var outputPath: String? { get }
112 |
113 | /// Print out extra information and all commands
114 | var verbose: Bool { get }
115 | }
116 |
117 | extension MatchfileProtocol {
118 | var type: String { return "development" }
119 | var additionalCertTypes: [String]? { return nil }
120 | var readonly: Bool { return false }
121 | var generateAppleCerts: Bool { return true }
122 | var skipProvisioningProfiles: Bool { return false }
123 | var appIdentifier: [String] { return [] }
124 | var username: String { return "" }
125 | var teamId: String? { return nil }
126 | var teamName: String? { return nil }
127 | var storageMode: String { return "git" }
128 | var gitUrl: String { return "" }
129 | var gitBranch: String { return "master" }
130 | var gitFullName: String? { return nil }
131 | var gitUserEmail: String? { return nil }
132 | var shallowClone: Bool { return false }
133 | var cloneBranchDirectly: Bool { return false }
134 | var gitBasicAuthorization: String? { return nil }
135 | var gitBearerAuthorization: String? { return nil }
136 | var googleCloudBucketName: String? { return nil }
137 | var googleCloudKeysFile: String? { return nil }
138 | var googleCloudProjectId: String? { return nil }
139 | var s3Region: String? { return nil }
140 | var s3AccessKey: String? { return nil }
141 | var s3SecretAccessKey: String? { return nil }
142 | var s3Bucket: String? { return nil }
143 | var s3ObjectPrefix: String? { return nil }
144 | var keychainName: String { return "login.keychain" }
145 | var keychainPassword: String? { return nil }
146 | var force: Bool { return false }
147 | var forceForNewDevices: Bool { return false }
148 | var skipConfirmation: Bool { return false }
149 | var skipDocs: Bool { return false }
150 | var platform: String { return "ios" }
151 | var templateName: String? { return nil }
152 | var profileName: String? { return nil }
153 | var failOnNameTaken: Bool { return false }
154 | var outputPath: String? { return nil }
155 | var verbose: Bool { return false }
156 | }
157 |
158 | // Please don't remove the lines below
159 | // They are used to detect outdated files
160 | // FastlaneRunnerAPIVersion [0.9.22]
161 |
--------------------------------------------------------------------------------
/fastlane/swift/SnapshotfileProtocol.swift:
--------------------------------------------------------------------------------
1 | protocol SnapshotfileProtocol: class {
2 | /// Path the workspace file
3 | var workspace: String? { get }
4 |
5 | /// Path the project file
6 | var project: String? { get }
7 |
8 | /// Pass additional arguments to xcodebuild for the test phase. Be sure to quote the setting names and values e.g. OTHER_LDFLAGS="-ObjC -lstdc++"
9 | var xcargs: String? { get }
10 |
11 | /// Use an extra XCCONFIG file to build your app
12 | var xcconfig: String? { get }
13 |
14 | /// A list of devices you want to take the screenshots from
15 | var devices: [String]? { get }
16 |
17 | /// A list of languages which should be used
18 | var languages: [String] { get }
19 |
20 | /// A list of launch arguments which should be used
21 | var launchArguments: [String] { get }
22 |
23 | /// The directory where to store the screenshots
24 | var outputDirectory: String { get }
25 |
26 | /// If the logs generated by the app (e.g. using NSLog, perror, etc.) in the Simulator should be written to the output_directory
27 | var outputSimulatorLogs: Bool { get }
28 |
29 | /// By default, the latest version should be used automatically. If you want to change it, do it here
30 | var iosVersion: String? { get }
31 |
32 | /// Don't open the HTML summary after running _snapshot_
33 | var skipOpenSummary: Bool { get }
34 |
35 | /// Do not check for most recent SnapshotHelper code
36 | var skipHelperVersionCheck: Bool { get }
37 |
38 | /// Enabling this option will automatically clear previously generated screenshots before running snapshot
39 | var clearPreviousScreenshots: Bool { get }
40 |
41 | /// Enabling this option will automatically uninstall the application before running it
42 | var reinstallApp: Bool { get }
43 |
44 | /// Enabling this option will automatically erase the simulator before running the application
45 | var eraseSimulator: Bool { get }
46 |
47 | /// Enabling this option wil automatically override the status bar to show 9:41 AM, full battery, and full reception
48 | var overrideStatusBar: Bool { get }
49 |
50 | /// Enabling this option will configure the Simulator's system language
51 | var localizeSimulator: Bool { get }
52 |
53 | /// Enabling this option will configure the Simulator to be in dark mode (false for light, true for dark)
54 | var darkMode: Bool? { get }
55 |
56 | /// The bundle identifier of the app to uninstall (only needed when enabling reinstall_app)
57 | var appIdentifier: String? { get }
58 |
59 | /// A list of photos that should be added to the simulator before running the application
60 | var addPhotos: [String]? { get }
61 |
62 | /// A list of videos that should be added to the simulator before running the application
63 | var addVideos: [String]? { get }
64 |
65 | /// A path to screenshots.html template
66 | var htmlTemplate: String? { get }
67 |
68 | /// The directory where to store the build log
69 | var buildlogPath: String { get }
70 |
71 | /// Should the project be cleaned before building it?
72 | var clean: Bool { get }
73 |
74 | /// Test without building, requires a derived data path
75 | var testWithoutBuilding: Bool? { get }
76 |
77 | /// The configuration to use when building the app. Defaults to 'Release'
78 | var configuration: String? { get }
79 |
80 | /// Additional xcpretty arguments
81 | var xcprettyArgs: String? { get }
82 |
83 | /// The SDK that should be used for building the application
84 | var sdk: String? { get }
85 |
86 | /// The scheme you want to use, this must be the scheme for the UI Tests
87 | var scheme: String? { get }
88 |
89 | /// The number of times a test can fail before snapshot should stop retrying
90 | var numberOfRetries: Int { get }
91 |
92 | /// Should snapshot stop immediately after the tests completely failed on one device?
93 | var stopAfterFirstError: Bool { get }
94 |
95 | /// The directory where build products and other derived data will go
96 | var derivedDataPath: String? { get }
97 |
98 | /// Should an Xcode result bundle be generated in the output directory
99 | var resultBundle: Bool { get }
100 |
101 | /// The name of the target you want to test (if you desire to override the Target Application from Xcode)
102 | var testTargetName: String? { get }
103 |
104 | /// Separate the log files per device and per language
105 | var namespaceLogFiles: String? { get }
106 |
107 | /// Take snapshots on multiple simulators concurrently. Note: This option is only applicable when running against Xcode 9
108 | var concurrentSimulators: Bool { get }
109 |
110 | /// Disable the simulator from showing the 'Slide to type' prompt
111 | var disableSlideToType: Bool { get }
112 |
113 | /// Sets a custom path for Swift Package Manager dependencies
114 | var clonedSourcePackagesPath: String? { get }
115 |
116 | /// The testplan associated with the scheme that should be used for testing
117 | var testplan: String? { get }
118 |
119 | /// Array of strings matching Test Bundle/Test Suite/Test Cases to run
120 | var onlyTesting: String? { get }
121 |
122 | /// Array of strings matching Test Bundle/Test Suite/Test Cases to skip
123 | var skipTesting: String? { get }
124 |
125 | /// Disable xcpretty formatting of build
126 | var disableXcpretty: Bool? { get }
127 | }
128 |
129 | extension SnapshotfileProtocol {
130 | var workspace: String? { return nil }
131 | var project: String? { return nil }
132 | var xcargs: String? { return nil }
133 | var xcconfig: String? { return nil }
134 | var devices: [String]? { return nil }
135 | var languages: [String] { return ["en-US"] }
136 | var launchArguments: [String] { return [""] }
137 | var outputDirectory: String { return "screenshots" }
138 | var outputSimulatorLogs: Bool { return false }
139 | var iosVersion: String? { return nil }
140 | var skipOpenSummary: Bool { return false }
141 | var skipHelperVersionCheck: Bool { return false }
142 | var clearPreviousScreenshots: Bool { return false }
143 | var reinstallApp: Bool { return false }
144 | var eraseSimulator: Bool { return false }
145 | var overrideStatusBar: Bool { return false }
146 | var localizeSimulator: Bool { return false }
147 | var darkMode: Bool? { return nil }
148 | var appIdentifier: String? { return nil }
149 | var addPhotos: [String]? { return nil }
150 | var addVideos: [String]? { return nil }
151 | var htmlTemplate: String? { return nil }
152 | var buildlogPath: String { return "~/Library/Logs/snapshot" }
153 | var clean: Bool { return false }
154 | var testWithoutBuilding: Bool? { return nil }
155 | var configuration: String? { return nil }
156 | var xcprettyArgs: String? { return nil }
157 | var sdk: String? { return nil }
158 | var scheme: String? { return nil }
159 | var numberOfRetries: Int { return 1 }
160 | var stopAfterFirstError: Bool { return false }
161 | var derivedDataPath: String? { return nil }
162 | var resultBundle: Bool { return false }
163 | var testTargetName: String? { return nil }
164 | var namespaceLogFiles: String? { return nil }
165 | var concurrentSimulators: Bool { return true }
166 | var disableSlideToType: Bool { return false }
167 | var clonedSourcePackagesPath: String? { return nil }
168 | var testplan: String? { return nil }
169 | var onlyTesting: String? { return nil }
170 | var skipTesting: String? { return nil }
171 | var disableXcpretty: Bool? { return nil }
172 | }
173 |
174 | // Please don't remove the lines below
175 | // They are used to detect outdated files
176 | // FastlaneRunnerAPIVersion [0.9.17]
177 |
--------------------------------------------------------------------------------
/fastlane/swift/GymfileProtocol.swift:
--------------------------------------------------------------------------------
1 | protocol GymfileProtocol: class {
2 | /// Path to the workspace file
3 | var workspace: String? { get }
4 |
5 | /// Path to the project file
6 | var project: String? { get }
7 |
8 | /// The project's scheme. Make sure it's marked as `Shared`
9 | var scheme: String? { get }
10 |
11 | /// Should the project be cleaned before building it?
12 | var clean: Bool { get }
13 |
14 | /// The directory in which the ipa file should be stored in
15 | var outputDirectory: String { get }
16 |
17 | /// The name of the resulting ipa file
18 | var outputName: String? { get }
19 |
20 | /// The configuration to use when building the app. Defaults to 'Release'
21 | var configuration: String? { get }
22 |
23 | /// Hide all information that's not necessary while building
24 | var silent: Bool { get }
25 |
26 | /// The name of the code signing identity to use. It has to match the name exactly. e.g. 'iPhone Distribution: SunApps GmbH'
27 | var codesigningIdentity: String? { get }
28 |
29 | /// Should we skip packaging the ipa?
30 | var skipPackageIpa: Bool { get }
31 |
32 | /// Should we skip packaging the pkg?
33 | var skipPackagePkg: Bool { get }
34 |
35 | /// Should the ipa file include symbols?
36 | var includeSymbols: Bool? { get }
37 |
38 | /// Should the ipa file include bitcode?
39 | var includeBitcode: Bool? { get }
40 |
41 | /// Method used to export the archive. Valid values are: app-store, ad-hoc, package, enterprise, development, developer-id
42 | var exportMethod: String? { get }
43 |
44 | /// Path to an export options plist or a hash with export options. Use 'xcodebuild -help' to print the full set of available options
45 | var exportOptions: [String: Any]? { get }
46 |
47 | /// Pass additional arguments to xcodebuild for the package phase. Be sure to quote the setting names and values e.g. OTHER_LDFLAGS="-ObjC -lstdc++"
48 | var exportXcargs: String? { get }
49 |
50 | /// Export ipa from previously built xcarchive. Uses archive_path as source
51 | var skipBuildArchive: Bool? { get }
52 |
53 | /// After building, don't archive, effectively not including -archivePath param
54 | var skipArchive: Bool? { get }
55 |
56 | /// Build without codesigning
57 | var skipCodesigning: Bool? { get }
58 |
59 | /// Platform to build when using a Catalyst enabled app. Valid values are: ios, macos
60 | var catalystPlatform: String? { get }
61 |
62 | /// Full name of 3rd Party Mac Developer Installer or Developer ID Installer certificate. Example: `3rd Party Mac Developer Installer: Your Company (ABC1234XWYZ)`
63 | var installerCertName: String? { get }
64 |
65 | /// The directory in which the archive should be stored in
66 | var buildPath: String? { get }
67 |
68 | /// The path to the created archive
69 | var archivePath: String? { get }
70 |
71 | /// The directory where built products and other derived data will go
72 | var derivedDataPath: String? { get }
73 |
74 | /// Should an Xcode result bundle be generated in the output directory
75 | var resultBundle: Bool { get }
76 |
77 | /// Path to the result bundle directory to create. Ignored if `result_bundle` if false
78 | var resultBundlePath: String? { get }
79 |
80 | /// The directory where to store the build log
81 | var buildlogPath: String { get }
82 |
83 | /// The SDK that should be used for building the application
84 | var sdk: String? { get }
85 |
86 | /// The toolchain that should be used for building the application (e.g. com.apple.dt.toolchain.Swift_2_3, org.swift.30p620160816a)
87 | var toolchain: String? { get }
88 |
89 | /// Use a custom destination for building the app
90 | var destination: String? { get }
91 |
92 | /// Optional: Sometimes you need to specify a team id when exporting the ipa file
93 | var exportTeamId: String? { get }
94 |
95 | /// Pass additional arguments to xcodebuild for the build phase. Be sure to quote the setting names and values e.g. OTHER_LDFLAGS="-ObjC -lstdc++"
96 | var xcargs: String? { get }
97 |
98 | /// Use an extra XCCONFIG file to build your app
99 | var xcconfig: String? { get }
100 |
101 | /// Suppress the output of xcodebuild to stdout. Output is still saved in buildlog_path
102 | var suppressXcodeOutput: Bool? { get }
103 |
104 | /// Disable xcpretty formatting of build output
105 | var disableXcpretty: Bool? { get }
106 |
107 | /// Use the test (RSpec style) format for build output
108 | var xcprettyTestFormat: Bool? { get }
109 |
110 | /// A custom xcpretty formatter to use
111 | var xcprettyFormatter: String? { get }
112 |
113 | /// Have xcpretty create a JUnit-style XML report at the provided path
114 | var xcprettyReportJunit: String? { get }
115 |
116 | /// Have xcpretty create a simple HTML report at the provided path
117 | var xcprettyReportHtml: String? { get }
118 |
119 | /// Have xcpretty create a JSON compilation database at the provided path
120 | var xcprettyReportJson: String? { get }
121 |
122 | /// Analyze the project build time and store the output in 'culprits.txt' file
123 | var analyzeBuildTime: Bool? { get }
124 |
125 | /// Have xcpretty use unicode encoding when reporting builds
126 | var xcprettyUtf: Bool? { get }
127 |
128 | /// Do not try to build a profile mapping from the xcodeproj. Match or a manually provided mapping should be used
129 | var skipProfileDetection: Bool { get }
130 |
131 | /// Sets a custom path for Swift Package Manager dependencies
132 | var clonedSourcePackagesPath: String? { get }
133 | }
134 |
135 | extension GymfileProtocol {
136 | var workspace: String? { return nil }
137 | var project: String? { return nil }
138 | var scheme: String? { return nil }
139 | var clean: Bool { return false }
140 | var outputDirectory: String { return "." }
141 | var outputName: String? { return nil }
142 | var configuration: String? { return nil }
143 | var silent: Bool { return false }
144 | var codesigningIdentity: String? { return nil }
145 | var skipPackageIpa: Bool { return false }
146 | var skipPackagePkg: Bool { return false }
147 | var includeSymbols: Bool? { return nil }
148 | var includeBitcode: Bool? { return nil }
149 | var exportMethod: String? { return nil }
150 | var exportOptions: [String: Any]? { return nil }
151 | var exportXcargs: String? { return nil }
152 | var skipBuildArchive: Bool? { return nil }
153 | var skipArchive: Bool? { return nil }
154 | var skipCodesigning: Bool? { return nil }
155 | var catalystPlatform: String? { return nil }
156 | var installerCertName: String? { return nil }
157 | var buildPath: String? { return nil }
158 | var archivePath: String? { return nil }
159 | var derivedDataPath: String? { return nil }
160 | var resultBundle: Bool { return false }
161 | var resultBundlePath: String? { return nil }
162 | var buildlogPath: String { return "~/Library/Logs/gym" }
163 | var sdk: String? { return nil }
164 | var toolchain: String? { return nil }
165 | var destination: String? { return nil }
166 | var exportTeamId: String? { return nil }
167 | var xcargs: String? { return nil }
168 | var xcconfig: String? { return nil }
169 | var suppressXcodeOutput: Bool? { return nil }
170 | var disableXcpretty: Bool? { return nil }
171 | var xcprettyTestFormat: Bool? { return nil }
172 | var xcprettyFormatter: String? { return nil }
173 | var xcprettyReportJunit: String? { return nil }
174 | var xcprettyReportHtml: String? { return nil }
175 | var xcprettyReportJson: String? { return nil }
176 | var analyzeBuildTime: Bool? { return nil }
177 | var xcprettyUtf: Bool? { return nil }
178 | var skipProfileDetection: Bool { return false }
179 | var clonedSourcePackagesPath: String? { return nil }
180 | }
181 |
182 | // Please don't remove the lines below
183 | // They are used to detect outdated files
184 | // FastlaneRunnerAPIVersion [0.9.28]
185 |
--------------------------------------------------------------------------------
/fastlane/swift/Runner.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Runner.swift
3 | // FastlaneSwiftRunner
4 | //
5 | // Created by Joshua Liebowitz on 8/26/17.
6 | //
7 |
8 | //
9 | // ** NOTE **
10 | // This file is provided by fastlane and WILL be overwritten in future updates
11 | // If you want to add extra functionality to this project, create a new file in a
12 | // new group so that it won't be marked for upgrade
13 | //
14 |
15 | import Foundation
16 |
17 | let logger: Logger = {
18 | Logger()
19 | }()
20 |
21 | let runner: Runner = {
22 | Runner()
23 | }()
24 |
25 | func desc(_: String) {
26 | // no-op, this is handled in fastlane/lane_list.rb
27 | }
28 |
29 | class Runner {
30 | private var thread: Thread!
31 | private var socketClient: SocketClient!
32 | private let dispatchGroup: DispatchGroup = DispatchGroup()
33 | private var returnValue: String? // lol, so safe
34 | private var currentlyExecutingCommand: RubyCommandable?
35 | private var shouldLeaveDispatchGroupDuringDisconnect = false
36 | private var executeNext: [String: Bool] = [:]
37 |
38 | func executeCommand(_ command: RubyCommandable) -> String {
39 | dispatchGroup.enter()
40 | currentlyExecutingCommand = command
41 | socketClient.send(rubyCommand: command)
42 |
43 | let secondsToWait = DispatchTimeInterval.seconds(SocketClient.defaultCommandTimeoutSeconds)
44 | // swiftlint:disable next
45 | let timeoutResult = waitWithPolling(self.executeNext[command.id], toEventually: { $0 == true }, timeout: SocketClient.defaultCommandTimeoutSeconds)
46 | executeNext.removeValue(forKey: command.id)
47 | let failureMessage = "command didn't execute in: \(SocketClient.defaultCommandTimeoutSeconds) seconds"
48 | let success = testDispatchTimeoutResult(timeoutResult, failureMessage: failureMessage, timeToWait: secondsToWait)
49 | guard success else {
50 | log(message: "command timeout")
51 | preconditionFailure()
52 | }
53 |
54 | if let _returnValue = returnValue {
55 | return _returnValue
56 | } else {
57 | return ""
58 | }
59 | }
60 |
61 | private func waitWithPolling(_ expression: @autoclosure @escaping () throws -> T, toEventually predicate: @escaping (T) -> Bool, timeout: Int, pollingInterval: DispatchTimeInterval = .milliseconds(4)) -> DispatchTimeoutResult {
62 | func memoizedClosure(_ closure: @escaping () throws -> T) -> (Bool) throws -> T {
63 | var cache: T?
64 | return { withoutCaching in
65 | if withoutCaching || cache == nil {
66 | cache = try closure()
67 | }
68 | guard let cache = cache else {
69 | preconditionFailure()
70 | }
71 |
72 | return cache
73 | }
74 | }
75 |
76 | let runLoop = RunLoop.current
77 | let timeoutDate = Date(timeInterval: TimeInterval(timeout), since: Date())
78 | var fulfilled: Bool = false
79 | let _expression = memoizedClosure(expression)
80 | repeat {
81 | do {
82 | let exp = try _expression(true)
83 | fulfilled = predicate(exp)
84 | } catch {
85 | fatalError("Error raised \(error.localizedDescription)")
86 | }
87 | if !fulfilled {
88 | runLoop.run(until: Date(timeIntervalSinceNow: pollingInterval.timeInterval))
89 | } else {
90 | break
91 | }
92 | } while Date().compare(timeoutDate) == .orderedAscending
93 |
94 | if fulfilled {
95 | return .success
96 | } else {
97 | return .timedOut
98 | }
99 | }
100 | }
101 |
102 | // Handle threading stuff
103 | extension Runner {
104 | func startSocketThread(port: UInt32) {
105 | let secondsToWait = DispatchTimeInterval.seconds(SocketClient.connectTimeoutSeconds)
106 |
107 | dispatchGroup.enter()
108 |
109 | socketClient = SocketClient(port: port, commandTimeoutSeconds: timeout, socketDelegate: self)
110 | thread = Thread(target: self, selector: #selector(startSocketComs), object: nil)
111 | guard let thread = thread else {
112 | preconditionFailure("Thread did not instantiate correctly")
113 | }
114 |
115 | thread.name = "socket thread"
116 | thread.start()
117 |
118 | let connectTimeout = DispatchTime.now() + secondsToWait
119 | let timeoutResult = dispatchGroup.wait(timeout: connectTimeout)
120 |
121 | let failureMessage = "couldn't start socket thread in: \(SocketClient.connectTimeoutSeconds) seconds"
122 | let success = testDispatchTimeoutResult(timeoutResult, failureMessage: failureMessage, timeToWait: secondsToWait)
123 | guard success else {
124 | log(message: "socket thread timeout")
125 | preconditionFailure()
126 | }
127 | }
128 |
129 | func disconnectFromFastlaneProcess() {
130 | shouldLeaveDispatchGroupDuringDisconnect = true
131 | dispatchGroup.enter()
132 | socketClient.sendComplete()
133 |
134 | let connectTimeout = DispatchTime.now() + 2
135 | _ = dispatchGroup.wait(timeout: connectTimeout)
136 | }
137 |
138 | @objc func startSocketComs() {
139 | guard let socketClient = self.socketClient else {
140 | return
141 | }
142 |
143 | socketClient.connectAndOpenStreams()
144 | dispatchGroup.leave()
145 | }
146 |
147 | fileprivate func testDispatchTimeoutResult(_ timeoutResult: DispatchTimeoutResult, failureMessage: String, timeToWait _: DispatchTimeInterval) -> Bool {
148 | switch timeoutResult {
149 | case .success:
150 | return true
151 | case .timedOut:
152 | log(message: "timeout: \(failureMessage)")
153 | return false
154 | }
155 | }
156 | }
157 |
158 | extension Runner: SocketClientDelegateProtocol {
159 | func commandExecuted(serverResponse: SocketClientResponse, completion: (SocketClient) -> Void) {
160 | switch serverResponse {
161 | case let .success(returnedObject, closureArgumentValue):
162 | verbose(message: "command executed")
163 | returnValue = returnedObject
164 | if let command = currentlyExecutingCommand as? RubyCommand {
165 | if let closureArgumentValue = closureArgumentValue, !closureArgumentValue.isEmpty {
166 | command.performCallback(callbackArg: closureArgumentValue, socket: socketClient) {
167 | self.executeNext[command.id] = true
168 | }
169 | } else {
170 | executeNext[command.id] = true
171 | }
172 | }
173 | dispatchGroup.leave()
174 | completion(socketClient)
175 | case .clientInitiatedCancelAcknowledged:
176 | verbose(message: "server acknowledged a cancel request")
177 | dispatchGroup.leave()
178 | if let command = currentlyExecutingCommand as? RubyCommand {
179 | executeNext[command.id] = true
180 | }
181 | completion(socketClient)
182 | case .alreadyClosedSockets, .connectionFailure, .malformedRequest, .malformedResponse, .serverError:
183 | log(message: "error encountered while executing command:\n\(serverResponse)")
184 | dispatchGroup.leave()
185 | if let command = currentlyExecutingCommand as? RubyCommand {
186 | executeNext[command.id] = true
187 | }
188 | completion(socketClient)
189 | case let .commandTimeout(timeout):
190 | log(message: "Runner timed out after \(timeout) second(s)")
191 | }
192 | }
193 |
194 | func connectionsOpened() {
195 | DispatchQueue.main.async {
196 | verbose(message: "connected!")
197 | }
198 | }
199 |
200 | func connectionsClosed() {
201 | DispatchQueue.main.async {
202 | if let thread = self.thread {
203 | thread.cancel()
204 | }
205 | self.thread = nil
206 | self.socketClient.closeSession()
207 | self.socketClient = nil
208 | verbose(message: "connection closed!")
209 | if self.shouldLeaveDispatchGroupDuringDisconnect {
210 | self.dispatchGroup.leave()
211 | }
212 | exit(0)
213 | }
214 | }
215 | }
216 |
217 | class Logger {
218 | enum LogMode {
219 | init(logMode: String) {
220 | switch logMode {
221 | case "normal", "default":
222 | self = .normal
223 | case "verbose":
224 | self = .verbose
225 | default:
226 | logger.log(message: "unrecognized log mode: \(logMode), defaulting to 'normal'")
227 | self = .normal
228 | }
229 | }
230 |
231 | case normal
232 | case verbose
233 | }
234 |
235 | public static var logMode: LogMode = .normal
236 |
237 | func log(message: String) {
238 | let timestamp = NSDate().timeIntervalSince1970
239 | print("[\(timestamp)]: \(message)")
240 | }
241 |
242 | func verbose(message: String) {
243 | if Logger.logMode == .verbose {
244 | let timestamp = NSDate().timeIntervalSince1970
245 | print("[\(timestamp)]: \(message)")
246 | }
247 | }
248 | }
249 |
250 | func log(message: String) {
251 | logger.log(message: message)
252 | }
253 |
254 | func verbose(message: String) {
255 | logger.verbose(message: message)
256 | }
257 |
258 | private extension DispatchTimeInterval {
259 | var timeInterval: TimeInterval {
260 | var result: TimeInterval = 0
261 | switch self {
262 | case let .seconds(value):
263 | result = TimeInterval(value)
264 | case let .milliseconds(value):
265 | result = TimeInterval(value) * 0.001
266 | case let .microseconds(value):
267 | result = TimeInterval(value) * 0.000_001
268 | case let .nanoseconds(value):
269 | result = TimeInterval(value) * 0.000_000_001
270 | case .never:
271 | fatalError()
272 | }
273 | return result
274 | }
275 | }
276 |
277 | // Please don't remove the lines below
278 | // They are used to detect outdated files
279 | // FastlaneRunnerAPIVersion [0.9.2]
280 |
--------------------------------------------------------------------------------
/fastlane/swift/DeliverfileProtocol.swift:
--------------------------------------------------------------------------------
1 | protocol DeliverfileProtocol: class {
2 | /// Your Apple ID Username
3 | var username: String { get }
4 |
5 | /// The bundle identifier of your app
6 | var appIdentifier: String? { get }
7 |
8 | /// The version that should be edited or created
9 | var appVersion: String? { get }
10 |
11 | /// Path to your ipa file
12 | var ipa: String? { get }
13 |
14 | /// Path to your pkg file
15 | var pkg: String? { get }
16 |
17 | /// If set the given build number (already uploaded to iTC) will be used instead of the current built one
18 | var buildNumber: String? { get }
19 |
20 | /// The platform to use (optional)
21 | var platform: String { get }
22 |
23 | /// Modify live metadata, this option disables ipa upload and screenshot upload
24 | var editLive: Bool { get }
25 |
26 | /// Force usage of live version rather than edit version
27 | var useLiveVersion: Bool { get }
28 |
29 | /// Path to the folder containing the metadata files
30 | var metadataPath: String? { get }
31 |
32 | /// Path to the folder containing the screenshots
33 | var screenshotsPath: String? { get }
34 |
35 | /// Skip uploading an ipa or pkg to App Store Connect
36 | var skipBinaryUpload: Bool { get }
37 |
38 | /// Don't upload the screenshots
39 | var skipScreenshots: Bool { get }
40 |
41 | /// Don't upload the metadata (e.g. title, description). This will still upload screenshots
42 | var skipMetadata: Bool { get }
43 |
44 | /// Don't update app version for submission
45 | var skipAppVersionUpdate: Bool { get }
46 |
47 | /// Skip the HTML report file verification
48 | var force: Bool { get }
49 |
50 | /// Clear all previously uploaded screenshots before uploading the new ones
51 | var overwriteScreenshots: Bool { get }
52 |
53 | /// Submit the new version for Review after uploading everything
54 | var submitForReview: Bool { get }
55 |
56 | /// Rejects the previously submitted build if it's in a state where it's possible
57 | var rejectIfPossible: Bool { get }
58 |
59 | /// Should the app be automatically released once it's approved? (Can not be used together with `auto_release_date`)
60 | var automaticRelease: Bool { get }
61 |
62 | /// Date in milliseconds for automatically releasing on pending approval (Can not be used together with `automatic_release`)
63 | var autoReleaseDate: Int? { get }
64 |
65 | /// Enable the phased release feature of iTC
66 | var phasedRelease: Bool { get }
67 |
68 | /// Reset the summary rating when you release a new version of the application
69 | var resetRatings: Bool { get }
70 |
71 | /// The price tier of this application
72 | var priceTier: String? { get }
73 |
74 | /// Path to the app rating's config
75 | var appRatingConfigPath: String? { get }
76 |
77 | /// Extra information for the submission (e.g. compliance specifications, IDFA settings)
78 | var submissionInformation: [String: Any]? { get }
79 |
80 | /// The ID of your App Store Connect team if you're in multiple teams
81 | var teamId: String? { get }
82 |
83 | /// The name of your App Store Connect team if you're in multiple teams
84 | var teamName: String? { get }
85 |
86 | /// The short ID of your Developer Portal team, if you're in multiple teams. Different from your iTC team ID!
87 | var devPortalTeamId: String? { get }
88 |
89 | /// The name of your Developer Portal team if you're in multiple teams
90 | var devPortalTeamName: String? { get }
91 |
92 | /// The provider short name to be used with the iTMSTransporter to identify your team. This value will override the automatically detected provider short name. To get provider short name run `pathToXcode.app/Contents/Applications/Application\ Loader.app/Contents/itms/bin/iTMSTransporter -m provider -u 'USERNAME' -p 'PASSWORD' -account_type itunes_connect -v off`. The short names of providers should be listed in the second column
93 | var itcProvider: String? { get }
94 |
95 | /// Run precheck before submitting to app review
96 | var runPrecheckBeforeSubmit: Bool { get }
97 |
98 | /// The default precheck rule level unless otherwise configured
99 | var precheckDefaultRuleLevel: String { get }
100 |
101 | /// **DEPRECATED!** Removed after the migration to the new App Store Connect API in June 2020 - An array of localized metadata items to upload individually by language so that errors can be identified. E.g. ['name', 'keywords', 'description']. Note: slow
102 | var individualMetadataItems: [String]? { get }
103 |
104 | /// **DEPRECATED!** Removed after the migration to the new App Store Connect API in June 2020 - Metadata: The path to the app icon
105 | var appIcon: String? { get }
106 |
107 | /// **DEPRECATED!** Removed after the migration to the new App Store Connect API in June 2020 - Metadata: The path to the Apple Watch app icon
108 | var appleWatchAppIcon: String? { get }
109 |
110 | /// Metadata: The copyright notice
111 | var copyright: String? { get }
112 |
113 | /// Metadata: The english name of the primary category (e.g. `Business`, `Books`)
114 | var primaryCategory: String? { get }
115 |
116 | /// Metadata: The english name of the secondary category (e.g. `Business`, `Books`)
117 | var secondaryCategory: String? { get }
118 |
119 | /// Metadata: The english name of the primary first sub category (e.g. `Educational`, `Puzzle`)
120 | var primaryFirstSubCategory: String? { get }
121 |
122 | /// Metadata: The english name of the primary second sub category (e.g. `Educational`, `Puzzle`)
123 | var primarySecondSubCategory: String? { get }
124 |
125 | /// Metadata: The english name of the secondary first sub category (e.g. `Educational`, `Puzzle`)
126 | var secondaryFirstSubCategory: String? { get }
127 |
128 | /// Metadata: The english name of the secondary second sub category (e.g. `Educational`, `Puzzle`)
129 | var secondarySecondSubCategory: String? { get }
130 |
131 | /// Metadata: A hash containing the trade representative contact information
132 | var tradeRepresentativeContactInformation: [String: Any]? { get }
133 |
134 | /// Metadata: A hash containing the review information
135 | var appReviewInformation: [String: Any]? { get }
136 |
137 | /// Metadata: Path to the app review attachment file
138 | var appReviewAttachmentFile: String? { get }
139 |
140 | /// Metadata: The localised app description
141 | var description: String? { get }
142 |
143 | /// Metadata: The localised app name
144 | var name: String? { get }
145 |
146 | /// Metadata: The localised app subtitle
147 | var subtitle: [String: Any]? { get }
148 |
149 | /// Metadata: An array of localised keywords
150 | var keywords: [String: Any]? { get }
151 |
152 | /// Metadata: An array of localised promotional texts
153 | var promotionalText: [String: Any]? { get }
154 |
155 | /// Metadata: Localised release notes for this version
156 | var releaseNotes: String? { get }
157 |
158 | /// Metadata: Localised privacy url
159 | var privacyUrl: String? { get }
160 |
161 | /// Metadata: Localised Apple TV privacy policy text
162 | var appleTvPrivacyPolicy: String? { get }
163 |
164 | /// Metadata: Localised support url
165 | var supportUrl: String? { get }
166 |
167 | /// Metadata: Localised marketing url
168 | var marketingUrl: String? { get }
169 |
170 | /// Metadata: List of languages to activate
171 | var languages: [String]? { get }
172 |
173 | /// Ignore errors when invalid languages are found in metadata and screenshot directories
174 | var ignoreLanguageDirectoryValidation: Bool { get }
175 |
176 | /// Should precheck check in-app purchases?
177 | var precheckIncludeInAppPurchases: Bool { get }
178 |
179 | /// The (spaceship) app ID of the app you want to use/modify
180 | var app: String { get }
181 | }
182 |
183 | extension DeliverfileProtocol {
184 | var username: String { return "" }
185 | var appIdentifier: String? { return nil }
186 | var appVersion: String? { return nil }
187 | var ipa: String? { return nil }
188 | var pkg: String? { return nil }
189 | var buildNumber: String? { return nil }
190 | var platform: String { return "ios" }
191 | var editLive: Bool { return false }
192 | var useLiveVersion: Bool { return false }
193 | var metadataPath: String? { return nil }
194 | var screenshotsPath: String? { return nil }
195 | var skipBinaryUpload: Bool { return false }
196 | var skipScreenshots: Bool { return false }
197 | var skipMetadata: Bool { return false }
198 | var skipAppVersionUpdate: Bool { return false }
199 | var force: Bool { return false }
200 | var overwriteScreenshots: Bool { return false }
201 | var submitForReview: Bool { return false }
202 | var rejectIfPossible: Bool { return false }
203 | var automaticRelease: Bool { return false }
204 | var autoReleaseDate: Int? { return nil }
205 | var phasedRelease: Bool { return false }
206 | var resetRatings: Bool { return false }
207 | var priceTier: String? { return nil }
208 | var appRatingConfigPath: String? { return nil }
209 | var submissionInformation: [String: Any]? { return nil }
210 | var teamId: String? { return nil }
211 | var teamName: String? { return nil }
212 | var devPortalTeamId: String? { return nil }
213 | var devPortalTeamName: String? { return nil }
214 | var itcProvider: String? { return nil }
215 | var runPrecheckBeforeSubmit: Bool { return true }
216 | var precheckDefaultRuleLevel: String { return "warn" }
217 | var individualMetadataItems: [String]? { return nil }
218 | var appIcon: String? { return nil }
219 | var appleWatchAppIcon: String? { return nil }
220 | var copyright: String? { return nil }
221 | var primaryCategory: String? { return nil }
222 | var secondaryCategory: String? { return nil }
223 | var primaryFirstSubCategory: String? { return nil }
224 | var primarySecondSubCategory: String? { return nil }
225 | var secondaryFirstSubCategory: String? { return nil }
226 | var secondarySecondSubCategory: String? { return nil }
227 | var tradeRepresentativeContactInformation: [String: Any]? { return nil }
228 | var appReviewInformation: [String: Any]? { return nil }
229 | var appReviewAttachmentFile: String? { return nil }
230 | var description: String? { return nil }
231 | var name: String? { return nil }
232 | var subtitle: [String: Any]? { return nil }
233 | var keywords: [String: Any]? { return nil }
234 | var promotionalText: [String: Any]? { return nil }
235 | var releaseNotes: String? { return nil }
236 | var privacyUrl: String? { return nil }
237 | var appleTvPrivacyPolicy: String? { return nil }
238 | var supportUrl: String? { return nil }
239 | var marketingUrl: String? { return nil }
240 | var languages: [String]? { return nil }
241 | var ignoreLanguageDirectoryValidation: Bool { return false }
242 | var precheckIncludeInAppPurchases: Bool { return true }
243 | var app: String { return "" }
244 | }
245 |
246 | // Please don't remove the lines below
247 | // They are used to detect outdated files
248 | // FastlaneRunnerAPIVersion [0.9.25]
249 |
--------------------------------------------------------------------------------
/fastlane/swift/ScanfileProtocol.swift:
--------------------------------------------------------------------------------
1 | protocol ScanfileProtocol: class {
2 | /// Path to the workspace file
3 | var workspace: String? { get }
4 |
5 | /// Path to the project file
6 | var project: String? { get }
7 |
8 | /// The project's scheme. Make sure it's marked as `Shared`
9 | var scheme: String? { get }
10 |
11 | /// The name of the simulator type you want to run tests on (e.g. 'iPhone 6')
12 | var device: String? { get }
13 |
14 | /// Array of devices to run the tests on (e.g. ['iPhone 6', 'iPad Air'])
15 | var devices: [String]? { get }
16 |
17 | /// Should skip auto detecting of devices if none were specified
18 | var skipDetectDevices: Bool { get }
19 |
20 | /// Enabling this option will automatically killall Simulator processes before the run
21 | var forceQuitSimulator: Bool { get }
22 |
23 | /// Enabling this option will automatically erase the simulator before running the application
24 | var resetSimulator: Bool { get }
25 |
26 | /// Enabling this option will disable the simulator from showing the 'Slide to type' prompt
27 | var disableSlideToType: Bool { get }
28 |
29 | /// Enabling this option will launch the first simulator prior to calling any xcodebuild command
30 | var prelaunchSimulator: Bool? { get }
31 |
32 | /// Enabling this option will automatically uninstall the application before running it
33 | var reinstallApp: Bool { get }
34 |
35 | /// The bundle identifier of the app to uninstall (only needed when enabling reinstall_app)
36 | var appIdentifier: String? { get }
37 |
38 | /// Array of strings matching Test Bundle/Test Suite/Test Cases to run
39 | var onlyTesting: String? { get }
40 |
41 | /// Array of strings matching Test Bundle/Test Suite/Test Cases to skip
42 | var skipTesting: String? { get }
43 |
44 | /// The testplan associated with the scheme that should be used for testing
45 | var testplan: String? { get }
46 |
47 | /// Array of strings matching test plan configurations to run
48 | var onlyTestConfigurations: String? { get }
49 |
50 | /// Array of strings matching test plan configurations to skip
51 | var skipTestConfigurations: String? { get }
52 |
53 | /// Run tests using the provided `.xctestrun` file
54 | var xctestrun: String? { get }
55 |
56 | /// The toolchain that should be used for building the application (e.g. `com.apple.dt.toolchain.Swift_2_3, org.swift.30p620160816a`)
57 | var toolchain: String? { get }
58 |
59 | /// Should the project be cleaned before building it?
60 | var clean: Bool { get }
61 |
62 | /// Should code coverage be generated? (Xcode 7 and up)
63 | var codeCoverage: Bool? { get }
64 |
65 | /// Should the address sanitizer be turned on?
66 | var addressSanitizer: Bool? { get }
67 |
68 | /// Should the thread sanitizer be turned on?
69 | var threadSanitizer: Bool? { get }
70 |
71 | /// Should the HTML report be opened when tests are completed?
72 | var openReport: Bool { get }
73 |
74 | /// Disable xcpretty formatting of build, similar to `output_style='raw'` but this will also skip the test results table
75 | var disableXcpretty: Bool? { get }
76 |
77 | /// The directory in which all reports will be stored
78 | var outputDirectory: String { get }
79 |
80 | /// Define how the output should look like. Valid values are: standard, basic, rspec, or raw (disables xcpretty during xcodebuild)
81 | var outputStyle: String? { get }
82 |
83 | /// Comma separated list of the output types (e.g. html, junit, json-compilation-database)
84 | var outputTypes: String { get }
85 |
86 | /// Comma separated list of the output files, corresponding to the types provided by :output_types (order should match). If specifying an output type of json-compilation-database with :use_clang_report_name enabled, that option will take precedence
87 | var outputFiles: String? { get }
88 |
89 | /// The directory where to store the raw log
90 | var buildlogPath: String { get }
91 |
92 | /// If the logs generated by the app (e.g. using NSLog, perror, etc.) in the Simulator should be written to the output_directory
93 | var includeSimulatorLogs: Bool { get }
94 |
95 | /// Suppress the output of xcodebuild to stdout. Output is still saved in buildlog_path
96 | var suppressXcodeOutput: Bool? { get }
97 |
98 | /// A custom xcpretty formatter to use
99 | var formatter: String? { get }
100 |
101 | /// Pass in xcpretty additional command line arguments (e.g. '--test --no-color' or '--tap --no-utf')
102 | var xcprettyArgs: String? { get }
103 |
104 | /// The directory where build products and other derived data will go
105 | var derivedDataPath: String? { get }
106 |
107 | /// Should zip the derived data build products and place in output path?
108 | var shouldZipBuildProducts: Bool { get }
109 |
110 | /// Should an Xcode result bundle be generated in the output directory
111 | var resultBundle: Bool { get }
112 |
113 | /// Generate the json compilation database with clang naming convention (compile_commands.json)
114 | var useClangReportName: Bool { get }
115 |
116 | /// Specify the exact number of test runners that will be spawned during parallel testing. Equivalent to -parallel-testing-worker-count
117 | var concurrentWorkers: Int? { get }
118 |
119 | /// Constrain the number of simulator devices on which to test concurrently. Equivalent to -maximum-concurrent-test-simulator-destinations
120 | var maxConcurrentSimulators: Int? { get }
121 |
122 | /// Do not run test bundles in parallel on the specified destinations. Testing will occur on each destination serially. Equivalent to -disable-concurrent-testing
123 | var disableConcurrentTesting: Bool { get }
124 |
125 | /// Should debug build be skipped before test build?
126 | var skipBuild: Bool { get }
127 |
128 | /// Test without building, requires a derived data path
129 | var testWithoutBuilding: Bool? { get }
130 |
131 | /// Build for testing only, does not run tests
132 | var buildForTesting: Bool? { get }
133 |
134 | /// The SDK that should be used for building the application
135 | var sdk: String? { get }
136 |
137 | /// The configuration to use when building the app. Defaults to 'Release'
138 | var configuration: String? { get }
139 |
140 | /// Pass additional arguments to xcodebuild. Be sure to quote the setting names and values e.g. OTHER_LDFLAGS="-ObjC -lstdc++"
141 | var xcargs: String? { get }
142 |
143 | /// Use an extra XCCONFIG file to build your app
144 | var xcconfig: String? { get }
145 |
146 | /// App name to use in slack message and logfile name
147 | var appName: String? { get }
148 |
149 | /// Target version of the app being build or tested. Used to filter out simulator version
150 | var deploymentTargetVersion: String? { get }
151 |
152 | /// Create an Incoming WebHook for your Slack group to post results there
153 | var slackUrl: String? { get }
154 |
155 | /// #channel or @username
156 | var slackChannel: String? { get }
157 |
158 | /// The message included with each message posted to slack
159 | var slackMessage: String? { get }
160 |
161 | /// Use webhook's default username and icon settings? (true/false)
162 | var slackUseWebhookConfiguredUsernameAndIcon: Bool { get }
163 |
164 | /// Overrides the webhook's username property if slack_use_webhook_configured_username_and_icon is false
165 | var slackUsername: String { get }
166 |
167 | /// Overrides the webhook's image property if slack_use_webhook_configured_username_and_icon is false
168 | var slackIconUrl: String { get }
169 |
170 | /// Don't publish to slack, even when an URL is given
171 | var skipSlack: Bool { get }
172 |
173 | /// Only post on Slack if the tests fail
174 | var slackOnlyOnFailure: Bool { get }
175 |
176 | /// Use only if you're a pro, use the other options instead
177 | var destination: String? { get }
178 |
179 | /// **DEPRECATED!** Use `--output_files` instead - Sets custom full report file name when generating a single report
180 | var customReportFileName: String? { get }
181 |
182 | /// Allows for override of the default `xcodebuild` command
183 | var xcodebuildCommand: String { get }
184 |
185 | /// Sets a custom path for Swift Package Manager dependencies
186 | var clonedSourcePackagesPath: String? { get }
187 |
188 | /// Should this step stop the build if the tests fail? Set this to false if you're using trainer
189 | var failBuild: Bool { get }
190 | }
191 |
192 | extension ScanfileProtocol {
193 | var workspace: String? { return nil }
194 | var project: String? { return nil }
195 | var scheme: String? { return nil }
196 | var device: String? { return nil }
197 | var devices: [String]? { return nil }
198 | var skipDetectDevices: Bool { return false }
199 | var forceQuitSimulator: Bool { return false }
200 | var resetSimulator: Bool { return false }
201 | var disableSlideToType: Bool { return true }
202 | var prelaunchSimulator: Bool? { return nil }
203 | var reinstallApp: Bool { return false }
204 | var appIdentifier: String? { return nil }
205 | var onlyTesting: String? { return nil }
206 | var skipTesting: String? { return nil }
207 | var testplan: String? { return nil }
208 | var onlyTestConfigurations: String? { return nil }
209 | var skipTestConfigurations: String? { return nil }
210 | var xctestrun: String? { return nil }
211 | var toolchain: String? { return nil }
212 | var clean: Bool { return false }
213 | var codeCoverage: Bool? { return nil }
214 | var addressSanitizer: Bool? { return nil }
215 | var threadSanitizer: Bool? { return nil }
216 | var openReport: Bool { return false }
217 | var disableXcpretty: Bool? { return nil }
218 | var outputDirectory: String { return "./test_output" }
219 | var outputStyle: String? { return nil }
220 | var outputTypes: String { return "html,junit" }
221 | var outputFiles: String? { return nil }
222 | var buildlogPath: String { return "~/Library/Logs/scan" }
223 | var includeSimulatorLogs: Bool { return false }
224 | var suppressXcodeOutput: Bool? { return nil }
225 | var formatter: String? { return nil }
226 | var xcprettyArgs: String? { return nil }
227 | var derivedDataPath: String? { return nil }
228 | var shouldZipBuildProducts: Bool { return false }
229 | var resultBundle: Bool { return false }
230 | var useClangReportName: Bool { return false }
231 | var concurrentWorkers: Int? { return nil }
232 | var maxConcurrentSimulators: Int? { return nil }
233 | var disableConcurrentTesting: Bool { return false }
234 | var skipBuild: Bool { return false }
235 | var testWithoutBuilding: Bool? { return nil }
236 | var buildForTesting: Bool? { return nil }
237 | var sdk: String? { return nil }
238 | var configuration: String? { return nil }
239 | var xcargs: String? { return nil }
240 | var xcconfig: String? { return nil }
241 | var appName: String? { return nil }
242 | var deploymentTargetVersion: String? { return nil }
243 | var slackUrl: String? { return nil }
244 | var slackChannel: String? { return nil }
245 | var slackMessage: String? { return nil }
246 | var slackUseWebhookConfiguredUsernameAndIcon: Bool { return false }
247 | var slackUsername: String { return "fastlane" }
248 | var slackIconUrl: String { return "https://fastlane.tools/assets/img/fastlane_icon.png" }
249 | var skipSlack: Bool { return false }
250 | var slackOnlyOnFailure: Bool { return false }
251 | var destination: String? { return nil }
252 | var customReportFileName: String? { return nil }
253 | var xcodebuildCommand: String { return "env NSUnbufferedIO=YES xcodebuild" }
254 | var clonedSourcePackagesPath: String? { return nil }
255 | var failBuild: Bool { return true }
256 | }
257 |
258 | // Please don't remove the lines below
259 | // They are used to detect outdated files
260 | // FastlaneRunnerAPIVersion [0.9.33]
261 |
--------------------------------------------------------------------------------
/fastlane/swift/SocketClient.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SocketClient.swift
3 | // FastlaneSwiftRunner
4 | //
5 | // Created by Joshua Liebowitz on 7/30/17.
6 | //
7 |
8 | //
9 | // ** NOTE **
10 | // This file is provided by fastlane and WILL be overwritten in future updates
11 | // If you want to add extra functionality to this project, create a new file in a
12 | // new group so that it won't be marked for upgrade
13 | //
14 |
15 | import Dispatch
16 | import Foundation
17 |
18 | public enum SocketClientResponse: Error {
19 | case alreadyClosedSockets
20 | case malformedRequest
21 | case malformedResponse
22 | case serverError
23 | case clientInitiatedCancelAcknowledged
24 | case commandTimeout(seconds: Int)
25 | case connectionFailure
26 | case success(returnedObject: String?, closureArgumentValue: String?)
27 | }
28 |
29 | class SocketClient: NSObject {
30 | enum SocketStatus {
31 | case ready
32 | case closed
33 | }
34 |
35 | static let connectTimeoutSeconds = 2
36 | static let defaultCommandTimeoutSeconds = 10_800 // 3 hours
37 | static let doneToken = "done" // TODO: remove these
38 | static let cancelToken = "cancelFastlaneRun"
39 |
40 | fileprivate var inputStream: InputStream!
41 | fileprivate var outputStream: OutputStream!
42 | fileprivate var cleaningUpAfterDone = false
43 | fileprivate let dispatchGroup: DispatchGroup = DispatchGroup()
44 | fileprivate let readSemaphore = DispatchSemaphore(value: 1)
45 | fileprivate let writeSemaphore = DispatchSemaphore(value: 1)
46 | fileprivate let commandTimeoutSeconds: Int
47 |
48 | private let writeQueue: DispatchQueue
49 | private let readQueue: DispatchQueue
50 | private let streamQueue: DispatchQueue
51 | private let host: String
52 | private let port: UInt32
53 |
54 | let maxReadLength = 65536 // max for ipc on 10.12 is kern.ipc.maxsockbuf: 8388608 ($sysctl kern.ipc.maxsockbuf)
55 |
56 | private(set) weak var socketDelegate: SocketClientDelegateProtocol?
57 |
58 | public private(set) var socketStatus: SocketStatus
59 |
60 | // localhost only, this prevents other computers from connecting
61 | init(host: String = "localhost", port: UInt32 = 2000, commandTimeoutSeconds: Int = defaultCommandTimeoutSeconds, socketDelegate: SocketClientDelegateProtocol) {
62 | self.host = host
63 | self.port = port
64 | self.commandTimeoutSeconds = commandTimeoutSeconds
65 | readQueue = DispatchQueue(label: "readQueue", qos: .background, attributes: .concurrent)
66 | writeQueue = DispatchQueue(label: "writeQueue", qos: .background, attributes: .concurrent)
67 | streamQueue = DispatchQueue.global(qos: .background)
68 | socketStatus = .closed
69 | self.socketDelegate = socketDelegate
70 | super.init()
71 | }
72 |
73 | func connectAndOpenStreams() {
74 | var readStream: Unmanaged?
75 | var writeStream: Unmanaged?
76 |
77 | streamQueue.sync {
78 | CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, self.host as CFString, self.port, &readStream, &writeStream)
79 |
80 | self.inputStream = readStream!.takeRetainedValue()
81 | self.outputStream = writeStream!.takeRetainedValue()
82 |
83 | self.inputStream.delegate = self
84 | self.outputStream.delegate = self
85 |
86 | self.inputStream.schedule(in: .main, forMode: .defaultRunLoopMode)
87 | self.outputStream.schedule(in: .main, forMode: .defaultRunLoopMode)
88 | }
89 |
90 | dispatchGroup.enter()
91 | readQueue.sync {
92 | self.inputStream.open()
93 | }
94 |
95 | dispatchGroup.enter()
96 | writeQueue.sync {
97 | self.outputStream.open()
98 | }
99 |
100 | let secondsToWait = DispatchTimeInterval.seconds(SocketClient.connectTimeoutSeconds)
101 | let connectTimeout = DispatchTime.now() + secondsToWait
102 |
103 | let timeoutResult = dispatchGroup.wait(timeout: connectTimeout)
104 | let failureMessage = "Couldn't connect to ruby process within: \(SocketClient.connectTimeoutSeconds) seconds"
105 |
106 | let success = testDispatchTimeoutResult(timeoutResult, failureMessage: failureMessage, timeToWait: secondsToWait)
107 |
108 | guard success else {
109 | socketDelegate?.commandExecuted(serverResponse: .connectionFailure) { _ in }
110 | return
111 | }
112 |
113 | socketStatus = .ready
114 | socketDelegate?.connectionsOpened()
115 | }
116 |
117 | public func send(rubyCommand: RubyCommandable) {
118 | verbose(message: "sending: \(rubyCommand.json)")
119 | send(string: rubyCommand.json)
120 | writeSemaphore.signal()
121 | }
122 |
123 | public func sendComplete() {
124 | closeSession(sendAbort: true)
125 | }
126 |
127 | private func testDispatchTimeoutResult(_ timeoutResult: DispatchTimeoutResult, failureMessage: String, timeToWait: DispatchTimeInterval) -> Bool {
128 | switch timeoutResult {
129 | case .success:
130 | return true
131 | case .timedOut:
132 | log(message: "Timeout: \(failureMessage)")
133 |
134 | if case let .seconds(seconds) = timeToWait {
135 | socketDelegate?.commandExecuted(serverResponse: .commandTimeout(seconds: seconds)) { _ in }
136 | }
137 | return false
138 | }
139 | }
140 |
141 | private func stopInputSession() {
142 | inputStream.close()
143 | }
144 |
145 | private func stopOutputSession() {
146 | outputStream.close()
147 | }
148 |
149 | private func sendThroughQueue(string: String) {
150 | let data = string.data(using: .utf8)!
151 | _ = data.withUnsafeBytes { self.outputStream.write($0, maxLength: data.count) }
152 | }
153 |
154 | private func privateSend(string: String) {
155 | writeQueue.sync {
156 | writeSemaphore.wait()
157 | self.sendThroughQueue(string: string)
158 | writeSemaphore.signal()
159 | let timeoutSeconds = self.cleaningUpAfterDone ? 1 : self.commandTimeoutSeconds
160 | let timeToWait = DispatchTimeInterval.seconds(timeoutSeconds)
161 | let commandTimeout = DispatchTime.now() + timeToWait
162 | let timeoutResult = writeSemaphore.wait(timeout: commandTimeout)
163 |
164 | _ = self.testDispatchTimeoutResult(timeoutResult, failureMessage: "Ruby process didn't return after: \(SocketClient.connectTimeoutSeconds) seconds", timeToWait: timeToWait)
165 | }
166 | }
167 |
168 | private func send(string: String) {
169 | guard !cleaningUpAfterDone else {
170 | // This will happen after we abort if there are commands waiting to be executed
171 | // Need to check state of SocketClient in command runner to make sure we can accept `send`
172 | socketDelegate?.commandExecuted(serverResponse: .alreadyClosedSockets) { _ in }
173 | return
174 | }
175 |
176 | if string == SocketClient.doneToken {
177 | cleaningUpAfterDone = true
178 | }
179 |
180 | privateSend(string: string)
181 | }
182 |
183 | func closeSession(sendAbort: Bool = true) {
184 | socketStatus = .closed
185 |
186 | stopInputSession()
187 |
188 | if sendAbort {
189 | send(rubyCommand: ControlCommand(commandType: .done))
190 | }
191 |
192 | stopOutputSession()
193 | socketDelegate?.connectionsClosed()
194 | }
195 |
196 | public func enter() {
197 | dispatchGroup.enter()
198 | }
199 |
200 | public func leave() {
201 | readSemaphore.signal()
202 | writeSemaphore.signal()
203 | }
204 | }
205 |
206 | extension SocketClient: StreamDelegate {
207 | func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
208 | guard !cleaningUpAfterDone else {
209 | // Still getting response from server eventhough we are done.
210 | // No big deal, we're closing the streams anyway.
211 | // That being said, we need to balance out the dispatchGroups
212 | dispatchGroup.leave()
213 | return
214 | }
215 |
216 | if aStream === inputStream {
217 | switch eventCode {
218 | case Stream.Event.openCompleted:
219 | dispatchGroup.leave()
220 |
221 | case Stream.Event.errorOccurred:
222 | verbose(message: "input stream error occurred")
223 | closeSession(sendAbort: true)
224 |
225 | case Stream.Event.hasBytesAvailable:
226 | read()
227 |
228 | case Stream.Event.endEncountered:
229 | // nothing special here
230 | break
231 |
232 | case Stream.Event.hasSpaceAvailable:
233 | // we don't care about this
234 | break
235 |
236 | default:
237 | verbose(message: "input stream caused unrecognized event: \(eventCode)")
238 | }
239 |
240 | } else if aStream === outputStream {
241 | switch eventCode {
242 | case Stream.Event.openCompleted:
243 | dispatchGroup.leave()
244 |
245 | case Stream.Event.errorOccurred:
246 | // probably safe to close all the things because Ruby already disconnected
247 | verbose(message: "output stream recevied error")
248 |
249 | case Stream.Event.endEncountered:
250 | // nothing special here
251 | break
252 |
253 | case Stream.Event.hasSpaceAvailable:
254 | // we don't care about this
255 | break
256 |
257 | default:
258 | verbose(message: "output stream caused unrecognized event: \(eventCode)")
259 | }
260 | }
261 | }
262 |
263 | func read() {
264 | readQueue.sync {
265 | self.readSemaphore.wait()
266 | var buffer = [UInt8](repeating: 0, count: maxReadLength)
267 | var output = ""
268 | while self.inputStream!.hasBytesAvailable {
269 | let bytesRead: Int = inputStream!.read(&buffer, maxLength: buffer.count)
270 | if bytesRead >= 0 {
271 | guard let read = String(bytes: buffer[..
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
43 |
49 |
50 |
51 |
57 |
63 |
64 |
65 |
71 |
77 |
78 |
79 |
85 |
91 |
92 |
93 |
99 |
105 |
106 |
107 |
113 |
119 |
120 |
121 |
127 |
133 |
134 |
135 |
141 |
147 |
148 |
149 |
155 |
161 |
162 |
163 |
169 |
175 |
176 |
177 |
183 |
189 |
190 |
191 |
197 |
203 |
204 |
205 |
211 |
217 |
218 |
219 |
225 |
231 |
232 |
233 |
239 |
245 |
246 |
247 |
253 |
259 |
260 |
261 |
267 |
273 |
274 |
275 |
281 |
287 |
288 |
289 |
295 |
301 |
302 |
303 |
309 |
315 |
316 |
317 |
323 |
329 |
330 |
331 |
337 |
343 |
344 |
345 |
351 |
357 |
358 |
359 |
365 |
371 |
372 |
373 |
379 |
385 |
386 |
387 |
388 |
389 |
394 |
395 |
401 |
402 |
403 |
404 |
406 |
412 |
413 |
414 |
416 |
422 |
423 |
424 |
426 |
432 |
433 |
434 |
436 |
442 |
443 |
444 |
446 |
452 |
453 |
454 |
456 |
462 |
463 |
464 |
466 |
472 |
473 |
474 |
476 |
482 |
483 |
484 |
486 |
492 |
493 |
494 |
496 |
502 |
503 |
504 |
506 |
512 |
513 |
514 |
515 |
516 |
526 |
528 |
534 |
535 |
536 |
537 |
543 |
544 |
550 |
551 |
552 |
553 |
555 |
556 |
559 |
560 |
561 |
--------------------------------------------------------------------------------
/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 0311E387230AC1B20060BB5C /* Plugins.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0311E386230AC1B20060BB5C /* Plugins.swift */; };
11 | 0311E38B230AC9490060BB5C /* Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0311E38A230AC9490060BB5C /* Actions.swift */; };
12 | B302067B1F5E3E9000DE6EBD /* SnapshotfileProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30206741F5E3E9000DE6EBD /* SnapshotfileProtocol.swift */; };
13 | B302067C1F5E3E9000DE6EBD /* GymfileProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30206751F5E3E9000DE6EBD /* GymfileProtocol.swift */; };
14 | B302067D1F5E3E9000DE6EBD /* MatchfileProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30206761F5E3E9000DE6EBD /* MatchfileProtocol.swift */; };
15 | B302067E1F5E3E9000DE6EBD /* PrecheckfileProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30206771F5E3E9000DE6EBD /* PrecheckfileProtocol.swift */; };
16 | B302067F1F5E3E9000DE6EBD /* ScanfileProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30206781F5E3E9000DE6EBD /* ScanfileProtocol.swift */; };
17 | B30206801F5E3E9000DE6EBD /* ScreengrabfileProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30206791F5E3E9000DE6EBD /* ScreengrabfileProtocol.swift */; };
18 | B30206811F5E3E9000DE6EBD /* DeliverfileProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B302067A1F5E3E9000DE6EBD /* DeliverfileProtocol.swift */; };
19 | B3BA65A61F5A269100B34850 /* Fastlane.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BA659D1F5A269100B34850 /* Fastlane.swift */; };
20 | B3BA65A71F5A269100B34850 /* LaneFileProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BA659E1F5A269100B34850 /* LaneFileProtocol.swift */; };
21 | B3BA65A81F5A269100B34850 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BA659F1F5A269100B34850 /* main.swift */; };
22 | B3BA65A91F5A269100B34850 /* RubyCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BA65A01F5A269100B34850 /* RubyCommand.swift */; };
23 | B3BA65AA1F5A269100B34850 /* Runner.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BA65A11F5A269100B34850 /* Runner.swift */; };
24 | B3BA65AB1F5A269100B34850 /* SocketClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BA65A21F5A269100B34850 /* SocketClient.swift */; };
25 | B3BA65AC1F5A269100B34850 /* SocketClientDelegateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BA65A31F5A269100B34850 /* SocketClientDelegateProtocol.swift */; };
26 | B3BA65AD1F5A269100B34850 /* SocketResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BA65A41F5A269100B34850 /* SocketResponse.swift */; };
27 | B3BA65AF1F5A2D5C00B34850 /* RunnerArgument.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BA65AE1F5A2D5C00B34850 /* RunnerArgument.swift */; };
28 | D55B28C31F6C588300DC42C5 /* Deliverfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55B28BC1F6C588300DC42C5 /* Deliverfile.swift */; };
29 | D55B28C41F6C588300DC42C5 /* Gymfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55B28BD1F6C588300DC42C5 /* Gymfile.swift */; };
30 | D55B28C51F6C588300DC42C5 /* Matchfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55B28BE1F6C588300DC42C5 /* Matchfile.swift */; };
31 | D55B28C61F6C588300DC42C5 /* Precheckfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55B28BF1F6C588300DC42C5 /* Precheckfile.swift */; };
32 | D55B28C71F6C588300DC42C5 /* Scanfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55B28C01F6C588300DC42C5 /* Scanfile.swift */; };
33 | D55B28C81F6C588300DC42C5 /* Screengrabfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55B28C11F6C588300DC42C5 /* Screengrabfile.swift */; };
34 | D55B28C91F6C588300DC42C5 /* Snapshotfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55B28C21F6C588300DC42C5 /* Snapshotfile.swift */; };
35 | D5A7C48F1F7C4DAF00A91DE6 /* Appfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A7C48D1F7C4DAF00A91DE6 /* Appfile.swift */; };
36 | D5A7C4901F7C4DAF00A91DE6 /* Fastfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A7C48E1F7C4DAF00A91DE6 /* Fastfile.swift */; };
37 | D5B8A5B31FFDC49E00536B24 /* ControlCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B8A5B21FFDC49D00536B24 /* ControlCommand.swift */; };
38 | D5BAFD121F7DAAFC0030B324 /* ArgumentProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5BAFD111F7DAAFC0030B324 /* ArgumentProcessor.swift */; };
39 | D5D1DE991FFEE8EA00502A00 /* RubyCommandable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5D1DE981FFEE8E900502A00 /* RubyCommandable.swift */; };
40 | /* End PBXBuildFile section */
41 |
42 | /* Begin PBXFileReference section */
43 | 0311E386230AC1B20060BB5C /* Plugins.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Plugins.swift; path = ../Plugins.swift; sourceTree = ""; };
44 | 0311E38A230AC9490060BB5C /* Actions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Actions.swift; path = ../Actions.swift; sourceTree = ""; };
45 | B30206741F5E3E9000DE6EBD /* SnapshotfileProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SnapshotfileProtocol.swift; path = ../SnapshotfileProtocol.swift; sourceTree = ""; };
46 | B30206751F5E3E9000DE6EBD /* GymfileProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GymfileProtocol.swift; path = ../GymfileProtocol.swift; sourceTree = ""; };
47 | B30206761F5E3E9000DE6EBD /* MatchfileProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MatchfileProtocol.swift; path = ../MatchfileProtocol.swift; sourceTree = ""; };
48 | B30206771F5E3E9000DE6EBD /* PrecheckfileProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PrecheckfileProtocol.swift; path = ../PrecheckfileProtocol.swift; sourceTree = ""; };
49 | B30206781F5E3E9000DE6EBD /* ScanfileProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ScanfileProtocol.swift; path = ../ScanfileProtocol.swift; sourceTree = ""; };
50 | B30206791F5E3E9000DE6EBD /* ScreengrabfileProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ScreengrabfileProtocol.swift; path = ../ScreengrabfileProtocol.swift; sourceTree = ""; };
51 | B302067A1F5E3E9000DE6EBD /* DeliverfileProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DeliverfileProtocol.swift; path = ../DeliverfileProtocol.swift; sourceTree = ""; };
52 | B3144C072005533400470AFE /* README.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = README.txt; sourceTree = ""; };
53 | B3144C08200553C800470AFE /* README.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = README.txt; sourceTree = ""; };
54 | B3144C09200553D400470AFE /* README.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = README.txt; sourceTree = ""; };
55 | B3144C0A200553DC00470AFE /* README.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = README.txt; sourceTree = ""; };
56 | B3BA659D1F5A269100B34850 /* Fastlane.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Fastlane.swift; path = ../Fastlane.swift; sourceTree = ""; };
57 | B3BA659E1F5A269100B34850 /* LaneFileProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LaneFileProtocol.swift; path = ../LaneFileProtocol.swift; sourceTree = ""; };
58 | B3BA659F1F5A269100B34850 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = main.swift; path = ../main.swift; sourceTree = ""; };
59 | B3BA65A01F5A269100B34850 /* RubyCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RubyCommand.swift; path = ../RubyCommand.swift; sourceTree = ""; };
60 | B3BA65A11F5A269100B34850 /* Runner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Runner.swift; path = ../Runner.swift; sourceTree = ""; };
61 | B3BA65A21F5A269100B34850 /* SocketClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketClient.swift; path = ../SocketClient.swift; sourceTree = ""; };
62 | B3BA65A31F5A269100B34850 /* SocketClientDelegateProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketClientDelegateProtocol.swift; path = ../SocketClientDelegateProtocol.swift; sourceTree = ""; };
63 | B3BA65A41F5A269100B34850 /* SocketResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketResponse.swift; path = ../SocketResponse.swift; sourceTree = ""; };
64 | B3BA65AE1F5A2D5C00B34850 /* RunnerArgument.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RunnerArgument.swift; path = ../RunnerArgument.swift; sourceTree = ""; };
65 | D556D6A91F6A08F5003108E3 /* FastlaneRunner */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = FastlaneRunner; sourceTree = BUILT_PRODUCTS_DIR; };
66 | D55B28BC1F6C588300DC42C5 /* Deliverfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Deliverfile.swift; path = ../Deliverfile.swift; sourceTree = ""; };
67 | D55B28BD1F6C588300DC42C5 /* Gymfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Gymfile.swift; path = ../Gymfile.swift; sourceTree = ""; };
68 | D55B28BE1F6C588300DC42C5 /* Matchfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Matchfile.swift; path = ../Matchfile.swift; sourceTree = ""; };
69 | D55B28BF1F6C588300DC42C5 /* Precheckfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Precheckfile.swift; path = ../Precheckfile.swift; sourceTree = ""; };
70 | D55B28C01F6C588300DC42C5 /* Scanfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Scanfile.swift; path = ../Scanfile.swift; sourceTree = ""; };
71 | D55B28C11F6C588300DC42C5 /* Screengrabfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Screengrabfile.swift; path = ../Screengrabfile.swift; sourceTree = ""; };
72 | D55B28C21F6C588300DC42C5 /* Snapshotfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Snapshotfile.swift; path = ../Snapshotfile.swift; sourceTree = ""; };
73 | D5A7C48D1F7C4DAF00A91DE6 /* Appfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Appfile.swift; path = ../../Appfile.swift; sourceTree = ""; };
74 | D5A7C48E1F7C4DAF00A91DE6 /* Fastfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Fastfile.swift; path = ../../Fastfile.swift; sourceTree = ""; };
75 | D5B8A5B21FFDC49D00536B24 /* ControlCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ControlCommand.swift; path = ../ControlCommand.swift; sourceTree = ""; };
76 | D5BAFD111F7DAAFC0030B324 /* ArgumentProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ArgumentProcessor.swift; path = ../ArgumentProcessor.swift; sourceTree = ""; };
77 | D5D1DE981FFEE8E900502A00 /* RubyCommandable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RubyCommandable.swift; path = ../RubyCommandable.swift; sourceTree = ""; };
78 | /* End PBXFileReference section */
79 |
80 | /* Begin PBXFrameworksBuildPhase section */
81 | B33BAF541F51F8D90001A751 /* Frameworks */ = {
82 | isa = PBXFrameworksBuildPhase;
83 | buildActionMask = 2147483647;
84 | files = (
85 | );
86 | runOnlyForDeploymentPostprocessing = 0;
87 | };
88 | /* End PBXFrameworksBuildPhase section */
89 |
90 | /* Begin PBXGroup section */
91 | B33BAF4E1F51F8D90001A751 = {
92 | isa = PBXGroup;
93 | children = (
94 | B3BA65B01F5A324A00B34850 /* Fastlane Runner */,
95 | D556D6A91F6A08F5003108E3 /* FastlaneRunner */,
96 | );
97 | sourceTree = "";
98 | };
99 | B3BA65B01F5A324A00B34850 /* Fastlane Runner */ = {
100 | isa = PBXGroup;
101 | children = (
102 | B3BA65B21F5A327B00B34850 /* Autogenerated API */,
103 | B3BA65B31F5A329800B34850 /* Fastfile Components */,
104 | B3BA65B11F5A325E00B34850 /* Networking */,
105 | D512BA011F7C7F40000D2137 /* Runner Code */,
106 | D5A7C48D1F7C4DAF00A91DE6 /* Appfile.swift */,
107 | D55B28BC1F6C588300DC42C5 /* Deliverfile.swift */,
108 | D5A7C48E1F7C4DAF00A91DE6 /* Fastfile.swift */,
109 | D55B28BD1F6C588300DC42C5 /* Gymfile.swift */,
110 | D55B28BE1F6C588300DC42C5 /* Matchfile.swift */,
111 | D55B28BF1F6C588300DC42C5 /* Precheckfile.swift */,
112 | D55B28C01F6C588300DC42C5 /* Scanfile.swift */,
113 | D55B28C11F6C588300DC42C5 /* Screengrabfile.swift */,
114 | D55B28C21F6C588300DC42C5 /* Snapshotfile.swift */,
115 | );
116 | name = "Fastlane Runner";
117 | sourceTree = "";
118 | };
119 | B3BA65B11F5A325E00B34850 /* Networking */ = {
120 | isa = PBXGroup;
121 | children = (
122 | B3144C072005533400470AFE /* README.txt */,
123 | D5B8A5B21FFDC49D00536B24 /* ControlCommand.swift */,
124 | B3BA65A01F5A269100B34850 /* RubyCommand.swift */,
125 | D5D1DE981FFEE8E900502A00 /* RubyCommandable.swift */,
126 | B3BA65A11F5A269100B34850 /* Runner.swift */,
127 | B3BA65A21F5A269100B34850 /* SocketClient.swift */,
128 | B3BA65A31F5A269100B34850 /* SocketClientDelegateProtocol.swift */,
129 | B3BA65A41F5A269100B34850 /* SocketResponse.swift */,
130 | );
131 | name = Networking;
132 | sourceTree = "";
133 | };
134 | B3BA65B21F5A327B00B34850 /* Autogenerated API */ = {
135 | isa = PBXGroup;
136 | children = (
137 | B3144C09200553D400470AFE /* README.txt */,
138 | 0311E38A230AC9490060BB5C /* Actions.swift */,
139 | B3BA659D1F5A269100B34850 /* Fastlane.swift */,
140 | B302067A1F5E3E9000DE6EBD /* DeliverfileProtocol.swift */,
141 | B30206751F5E3E9000DE6EBD /* GymfileProtocol.swift */,
142 | B30206761F5E3E9000DE6EBD /* MatchfileProtocol.swift */,
143 | 0311E386230AC1B20060BB5C /* Plugins.swift */,
144 | B30206771F5E3E9000DE6EBD /* PrecheckfileProtocol.swift */,
145 | B30206781F5E3E9000DE6EBD /* ScanfileProtocol.swift */,
146 | B30206791F5E3E9000DE6EBD /* ScreengrabfileProtocol.swift */,
147 | B30206741F5E3E9000DE6EBD /* SnapshotfileProtocol.swift */,
148 | );
149 | name = "Autogenerated API";
150 | sourceTree = "";
151 | };
152 | B3BA65B31F5A329800B34850 /* Fastfile Components */ = {
153 | isa = PBXGroup;
154 | children = (
155 | B3144C08200553C800470AFE /* README.txt */,
156 | B3BA659E1F5A269100B34850 /* LaneFileProtocol.swift */,
157 | );
158 | name = "Fastfile Components";
159 | sourceTree = "";
160 | };
161 | D512BA011F7C7F40000D2137 /* Runner Code */ = {
162 | isa = PBXGroup;
163 | children = (
164 | B3144C0A200553DC00470AFE /* README.txt */,
165 | D5BAFD111F7DAAFC0030B324 /* ArgumentProcessor.swift */,
166 | B3BA659F1F5A269100B34850 /* main.swift */,
167 | B3BA65AE1F5A2D5C00B34850 /* RunnerArgument.swift */,
168 | );
169 | name = "Runner Code";
170 | sourceTree = "";
171 | };
172 | /* End PBXGroup section */
173 |
174 | /* Begin PBXNativeTarget section */
175 | B33BAF561F51F8D90001A751 /* FastlaneRunner */ = {
176 | isa = PBXNativeTarget;
177 | buildConfigurationList = B33BAF5E1F51F8D90001A751 /* Build configuration list for PBXNativeTarget "FastlaneRunner" */;
178 | buildPhases = (
179 | B33BAF531F51F8D90001A751 /* Sources */,
180 | B33BAF541F51F8D90001A751 /* Frameworks */,
181 | D529C72B1F68BB1C0036536D /* ShellScript */,
182 | );
183 | buildRules = (
184 | );
185 | dependencies = (
186 | );
187 | name = FastlaneRunner;
188 | productName = FastlaneSwiftRunner;
189 | productReference = D556D6A91F6A08F5003108E3 /* FastlaneRunner */;
190 | productType = "com.apple.product-type.tool";
191 | };
192 | /* End PBXNativeTarget section */
193 |
194 | /* Begin PBXProject section */
195 | B33BAF4F1F51F8D90001A751 /* Project object */ = {
196 | isa = PBXProject;
197 | attributes = {
198 | LastSwiftUpdateCheck = 0830;
199 | LastUpgradeCheck = 0900;
200 | ORGANIZATIONNAME = "Joshua Liebowitz";
201 | TargetAttributes = {
202 | B33BAF561F51F8D90001A751 = {
203 | CreatedOnToolsVersion = 8.3.3;
204 | LastSwiftMigration = 0900;
205 | ProvisioningStyle = Automatic;
206 | };
207 | };
208 | };
209 | buildConfigurationList = B33BAF521F51F8D90001A751 /* Build configuration list for PBXProject "FastlaneSwiftRunner" */;
210 | compatibilityVersion = "Xcode 3.2";
211 | developmentRegion = English;
212 | hasScannedForEncodings = 0;
213 | knownRegions = (
214 | English,
215 | en,
216 | );
217 | mainGroup = B33BAF4E1F51F8D90001A751;
218 | productRefGroup = B33BAF4E1F51F8D90001A751;
219 | projectDirPath = "";
220 | projectRoot = "";
221 | targets = (
222 | B33BAF561F51F8D90001A751 /* FastlaneRunner */,
223 | );
224 | };
225 | /* End PBXProject section */
226 |
227 | /* Begin PBXShellScriptBuildPhase section */
228 | D529C72B1F68BB1C0036536D /* ShellScript */ = {
229 | isa = PBXShellScriptBuildPhase;
230 | buildActionMask = 2147483647;
231 | files = (
232 | );
233 | inputPaths = (
234 | );
235 | outputPaths = (
236 | );
237 | runOnlyForDeploymentPostprocessing = 0;
238 | shellPath = /bin/sh;
239 | shellScript = "cd \"${SRCROOT}\"\ncd ../..\ncp \"${TARGET_BUILD_DIR}/${EXECUTABLE_PATH}\" .";
240 | };
241 | /* End PBXShellScriptBuildPhase section */
242 |
243 | /* Begin PBXSourcesBuildPhase section */
244 | B33BAF531F51F8D90001A751 /* Sources */ = {
245 | isa = PBXSourcesBuildPhase;
246 | buildActionMask = 2147483647;
247 | files = (
248 | B3BA65A91F5A269100B34850 /* RubyCommand.swift in Sources */,
249 | D5D1DE991FFEE8EA00502A00 /* RubyCommandable.swift in Sources */,
250 | D55B28C41F6C588300DC42C5 /* Gymfile.swift in Sources */,
251 | B302067D1F5E3E9000DE6EBD /* MatchfileProtocol.swift in Sources */,
252 | B3BA65AC1F5A269100B34850 /* SocketClientDelegateProtocol.swift in Sources */,
253 | B3BA65A71F5A269100B34850 /* LaneFileProtocol.swift in Sources */,
254 | D55B28C61F6C588300DC42C5 /* Precheckfile.swift in Sources */,
255 | B302067F1F5E3E9000DE6EBD /* ScanfileProtocol.swift in Sources */,
256 | D55B28C51F6C588300DC42C5 /* Matchfile.swift in Sources */,
257 | B30206801F5E3E9000DE6EBD /* ScreengrabfileProtocol.swift in Sources */,
258 | D5BAFD121F7DAAFC0030B324 /* ArgumentProcessor.swift in Sources */,
259 | B302067C1F5E3E9000DE6EBD /* GymfileProtocol.swift in Sources */,
260 | B302067B1F5E3E9000DE6EBD /* SnapshotfileProtocol.swift in Sources */,
261 | D55B28C31F6C588300DC42C5 /* Deliverfile.swift in Sources */,
262 | D5A7C4901F7C4DAF00A91DE6 /* Fastfile.swift in Sources */,
263 | 0311E38B230AC9490060BB5C /* Actions.swift in Sources */,
264 | D5A7C48F1F7C4DAF00A91DE6 /* Appfile.swift in Sources */,
265 | B3BA65AB1F5A269100B34850 /* SocketClient.swift in Sources */,
266 | B30206811F5E3E9000DE6EBD /* DeliverfileProtocol.swift in Sources */,
267 | B3BA65AA1F5A269100B34850 /* Runner.swift in Sources */,
268 | B3BA65AF1F5A2D5C00B34850 /* RunnerArgument.swift in Sources */,
269 | D5B8A5B31FFDC49E00536B24 /* ControlCommand.swift in Sources */,
270 | B302067E1F5E3E9000DE6EBD /* PrecheckfileProtocol.swift in Sources */,
271 | B3BA65AD1F5A269100B34850 /* SocketResponse.swift in Sources */,
272 | B3BA65A81F5A269100B34850 /* main.swift in Sources */,
273 | D55B28C71F6C588300DC42C5 /* Scanfile.swift in Sources */,
274 | 0311E387230AC1B20060BB5C /* Plugins.swift in Sources */,
275 | D55B28C91F6C588300DC42C5 /* Snapshotfile.swift in Sources */,
276 | B3BA65A61F5A269100B34850 /* Fastlane.swift in Sources */,
277 | D55B28C81F6C588300DC42C5 /* Screengrabfile.swift in Sources */,
278 | );
279 | runOnlyForDeploymentPostprocessing = 0;
280 | };
281 | /* End PBXSourcesBuildPhase section */
282 |
283 | /* Begin XCBuildConfiguration section */
284 | B33BAF5C1F51F8D90001A751 /* Debug */ = {
285 | isa = XCBuildConfiguration;
286 | buildSettings = {
287 | ALWAYS_SEARCH_USER_PATHS = NO;
288 | CLANG_ANALYZER_NONNULL = YES;
289 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
290 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
291 | CLANG_CXX_LIBRARY = "libc++";
292 | CLANG_ENABLE_MODULES = YES;
293 | CLANG_ENABLE_OBJC_ARC = YES;
294 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
295 | CLANG_WARN_BOOL_CONVERSION = YES;
296 | CLANG_WARN_COMMA = YES;
297 | CLANG_WARN_CONSTANT_CONVERSION = YES;
298 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
299 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
300 | CLANG_WARN_EMPTY_BODY = YES;
301 | CLANG_WARN_ENUM_CONVERSION = YES;
302 | CLANG_WARN_INFINITE_RECURSION = YES;
303 | CLANG_WARN_INT_CONVERSION = YES;
304 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
305 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
306 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
307 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
308 | CLANG_WARN_STRICT_PROTOTYPES = YES;
309 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
310 | CLANG_WARN_UNREACHABLE_CODE = YES;
311 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
312 | CODE_SIGN_IDENTITY = "-";
313 | COPY_PHASE_STRIP = NO;
314 | DEBUG_INFORMATION_FORMAT = dwarf;
315 | ENABLE_STRICT_OBJC_MSGSEND = YES;
316 | ENABLE_TESTABILITY = YES;
317 | GCC_C_LANGUAGE_STANDARD = gnu99;
318 | GCC_DYNAMIC_NO_PIC = NO;
319 | GCC_NO_COMMON_BLOCKS = YES;
320 | GCC_OPTIMIZATION_LEVEL = 0;
321 | GCC_PREPROCESSOR_DEFINITIONS = (
322 | "DEBUG=1",
323 | "$(inherited)",
324 | );
325 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
326 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
327 | GCC_WARN_UNDECLARED_SELECTOR = YES;
328 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
329 | GCC_WARN_UNUSED_FUNCTION = YES;
330 | GCC_WARN_UNUSED_VARIABLE = YES;
331 | MACOSX_DEPLOYMENT_TARGET = 10.12;
332 | MTL_ENABLE_DEBUG_INFO = YES;
333 | ONLY_ACTIVE_ARCH = YES;
334 | SDKROOT = macosx;
335 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
336 | SWIFT_SWIFT3_OBJC_INFERENCE = Off;
337 | };
338 | name = Debug;
339 | };
340 | B33BAF5D1F51F8D90001A751 /* Release */ = {
341 | isa = XCBuildConfiguration;
342 | buildSettings = {
343 | ALWAYS_SEARCH_USER_PATHS = NO;
344 | CLANG_ANALYZER_NONNULL = YES;
345 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
346 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
347 | CLANG_CXX_LIBRARY = "libc++";
348 | CLANG_ENABLE_MODULES = YES;
349 | CLANG_ENABLE_OBJC_ARC = YES;
350 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
351 | CLANG_WARN_BOOL_CONVERSION = YES;
352 | CLANG_WARN_COMMA = YES;
353 | CLANG_WARN_CONSTANT_CONVERSION = YES;
354 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
355 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
356 | CLANG_WARN_EMPTY_BODY = YES;
357 | CLANG_WARN_ENUM_CONVERSION = YES;
358 | CLANG_WARN_INFINITE_RECURSION = YES;
359 | CLANG_WARN_INT_CONVERSION = YES;
360 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
361 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
362 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
363 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
364 | CLANG_WARN_STRICT_PROTOTYPES = YES;
365 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
366 | CLANG_WARN_UNREACHABLE_CODE = YES;
367 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
368 | CODE_SIGN_IDENTITY = "-";
369 | COPY_PHASE_STRIP = NO;
370 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
371 | ENABLE_NS_ASSERTIONS = NO;
372 | ENABLE_STRICT_OBJC_MSGSEND = YES;
373 | GCC_C_LANGUAGE_STANDARD = gnu99;
374 | GCC_NO_COMMON_BLOCKS = YES;
375 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
376 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
377 | GCC_WARN_UNDECLARED_SELECTOR = YES;
378 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
379 | GCC_WARN_UNUSED_FUNCTION = YES;
380 | GCC_WARN_UNUSED_VARIABLE = YES;
381 | MACOSX_DEPLOYMENT_TARGET = 10.12;
382 | MTL_ENABLE_DEBUG_INFO = NO;
383 | SDKROOT = macosx;
384 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
385 | SWIFT_SWIFT3_OBJC_INFERENCE = Off;
386 | };
387 | name = Release;
388 | };
389 | B33BAF5F1F51F8D90001A751 /* Debug */ = {
390 | isa = XCBuildConfiguration;
391 | buildSettings = {
392 | CLANG_ENABLE_MODULES = YES;
393 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
394 | PRODUCT_NAME = "$(TARGET_NAME)";
395 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
396 | SWIFT_VERSION = 4.0;
397 | };
398 | name = Debug;
399 | };
400 | B33BAF601F51F8D90001A751 /* Release */ = {
401 | isa = XCBuildConfiguration;
402 | buildSettings = {
403 | CLANG_ENABLE_MODULES = YES;
404 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
405 | PRODUCT_NAME = "$(TARGET_NAME)";
406 | SWIFT_VERSION = 4.0;
407 | };
408 | name = Release;
409 | };
410 | /* End XCBuildConfiguration section */
411 |
412 | /* Begin XCConfigurationList section */
413 | B33BAF521F51F8D90001A751 /* Build configuration list for PBXProject "FastlaneSwiftRunner" */ = {
414 | isa = XCConfigurationList;
415 | buildConfigurations = (
416 | B33BAF5C1F51F8D90001A751 /* Debug */,
417 | B33BAF5D1F51F8D90001A751 /* Release */,
418 | );
419 | defaultConfigurationIsVisible = 0;
420 | defaultConfigurationName = Release;
421 | };
422 | B33BAF5E1F51F8D90001A751 /* Build configuration list for PBXNativeTarget "FastlaneRunner" */ = {
423 | isa = XCConfigurationList;
424 | buildConfigurations = (
425 | B33BAF5F1F51F8D90001A751 /* Debug */,
426 | B33BAF601F51F8D90001A751 /* Release */,
427 | );
428 | defaultConfigurationIsVisible = 0;
429 | defaultConfigurationName = Release;
430 | };
431 | /* End XCConfigurationList section */
432 | };
433 | rootObject = B33BAF4F1F51F8D90001A751 /* Project object */;
434 | }
435 |
--------------------------------------------------------------------------------