├── .gitmodules
├── Documentation
├── install-man.sh
├── build-man.sh
├── auth_man_pages.md
├── building.md
├── modulo-init.1.md
├── modulo-init.1.ronn
├── modulo-init.1
├── modulo-layout.1.md
├── modulo-layout.1.ronn
├── modulo-update.1.md
├── modulo-update.1.ronn
├── modulo.1.md
├── modulo.1.ronn
├── modulo.1
├── modulo-update.1
├── modulo-layout.1
├── modulo-add.1.md
├── modulo-add.1.ronn
└── modulo-add.1
├── Modules
├── .DS_Store
├── ELCLI
│ ├── .DS_Store
│ ├── ELCLITests
│ │ ├── ELCLITests-Bridging-Header.h
│ │ ├── Info.plist
│ │ └── CommitCommand.swift
│ ├── ELCLI.xcodeproj
│ │ └── project.xcworkspace
│ │ │ └── contents.xcworkspacedata
│ ├── ELCLI
│ │ ├── ELCLI.h
│ │ ├── Commands
│ │ │ ├── VersionCommand.swift
│ │ │ └── HelpCommand.swift
│ │ ├── Info.plist
│ │ ├── Options.swift
│ │ └── Output.swift
│ ├── README.md
│ ├── .gitignore
│ └── LICENSE
├── ELCodable
│ ├── .travis.yml
│ ├── ELCodable.xcodeproj
│ │ └── project.xcworkspace
│ │ │ └── contents.xcworkspacedata
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── ELCodable
│ │ ├── Decimal.swift
│ │ ├── ELCodable.h
│ │ ├── Decodable.swift
│ │ ├── Info.plist
│ │ ├── Encodable.swift
│ │ ├── EncodeOperators.swift
│ │ ├── EncodableExtensions.swift
│ │ ├── DecodeOperators.swift
│ │ └── DecodableExtensions.swift
│ ├── ELCodable_osx
│ │ ├── ELCodable_osx.h
│ │ └── Info.plist
│ ├── ELCodableTests
│ │ ├── DynamicKeyedData.json
│ │ ├── Info.plist
│ │ ├── NestedErrorTesting.json
│ │ ├── DecimalTests.swift
│ │ ├── KeyPathTests.swift
│ │ ├── OptionalTests.json
│ │ ├── jsontest_models.json
│ │ ├── JSONTests.swift
│ │ ├── DynamicKeyTest.swift
│ │ ├── OptionalTests.swift
│ │ └── NestedErrorTesting.swift
│ ├── ELCodable_osxTests
│ │ ├── Info.plist
│ │ └── ELCodable_osxTests.swift
│ └── LICENSE
└── ELFoundation
│ ├── ELFoundation.xcodeproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── ELFoundation_osx.xcscheme
│ ├── .travis.yml
│ ├── CHANGELOG.md
│ ├── ELFoundation
│ ├── ELFoundation.h
│ ├── Extensions
│ │ ├── NSBundle.swift
│ │ ├── NSObject.swift
│ │ ├── String.swift
│ │ ├── NSURL.swift
│ │ ├── NSError.swift
│ │ └── NSThread.swift
│ ├── Info.plist
│ ├── Utilities
│ │ ├── Exceptions.swift
│ │ ├── ObjectAssociation.swift
│ │ ├── Swizzling.swift
│ │ └── Synchronization.swift
│ └── TestExtensions
│ │ ├── XCTestCase+Exceptions.m
│ │ ├── XCTestCase+Exceptions.h
│ │ └── TestHelper.swift
│ ├── .gitignore
│ ├── ELFoundation_osx
│ ├── ELFoundation_osx.h
│ └── Info.plist
│ ├── ELFoundationTests
│ ├── Info.plist
│ ├── NSBundleTests.swift
│ ├── NSObjectTests.swift
│ ├── NSURLTests.swift
│ ├── NSThreadTests.swift
│ ├── StringTests.swift
│ └── ELFoundationTests.swift
│ ├── ELFoundation_osxTests
│ └── Info.plist
│ ├── ELFoundation copy-Info.plist
│ ├── LICENSE
│ └── README.md
├── ModuloKitTests
├── ModuloKitTests-Bridging-Header.h
├── Info.plist
├── Utils.swift
├── ModuloKitTests.swift
├── XCTestCase+Exceptions.m
├── XCTestCase+Exceptions.h
├── TestDummyApp.swift
├── TestCheckout.swift
├── TestAdd.swift
├── TestUpdate.swift
├── TestGit.swift
└── TestStatus.swift
├── modulo.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcuserdata
│ │ └── brandonsneed.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── modulo.xcscmblueprint
└── xcuserdata
│ ├── brandon.xcuserdatad
│ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── ModuloKit.xcscheme
│ ├── brandonsneed.xcuserdatad
│ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── modulo.xcscheme
│ └── brsneed.xcuserdatad
│ └── xcschemes
│ ├── xcschememanagement.plist
│ └── ModuloKit.xcscheme
├── ModuloKit
├── System
│ ├── System.h
│ ├── System.m
│ └── BridgingHeader.h
├── ModuloKit.h
├── SemverCodable.swift
├── Info.plist
├── Specs
│ ├── OptionsSpec.swift
│ └── DependencySpec.swift
├── Commands
│ ├── RemoveCommand.swift
│ ├── StatusCommand.swift
│ ├── InitCommand.swift
│ ├── AddCommand.swift
│ ├── DefaultsCommand.swift
│ └── UpdateCommand.swift
├── Modulo.swift
├── Reachability.swift
└── ErrorCode.swift
├── Formula
└── brew-howto.md
├── .gitignore
├── modulo
└── main.swift
├── Makefile
└── LICENSE
/.gitmodules:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Documentation/install-man.sh:
--------------------------------------------------------------------------------
1 | sudo cp *.1 /usr/local/share/man/man1/
2 |
--------------------------------------------------------------------------------
/Modules/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/modulo-dm/modulo/HEAD/Modules/.DS_Store
--------------------------------------------------------------------------------
/Modules/ELCLI/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/modulo-dm/modulo/HEAD/Modules/ELCLI/.DS_Store
--------------------------------------------------------------------------------
/Modules/ELCLI/ELCLITests/ELCLITests-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 | #import "XCTestCase+Exceptions.h"
--------------------------------------------------------------------------------
/ModuloKitTests/ModuloKitTests-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 | #import "XCTestCase+Exceptions.h"
6 |
--------------------------------------------------------------------------------
/Modules/ELCodable/.travis.yml:
--------------------------------------------------------------------------------
1 | language: objective-c
2 | osx_image: xcode8
3 | script:
4 | - xcodebuild -project ELCodable.xcodeproj -scheme ELCodable -sdk iphonesimulator test -destination 'platform=iOS Simulator,name=iPhone 6,OS=10.0'
5 |
--------------------------------------------------------------------------------
/modulo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Modules/ELCLI/ELCLI.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/modulo.xcodeproj/project.xcworkspace/xcuserdata/brandonsneed.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/modulo-dm/modulo/HEAD/modulo.xcodeproj/project.xcworkspace/xcuserdata/brandonsneed.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodable.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundation.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/.travis.yml:
--------------------------------------------------------------------------------
1 | language: objective-c
2 | osx_image: xcode8
3 | script:
4 | - xcodebuild -project ELFoundation.xcodeproj -scheme ELFoundation -sdk iphonesimulator test -destination 'platform=iOS Simulator,name=iPhone 6,OS=10.0' CODE_SIGNING_REQUIRED=NO
5 |
--------------------------------------------------------------------------------
/Documentation/build-man.sh:
--------------------------------------------------------------------------------
1 | DATE=`date +%Y-%m-%d`
2 |
3 | ronn --roff *.ronn --date="$DATE" --manual="Modulo manual" --organization="Modulo"
4 |
5 | # copy all the .ronn files to .md so they can be viewed/linked on github.
6 | for x in *.ronn; do n=${x/.ronn/.md}; cp $x $n; done
7 |
--------------------------------------------------------------------------------
/ModuloKit/System/System.h:
--------------------------------------------------------------------------------
1 | //
2 | // System.h
3 | // modulo
4 | //
5 | // Created by Sneed, Brandon on 12/13/16.
6 | // Copyright © 2016 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NSInteger modulo_system(NSString *command);
12 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # [1.1.0](https://github.com/Electrode-iOS/ELFoundation/releases/tag/v1.1.0)
2 |
3 | - Add support for Xcode 8, Swift 2.3, and iOS SDK 10
4 |
5 | # [1.0.2](https://github.com/Electrode-iOS/ELFoundation/releases/tag/v1.0.2)
6 |
7 | - Update schemes to support Xcode 7.3
8 |
--------------------------------------------------------------------------------
/ModuloKit/System/System.m:
--------------------------------------------------------------------------------
1 | //
2 | // System.m
3 | // modulo
4 | //
5 | // Created by Sneed, Brandon on 12/13/16.
6 | // Copyright © 2016 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | #import "System.h"
10 |
11 | NSInteger modulo_system(NSString *command) {
12 | return system(command.UTF8String);
13 | }
14 |
--------------------------------------------------------------------------------
/ModuloKit/System/BridgingHeader.h:
--------------------------------------------------------------------------------
1 | //
2 | // BridgingHeader.h
3 | // modulo
4 | //
5 | // Created by Sneed, Brandon on 12/13/16.
6 | // Copyright © 2016 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | #ifndef BridgingHeader_h
10 | #define BridgingHeader_h
11 |
12 | #import "System.h"
13 |
14 | #endif /* BridgingHeader_h */
15 |
--------------------------------------------------------------------------------
/modulo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Documentation/auth_man_pages.md:
--------------------------------------------------------------------------------
1 | Using ronn: https://github.com/rtomayko/ronn/blob/master/README.md
2 |
3 | Example: http://rtomayko.github.io/ronn/ronn-format.7
4 | Source for example: https://github.com/rtomayko/ronn/blob/master/man/ronn-format.7.ronn
5 |
6 | See `modulo.1.ronn` for a starting point for new man pages.
7 | See `building.md` for how to build/install man pages.
8 |
--------------------------------------------------------------------------------
/Modules/ELCodable/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | build/
4 | *.pbxuser
5 | !default.pbxuser
6 | *.mode1v3
7 | !default.mode1v3
8 | *.mode2v3
9 | !default.mode2v3
10 | *.perspectivev3
11 | !default.perspectivev3
12 | xcuserdata
13 | *.xccheckout
14 | *.moved-aside
15 | DerivedData
16 | *.hmap
17 | *.ipa
18 | *.xcscmblueprint
19 | *.xcsettings
20 | *.xcuserstate
21 | .DS_Store
22 |
--------------------------------------------------------------------------------
/Formula/brew-howto.md:
--------------------------------------------------------------------------------
1 | - Build latest documentation via build-man.sh, commit.
2 | - Make a new tagged modulo release.
3 | - "curl -O "
4 | - update the sha256
5 | - "brew tests" -- make sure tests are installed.
6 | - "brew install --build-from-source "
7 | - "brew test "
8 | - "brew audit --strict "
9 | - PR changes to formula to homebrew-core.
10 |
--------------------------------------------------------------------------------
/Modules/ELCodable/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # [2.0.0](https://github.com/Electrode-iOS/ELCodable/releases/tag/v2.0.0)
2 |
3 | ## New Features
4 |
5 | - Added subscript to retrieve values for a given key index or array indexes.
6 | - Added an OS X target.
7 | - Made `data()` public.
8 |
9 | ## Removals
10 |
11 | - Remove return values from compound operators
12 | - Remove extra `inout` from `*` operator
13 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodable/Decimal.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Decimal.swift
3 | // Decimal
4 | //
5 | // Created by Brandon Sneed on 11/7/15.
6 | // Copyright © 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension Decimal {
12 | public var value: NSDecimalNumber {
13 | get {
14 | return (self as NSDecimalNumber)
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Documentation/building.md:
--------------------------------------------------------------------------------
1 | ## Build Dependencies
2 |
3 | * \>= Xcode 8.1
4 | * Git
5 | * Ronn (sudo gem install ronn)
6 |
7 | ### Modulo binary, from Source
8 |
9 | Clone this repo, then ...
10 |
11 | ```bash
12 | $ cd $repo
13 | $ xcodebuild -project modulo.xcodeproj -scheme modulo -configuration Release SYMROOT=build
14 | ```
15 |
16 | This will leave the modulo binary in `/tmp/modulo`
17 |
18 | ### Modulo documentation, via Ronn
19 |
20 | ```bash
21 | $ ...
22 | ```
23 |
--------------------------------------------------------------------------------
/Modules/ELCLI/ELCLI/ELCLI.h:
--------------------------------------------------------------------------------
1 | //
2 | // ELCLI.h
3 | // ELCLI
4 | //
5 | // Created by Brandon Sneed on 7/27/15.
6 | // Copyright (c) 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for ELCLI.
12 | FOUNDATION_EXPORT double ELCLIVersionNumber;
13 |
14 | //! Project version string for ELCLI.
15 | FOUNDATION_EXPORT const unsigned char ELCLIVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Modules/ELCLI/README.md:
--------------------------------------------------------------------------------
1 | # ELCLI
2 |
3 | A framework for parsing command lines in Swift.
4 |
5 | ## Requirements
6 |
7 | ELCLI requires Swift 2.1, Xcode 7.2 and depends on [`ELFoundation.framework`](https://github.com/Electrode-iOS/ELFoundation).
8 |
9 | [Electrode-iOS](https://github.com/Electrode-iOS/) frameworks are designed to live side-by-side in the file system, like so:
10 |
11 | * \MyProject
12 | * \MyProject\ELFoundation
13 |
14 | ## Installation
15 |
16 | Install by adding `ELCLI.xcodeproj` to your project and configuring your target to link `ELCLI.framework`.
17 |
18 | ## Usage
19 |
20 | TODO
21 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodable/ELCodable.h:
--------------------------------------------------------------------------------
1 | //
2 | // ELCodable.h
3 | // ELCodable
4 | //
5 | // Created by Brandon Sneed on 11/12/15.
6 | // Copyright © 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for ELCodable.
12 | FOUNDATION_EXPORT double ELCodableVersionNumber;
13 |
14 | //! Project version string for ELCodable.
15 | FOUNDATION_EXPORT const unsigned char ELCodableVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/ModuloKit/ModuloKit.h:
--------------------------------------------------------------------------------
1 | //
2 | // ModuloKit.h
3 | // ModuloKit
4 | //
5 | // Created by Brandon Sneed on 6/15/16.
6 | // Copyright © 2016 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for ModuloKit.
12 | FOUNDATION_EXPORT double ModuloKitVersionNumber;
13 |
14 | //! Project version string for ModuloKit.
15 | FOUNDATION_EXPORT const unsigned char ModuloKitVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 | #import
20 |
--------------------------------------------------------------------------------
/modulo.xcodeproj/xcuserdata/brandon.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Combined .gitignore from github/gitignore/master/Swift.gitignore and Xcode.gitignore
2 |
3 | ## Build generated
4 | build/
5 | .build/
6 | DerivedData/
7 |
8 | ## Various settings
9 | *.pbxuser
10 | !default.pbxuser
11 | *.mode1v3
12 | !default.mode1v3
13 | *.mode2v3
14 | !default.mode2v3
15 | *.perspectivev3
16 | !default.perspectivev3
17 | xcuserdata/
18 |
19 | ## Other
20 | *.moved-aside
21 | *.xcuserstate
22 | *.xcscmblueprint
23 |
24 | ## Obj-C/Swift specific
25 | *.hmap
26 | *.ipa
27 | *.dSYM.zip
28 | *.dSYM
29 |
30 | ## Playgrounds
31 | timeline.xctimeline
32 | playground.xcworkspace
33 | .DS_Store
34 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodable_osx/ELCodable_osx.h:
--------------------------------------------------------------------------------
1 | //
2 | // ELCodable_osx.h
3 | // ELCodable_osx
4 | //
5 | // Created by Brandon Sneed on 6/16/16.
6 | // Copyright © 2016 WalmartLabs. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for ELCodable_osx.
12 | FOUNDATION_EXPORT double ELCodable_osxVersionNumber;
13 |
14 | //! Project version string for ELCodable_osx.
15 | FOUNDATION_EXPORT const unsigned char ELCodable_osxVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundation/ELFoundation.h:
--------------------------------------------------------------------------------
1 | //
2 | // ELFoundation.h
3 | // ELFoundation
4 | //
5 | // Created by Brandon Sneed on 2/19/15.
6 | // Copyright (c) 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for ELFoundation.
12 | FOUNDATION_EXPORT double ELFoundationVersionNumber;
13 |
14 | //! Project version string for ELFoundation.
15 | FOUNDATION_EXPORT const unsigned char ELFoundationVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodableTests/DynamicKeyedData.json:
--------------------------------------------------------------------------------
1 | {
2 | "apiVersion": "v1",
3 | "data": {
4 | "5260": {
5 | "availabilityInStore": 15,
6 | "format": "EAN13",
7 | "identifier": "0078742079905",
8 | "location": {
9 | "aisle": "3",
10 | "section": "20",
11 | "zone": "A"
12 | },
13 | "name": "GV N-STIR CRMY 26.5Z",
14 | "packagePrice": 3.32,
15 | "unitPrice": 3.32
16 | }
17 | },
18 | "meta": {
19 | "isExtruded": true,
20 | "pluginVersion": "v1.0.0"
21 | }
22 | }
--------------------------------------------------------------------------------
/Modules/ELFoundation/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | build/
4 | *.pbxuser
5 | !default.pbxuser
6 | *.mode1v3
7 | !default.mode1v3
8 | *.mode2v3
9 | !default.mode2v3
10 | *.perspectivev3
11 | !default.perspectivev3
12 | xcuserdata
13 | *.xccheckout
14 | *.moved-aside
15 | DerivedData
16 | *.hmap
17 | *.ipa
18 | *.xcscmblueprint
19 | *.xcuserstate
20 |
21 | # CocoaPods
22 | #
23 | # We recommend against adding the Pods directory to your .gitignore. However
24 | # you should judge for yourself, the pros and cons are mentioned at:
25 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
26 | #
27 | # Pods/
28 | .DS_Store
29 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundation_osx/ELFoundation_osx.h:
--------------------------------------------------------------------------------
1 | //
2 | // ELFoundation_osx.h
3 | // ELFoundation_osx
4 | //
5 | // Created by Brandon Sneed on 8/11/15.
6 | // Copyright © 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for ELFoundation_osx.
12 | FOUNDATION_EXPORT double ELFoundation_osxVersionNumber;
13 |
14 | //! Project version string for ELFoundation_osx.
15 | FOUNDATION_EXPORT const unsigned char ELFoundation_osxVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/modulo/main.swift:
--------------------------------------------------------------------------------
1 | //
2 | // main.swift
3 | // modulo
4 | //
5 | // Created by Brandon Sneed on 6/17/16.
6 | // Copyright © 2016 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // such complexity! :D
12 |
13 | /*
14 |
15 | The general idea is that we build with source, but we set ModuloKit as a target
16 | dependency. That'll make sure it builds before modulo does. Modulo then includes
17 | the source files from ModuloKit and the frameworks it depends on. This will
18 | ensure that frameworks continue to build as changes are made in both source-only
19 | and framework form.
20 |
21 | ModuloKit then gives us a place by which we can write unit tests.
22 |
23 | */
24 |
25 | Modulo.run()
26 |
27 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodable/Decodable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Decodable.swift
3 | // Codable
4 | //
5 | // Created by Brandon Sneed on 11/2/15.
6 | // Copyright © 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public enum ELDecodeError: Error {
12 | case emptyJSON
13 | case undecodable
14 | case validationUnimplemented
15 | case validationFailed
16 | case notFound(key: String)
17 | }
18 |
19 | public protocol ELDecodable {
20 | static func decode(_ json: JSON?) throws -> Self
21 | func validate() throws -> Self
22 | }
23 |
24 | public extension ELDecodable {
25 | func validate() throws -> Self {
26 | // do nothing. user to override.
27 | throw ELDecodeError.validationUnimplemented
28 | //return self
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Modules/ELCLI/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | build/
4 | *.pbxuser
5 | !default.pbxuser
6 | *.mode1v3
7 | !default.mode1v3
8 | *.mode2v3
9 | !default.mode2v3
10 | *.perspectivev3
11 | !default.perspectivev3
12 | xcuserdata
13 | *.xccheckout
14 | *.moved-aside
15 | DerivedData
16 | *.hmap
17 | *.ipa
18 | *.xcuserstate
19 |
20 | # CocoaPods
21 | #
22 | # We recommend against adding the Pods directory to your .gitignore. However
23 | # you should judge for yourself, the pros and cons are mentioned at:
24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
25 | #
26 | # Pods/
27 |
28 | # Carthage
29 | #
30 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
31 | # Carthage/Checkouts
32 |
33 | Carthage/Build
34 | xcshareddata
35 |
--------------------------------------------------------------------------------
/ModuloKitTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Modules/ELCLI/ELCLITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodableTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodable_osxTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundationTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundation_osxTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundation/Extensions/NSBundle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSBundle.swift
3 | // THGDispatch
4 | //
5 | // Created by Brandon Sneed on 2/16/15.
6 | // Copyright (c) 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public extension Bundle {
12 | /**
13 | Returns the reverse DNS style bundle identifier
14 |
15 | - returns: The reverse DNS style bundle identifier
16 |
17 | Example: com.walmartlabs.thgfoundation
18 | */
19 | public func reverseBundleIdentifier() -> String? {
20 | if let id = bundleIdentifier {
21 | let components: [String] = id.components(separatedBy: ".")
22 | let reverseComponents = Array(components.reversed())
23 | let result = reverseComponents.joined(separator: ".")
24 | return result
25 | }
26 |
27 | return nil
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/ModuloKit/SemverCodable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SemverCodable.swift
3 | // modulo
4 | //
5 | // Created by Sneed, Brandon on 6/1/17.
6 | // Copyright © 2017 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | #if NOFRAMEWORKS
11 | #else
12 | import ELCodable
13 | #endif
14 |
15 | extension SemverRange: ELEncodable {
16 | public func encode() throws -> JSON {
17 | if self.valid {
18 | return JSON(self.original)
19 | } else {
20 | throw ELEncodeError.unencodable
21 | }
22 | }
23 | }
24 |
25 | extension SemverRange: ELDecodable {
26 | public static func decode(_ json: JSON?) throws -> SemverRange {
27 | if let value = json?.string {
28 | let range = SemverRange(value)
29 | if range.valid {
30 | return range
31 | }
32 | }
33 |
34 | throw ELDecodeError.undecodable
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodableTests/NestedErrorTesting.json:
--------------------------------------------------------------------------------
1 | {
2 | "description" : "Walmart",
3 | "iD" : "2280",
4 | "hoursOfOperation" : [
5 | {
6 | "day" : "Sun - Sat",
7 | "time" : "07:00AM - 10:00PM"
8 | }
9 | ],
10 | "phone" : "(650) 917-0796",
11 | "storeNumber" : "2280",
12 | "storeType" : "2",
13 | "storeServices" : [
14 | ],
15 | "longitude" : "-122.10944299",
16 | "storeClosedTemporarily" : "false",
17 | "latitude" : "37.40088999",
18 | "mscoEnabled" : "false",
19 | "rxFiltered" : "false",
20 | "openDate" : "11\/1\/1995",
21 | "address" : {
22 | "registry" : "false",
23 | "country" : "United States",
24 | "state" : "CA",
25 | "city" : "Mountain View",
26 | "street1" : "600 Showers Dr",
27 | "zip" : "94040"
28 | },
29 | "reOpenDate" : "1\/12\/2016",
30 | "localAdAvailable" : "true",
31 | "availableForS2S" : "true",
32 | "storeOpeningSoon" : "false"
33 | }
34 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodable/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 2.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundation/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundation copy-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/modulo.xcodeproj/xcuserdata/brandonsneed.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodable/Encodable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Encodable.swift
3 | // Codable
4 | //
5 | // Created by Brandon Sneed on 11/9/15.
6 | // Copyright © 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public enum ELEncodeError: Error {
12 | case unencodable
13 | case validationUnumplemented
14 | case validationFailed
15 | }
16 |
17 | public protocol ELEncodable {
18 | func encode() throws -> JSON
19 | }
20 |
21 | public typealias ELEncodeFormat = Array<(String, JSON)>
22 |
23 | public extension ELEncodable {
24 | func validateEncode() throws -> Self {
25 | // do nothing. user to override.
26 | throw ELEncodeError.validationUnumplemented
27 | }
28 |
29 | func encodeToJSON(_ format: ELEncodeFormat) throws -> JSON {
30 | var json = JSON()
31 | for tuple in format {
32 | json[tuple.0] = tuple.1
33 | }
34 | return json
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/modulo.xcodeproj/xcuserdata/brandonsneed.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | ModuloKit.xcscheme
8 |
9 | orderHint
10 | 4
11 |
12 | modulo.xcscheme
13 |
14 | orderHint
15 | 3
16 |
17 |
18 | SuppressBuildableAutocreation
19 |
20 | CAE55C401D14928B00411727
21 |
22 | primary
23 |
24 |
25 | CAE55C4F1D1492A500411727
26 |
27 | primary
28 |
29 |
30 | CAE55C581D1492A500411727
31 |
32 | primary
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/modulo.xcodeproj/xcuserdata/brsneed.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | ModuloKit.xcscheme
8 |
9 | orderHint
10 | 1
11 |
12 | modulo.xcscheme_^#shared#^_
13 |
14 | orderHint
15 | 0
16 |
17 |
18 | SuppressBuildableAutocreation
19 |
20 | CAE55C401D14928B00411727
21 |
22 | primary
23 |
24 |
25 | CAE55C4F1D1492A500411727
26 |
27 | primary
28 |
29 |
30 | CAE55C581D1492A500411727
31 |
32 | primary
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodableTests/DecimalTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DecimalTests.swift
3 | // ELCodable
4 | //
5 | // Created by Brandon Sneed on 1/15/16.
6 | // Copyright © 2016 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import ELCodable
11 |
12 | class DecimalTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testEquality() {
25 | let doubleValue: Double = 264.91
26 | let jsonValue = JSON(doubleValue)
27 |
28 | let subtotal = Decimal(jsonValue.decimal!)
29 |
30 | XCTAssertEqual(subtotal, Decimal(doubleValue))
31 | }
32 |
33 | }
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundationTests/NSBundleTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSBundleTests.swift
3 | // ELFoundation
4 | //
5 | // Created by Steven Riggins on 7/7/15.
6 | // Copyright © 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import ELFoundation
11 |
12 | class NSBundleTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testReverseBundleIdentifier() {
25 | let bundle = Bundle(identifier: "com.walmartlabs.ELFoundation")
26 | let reverseIdentifier = bundle?.reverseBundleIdentifier()
27 |
28 | XCTAssertTrue(reverseIdentifier == "ELFoundation.walmartlabs.com")
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/modulo.xcodeproj/xcuserdata/brandon.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | ModuloKit.xcscheme
8 |
9 | orderHint
10 | 1
11 |
12 | modulo.xcscheme
13 |
14 | isShown
15 |
16 | orderHint
17 | 0
18 |
19 |
20 | SuppressBuildableAutocreation
21 |
22 | CAE55C401D14928B00411727
23 |
24 | primary
25 |
26 |
27 | CAE55C4F1D1492A500411727
28 |
29 | primary
30 |
31 |
32 | CAE55C581D1492A500411727
33 |
34 | primary
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/Modules/ELCLI/ELCLI/Commands/VersionCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VersionCommand.swift
3 | // ELCLI
4 | //
5 | // Created by Brandon Sneed on 7/27/15.
6 | // Copyright (c) 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | open class VersionCommand: Command {
12 | fileprivate let cli: CLI
13 |
14 | open var name: String { return "--version" }
15 | open var shortHelpDescription: String { return "" }
16 | open var longHelpDescription: String { return "" }
17 | open var failOnUnrecognizedOptions: Bool { return false }
18 |
19 | open var verbose: Bool = false
20 | open var quiet: Bool = false
21 |
22 | open func configureOptions() {
23 | // do nothing
24 | }
25 |
26 | open func execute(_ otherParams: Array?) -> Int {
27 | writeln(.stdout, "\(cli.appName) version \(cli.appVersion), \(cli.appDescription)")
28 |
29 | return 0
30 | }
31 |
32 | init(cli: CLI) {
33 | self.cli = cli
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/ModuloKit/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSHumanReadableCopyright
24 | Copyright © 2016 TheHolyGrail. All rights reserved.
25 | NSPrincipalClass
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Modules/ELCLI/ELCLI/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSHumanReadableCopyright
24 | Copyright © 2015 WalmartLabs. All rights reserved.
25 | NSPrincipalClass
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodable_osx/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSHumanReadableCopyright
24 | Copyright © 2016 WalmartLabs. All rights reserved.
25 | NSPrincipalClass
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundation_osx/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSHumanReadableCopyright
24 | Copyright © 2015 WalmartLabs. All rights reserved.
25 | NSPrincipalClass
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # By default export all variables
2 | export
3 |
4 | .PHONY: install release debug build setup clean
5 |
6 | PROJECT ?= 'modulo.xcodeproj'
7 | SCHEME ?= 'modulo'
8 | SYMROOT ?= 'build'
9 | CONFIGURATION ?= 'Debug'
10 |
11 | # Build for debugging
12 | debug: build
13 |
14 | # Install `modulo` to `/usr/local/bin`
15 | install: release
16 | cp $(SYMROOT)/Release/modulo /usr/local/bin/
17 |
18 | # Build for release
19 | release: CONFIGURATION = 'Release'
20 | release: build
21 |
22 |
23 | # Build modulo
24 | # This will build the `PROJECT` with the given `SCHEME`
25 | # to the `SYMROOT` with a given `CONFIGURATION`
26 | # Defaults for these values are
27 | # `PROJECT` - `modulo.xcodeproj`
28 | # `SCHEME` - `modulo`
29 | # `SYMROOM` - `build`
30 | # `CONFIGURATION` - `Debug`
31 | #
32 | # These can be overwritten via ENV variables.
33 | build: setup
34 | xcodebuild -project $(PROJECT) -scheme $(SCHEME) -configuration $(CONFIGURATION) SYMROOT=$(SYMROOT)
35 |
36 | # Setup the environment
37 | setup:
38 | mkdir -p $(SYMROOT)
39 |
40 | clean:
41 | rm -rfv $(SYMROOT)
42 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundation/Extensions/NSObject.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject.swift
3 | // ELFoundation
4 | //
5 | // Created by Brandon Sneed on 12/8/15.
6 | // Copyright © 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public extension NSObject {
12 | /**
13 | Returns the NSBundle containing self's class.
14 | */
15 | public static func bundle() -> Bundle {
16 | return Bundle(for: self)
17 | }
18 |
19 | /**
20 | Returns the NSBundle containing self's class.
21 | */
22 | public func bundle() -> Bundle {
23 | return type(of: self).bundle()
24 | }
25 |
26 | /**
27 | Returns a plugin ID based on bundleID.
28 | */
29 | public static func pluginIdentifier() -> String {
30 | let bundleID = self.bundle().bundleIdentifier!
31 | return bundleID
32 | }
33 |
34 | /**
35 | Returns a plugin ID based on bundleID.
36 | */
37 | public func pluginIdentifier() -> String {
38 | return type(of: self).pluginIdentifier()
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/ModuloKitTests/Utils.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Utils.swift
3 | // modulo
4 | //
5 | // Created by Brandon Sneed on 7/11/16.
6 | // Copyright © 2016 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ELCLI
11 | import ELFoundation
12 | @testable import ModuloKit
13 |
14 | func moduloReset() {
15 | FileManager.setWorkingPath("/private/tmp")
16 | Git().remove("test-dummy")
17 | Git().remove("test-add")
18 | Git().remove("test-init")
19 | Git().remove("test-add-update")
20 | Git().remove("test-dep1")
21 | Git().remove("test-dep2")
22 | Git().remove("test-checkout")
23 | Git().remove("checkout-test")
24 | Git().remove("test-simeon")
25 |
26 | State.instance.clear()
27 | }
28 |
29 | func touchFile(_ path: String) {
30 | try! path.write(toFile: path, atomically: true, encoding: String.Encoding.utf8)
31 | }
32 |
33 | func runCommand(_ command: String) {
34 | Git().runCommand(command)
35 | }
36 |
37 | func testCommit(_ message: String) {
38 | Git().runCommand("git commit -m \"\(message)\" --no-verify")
39 | }
40 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundationTests/NSObjectTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSObjectTests.swift
3 | // ELFoundation
4 | //
5 | // Created by Sam Grover on 2/1/16.
6 | // Copyright © 2016 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import ELFoundation
11 |
12 | class NSObjectTests: XCTestCase {
13 |
14 | class Foo: NSObject {
15 |
16 | }
17 |
18 | override func setUp() {
19 | super.setUp()
20 | // Put setup code here. This method is called before the invocation of each test method in the class.
21 | }
22 |
23 | override func tearDown() {
24 | // Put teardown code here. This method is called after the invocation of each test method in the class.
25 | super.tearDown()
26 | }
27 |
28 | func testStaticBundle() {
29 | XCTAssertTrue("com.walmartlabs.ELFoundationTests" == Foo.bundle().bundleIdentifier!)
30 | }
31 |
32 | func testBundle() {
33 | let foo = Foo()
34 | XCTAssertTrue("com.walmartlabs.ELFoundationTests" == foo.bundle().bundleIdentifier!)
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundationTests/NSURLTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSURLTests.swift
3 | // ELFoundation
4 | //
5 | // Created by Brandon Sneed on 4/15/16.
6 | // Copyright © 2016 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import ELFoundation
11 |
12 | class NSURLTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testQueryDictionary() {
25 | let url = URL(string: "http://blah.com/something?key1=value1&key2=value2&key3=this%20be%20value%203%2C%20y0")
26 |
27 | let dict = url!.queryDictionary!
28 |
29 | XCTAssertTrue(dict["key1"] == "value1")
30 | XCTAssertTrue(dict["key2"] == "value2")
31 | XCTAssertTrue(dict["key3"] == "this be value 3, y0")
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundationTests/NSThreadTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSThreadTests.swift
3 | // ELFoundation
4 | //
5 | // Created by Sam Grover on 2/2/16.
6 | // Copyright © 2016 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class NSThreadTests: XCTestCase {
12 |
13 | override func setUp() {
14 | super.setUp()
15 | // Put setup code here. This method is called before the invocation of each test method in the class.
16 | }
17 |
18 | override func tearDown() {
19 | // Put teardown code here. This method is called after the invocation of each test method in the class.
20 | super.tearDown()
21 | }
22 |
23 | func testDateFormatter() {
24 | let RFC3339TestDate = "1996-12-19T16:39:57-08:00"
25 | let RFC3339TestDateDescription = "1996-12-20 00:39:57 +0000"
26 | let RFC3339DateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
27 |
28 | let df = Thread.dateFormatter(RFC3339DateFormat)
29 | let date = df.date(from: RFC3339TestDate)
30 | XCTAssertTrue(date!.description == RFC3339TestDateDescription)
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundationTests/StringTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StringTests.swift
3 | // ELFoundation
4 | //
5 | // Created by Sam Grover on 2/1/16.
6 | // Copyright © 2016 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class StringTests: XCTestCase {
12 |
13 | override func setUp() {
14 | super.setUp()
15 | // Put setup code here. This method is called before the invocation of each test method in the class.
16 | }
17 |
18 | override func tearDown() {
19 | // Put teardown code here. This method is called after the invocation of each test method in the class.
20 | super.tearDown()
21 | }
22 |
23 | func testGUID() {
24 | do {
25 | let regex = try NSRegularExpression(pattern: "^.{8}-.{4}-.{4}-.{4}-.{12}$", options: [])
26 | let guid = String.GUID()
27 | let numMatches = regex.numberOfMatches(in: String.GUID(), options: [], range: NSRange(location: 0, length: guid.characters.count))
28 | XCTAssertTrue(numMatches == 1)
29 | } catch {
30 | XCTAssertTrue(false)
31 | }
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/ModuloKit/Specs/OptionsSpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OptionsSpec.swift
3 | // ModuloKit
4 | //
5 | // Created by Daniel Miedema on 9/25/18.
6 | // Copyright © 2018 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | #if NOFRAMEWORKS
11 | #else
12 | import ELCodable
13 | #endif
14 |
15 | public struct OptionsSpec {
16 | /// Should we have `verbose` on all commands
17 | var alwaysVerbose: Bool = false
18 | /// Path to store our 'modules'/dependencies in
19 | var depdencyInstallationPath: String = "modules"
20 | }
21 |
22 | extension OptionsSpec: ELDecodable {
23 | public static func decode(_ json: JSON?) throws -> OptionsSpec {
24 | return try OptionsSpec(
25 | alwaysVerbose: json ==> "alwaysVerbose",
26 | depdencyInstallationPath: json ==> "depdencyInstallationPath"
27 | )
28 | }
29 | }
30 |
31 | extension OptionsSpec: ELEncodable {
32 | public func encode() throws -> JSON {
33 | return try encodeToJSON([
34 | "alwaysVerbose" <== alwaysVerbose,
35 | "depdencyInstallationPath" <== depdencyInstallationPath
36 | ])
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Brandon Sneed, Peat Bakke
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/ModuloKitTests/ModuloKitTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ModuloKitTests.swift
3 | // ModuloKitTests
4 | //
5 | // Created by Brandon Sneed on 6/17/16.
6 | // Copyright © 2016 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ModuloKit
11 |
12 | class ModuloKitTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 | }
28 |
29 | func testPerformanceExample() {
30 | // This is an example of a performance test case.
31 | self.measure {
32 | // Put the code you want to measure the time of here.
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/Modules/ELCLI/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 WalmartLabs
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodable_osxTests/ELCodable_osxTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ELCodable_osxTests.swift
3 | // ELCodable_osxTests
4 | //
5 | // Created by Brandon Sneed on 6/16/16.
6 | // Copyright © 2016 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ELCodable_osx
11 |
12 | class ELCodable_osxTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 | }
28 |
29 | func testPerformanceExample() {
30 | // This is an example of a performance test case.
31 | self.measureBlock {
32 | // Put the code you want to measure the time of here.
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/Modules/ELCodable/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Walmart, WalmartLabs, and other Contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015-2016 Walmart, WalmartLabs, and other Contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundation/Extensions/String.swift:
--------------------------------------------------------------------------------
1 | //
2 | // String.swift
3 | // ELFoundation
4 | //
5 | // Created by Brandon Sneed on 3/16/15.
6 | // Copyright (c) 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public extension String {
12 | /**
13 | Returns a GUID in the form of "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX".
14 |
15 | - returns: A unique string identifier.
16 | */
17 | static public func GUID() -> String {
18 | return UUID().uuidString
19 | }
20 |
21 | }
22 |
23 | public extension String {
24 | public func padFront(_ maxLength: Int) -> String {
25 | var spaces = ""
26 | if maxLength > self.count {
27 | for _ in 0..<(maxLength - self.count) {
28 | spaces += " "
29 | }
30 | }
31 |
32 | return "\(spaces)\(self)"
33 | }
34 |
35 | public func padBack(_ maxLength: Int) -> String {
36 | var spaces = ""
37 | if maxLength > self.count {
38 | for _ in 0..<(maxLength - self.count) {
39 | spaces += " "
40 | }
41 | }
42 |
43 | return "\(self)\(spaces)"
44 | }
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/Modules/ELCLI/ELCLI/Options.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Options.swift
3 | // ELCLI
4 | //
5 | // Created by Brandon Sneed on 7/27/15.
6 | // Copyright (c) 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public typealias OptionClosure = (_ option: String?, _ value: String?) -> Void
12 |
13 | public struct Option {
14 | let usage: String?
15 | let flags: Array?
16 | let valueSignatures: Array?
17 | let closure: OptionClosure
18 |
19 | init(flags: Array?, usage: String?, valueSignatures: Array?, closure: @escaping OptionClosure) {
20 | self.flags = flags
21 | self.usage = usage
22 | self.valueSignatures = valueSignatures
23 | self.closure = closure
24 | }
25 |
26 | init(flags: Array?, usage: String?, closure: @escaping OptionClosure) {
27 | self.flags = flags
28 | self.usage = usage
29 | self.valueSignatures = nil
30 | self.closure = closure
31 | }
32 |
33 | init(valueSignatures: Array?, closure: @escaping OptionClosure) {
34 | self.flags = nil
35 | self.usage = nil
36 | self.valueSignatures = valueSignatures
37 | self.closure = closure
38 | }
39 |
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/ModuloKit/Commands/RemoveCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RemoveCommand.swift
3 | // modulo
4 | //
5 | // Created by Brandon Sneed on 7/18/16.
6 | // Copyright © 2016 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | #if NOFRAMEWORKS
11 | #else
12 | import ELCLI
13 | #endif
14 |
15 | open class RemoveCommand: NSObject, Command {
16 | // Protocol conformance
17 | open var name: String { return "remove" }
18 | open var shortHelpDescription: String { return "Removes a module from the list of dependencies" }
19 | open var longHelpDescription: String {
20 | return "Removes a module from the list of dependencies and performs checking to see if it is used elsewhere. The filesystem is left intact for you to delete it manually at your convenience."
21 | }
22 | open var failOnUnrecognizedOptions: Bool { return true }
23 |
24 | open var verbose: Bool = State.instance.options.alwaysVerbose
25 | open var quiet: Bool = false
26 |
27 | open func configureOptions() {
28 |
29 | }
30 |
31 | open func execute(_ otherParams: Array?) -> Int {
32 | let actions = Actions()
33 | let result = actions.checkDependenciesStatus()
34 | return result.rawValue
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/ModuloKitTests/XCTestCase+Exceptions.m:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | These files are not to be included in any targets except test case targets.
4 | Simply drag them to your project and make sure only the Tests target is checked.
5 | You'll be prompted to create an objc-bridging header. Say yes, then add
6 | this to the newly created header:
7 |
8 | #import "XCTestCase+Exceptions.h"
9 |
10 | These methods should now be accessible from within Swift without doing
11 | anything additional.
12 |
13 | */
14 |
15 | #import "XCTestCase+Exceptions.h"
16 |
17 | @implementation XCTestCase (Exceptions)
18 |
19 | - (void)XCTAssertThrows:(void (^)(void))block :(NSString *)message {
20 | XCTAssertThrows(block(), @"%@", message);
21 | }
22 |
23 | - (void)XCTAssertThrowsSpecific:(void (^)(void))block :(NSString *)exceptionName :(NSString *)message {
24 | BOOL __didThrow = NO;
25 | @try {
26 | block();
27 | }
28 | @catch (NSException *exception) {
29 | __didThrow = YES;
30 | XCTAssertEqualObjects(exception.name, exceptionName, @"%@", message);
31 | }
32 | @catch (...) {
33 | __didThrow = YES;
34 | XCTFail(@"%@", message);
35 | }
36 |
37 | if (!__didThrow) {
38 | XCTFail(@"%@", message);
39 | }
40 | }
41 |
42 | @end
43 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundation/Utilities/Exceptions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Exceptions.swift
3 | // ELFoundation
4 | //
5 | // Created by Brandon Sneed on 2/19/15.
6 | // Copyright (c) 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /**
12 | The name of the exception thrown by 'exceptionFailture(...)'.
13 | */
14 | public let ELExceptionFailure = "ELExceptionFailure"
15 |
16 | /**
17 | This function is intended to be used to catch programming errors and undefined code
18 | paths. To handle unrecoverable errors, see 'assertionFailure'.
19 |
20 | Raises an exception and can be used on testable code. This is to be used as an
21 | alternative to assertionFailure(), which blows up tests.
22 |
23 | - parameter message: Message string to be used.
24 |
25 | Example: exceptionFailure("This object is invalid. \(obj)")
26 | */
27 | public func exceptionFailure(_ message: String) {
28 | let args: [CVarArg] = []
29 | if isInUnitTest() {
30 | NSException.raise(NSExceptionName(rawValue: ELExceptionFailure), format: message, arguments: getVaList(args))
31 | } else {
32 | #if DEBUG
33 | NSException.raise(NSExceptionName(rawValue: ELExceptionFailure), format: message, arguments: getVaList(args))
34 | #endif
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundation/TestExtensions/XCTestCase+Exceptions.m:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | These files are not to be included in any targets except test case targets.
4 | Simply drag them to your project and make sure only the Tests target is checked.
5 | You'll be prompted to create an objc-bridging header. Say yes, then add
6 | this to the newly created header:
7 |
8 | #import "XCTestCase+Exceptions.h"
9 |
10 | These methods should now be accessible from within Swift without doing
11 | anything additional.
12 |
13 | */
14 |
15 | #import "XCTestCase+Exceptions.h"
16 |
17 | @implementation XCTestCase (Exceptions)
18 |
19 | - (void)XCTAssertThrows:(void (^)(void))block :(NSString *)message {
20 | XCTAssertThrows(block(), @"%@", message);
21 | }
22 |
23 | - (void)XCTAssertThrowsSpecific:(void (^)(void))block :(NSString *)exceptionName :(NSString *)message {
24 | BOOL __didThrow = NO;
25 | @try {
26 | block();
27 | }
28 | @catch (NSException *exception) {
29 | __didThrow = YES;
30 | XCTAssertEqualObjects(exception.name, exceptionName, @"%@", message);
31 | }
32 | @catch (...) {
33 | __didThrow = YES;
34 | XCTFail(@"%@", message);
35 | }
36 |
37 | if (!__didThrow) {
38 | XCTFail(@"%@", message);
39 | }
40 | }
41 |
42 | @end
43 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundation/Utilities/ObjectAssociation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ObjectAssociation.swift
3 | // ELFoundation
4 | //
5 | // Created by Brandon Sneed on 8/11/15.
6 | // Copyright © 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | final private class Wrapper: NSObject {
12 | var value: T?
13 | init(_ x: T) {
14 | value = x
15 | }
16 | }
17 |
18 | /**
19 | Sets an value to be associated with 'object'. Be careful when using swift types
20 | like Arrays and whatnot where mutability is involved.
21 | */
22 | public func setAssociatedObject(_ object: AnyObject, value: T, associativeKey: UnsafeRawPointer, policy: objc_AssociationPolicy) {
23 | //print("set, T = \(T.self)")
24 | objc_setAssociatedObject(object, associativeKey, Wrapper(value), policy)
25 | }
26 |
27 | /**
28 | Gets a value associated with 'object'. Be careful when using swift types
29 | like Arrays and whatnot where mutability is involved.
30 | */
31 | public func getAssociatedObject(_ object: AnyObject, associativeKey: UnsafeRawPointer) -> T! {
32 | let result = objc_getAssociatedObject(object, associativeKey)
33 | //print("get, T = \(T.self)")
34 | if let v = result as? Wrapper {
35 | return v.value
36 | } else {
37 | return nil
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Documentation/modulo-init.1.md:
--------------------------------------------------------------------------------
1 | modulo-init(1) -- Initialize a project for use with Modulo.
2 | ====
3 |
4 | ## SYNOPSIS
5 |
6 | `modulo init` [--app]
7 | `modulo init` [--module]
8 |
9 | ## DESCRIPTION
10 |
11 | This command initializes a project/directory for use with Modulo. A `.modulo` file is created to track dependencies, and other details. The two modes of operation are documented below.
12 |
13 | ## OPTIONS
14 |
15 | * `--app`:
16 | Initializes modulo as an application. Any dependencies will be located in `.\modules` upon add/update. This option also adds an entry to SCM's ignore file to ignore the `modules` directory.
17 |
18 | * `--module`:
19 | Initializes modulo as an module. Any dependencies will be located in `..\` upon add/update.
20 |
21 | * `-v, --verbose`:
22 | Prints verbose output. Use this to see what underlying SCM commands are being used and any other important information.
23 |
24 | * `-h, --help`:
25 | Prints the help for this command.
26 |
27 | ## SEE ALSO
28 |
29 | modulo-layout(1), modulo-add(1)
30 |
31 | ## REPORTING BUGS
32 |
33 | Report bugs to the Github Project located at https://github.com/modulo-dm/modulo/. You'll be able to see the status and track any issues you create.
34 |
35 | ## AUTHORS
36 |
37 | Brandon Sneed
38 | Peat Bakke
39 |
40 |
41 |
--------------------------------------------------------------------------------
/Documentation/modulo-init.1.ronn:
--------------------------------------------------------------------------------
1 | modulo-init(1) -- Initialize a project for use with Modulo.
2 | ====
3 |
4 | ## SYNOPSIS
5 |
6 | `modulo init` [--app]
7 | `modulo init` [--module]
8 |
9 | ## DESCRIPTION
10 |
11 | This command initializes a project/directory for use with Modulo. A `.modulo` file is created to track dependencies, and other details. The two modes of operation are documented below.
12 |
13 | ## OPTIONS
14 |
15 | * `--app`:
16 | Initializes modulo as an application. Any dependencies will be located in `.\modules` upon add/update. This option also adds an entry to SCM's ignore file to ignore the `modules` directory.
17 |
18 | * `--module`:
19 | Initializes modulo as an module. Any dependencies will be located in `..\` upon add/update.
20 |
21 | * `-v, --verbose`:
22 | Prints verbose output. Use this to see what underlying SCM commands are being used and any other important information.
23 |
24 | * `-h, --help`:
25 | Prints the help for this command.
26 |
27 | ## SEE ALSO
28 |
29 | modulo-layout(1), modulo-add(1)
30 |
31 | ## REPORTING BUGS
32 |
33 | Report bugs to the Github Project located at https://github.com/modulo-dm/modulo/. You'll be able to see the status and track any issues you create.
34 |
35 | ## AUTHORS
36 |
37 | Brandon Sneed
38 | Peat Bakke
39 |
40 |
41 |
--------------------------------------------------------------------------------
/ModuloKit/Commands/StatusCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StatusCommand.swift
3 | // modulo
4 | //
5 | // Created by Brandon Sneed on 7/11/16.
6 | // Copyright © 2016 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | #if NOFRAMEWORKS
12 | #else
13 | import ELCLI
14 | #endif
15 |
16 | open class StatusCommand: NSObject, Command {
17 | // Protocol conformance
18 | open var name: String { return "status" }
19 | open var shortHelpDescription: String { return "Gathers status about the module tree" }
20 | open var longHelpDescription: String {
21 | return "Gathers status about the module tree. Uncommitted, unpushed, branch or tag mismatches, etc."
22 | }
23 | open var failOnUnrecognizedOptions: Bool { return true }
24 | open var ignoreMain: Bool = false
25 |
26 | open var verbose: Bool = State.instance.options.alwaysVerbose
27 | open var quiet: Bool = false
28 |
29 | open func configureOptions() {
30 | addOption(["--ignoremain"], usage: "ignores the main project, scans modules only") { (option, value) in
31 | self.ignoreMain = true
32 | }
33 |
34 | }
35 |
36 | open func execute(_ otherParams: Array?) -> Int {
37 | let actions = Actions()
38 | let result = actions.checkDependenciesStatus(ignoreMain: ignoreMain)
39 | return result.rawValue
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Modules/ELCLI/ELCLI/Commands/HelpCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HelpCommand.swift
3 | // ELCLI
4 | //
5 | // Created by Brandon Sneed on 7/27/15.
6 | // Copyright (c) 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | open class HelpCommand: Command {
12 | fileprivate let cli: CLI
13 |
14 | open var name: String { return "--help" }
15 | open var shortHelpDescription: String { return "" }
16 | open var longHelpDescription: String { return "" }
17 | open var failOnUnrecognizedOptions: Bool { return false }
18 |
19 | open var verbose: Bool = false
20 | open var quiet: Bool = false
21 |
22 | open func configureOptions() {
23 | // do nothing
24 | }
25 |
26 | @discardableResult
27 | open func execute(_ otherParams: Array?) -> Int {
28 | write(.stdout, "usage: ")
29 | write(.stdout, "\(ProcessInfo.processInfo.processName) ")
30 | writeln(.stdout, " []\n")
31 |
32 | writeln(.stdout, "The most commonly used \(cli.appName) commands are:")
33 |
34 | let commands = cli.commands
35 | for index in 0.. 0 {
35 | return result
36 | }
37 | }
38 | // if we didn't return prior to this, send back nil.
39 | return nil
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/ModuloKit/Modulo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Modulo.swift
3 | // ModuloKit
4 | //
5 | // Created by Brandon Sneed on 6/15/16.
6 | // Copyright © 2016 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | #if NOFRAMEWORKS
12 | #else
13 | import ELCLI
14 | import ELFoundation
15 | #endif
16 |
17 | @objc
18 | open class Modulo: NSObject {
19 |
20 | public static func run() {
21 | let error = run([])
22 | exit(Int32(error.rawValue))
23 | }
24 |
25 | public static func run(_ args: [String]) -> ErrorCode {
26 | let cli = CLI(name: "modulo", version: "0.7.0", description: "A simple dependency manager")
27 |
28 | // before we do anything make sure our options are applied to our
29 | // current state. If we don't have a working spec the defaults will do fine
30 | if let options = ModuleSpec.workingSpec()?.options {
31 | State.instance.options = options
32 | }
33 |
34 | if args.count > 0 {
35 | cli.allArgumentsToExecutable = args
36 | }
37 |
38 | cli.addCommands([InitCommand(), AddCommand(), UpdateCommand(), StatusCommand(), MapCommand(), SetCommand(), DefaultsCommand()])
39 |
40 | if let error = ErrorCode(rawValue: cli.run()) {
41 | if error == .success {
42 | State.instance.showFinalInformation()
43 | }
44 |
45 | return error
46 | }
47 |
48 | return ErrorCode.unknownError
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/ModuloKitTests/XCTestCase+Exceptions.h:
--------------------------------------------------------------------------------
1 | /**
2 |
3 | These files are not to be included in any targets except test case targets.
4 | Simply drag them to your project and make sure only the Tests target is checked.
5 | You'll be prompted to create an objc-bridging header. Say yes, then add
6 | this to the newly created header:
7 |
8 | #import "XCTestCase+Exceptions.h"
9 |
10 | These methods should now be accessible from within Swift without doing
11 | anything additional.
12 |
13 | */
14 |
15 | @import Foundation;
16 | @import XCTest;
17 |
18 | @interface XCTestCase (Exceptions)
19 |
20 | /**
21 | Replacement for the stock objc XCTAssertThrows, which is unavailable in Swift.
22 |
23 | :param: block The block to execute.
24 | :param: message The message to be displayed on failure to throw an exception.
25 |
26 | Example (Swift): XCTAssertThrows({ testThrow() }, "This method should've thrown an exception!")
27 | */
28 | - (void)XCTAssertThrows:(void (^)(void))block :(NSString *)message;
29 |
30 | /**
31 | Replacement for the stock objc XCTAssertThrowsSpecific, which is unavailable in Swift.
32 |
33 | :param: block The block to execute.
34 | :param: name The name of the assertion to look for.
35 | :param: message The message to be displayed on failure to throw an exception.
36 |
37 | Example (Swift): XCTAssertThrowsSpecific({ testThrow() }, "THG", "This method should've thrown a THG exception!")
38 | */
39 | - (void)XCTAssertThrowsSpecific:(void (^)(void))block :(NSString *)name :(NSString *)message;
40 |
41 | @end
42 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundation/TestExtensions/XCTestCase+Exceptions.h:
--------------------------------------------------------------------------------
1 | /**
2 |
3 | These files are not to be included in any targets except test case targets.
4 | Simply drag them to your project and make sure only the Tests target is checked.
5 | You'll be prompted to create an objc-bridging header. Say yes, then add
6 | this to the newly created header:
7 |
8 | #import "XCTestCase+Exceptions.h"
9 |
10 | These methods should now be accessible from within Swift without doing
11 | anything additional.
12 |
13 | */
14 |
15 | @import Foundation;
16 | @import XCTest;
17 |
18 | @interface XCTestCase (Exceptions)
19 |
20 | /**
21 | Replacement for the stock objc XCTAssertThrows, which is unavailable in Swift.
22 |
23 | :param: block The block to execute.
24 | :param: message The message to be displayed on failure to throw an exception.
25 |
26 | Example (Swift): XCTAssertThrows({ testThrow() }, "This method should've thrown an exception!")
27 | */
28 | - (void)XCTAssertThrows:(void (^)(void))block :(NSString *)message;
29 |
30 | /**
31 | Replacement for the stock objc XCTAssertThrowsSpecific, which is unavailable in Swift.
32 |
33 | :param: block The block to execute.
34 | :param: name The name of the assertion to look for.
35 | :param: message The message to be displayed on failure to throw an exception.
36 |
37 | Example (Swift): XCTAssertThrowsSpecific({ testThrow() }, "THG", "This method should've thrown a THG exception!")
38 | */
39 | - (void)XCTAssertThrowsSpecific:(void (^)(void))block :(NSString *)name :(NSString *)message;
40 |
41 | @end
42 |
--------------------------------------------------------------------------------
/Documentation/modulo-init.1:
--------------------------------------------------------------------------------
1 | .\" generated with Ronn/v0.7.3
2 | .\" http://github.com/rtomayko/ronn/tree/0.7.3
3 | .
4 | .TH "MODULO\-INIT" "1" "July 2017" "Modulo" "Modulo manual"
5 | .
6 | .SH "NAME"
7 | \fBmodulo\-init\fR \- Initialize a project for use with Modulo\.
8 | .
9 | .SH "SYNOPSIS"
10 | \fBmodulo init\fR [\-\-app]
11 | .
12 | .br
13 | \fBmodulo init\fR [\-\-module]
14 | .
15 | .br
16 | .
17 | .SH "DESCRIPTION"
18 | This command initializes a project/directory for use with Modulo\. A \fB\.modulo\fR file is created to track dependencies, and other details\. The two modes of operation are documented below\.
19 | .
20 | .SH "OPTIONS"
21 | .
22 | .TP
23 | \fB\-\-app\fR
24 | Initializes modulo as an application\. Any dependencies will be located in \fB\.\emodules\fR upon add/update\. This option also adds an entry to SCM\'s ignore file to ignore the \fBmodules\fR directory\.
25 | .
26 | .TP
27 | \fB\-\-module\fR
28 | Initializes modulo as an module\. Any dependencies will be located in \fB\.\.\e\fR upon add/update\.
29 | .
30 | .TP
31 | \fB\-v, \-\-verbose\fR
32 | Prints verbose output\. Use this to see what underlying SCM commands are being used and any other important information\.
33 | .
34 | .TP
35 | \fB\-h, \-\-help\fR
36 | Prints the help for this command\.
37 | .
38 | .SH "SEE ALSO"
39 | modulo\-layout(1), modulo\-add(1)
40 | .
41 | .SH "REPORTING BUGS"
42 | Report bugs to the Github Project located at https://github\.com/modulo\-dm/modulo/\. You\'ll be able to see the status and track any issues you create\.
43 | .
44 | .SH "AUTHORS"
45 | .
46 | .nf
47 |
48 | Brandon Sneed
49 | Peat Bakke
50 | .
51 | .fi
52 |
53 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundation/Extensions/NSError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSError.swift
3 | // ELFoundation
4 | //
5 | // Created by Brandon Sneed on 3/25/15.
6 | // Copyright (c) 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /**
12 | Protocol to make using NSError's in swift easier to use.
13 |
14 | Example:
15 |
16 | enum ELMyError: Int, NSErrorEnum {
17 | case FileNotFound
18 | case LostACoconut
19 |
20 | public var domain: String {
21 | return "com.walmartlabs.ELMyError"
22 | }
23 |
24 | public var errorDescription: String {
25 | case FileNotFound:
26 | return "File not found."
27 | case LostACoconut:
28 | return "An african swallow stole a coconut."
29 | }
30 | }
31 | */
32 | public protocol NSErrorEnum {
33 | /// Returns the raw value of the enum. The enum MUST be an Int.
34 | var rawValue: Int { get }
35 | /// Returns the domain of the error enum. ie: "com.walmartlabs.ELMyError"
36 | var domain: String { get }
37 | /// Returns an error description string representing the enum's value.
38 | var errorDescription: String { get }
39 | }
40 |
41 | extension NSError {
42 | /**
43 | Convenience init that takes an enum conforming to the NSErrorEnum protocol to build an NSError object.
44 |
45 | Example:
46 |
47 | let error = NSError(ELMyError.LostACoconut)
48 | */
49 | convenience public init(_ code: NSErrorEnum) {
50 | self.init(domain:code.domain, code: code.rawValue, userInfo: [NSLocalizedDescriptionKey: code.errorDescription])
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodable/EncodeOperators.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EncodeOperators.swift
3 | // Codable
4 | //
5 | // Created by Brandon Sneed on 11/10/15.
6 | // Copyright © 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | //infix operator <== { associativity right precedence 150 }
12 |
13 | infix operator <== : ELEncodingPrecedence
14 |
15 | precedencegroup ELEncodingPrecedence {
16 | associativity: right
17 | higherThan: CastingPrecedence
18 | }
19 |
20 | public func <== (lhs: String, rhs: T) throws -> (String, JSON) {
21 | let value = try? rhs.encode()
22 | if let value = value {
23 | return (lhs, value)
24 | } else {
25 | throw ELEncodeError.unencodable
26 | }
27 | }
28 |
29 | public func <== (lhs: String, rhs: [T]) throws -> (String, JSON) {
30 | let value = try? rhs.encode()
31 | if let value = value {
32 | return (lhs, value)
33 | } else {
34 | throw ELEncodeError.unencodable
35 | }
36 | }
37 |
38 | public func <== (lhs: String, rhs: T?) throws -> (String, JSON) {
39 | if rhs == nil {
40 | return (lhs, JSON())
41 | }
42 |
43 | let value = try? rhs?.encode()
44 | if let value = value {
45 | return (lhs, value!)
46 | } else {
47 | return (lhs, JSON())
48 | }
49 | }
50 |
51 | public func <== (lhs: String, rhs: [T]?) throws -> (String, JSON) {
52 | if rhs == nil {
53 | return (lhs, JSON())
54 | }
55 |
56 | let value = try? rhs?.encode()
57 | if let value = value {
58 | return (lhs, value!)
59 | } else {
60 | return (lhs, JSON())
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/ModuloKit/Specs/DependencySpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DependencySpec.swift
3 | // ModuloKit
4 | //
5 | // Created by Brandon Sneed on 6/16/16.
6 | // Copyright © 2016 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | #if NOFRAMEWORKS
11 | #else
12 | import ELCodable
13 | #endif
14 |
15 | public struct DependencySpec {
16 | // repository url to fetch the dep from
17 | var repositoryURL: String
18 | // version or version range
19 | var version: SemverRange?
20 |
21 | var unmanaged: Bool {
22 | get {
23 | return (version == nil)
24 | }
25 | }
26 | }
27 |
28 | extension DependencySpec: ELDecodable {
29 | public static func decode(_ json: JSON?) throws -> DependencySpec {
30 | return try DependencySpec(
31 | repositoryURL: json ==> "repositoryURL",
32 | version: json ==> "version"
33 | )
34 | }
35 |
36 | public func validate() throws -> DependencySpec {
37 | return self
38 | }
39 | }
40 |
41 | extension DependencySpec: ELEncodable {
42 | public func encode() throws -> JSON {
43 | return try encodeToJSON([
44 | "repositoryURL" <== repositoryURL,
45 | "version" <== version
46 | ])
47 | }
48 | }
49 |
50 | extension DependencySpec {
51 | public func name() -> String {
52 | return repositoryURL.nameFromRemoteURL()
53 | }
54 | }
55 |
56 | extension DependencySpec: Hashable {
57 | public var hashValue: Int {
58 | return repositoryURL.hashValue
59 | }
60 | }
61 |
62 | public func ==(lhs: DependencySpec, rhs: DependencySpec) -> Bool {
63 | return lhs.repositoryURL == rhs.repositoryURL
64 | }
65 |
66 |
67 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundation/TestExtensions/TestHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestHelper.swift
3 | // ELFoundation
4 | //
5 | // Created by Brandon Sneed on 8/13/15.
6 | // Copyright © 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /**
12 | Determines if a given block of code is being run within the context of
13 | a unit test.
14 | */
15 | public func isInUnitTest() -> Bool {
16 | if ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil {
17 | return true
18 | }
19 | return false
20 | }
21 |
22 | private enum WaitConditionError: Error {
23 | case timeout
24 | }
25 |
26 | extension NSObject {
27 | /**
28 | Pumps the run loop while waiting for the given conditions check to return true, or the timeout has
29 | expired. This function should only be used within unit tests, and will throw an exception if not.
30 | - parameter timeout: The timeout, in seconds.
31 | - parameter conditionsCheck: A block that performs the condition check and returns true/false.
32 | */
33 | public func waitForConditionsWithTimeout(_ timeout: TimeInterval, conditionsCheck: () -> Bool) throws {
34 | if isInUnitTest() {
35 | var condition = false
36 | let startTime = Date()
37 |
38 | while (!condition) {
39 | RunLoop.current.run(until: Date.distantPast)
40 | condition = conditionsCheck()
41 | let currentTime = Date().timeIntervalSince(startTime)
42 | if currentTime > timeout {
43 | throw WaitConditionError.timeout
44 | }
45 | }
46 | } else {
47 | exceptionFailure("waitForConditionsWithTimeout should only be used in unit tests.")
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Documentation/modulo-layout.1.md:
--------------------------------------------------------------------------------
1 | modulo-layout(1) -- Explains the file system layout
2 | ====
3 |
4 | ## RELATIONSHIPS
5 |
6 | Modulo understands relationships between _modules_ and _applications_. Modules may be dependent as peers, whereas an application depends on a set of modules:
7 |
8 | Module -> [Module, Module, ...]
9 | Application -> [Module, Module, ...]
10 |
11 | (Note: nothing can be dependent on an application)
12 |
13 | As an example, let's consider an application named "Fancy App" that depends on some shared components and media assets. To make it a little more complicated, one of the shared components also depends on a utility library.
14 |
15 | In other words, there are two sets of dependencies to be managed:
16 |
17 | Fancy App -> [Component A, Component B, Assets]
18 | Component A -> [Utilities]
19 |
20 | These dependencies will get arranged directory structure as such:
21 |
22 | Fancy App/
23 | modules/
24 | Component A/
25 | Component B/
26 | Utilities/
27 | Assets/
28 |
29 | Note that "Fancy App" is the root, and that all of the modules are checked out into the `modules/` directory, including the `Utilities` dependency.
30 |
31 | To put a twist on this scenario, if you're developing on `Component A` in isolation, and you only want to check it out with it's dependencies, you would end up with a directory structure like this:
32 |
33 | Component A/
34 | Utilities/
35 |
36 | ... Where `Component A` and `Utilities` are peers in the file system.
37 |
38 | ## SEE ALSO
39 |
40 | modulo(1), modulo-init(1), modulo-update(1)
41 |
42 | ## REPORTING BUGS
43 |
44 | Report bugs to the Github Project located at https://github.com/modulo-dm/modulo/. You'll be able to see the status and track any issues you create.
45 |
46 | ## AUTHORS
47 |
48 | Brandon Sneed
49 | Peat Bakke
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Documentation/modulo-layout.1.ronn:
--------------------------------------------------------------------------------
1 | modulo-layout(1) -- Explains the file system layout
2 | ====
3 |
4 | ## RELATIONSHIPS
5 |
6 | Modulo understands relationships between _modules_ and _applications_. Modules may be dependent as peers, whereas an application depends on a set of modules:
7 |
8 | Module -> [Module, Module, ...]
9 | Application -> [Module, Module, ...]
10 |
11 | (Note: nothing can be dependent on an application)
12 |
13 | As an example, let's consider an application named "Fancy App" that depends on some shared components and media assets. To make it a little more complicated, one of the shared components also depends on a utility library.
14 |
15 | In other words, there are two sets of dependencies to be managed:
16 |
17 | Fancy App -> [Component A, Component B, Assets]
18 | Component A -> [Utilities]
19 |
20 | These dependencies will get arranged directory structure as such:
21 |
22 | Fancy App/
23 | modules/
24 | Component A/
25 | Component B/
26 | Utilities/
27 | Assets/
28 |
29 | Note that "Fancy App" is the root, and that all of the modules are checked out into the `modules/` directory, including the `Utilities` dependency.
30 |
31 | To put a twist on this scenario, if you're developing on `Component A` in isolation, and you only want to check it out with it's dependencies, you would end up with a directory structure like this:
32 |
33 | Component A/
34 | Utilities/
35 |
36 | ... Where `Component A` and `Utilities` are peers in the file system.
37 |
38 | ## SEE ALSO
39 |
40 | modulo(1), modulo-init(1), modulo-update(1)
41 |
42 | ## REPORTING BUGS
43 |
44 | Report bugs to the Github Project located at https://github.com/modulo-dm/modulo/. You'll be able to see the status and track any issues you create.
45 |
46 | ## AUTHORS
47 |
48 | Brandon Sneed
49 | Peat Bakke
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundation/Extensions/NSThread.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSThread.swift
3 | // ELFoundation
4 | //
5 | // Created by Brandon Sneed on 3/16/15.
6 | // Copyright (c) 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public extension Thread {
12 | fileprivate static let formatterCacheKey = "ELFoundation.dateFormatter"
13 |
14 | /**
15 | Creates and returns a date formatter for the format and locale. The first time a format is passed in
16 | the date formatter is created and cached per thread. This ensures that the costly creation of a date formatter is
17 | only done once. Formatters are also created per thread as their underlying implementation hasn't been thread-safe
18 | until recent versions of iOS. This last requirement may be removed in a future version of this method.
19 |
20 | - parameter format: The date format for the creating the date formatter.
21 | - parameter locale: The locale for the date formatter.
22 | - returns: The date formatter.
23 | */
24 | public class func dateFormatter(_ format: String, locale: Locale? = Locale.current) -> DateFormatter {
25 | let threadDictionary = Thread.current.threadDictionary
26 |
27 | var cache: Dictionary? = threadDictionary.object(forKey: formatterCacheKey) as? Dictionary
28 | if cache == nil {
29 | cache = Dictionary()
30 | }
31 |
32 | let formatKey = format + "_" + locale!.identifier
33 | if let existing = cache?[formatKey] {
34 | return existing
35 | }
36 |
37 | let result = DateFormatter()
38 | result.locale = locale
39 | result.dateFormat = format
40 | cache?[formatKey] = result
41 |
42 | threadDictionary[formatterCacheKey] = cache
43 |
44 | return result;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Documentation/modulo-update.1.md:
--------------------------------------------------------------------------------
1 | modulo-update(1) -- Update the project based on the current set of dependencies.
2 | ====
3 |
4 | ## SYNOPSIS
5 |
6 | `modulo update` [--all]
7 | `modulo update`
8 |
9 | ## DESCRIPTION
10 |
11 | This command updates any previously specified dependencies. Updates can consist of the following:
12 |
13 | * Cloning any dependencies that don't exist in the filesystem yet.
14 | * Performing a fetch on dependencies to get any new tags/branches/commits
15 | * Verifying that it's safe to check out the specified tag/branch/commit.
16 | * Checking out the specified tag/branch/commit for each dependency.
17 |
18 | ## OPTIONS
19 |
20 | * `-a, --all`:
21 | This will iterate through all dependencies and perform an update.
22 |
23 | * :
24 | Instructs Modulo to just perform an update on the specified dependency. See `map` for a list of dependencies.
25 |
26 | * `--nonzero:
27 | Returns a non-zero result if modulo actually cloned dependencies. This is useful for CI build systems.
28 |
29 | * `--host `:
30 | Checks for ability to connect to host name before continuing. This allows for developers to work off-line without being interrupted.
31 |
32 | * `--meh`:
33 | Update will perform a no-op if modulo isn't being used on this project. Useful for build system integration.
34 |
35 | * `-v, --verbose`:
36 | Prints verbose output. Use this to see what underlying SCM commands are being used and any other important information.
37 |
38 | * `-h, --help`:
39 | Prints the help for this command.
40 |
41 | ## SEE ALSO
42 |
43 | modulo-layout(1), modulo-map(1)
44 |
45 | ## REPORTING BUGS
46 |
47 | Report bugs to the Github Project located at https://github.com/modulo-dm/modulo/. You'll be able to see the status and track any issues you create.
48 |
49 | ## AUTHORS
50 |
51 | Brandon Sneed
52 | Peat Bakke
53 |
54 |
55 |
--------------------------------------------------------------------------------
/Documentation/modulo-update.1.ronn:
--------------------------------------------------------------------------------
1 | modulo-update(1) -- Update the project based on the current set of dependencies.
2 | ====
3 |
4 | ## SYNOPSIS
5 |
6 | `modulo update` [--all]
7 | `modulo update`
8 |
9 | ## DESCRIPTION
10 |
11 | This command updates any previously specified dependencies. Updates can consist of the following:
12 |
13 | * Cloning any dependencies that don't exist in the filesystem yet.
14 | * Performing a fetch on dependencies to get any new tags/branches/commits
15 | * Verifying that it's safe to check out the specified tag/branch/commit.
16 | * Checking out the specified tag/branch/commit for each dependency.
17 |
18 | ## OPTIONS
19 |
20 | * `-a, --all`:
21 | This will iterate through all dependencies and perform an update.
22 |
23 | * :
24 | Instructs Modulo to just perform an update on the specified dependency. See `map` for a list of dependencies.
25 |
26 | * `--nonzero:
27 | Returns a non-zero result if modulo actually cloned dependencies. This is useful for CI build systems.
28 |
29 | * `--host `:
30 | Checks for ability to connect to host name before continuing. This allows for developers to work off-line without being interrupted.
31 |
32 | * `--meh`:
33 | Update will perform a no-op if modulo isn't being used on this project. Useful for build system integration.
34 |
35 | * `-v, --verbose`:
36 | Prints verbose output. Use this to see what underlying SCM commands are being used and any other important information.
37 |
38 | * `-h, --help`:
39 | Prints the help for this command.
40 |
41 | ## SEE ALSO
42 |
43 | modulo-layout(1), modulo-map(1)
44 |
45 | ## REPORTING BUGS
46 |
47 | Report bugs to the Github Project located at https://github.com/modulo-dm/modulo/. You'll be able to see the status and track any issues you create.
48 |
49 | ## AUTHORS
50 |
51 | Brandon Sneed
52 | Peat Bakke
53 |
54 |
55 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodableTests/KeyPathTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // KeyPathTests.swift
3 | // ELCodable
4 | //
5 | // Created by Brandon Sneed on 3/15/16.
6 | // Copyright © 2016 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import ELCodable
11 |
12 | struct VersionModel {
13 | let minVersion: String
14 | let url: String
15 | let version: String
16 | }
17 |
18 | extension VersionModel: Decodable {
19 | static func decode(json: JSON?) throws -> VersionModel {
20 | return try VersionModel(
21 | minVersion: json?["appVersion"]?["iOS"] ==> "minVersion",
22 | url: json?["appVersion"]?["iOS"] ==> "url",
23 | version: json?["appVersion"]?["iOS"] ==> "version"
24 | )
25 | }
26 | }
27 |
28 | class KeyPathTests: XCTestCase {
29 |
30 | override func setUp() {
31 | super.setUp()
32 | // Put setup code here. This method is called before the invocation of each test method in the class.
33 | }
34 |
35 | override func tearDown() {
36 | // Put teardown code here. This method is called after the invocation of each test method in the class.
37 | super.tearDown()
38 | }
39 |
40 | func testUglyKeyPath() {
41 | guard let json = JSON(bundleClass: ELCodableTests.self, filename: "jsontest_models.json") else {
42 | assertionFailure("the json is missing.")
43 | return
44 | }
45 |
46 | var thrownError: ErrorType? = nil
47 |
48 | do {
49 | let model = try VersionModel.decode(json)
50 | XCTAssertTrue(model.minVersion == "0.1.4")
51 | XCTAssertTrue(model.url == "https://walmart.com/change-me")
52 | XCTAssertTrue(model.version == "0.1.4")
53 | } catch let error {
54 | thrownError = error
55 | }
56 |
57 | XCTAssertTrue(thrownError == nil)
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodableTests/OptionalTests.json:
--------------------------------------------------------------------------------
1 | {
2 | "data": {
3 | "storeId": 2280,
4 | "items": [
5 | {
6 | "format": "UPC",
7 | "identifier": "887276062013",
8 | "quantity": 1,
9 | "itemId": 554069138,
10 | "departmentId": 72,
11 | "subCategoryId": 42,
12 | "name": "SAM 55 LED 55J6200",
13 | "normalizedUpc": "88727606201",
14 | "unitPrice": 748,
15 | "upc": "88727606201",
16 | "packagePrice": 748,
17 | "isWeighted": false,
18 | "price": 748,
19 | "isProductFee": false,
20 | "taxRates": {
21 | "tax1": 8.75
22 | },
23 | "tax": 65.45
24 | },
25 | {
26 | "format" : "UPC",
27 | "identifier": "0068113180661",
28 | "quantity": 1,
29 | "itemId": 593908,
30 | "departmentId": 72,
31 | "subCategoryId": 85,
32 | "name": "CA RECYCLE FEE",
33 | "normalizedUpc": "68113180661",
34 | "unitPrice": 5,
35 | "upc": "0068113180661",
36 | "packagePrice": 5,
37 | "isWeighted": false,
38 | "price": 5,
39 | "isProductFee": true,
40 | "taxRates": {
41 | "tax12": 0
42 | },
43 | "tax": 0
44 | }
45 | ],
46 | "subtotal": 748,
47 | "productFees": 5,
48 | "tax": 65.45,
49 | "taxAmounts": {
50 | "tax1": 65.45,
51 | "tax12": 0
52 | },
53 | "total": 818.45
54 | }
55 | }
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodable/EncodableExtensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EncodableExtensions.swift
3 | // Codable
4 | //
5 | // Created by Brandon Sneed on 11/10/15.
6 | // Copyright © 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension String: ELEncodable {
12 | public func encode() throws -> JSON {
13 | return JSON(self as AnyObject?)
14 | }
15 | }
16 |
17 | extension Float: ELEncodable {
18 | public func encode() throws -> JSON {
19 | return JSON(self as AnyObject?)
20 | }
21 | }
22 |
23 | extension Double: ELEncodable {
24 | public func encode() throws -> JSON {
25 | return JSON(self as AnyObject?)
26 | }
27 | }
28 |
29 | extension Int: ELEncodable {
30 | public func encode() throws -> JSON {
31 | return JSON(self as AnyObject?)
32 | }
33 | }
34 |
35 | extension Int64: ELEncodable {
36 | public func encode() throws -> JSON {
37 | return JSON(NSNumber(value: self as Int64))
38 | }
39 | }
40 |
41 | extension UInt: ELEncodable {
42 | public func encode() throws -> JSON {
43 | return JSON(self as AnyObject?)
44 | }
45 | }
46 |
47 | extension UInt64: ELEncodable {
48 | public func encode() throws -> JSON {
49 | return JSON(NSNumber(value: self as UInt64))
50 | }
51 | }
52 |
53 | extension Bool: ELEncodable {
54 | public func encode() throws -> JSON {
55 | return JSON(self as AnyObject?)
56 | }
57 | }
58 |
59 | extension Decimal: ELEncodable {
60 | public func encode() throws -> JSON {
61 | return JSON(self.value)
62 | }
63 | }
64 |
65 | extension Array where Element: ELEncodable {
66 | public func encode() throws -> JSON {
67 | var array = [Any]()
68 | for item in self {
69 | let jsonItem = try item.encode()
70 | if let object = jsonItem.object {
71 | array.append(object)
72 | }
73 | }
74 | return JSON(array as AnyObject?)
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/ModuloKit/Reachability.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Reachability.swift
3 | // modulo
4 | //
5 | // Created by Sneed, Brandon on 7/10/17.
6 | // Copyright © 2017 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import SystemConfiguration
11 |
12 | func canConnect(hostname: String) -> Bool {
13 | guard let ref = SCNetworkReachabilityCreateWithName(nil, hostname) else {
14 | return false
15 | }
16 |
17 | var flags = SCNetworkReachabilityFlags()
18 | let gotFlags = SCNetworkReachabilityGetFlags(ref, &flags)
19 |
20 | let result = gotFlags && flags.contains(.reachable) && !flags.contains(.connectionRequired)
21 |
22 | return result
23 | }
24 |
25 | /*func internetIsReachable() -> Bool {
26 | var zeroAddress = sockaddr()
27 | zeroAddress.sa_len = UInt8(MemoryLayout.size)
28 | zeroAddress.sa_family = sa_family_t(AF_INET)
29 |
30 | guard let ref: SCNetworkReachability = withUnsafePointer(to: &zeroAddress, {
31 | SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
32 | }) else {
33 | return false
34 | }
35 |
36 | var reachabilityFlags = SCNetworkReachabilityFlags()
37 | let flags = withUnsafeMutablePointer(to: &reachabilityFlags) {
38 | SCNetworkReachabilityGetFlags(ref, UnsafeMutablePointer($0))
39 | }
40 |
41 | /*
42 | guard isReachableFlagSet else { return false }
43 |
44 | if isConnectionRequiredAndTransientFlagSet {
45 | return false
46 | }
47 |
48 | if isRunningOnDevice {
49 | if isOnWWANFlagSet && !reachableOnWWAN {
50 | // We don't want to connect when on 3G.
51 | return false
52 | }
53 | }
54 |
55 | return true
56 | */
57 |
58 |
59 | let reachable = reachabilityFlags.contains(.reachable)
60 | let connRequired = reachabilityFlags.intersection([.connectionRequired, .transientConnection]) == [.connectionRequired, .transientConnection]
61 |
62 | }*/
63 |
--------------------------------------------------------------------------------
/Documentation/modulo.1.md:
--------------------------------------------------------------------------------
1 | modulo(1) -- A source-only dependency manager
2 | ====
3 |
4 | ## SYNOPSIS
5 |
6 | `modulo` [--version] [--help]
7 |
8 | ## DESCRIPTION
9 |
10 | Modulo is a source-only dependency manager. Its primary goal is to orchestrate repositories and filesystem assets for large, modular projects. For example, collections of services or libraries or components that have versioned dependencies between themselves.
11 |
12 | Modulo manages collections of dependent, versioned repositories. It leaves build concerns to build systems (eg: Xcode, Xcodebuild, Maven, make, etc), and is designed to be agnostic about source code management systems (eg: Git, Subversion*).
13 |
14 | A formatted and hyperlinked copy of the latest Modulo documentation can be viewed at https://github.com/modulo-dm/modulo
15 |
16 | \* only git is currently supported at the moment, others to follow
17 |
18 | ## OPTIONS
19 |
20 | * `--version`:
21 | Prints the Modulo version number.
22 |
23 | * `-h, --help`:
24 | Prints the synopsis and a list of the most commonly used commands.
25 |
26 | ## MODULO COMMANDS
27 |
28 | We divide modulo into high level commands, each with their own `--help` information.
29 |
30 | * `modulo-init(1)`:
31 | Initialize Modulo for a given project.
32 |
33 | * `modulo-add(1)`:
34 | Add a dependency to a given project.
35 |
36 | * `modulo-update(1)`:
37 | Update dependencies on a given project.
38 |
39 | * `modulo-remove(1)`:
40 | Remove dependency from a given project.
41 |
42 | * `modulo-status(1)`:
43 | Shows the overall status of a project and it's dependencies.
44 |
45 | * `modulo-map(1)`:
46 | Display a map of the dependency tree for a given project.
47 |
48 | ## FILE/DIRECTORY STRUCTURE
49 |
50 | Please see `modulo-layout(1)`
51 |
52 | ## REPORTING BUGS
53 |
54 | Report bugs to the Github Project located at https://github.com/modulo-dm/modulo/. You'll be able to see the status and track any issues you create.
55 |
56 | ## AUTHORS
57 |
58 | Brandon Sneed
59 | Peat Bakke
60 |
61 |
62 |
--------------------------------------------------------------------------------
/Documentation/modulo.1.ronn:
--------------------------------------------------------------------------------
1 | modulo(1) -- A source-only dependency manager
2 | ====
3 |
4 | ## SYNOPSIS
5 |
6 | `modulo` [--version] [--help]
7 |
8 | ## DESCRIPTION
9 |
10 | Modulo is a source-only dependency manager. Its primary goal is to orchestrate repositories and filesystem assets for large, modular projects. For example, collections of services or libraries or components that have versioned dependencies between themselves.
11 |
12 | Modulo manages collections of dependent, versioned repositories. It leaves build concerns to build systems (eg: Xcode, Xcodebuild, Maven, make, etc), and is designed to be agnostic about source code management systems (eg: Git, Subversion*).
13 |
14 | A formatted and hyperlinked copy of the latest Modulo documentation can be viewed at https://github.com/modulo-dm/modulo
15 |
16 | \* only git is currently supported at the moment, others to follow
17 |
18 | ## OPTIONS
19 |
20 | * `--version`:
21 | Prints the Modulo version number.
22 |
23 | * `-h, --help`:
24 | Prints the synopsis and a list of the most commonly used commands.
25 |
26 | ## MODULO COMMANDS
27 |
28 | We divide modulo into high level commands, each with their own `--help` information.
29 |
30 | * `modulo-init(1)`:
31 | Initialize Modulo for a given project.
32 |
33 | * `modulo-add(1)`:
34 | Add a dependency to a given project.
35 |
36 | * `modulo-update(1)`:
37 | Update dependencies on a given project.
38 |
39 | * `modulo-remove(1)`:
40 | Remove dependency from a given project.
41 |
42 | * `modulo-status(1)`:
43 | Shows the overall status of a project and it's dependencies.
44 |
45 | * `modulo-map(1)`:
46 | Display a map of the dependency tree for a given project.
47 |
48 | ## FILE/DIRECTORY STRUCTURE
49 |
50 | Please see `modulo-layout(1)`
51 |
52 | ## REPORTING BUGS
53 |
54 | Report bugs to the Github Project located at https://github.com/modulo-dm/modulo/. You'll be able to see the status and track any issues you create.
55 |
56 | ## AUTHORS
57 |
58 | Brandon Sneed
59 | Peat Bakke
60 |
61 |
62 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/README.md:
--------------------------------------------------------------------------------
1 | # ELFoundation
2 |
3 | [](https://github.com/Electrode-iOS/ELFoundation/releases/latest)
4 | [](https://travis-ci.org/Electrode-iOS/ELFoundation)
5 | [](https://github.com/Carthage/Carthage)
6 |
7 | ELFoundation is a collection of Swift utilities for iOS development.
8 |
9 | ## Requirements
10 |
11 | ELFoundation requires Swift 3 and Xcode 8.
12 |
13 | ## Installation
14 |
15 | ### Carthage
16 |
17 | Install with [Carthage](https://github.com/Carthage/Carthage) by adding the framework to your project's [Cartfile](https://github.com/Carthage/Carthage/blob/master/Documentation/Artifacts.md#cartfile).
18 |
19 | ```
20 | github "Electrode-iOS/ELFoundation" ~> 1.1.0
21 | ```
22 |
23 | ### Manual
24 |
25 | Install by adding `ELFoundation.xcodeproj` to your project and configuring your target to link `ELFoundation.framework`.
26 |
27 | ## Usage
28 |
29 | * `exceptionFailure` - A replacement for assertionFailure, usable in tests.
30 | * `synchronized` - Akin to @synchronized() in Objective-C.
31 | * `Spinlock` - A basic spinlock implementation for synchronization.
32 | * `Object Association` - Objective-C style object association.
33 | * `Swizzling` - Objective-C style swizzling.
34 | * `String (extensions)` - Handy extensions.
35 | * `Array (extensions)` - Handy extensions.
36 | * `NSObject (extensions)` - Handy extensions.
37 | * `NSThread (extensions)` - Handy extensions.
38 | * `NSError (extensions)` - Handy extensions.
39 | * `NSBundle (extensions)` - Handy extensions.
40 | * `XCTestCase (extensions)` - Gets XCTAssertThrows working in Swift.
41 |
42 | ## Some Examples
43 |
44 | Synchronized property access:
45 |
46 | ```Swift
47 | public var suspended: Bool {
48 | get {
49 | return lock.around {
50 | self.suspended
51 | }
52 | }
53 |
54 | set(value) {
55 | lock.around {
56 | self.suspended = value
57 | }
58 | }
59 | }
60 | ```
61 |
--------------------------------------------------------------------------------
/Modules/ELCLI/ELCLITests/CommitCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CommitCommand.swift
3 | // ELCLI
4 | //
5 | // Created by Brandon Sneed on 8/12/15.
6 | // Copyright © 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ELCLI
11 |
12 | public class CommitCommand: NSObject, Command {
13 | // Internal properties
14 | public var all: Bool = false
15 | public var patch: Bool = false
16 | public var commit: String? = nil
17 | public var message: String? = nil
18 |
19 | public var nonFlagValues = Array()
20 |
21 | // Protocol conformance
22 | public var name: String { return "commit" }
23 | public var helpDescription: String { return "Record changes to the repository" }
24 | public var failOnUnrecognizedOptions: Bool { return true }
25 |
26 | public var verbose: Bool = false
27 | public var quiet: Bool = false
28 |
29 | public func configureOptions() {
30 | addOption(["-a", "--all"], usage: "commit all changed files") { (option, value) -> Void in
31 | self.all = true
32 | }
33 |
34 | addOption(["-p", "--patch"], usage: "interactively add changes") { (option, value) -> Void in
35 | self.patch = true
36 | }
37 |
38 | addOptionValue(["-c", "-C", "--commit"], usage: "reuse message from specified commit", valueSignature: "") { (option, value) -> Void in
39 | self.commit = value
40 | }
41 |
42 | addOptionValue(["-m", "--message"], usage: "commit message", valueSignature: "") { (option, value) -> Void in
43 | self.message = value
44 | }
45 |
46 | addFlaglessOptionValues(["", ""]) { (option, value) -> Void in
47 | if let value = value {
48 | self.nonFlagValues.append(value)
49 | }
50 | }
51 | }
52 |
53 | public func execute(otherParams: Array?) -> CLIResult {
54 | var result = CLIResult()
55 |
56 | result.resultCode = 0
57 | result.resultDescription = "Success"
58 | result.executedCommand = self
59 |
60 | return result
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundationTests/ELFoundationTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ELFoundationTests.swift
3 | // ELFoundationTests
4 | //
5 | // Created by Brandon Sneed on 2/19/15.
6 | // Copyright (c) 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import ELFoundation
11 |
12 | class Foo: NSObject {
13 | dynamic func returnsOne() -> Int {
14 | return 1
15 | }
16 |
17 | dynamic class func returnsThree() -> Int {
18 | return 3
19 | }
20 | }
21 |
22 | extension Foo {
23 | dynamic func returnsTwo() -> Int {
24 | return 2
25 | }
26 |
27 | dynamic class func returnsFour() -> Int {
28 | return 4
29 | }
30 | }
31 |
32 | class Bar {
33 |
34 | }
35 |
36 | class ELFoundationTests: XCTestCase {
37 |
38 | override func setUp() {
39 | super.setUp()
40 | // Put setup code here. This method is called before the invocation of each test method in the class.
41 | }
42 |
43 | override func tearDown() {
44 | // Put teardown code here. This method is called after the invocation of each test method in the class.
45 | super.tearDown()
46 | }
47 |
48 | func test_swizzleInstanceMethod_replacesImplementationWithSwizzledSelector() {
49 | let foo = Foo()
50 | XCTAssertTrue(foo.returnsOne() == 1)
51 |
52 | Foo.swizzleInstanceMethod(#selector(Foo.returnsOne), swizzledSelector: #selector(Foo.returnsTwo))
53 |
54 | XCTAssertTrue(foo.returnsOne() == 2)
55 | }
56 |
57 | func test_swizzleClassMethod_replacesImplementationWithSwizzledSelector() {
58 | XCTAssertTrue(Foo.returnsThree() == 3)
59 |
60 | Foo.swizzleClassMethod(#selector(Foo.returnsThree), swizzledSelector: #selector(Foo.returnsFour))
61 |
62 | XCTAssertTrue(Foo.returnsThree() == 4)
63 | }
64 |
65 | func testObjectAssociation() {
66 | let bar = Bar()
67 | let storedValue = "O'HAI"
68 | setAssociatedObject(bar, value: storedValue, associativeKey: "AnAssociationkey", policy: objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
69 | let retrievedValue = getAssociatedObject(bar, associativeKey: "AnAssociationkey") as String!
70 | XCTAssertTrue(retrievedValue == storedValue)
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodable/DecodeOperators.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DecodeOperators.swift
3 | // Codable
4 | //
5 | // Created by Brandon Sneed on 11/3/15.
6 | // Copyright © 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | //infix operator ==> { associativity right precedence 150 }
12 |
13 | infix operator ==> : DecodingPrecedence
14 |
15 | precedencegroup DecodingPrecedence {
16 | associativity: right
17 | higherThan: CastingPrecedence
18 | }
19 |
20 | public func ==> (lhs: JSON?, rhs: String) throws -> T {
21 | guard let json = lhs else {
22 | throw ELDecodeError.emptyJSON
23 | }
24 |
25 | do {
26 | let value: T? = try? T.decode(json[rhs])
27 | if let value = value {
28 | return value
29 | } else {
30 | throw ELDecodeError.notFound(key: rhs)
31 | }
32 | } catch let error {
33 | throw error
34 | }
35 | }
36 |
37 | public func ==> (lhs: JSON?, rhs: String) throws -> [T] {
38 | guard let json = lhs else {
39 | throw ELDecodeError.emptyJSON
40 | }
41 |
42 | guard let array = json[rhs]?.array else {
43 | throw ELDecodeError.notFound(key: rhs)
44 | }
45 |
46 | var results = [T]()
47 |
48 | for json in array {
49 | // will throw a NotFound() if this decode fails.
50 | let value = try T.decode(json)
51 | results.append(value)
52 | }
53 |
54 | return results
55 | }
56 |
57 | public func ==> (lhs: JSON?, rhs: String) throws -> T? {
58 | guard let json = lhs else {
59 | throw ELDecodeError.emptyJSON
60 | }
61 |
62 | let value = try? T.decode(json[rhs])
63 | if let value = value {
64 | return value
65 | } else {
66 | return nil
67 | }
68 | }
69 |
70 | public func ==> (lhs: JSON?, rhs: String) throws -> [T]? {
71 | guard let json = lhs else {
72 | throw ELDecodeError.emptyJSON
73 | }
74 |
75 | guard let array = json[rhs]?.array else {
76 | return nil
77 | }
78 |
79 | var results = [T]()
80 |
81 | for json in array {
82 | if let value = try? T.decode(json) {
83 | results.append(value)
84 | }
85 | }
86 |
87 | return results
88 | }
89 |
90 |
--------------------------------------------------------------------------------
/Documentation/modulo.1:
--------------------------------------------------------------------------------
1 | .\" generated with Ronn/v0.7.3
2 | .\" http://github.com/rtomayko/ronn/tree/0.7.3
3 | .
4 | .TH "MODULO" "1" "July 2017" "Modulo" "Modulo manual"
5 | .
6 | .SH "NAME"
7 | \fBmodulo\fR \- A source\-only dependency manager
8 | .
9 | .SH "SYNOPSIS"
10 | \fBmodulo\fR [\-\-version] [\-\-help]
11 | .
12 | .SH "DESCRIPTION"
13 | Modulo is a source\-only dependency manager\. Its primary goal is to orchestrate repositories and filesystem assets for large, modular projects\. For example, collections of services or libraries or components that have versioned dependencies between themselves\.
14 | .
15 | .P
16 | Modulo manages collections of dependent, versioned repositories\. It leaves build concerns to build systems (eg: Xcode, Xcodebuild, Maven, make, etc), and is designed to be agnostic about source code management systems (eg: Git, Subversion*)\.
17 | .
18 | .P
19 | A formatted and hyperlinked copy of the latest Modulo documentation can be viewed at https://github\.com/modulo\-dm/modulo
20 | .
21 | .P
22 | * only git is currently supported at the moment, others to follow
23 | .
24 | .SH "OPTIONS"
25 | .
26 | .TP
27 | \fB\-\-version\fR
28 | Prints the Modulo version number\.
29 | .
30 | .TP
31 | \fB\-h, \-\-help\fR
32 | Prints the synopsis and a list of the most commonly used commands\.
33 | .
34 | .SH "MODULO COMMANDS"
35 | We divide modulo into high level commands, each with their own \fB\-\-help\fR information\.
36 | .
37 | .TP
38 | \fBmodulo\-init(1)\fR
39 | Initialize Modulo for a given project\.
40 | .
41 | .TP
42 | \fBmodulo\-add(1)\fR
43 | Add a dependency to a given project\.
44 | .
45 | .TP
46 | \fBmodulo\-update(1)\fR
47 | Update dependencies on a given project\.
48 | .
49 | .TP
50 | \fBmodulo\-remove(1)\fR
51 | Remove dependency from a given project\.
52 | .
53 | .TP
54 | \fBmodulo\-status(1)\fR
55 | Shows the overall status of a project and it\'s dependencies\.
56 | .
57 | .TP
58 | \fBmodulo\-map(1)\fR
59 | Display a map of the dependency tree for a given project\.
60 | .
61 | .SH "FILE/DIRECTORY STRUCTURE"
62 | Please see \fBmodulo\-layout(1)\fR
63 | .
64 | .SH "REPORTING BUGS"
65 | Report bugs to the Github Project located at https://github\.com/modulo\-dm/modulo/\. You\'ll be able to see the status and track any issues you create\.
66 | .
67 | .SH "AUTHORS"
68 | Brandon Sneed \fIbrandon@redf\.net\fR
69 | .
70 | .br
71 | Peat Bakke \fIpeat@peat\.org\fR
72 |
--------------------------------------------------------------------------------
/Documentation/modulo-update.1:
--------------------------------------------------------------------------------
1 | .\" generated with Ronn/v0.7.3
2 | .\" http://github.com/rtomayko/ronn/tree/0.7.3
3 | .
4 | .TH "MODULO\-UPDATE" "1" "July 2017" "Modulo" "Modulo manual"
5 | .
6 | .SH "NAME"
7 | \fBmodulo\-update\fR \- Update the project based on the current set of dependencies\.
8 | .
9 | .SH "SYNOPSIS"
10 | \fBmodulo update\fR [\-\-all]
11 | .
12 | .br
13 | \fBmodulo update\fR \fIdependencyname\fR
14 | .
15 | .br
16 | .
17 | .SH "DESCRIPTION"
18 | This command updates any previously specified dependencies\. Updates can consist of the following:
19 | .
20 | .IP "\(bu" 4
21 | Cloning any dependencies that don\'t exist in the filesystem yet\.
22 | .
23 | .IP "\(bu" 4
24 | Performing a fetch on dependencies to get any new tags/branches/commits
25 | .
26 | .IP "\(bu" 4
27 | Verifying that it\'s safe to check out the specified tag/branch/commit\.
28 | .
29 | .IP "\(bu" 4
30 | Checking out the specified tag/branch/commit for each dependency\.
31 | .
32 | .IP "" 0
33 | .
34 | .SH "OPTIONS"
35 | .
36 | .TP
37 | \fB\-a, \-\-all\fR
38 | This will iterate through all dependencies and perform an update\.
39 | .
40 | .TP
41 | \fIdependencyname\fR
42 | Instructs Modulo to just perform an update on the specified dependency\. See \fBmap\fR for a list of dependencies\.
43 | .
44 | .TP
45 | `\-\-nonzero
46 | Returns a non\-zero result if modulo actually cloned dependencies\. This is useful for CI build systems\.
47 | .
48 | .TP
49 | \fB\-\-host \fR
50 | Checks for ability to connect to host name before continuing\. This allows for developers to work off\-line without being interrupted\.
51 | .
52 | .TP
53 | \fB\-\-meh\fR
54 | Update will perform a no\-op if modulo isn\'t being used on this project\. Useful for build system integration\.
55 | .
56 | .TP
57 | \fB\-v, \-\-verbose\fR
58 | Prints verbose output\. Use this to see what underlying SCM commands are being used and any other important information\.
59 | .
60 | .TP
61 | \fB\-h, \-\-help\fR
62 | Prints the help for this command\.
63 | .
64 | .SH "SEE ALSO"
65 | modulo\-layout(1), modulo\-map(1)
66 | .
67 | .SH "REPORTING BUGS"
68 | Report bugs to the Github Project located at https://github\.com/modulo\-dm/modulo/\. You\'ll be able to see the status and track any issues you create\.
69 | .
70 | .SH "AUTHORS"
71 | Brandon Sneed \fIbrandon@redf\.net\fR
72 | .
73 | .br
74 | Peat Bakke \fIpeat@peat\.org\fR
75 | .
76 | .br
77 |
78 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodableTests/jsontest_models.json:
--------------------------------------------------------------------------------
1 | {
2 | "mystring": "hello",
3 | "myuint": 1234,
4 | "mynumber": 3.14,
5 | "myarray1": [
6 | "1",
7 | "2",
8 | "3",
9 | "4"
10 | ],
11 | "myarray2": [
12 | "1",
13 | "2",
14 | "3",
15 | "4"
16 | ],
17 | "myobject": {
18 | "mystring": "sub-hello"
19 | },
20 | "myobjectarray": [
21 | {
22 | "mystring": "value1",
23 | },
24 | {
25 | "mystring": "value2",
26 | },
27 | {
28 | "mystring": "value3",
29 | },
30 | {
31 | "mystring": "value4",
32 | },
33 | ],
34 | "mydictionary": {
35 | "someItem": {
36 | "mystring": "someItem"
37 | },
38 | "someOtherItem": {
39 | "mystring": "someOtherItem"
40 | }
41 | },
42 | "null": null,
43 | "string": "a string",
44 | "stringNumber": "1234",
45 | "bool": true,
46 | "int": -1234,
47 | "int32": -2147483647,
48 | "int64": -9223372036854775807,
49 | "uint": 4294967295,
50 | "uint32": 4294967295,
51 | "uint64": 18446744073709551615,
52 | "float": 0.08251977,
53 | "double": 0.333333333333333314829616256247390992939,
54 | "boolString": "yes",
55 | "intString": "-1234",
56 | "int32String": "-2147483647",
57 | "int64String": "-9223372036854775807",
58 | "uintString": "1234",
59 | "uint32String": "4294967295",
60 | "uint64String": "18446744073709551615",
61 | "floatString": "0.00000011920928955078125",
62 | "doubleString": "0.99999999999999994444444444444444444444333333333333333314829616256247390992939",
63 | "decimalNumber": 3402823669209384634633746074317682114550000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,
64 | "appVersion": {
65 | "android": {
66 | "minSDK": "5.1",
67 | "minVersion": "0.1.4",
68 | "url": "https://walmart.com/change-me",
69 | "version": "0.1.4"
70 | },
71 | "iOS": {
72 | "minVersion": "0.1.4",
73 | "url": "https://walmart.com/change-me",
74 | "version": "0.1.4"
75 | }
76 | },
77 | "storeIdWhitelist": [ 5260 ]
78 | }
--------------------------------------------------------------------------------
/Documentation/modulo-layout.1:
--------------------------------------------------------------------------------
1 | .\" generated with Ronn/v0.7.3
2 | .\" http://github.com/rtomayko/ronn/tree/0.7.3
3 | .
4 | .TH "MODULO\-LAYOUT" "1" "July 2017" "Modulo" "Modulo manual"
5 | .
6 | .SH "NAME"
7 | \fBmodulo\-layout\fR \- Explains the file system layout
8 | .
9 | .SH "RELATIONSHIPS"
10 | Modulo understands relationships between \fImodules\fR and \fIapplications\fR\. Modules may be dependent as peers, whereas an application depends on a set of modules:
11 | .
12 | .IP "" 4
13 | .
14 | .nf
15 |
16 | Module \-> [Module, Module, \.\.\.]
17 | Application \-> [Module, Module, \.\.\.]
18 | .
19 | .fi
20 | .
21 | .IP "" 0
22 | .
23 | .P
24 | (Note: nothing can be dependent on an application)
25 | .
26 | .P
27 | As an example, let\'s consider an application named "Fancy App" that depends on some shared components and media assets\. To make it a little more complicated, one of the shared components also depends on a utility library\.
28 | .
29 | .P
30 | In other words, there are two sets of dependencies to be managed:
31 | .
32 | .IP "" 4
33 | .
34 | .nf
35 |
36 | Fancy App \-> [Component A, Component B, Assets]
37 | Component A \-> [Utilities]
38 | .
39 | .fi
40 | .
41 | .IP "" 0
42 | .
43 | .P
44 | These dependencies will get arranged directory structure as such:
45 | .
46 | .IP "" 4
47 | .
48 | .nf
49 |
50 | Fancy App/
51 | modules/
52 | Component A/
53 | Component B/
54 | Utilities/
55 | Assets/
56 | .
57 | .fi
58 | .
59 | .IP "" 0
60 | .
61 | .P
62 | Note that "Fancy App" is the root, and that all of the modules are checked out into the \fBmodules/\fR directory, including the \fBUtilities\fR dependency\.
63 | .
64 | .P
65 | To put a twist on this scenario, if you\'re developing on \fBComponent A\fR in isolation, and you only want to check it out with it\'s dependencies, you would end up with a directory structure like this:
66 | .
67 | .IP "" 4
68 | .
69 | .nf
70 |
71 | Component A/
72 | Utilities/
73 | .
74 | .fi
75 | .
76 | .IP "" 0
77 | .
78 | .P
79 | \&\.\.\. Where \fBComponent A\fR and \fBUtilities\fR are peers in the file system\.
80 | .
81 | .SH "SEE ALSO"
82 | modulo(1), modulo\-init(1), modulo\-update(1)
83 | .
84 | .SH "REPORTING BUGS"
85 | Report bugs to the Github Project located at https://github\.com/modulo\-dm/modulo/\. You\'ll be able to see the status and track any issues you create\.
86 | .
87 | .SH "AUTHORS"
88 | .
89 | .nf
90 |
91 | Brandon Sneed
92 | Peat Bakke
93 | .
94 | .fi
95 |
96 |
--------------------------------------------------------------------------------
/ModuloKit/ErrorCode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ErrorCodes.swift
3 | // ModuloKit
4 | //
5 | // Created by Brandon Sneed on 6/16/16.
6 | // Copyright © 2016 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | #if NOFRAMEWORKS
11 | #else
12 | import ELCLI
13 | import ELFoundation
14 | #endif
15 |
16 | public enum ErrorCode: Int {
17 | case success = 0
18 | case unknownError
19 | case commandError
20 | case specNotFound
21 | case specNotWritable
22 | case scmNotFound
23 | case scmNotInitialized
24 | case alreadyInitialized
25 | case notInitialized
26 | case noMatchingDependencies
27 | case dependencyAlreadyExists
28 | case dependencyUnclean
29 | case dependencyUnknown
30 |
31 | var description: String {
32 | var result: String = ""
33 | switch self {
34 | case .success:
35 | break
36 | case .unknownError:
37 | result = "An unknown error occurred."
38 | case .commandError:
39 | result = "There was an error in the command line used."
40 | case .specNotFound:
41 | result = ".modulo file not found."
42 | case .specNotWritable:
43 | result = ".modulo cannot be written to, check permissions."
44 | case .scmNotFound:
45 | result = "No supported SCM was found."
46 | case .scmNotInitialized:
47 | result = "An SCM has not been initialized in this directory."
48 | case .alreadyInitialized:
49 | result = "Modulo has already been initialized."
50 | case .notInitialized:
51 | result = "Modulo has not been initialized."
52 | case .noMatchingDependencies:
53 | result = "No matching dependencies were found."
54 | case .dependencyAlreadyExists:
55 | result = "The dependency already exists."
56 | case .dependencyUnclean:
57 | result = "The dependency is not clean."
58 | case .dependencyUnknown:
59 | result = "The specified dependency is unknown."
60 | }
61 | return result
62 | }
63 | }
64 |
65 | internal func exit(_ code: ErrorCode, closure: (() -> Void)? = nil) {
66 | if code != .success {
67 | writeln(.stderr, code.description)
68 | }
69 |
70 | if let closure = closure {
71 | closure()
72 | }
73 |
74 | if isInUnitTest() {
75 | exceptionFailure(code.description)
76 | } else {
77 | exit(Int32(code.rawValue))
78 | }
79 | }
80 |
81 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundation/Utilities/Swizzling.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Swizzling.swift
3 | // ELFoundation
4 | //
5 | // Created by Brandon Sneed on 12/9/15.
6 | // Copyright © 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /**
12 | For the love of pete and the Flying Spaghetti Monster...
13 |
14 | Do not use this stuff unless you've inquired with no less than a Rabbi, a Priest,
15 | and a Shaman... and a few other engineers to figure out if there is a better way.
16 |
17 | */
18 | public extension NSObject {
19 | /// Swizzles a class method on an Objective-C object.
20 | public class func swizzleClassMethod(_ originalSelector: Selector, swizzledSelector:Selector) {
21 | guard let c: AnyClass = object_getClass(self),
22 | let originalMethod = class_getClassMethod(c, originalSelector),
23 | let swizzledMethod = class_getClassMethod(c, swizzledSelector) else {
24 | print("Error replacing \(originalSelector) on \(String(describing: object_getClass(self))) with \(swizzledSelector).")
25 | return
26 | }
27 |
28 | let didAddMethod = class_addMethod(c, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
29 |
30 | if didAddMethod {
31 | class_replaceMethod(c, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
32 | } else {
33 | method_exchangeImplementations(originalMethod, swizzledMethod);
34 | }
35 | }
36 |
37 |
38 | /// Swizzles an instance method on an Objective-C object.
39 | public class func swizzleInstanceMethod(_ originalSelector: Selector, swizzledSelector:Selector) {
40 | guard let originalMethod = class_getInstanceMethod(self, originalSelector),
41 | let swizzledMethod = class_getInstanceMethod(self, swizzledSelector) else {
42 | print("Error replacing \(originalSelector) with \(swizzledSelector).")
43 | return
44 | }
45 |
46 | let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
47 |
48 | if didAddMethod {
49 | class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
50 | } else {
51 | method_exchangeImplementations(originalMethod, swizzledMethod);
52 | }
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/ModuloKitTests/TestDummyApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestDummyApp.swift
3 | // modulo
4 | //
5 | // Created by Sneed, Brandon on 12/12/16.
6 | // Copyright © 2016 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ModuloKit
11 |
12 | class TestDummyApp: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | moduloReset()
17 | print("working path = \(FileManager.workingPath())")
18 | }
19 |
20 | override func tearDown() {
21 | super.tearDown()
22 | }
23 |
24 | func testFreshStart() {
25 | runCommand("mkdir test-dummy")
26 |
27 | FileManager.setWorkingPath("test-dummy")
28 |
29 | runCommand("git init")
30 |
31 | var result = Modulo.run(["init", "--app"])
32 | XCTAssertTrue(result == .success)
33 |
34 | result = Modulo.run(["add", "git@github.com:modulo-dm/test-add-update.git", "--unmanaged", "-u", "-v"])
35 | XCTAssertTrue(result == .success)
36 |
37 | let spec = ModuleSpec.load(contentsOfFile: specFilename)
38 | XCTAssertTrue(spec!.module == false)
39 | XCTAssertTrue(spec!.name == "test-dummy")
40 | XCTAssertTrue(spec!.dependencies.count > 0)
41 | XCTAssertTrue(spec!.dependencyForURL("git@github.com:modulo-dm/test-add-update.git") != nil)
42 |
43 | let checkedOut = Git().branchName("modules/test-add-update")
44 | XCTAssertTrue(checkedOut == "master")
45 |
46 | XCTAssertTrue(FileManager.fileExists("modules/test-add-update"))
47 | XCTAssertTrue(FileManager.fileExists("modules/test-dep1"))
48 | XCTAssertTrue(FileManager.fileExists("modules/test-dep2"))
49 | }
50 |
51 | func testClonedAppStart() {
52 | let status = Git().clone("git@github.com:modulo-dm/test-dummy.git", path: "test-dummy")
53 | XCTAssertTrue(status == .success)
54 |
55 | FileManager.setWorkingPath("test-dummy")
56 |
57 | let result = Modulo.run(["update", "--all", "-v"])
58 | XCTAssertTrue(result == .success)
59 |
60 | let spec = ModuleSpec.load(contentsOfFile: specFilename)
61 | XCTAssertTrue(spec!.module == false)
62 | XCTAssertTrue(spec!.name == "test-dummy")
63 | XCTAssertTrue(spec!.dependencies.count > 0)
64 | XCTAssertTrue(spec!.dependencyForURL("git@github.com:modulo-dm/test-add-update.git") != nil)
65 |
66 | XCTAssertTrue(FileManager.fileExists("modules/test-add-update"))
67 | XCTAssertTrue(FileManager.fileExists("modules/test-dep1"))
68 | XCTAssertTrue(FileManager.fileExists("modules/test-dep2"))
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodableTests/JSONTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // JSONTests.swift
3 | // Codable
4 | //
5 | // Created by Brandon Sneed on 10/27/15.
6 | // Copyright © 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ELCodable
11 |
12 | class JSONTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testReadingFromJSON() {
25 | let json = JSON(bundleClass: ELCodableTests.self, filename: "jsontest_models.json")
26 |
27 | // types
28 | /*
29 | case Number
30 | case String
31 | case Bool
32 | case Array
33 | case Dictionary
34 | case Null
35 | case Unknown
36 | */
37 |
38 | XCTAssertTrue(json?["mystring"]?.type == .String)
39 | XCTAssertTrue(json?["decimalNumber"]?.type == .Number)
40 | XCTAssertTrue(json?["bool"]?.type == .Bool)
41 | XCTAssertTrue(json?["double"]?.type == .Number)
42 | XCTAssertTrue(json?["int"]?.type == .Number)
43 | XCTAssertTrue(json?["myarray1"]?.type == .Array)
44 | XCTAssertTrue(json?["mydictionary"]?.type == .Dictionary)
45 | XCTAssertTrue(json?["null"]?.type == .Null)
46 | }
47 |
48 | func testWritingToJSON() {
49 | let dictData = ["key1": "value1", "key2": 1234]
50 | let arrayData = ["1", "2", "3", "4"]
51 | let stringData = "true"
52 | let numberData = 123456789
53 |
54 | var json = JSON()
55 | json["stringData"] = JSON(stringData)
56 | json["numberData"] = JSON(numberData)
57 | json["arrayData"] = JSON(arrayData)
58 | json["dictData"] = JSON(dictData)
59 |
60 | print(json)
61 | }
62 |
63 | func testCollectionStuff() {
64 | let dictData = ["key1": "value1", "key2": 1234]
65 | let arrayData = ["1", "2", "3", "4"]
66 | let stringData = "true"
67 | let numberData = 123456789
68 |
69 | var json = JSON()
70 | json["stringData"] = JSON(stringData)
71 | json["numberData"] = JSON(numberData)
72 | json["arrayData"] = JSON(arrayData)
73 | json["dictData"] = JSON(dictData)
74 |
75 | XCTAssertTrue(json["arrayData"]!.array! == JSON(arrayData).array!)
76 | XCTAssertTrue(json["dictData"]!.dictionary! == JSON(dictData).dictionary!)
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodableTests/DynamicKeyTest.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DynamicKeyTest.swift
3 | // ELCodable
4 | //
5 | // Created by Brandon Sneed on 7/21/16.
6 | // Copyright © 2016 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import ELCodable
11 |
12 | struct MyData {
13 | let availableInStore: Int
14 | let format: String
15 | let identifier: String
16 | let location: LocationData
17 | let name: String
18 | let packagePrice: Decimal
19 | let unitPrice: Decimal
20 | }
21 |
22 | extension MyData: Decodable {
23 | static func decode(json: JSON?) throws -> MyData {
24 | let buriedJson = json?["data"]?[0]
25 |
26 | return try MyData(
27 | availableInStore: buriedJson ==> "availabilityInStore",
28 | format: buriedJson ==> "format",
29 | identifier: buriedJson ==> "identifier",
30 | location: buriedJson ==> "location",
31 | name: buriedJson ==> "name",
32 | packagePrice: buriedJson ==> "packagePrice",
33 | unitPrice: buriedJson ==> "unitPrice"
34 | )
35 | }
36 | }
37 |
38 | struct LocationData {
39 | let aisle: String
40 | let section: String
41 | let zone: String
42 | }
43 |
44 | extension LocationData: Decodable {
45 | static func decode(json: JSON?) throws -> LocationData {
46 | return try LocationData(
47 | aisle: json ==> "aisle",
48 | section: json ==> "section",
49 | zone: json ==> "zone"
50 | )
51 | }
52 | }
53 |
54 |
55 |
56 | class DynamicKeyTest: XCTestCase {
57 |
58 | override func setUp() {
59 | super.setUp()
60 | // Put setup code here. This method is called before the invocation of each test method in the class.
61 | }
62 |
63 | override func tearDown() {
64 | // Put teardown code here. This method is called after the invocation of each test method in the class.
65 | super.tearDown()
66 | }
67 |
68 | func testRandomKeyExtraction() {
69 | guard let json = JSON(bundleClass: ELCodableTests.self, filename: "DynamicKeyedData.json") else {
70 | assertionFailure("the json is missing.")
71 | return
72 | }
73 |
74 | var thrownError: ErrorType? = nil
75 |
76 | do {
77 | let model = try MyData.decode(json)
78 | XCTAssertTrue(model.availableInStore == 15)
79 | XCTAssertTrue(model.format == "EAN13")
80 | XCTAssertTrue(model.location.zone == "A")
81 | XCTAssertTrue(model.unitPrice == Decimal(3.32))
82 | } catch let error {
83 | thrownError = error
84 | }
85 |
86 | XCTAssertTrue(thrownError == nil)
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/modulo.xcodeproj/project.xcworkspace/xcshareddata/modulo.xcscmblueprint:
--------------------------------------------------------------------------------
1 | {
2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "CDCC524B3D0D75DAC1D1CE8037A686D7006F68B7",
3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
4 |
5 | },
6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
7 | "8793D34A7BF94DA191D8F935B1E0425A8C1B2681" : 0,
8 | "CDCC524B3D0D75DAC1D1CE8037A686D7006F68B7" : 0,
9 | "3AA9B528BC4DFC86D9B300333E6A7EF9B619AC2B" : 0,
10 | "B78D931F23AF2B103B07F472BC9BDF733D7C9BCF" : 0
11 | },
12 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "4B054CB3-2BAA-4373-AFFD-D86A0889C2A3",
13 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
14 | "8793D34A7BF94DA191D8F935B1E0425A8C1B2681" : "modulo\/modules\/ELFoundation\/",
15 | "CDCC524B3D0D75DAC1D1CE8037A686D7006F68B7" : "modulo\/",
16 | "3AA9B528BC4DFC86D9B300333E6A7EF9B619AC2B" : "modulo\/modules\/ELCLI\/",
17 | "B78D931F23AF2B103B07F472BC9BDF733D7C9BCF" : "modulo\/modules\/ELCodable\/"
18 | },
19 | "DVTSourceControlWorkspaceBlueprintNameKey" : "modulo",
20 | "DVTSourceControlWorkspaceBlueprintVersion" : 204,
21 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "modulo.xcodeproj",
22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
23 | {
24 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:Electrode-iOS\/ELCLI.git",
25 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
26 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "3AA9B528BC4DFC86D9B300333E6A7EF9B619AC2B"
27 | },
28 | {
29 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:Electrode-iOS\/ELFoundation.git",
30 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
31 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "8793D34A7BF94DA191D8F935B1E0425A8C1B2681"
32 | },
33 | {
34 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:Electrode-iOS\/ELCodable.git",
35 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
36 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "B78D931F23AF2B103B07F472BC9BDF733D7C9BCF"
37 | },
38 | {
39 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:modulo-dm\/modulo.git",
40 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
41 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "CDCC524B3D0D75DAC1D1CE8037A686D7006F68B7"
42 | }
43 | ]
44 | }
--------------------------------------------------------------------------------
/Documentation/modulo-add.1.md:
--------------------------------------------------------------------------------
1 | modulo-add(1) -- Initialize a project for use with Modulo.
2 | ====
3 |
4 | ## SYNOPSIS
5 |
6 | `modulo add` [-u]
7 | `modulo add` --tag [-u]
8 | `modulo add` --branch [-u]
9 | `modulo add` --commit [-u]
10 |
11 | ## DESCRIPTION
12 |
13 | This command adds a dependency to the current project. When no tag/branch/commit is specified, `origin/master` is assumed.
14 |
15 | No cloning of dependencies, etc. takes place here unless `--update` is specified.
16 |
17 | Any dependencies that are cloned (even branches) are in a detached-head state. This forces the same workflow to be used regardless of the checkout type.
18 |
19 | ## OPTIONS
20 |
21 | * `--tag` :
22 | This option specifies that a semver tag or range should be checked out. Modulo treats semver as `breaking.feature.fix` since that is more meaningful to most.
23 |
24 | Modulo's semver implementation follows the `npm` implementation very closely. To read more, visit:
25 |
26 | https://docs.npmjs.com/getting-started/semantic-versioning
27 |
28 | * `--branch` :
29 | Specify the branch desired on checkedout.
30 | It's preferrable to specify the remote, ie: `origin/mybranch`. If omitted, `origin` will be the assumed remote.'
31 |
32 | * `--commit` :
33 | Specify the commit hash to be used on checkout. This accepts both short and long hashes.
34 |
35 | * `-u, --update`:
36 | Immediately perform an `update` after adding the dependency. This will clone if necessary, as well as perform any dependency compatibility checks.
37 |
38 | * `-v, --verbose`:
39 | Prints verbose output. Use this to see what underlying SCM commands are being used and any other important information.
40 |
41 | * `-h, --help`:
42 | Prints the help for this command.
43 |
44 | ## EXAMPLES
45 |
46 | `modulo add --tag ">=1.1 < 2.0.0" --update git@github.com/something/yadda.git`
47 |
48 | This will do the following
49 | * Add yadda.git as a dependency.
50 | * Clone yadda.git, because --update was specified.
51 | * Checkout the latest tag that is greater than or equal to 1.1.0, but less than 2.0.0
52 |
53 | `modulo add --branch master git@github.com/something/yadda.git`
54 |
55 | This will
56 | * Add yadda.git as a dependency.
57 | * Record that when performing update, the branch `origin/master` is to be checked out.
58 |
59 | ## SEE ALSO
60 |
61 | modulo-layout(1), modulo-update(1), modulo-remove(1)
62 |
63 | ## REPORTING BUGS
64 |
65 | Report bugs to the Github Project located at https://github.com/modulo-dm/modulo/. You'll be able to see the status and track any issues you create.
66 |
67 | ## AUTHORS
68 |
69 | Brandon Sneed
70 | Peat Bakke
71 |
72 |
73 |
--------------------------------------------------------------------------------
/Documentation/modulo-add.1.ronn:
--------------------------------------------------------------------------------
1 | modulo-add(1) -- Initialize a project for use with Modulo.
2 | ====
3 |
4 | ## SYNOPSIS
5 |
6 | `modulo add` [-u]
7 | `modulo add` --tag [-u]
8 | `modulo add` --branch [-u]
9 | `modulo add` --commit [-u]
10 |
11 | ## DESCRIPTION
12 |
13 | This command adds a dependency to the current project. When no tag/branch/commit is specified, `origin/master` is assumed.
14 |
15 | No cloning of dependencies, etc. takes place here unless `--update` is specified.
16 |
17 | Any dependencies that are cloned (even branches) are in a detached-head state. This forces the same workflow to be used regardless of the checkout type.
18 |
19 | ## OPTIONS
20 |
21 | * `--tag` :
22 | This option specifies that a semver tag or range should be checked out. Modulo treats semver as `breaking.feature.fix` since that is more meaningful to most.
23 |
24 | Modulo's semver implementation follows the `npm` implementation very closely. To read more, visit:
25 |
26 | https://docs.npmjs.com/getting-started/semantic-versioning
27 |
28 | * `--branch` :
29 | Specify the branch desired on checkedout.
30 | It's preferrable to specify the remote, ie: `origin/mybranch`. If omitted, `origin` will be the assumed remote.'
31 |
32 | * `--commit` :
33 | Specify the commit hash to be used on checkout. This accepts both short and long hashes.
34 |
35 | * `-u, --update`:
36 | Immediately perform an `update` after adding the dependency. This will clone if necessary, as well as perform any dependency compatibility checks.
37 |
38 | * `-v, --verbose`:
39 | Prints verbose output. Use this to see what underlying SCM commands are being used and any other important information.
40 |
41 | * `-h, --help`:
42 | Prints the help for this command.
43 |
44 | ## EXAMPLES
45 |
46 | `modulo add --tag ">=1.1 < 2.0.0" --update git@github.com/something/yadda.git`
47 |
48 | This will do the following
49 | * Add yadda.git as a dependency.
50 | * Clone yadda.git, because --update was specified.
51 | * Checkout the latest tag that is greater than or equal to 1.1.0, but less than 2.0.0
52 |
53 | `modulo add --branch master git@github.com/something/yadda.git`
54 |
55 | This will
56 | * Add yadda.git as a dependency.
57 | * Record that when performing update, the branch `origin/master` is to be checked out.
58 |
59 | ## SEE ALSO
60 |
61 | modulo-layout(1), modulo-update(1), modulo-remove(1)
62 |
63 | ## REPORTING BUGS
64 |
65 | Report bugs to the Github Project located at https://github.com/modulo-dm/modulo/. You'll be able to see the status and track any issues you create.
66 |
67 | ## AUTHORS
68 |
69 | Brandon Sneed
70 | Peat Bakke
71 |
72 |
73 |
--------------------------------------------------------------------------------
/ModuloKitTests/TestCheckout.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestCheckout.swift
3 | // modulo
4 | //
5 | // Created by Sneed, Brandon on 1/15/17.
6 | // Copyright © 2017 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ModuloKit
11 |
12 | class TestCheckout: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | moduloReset()
18 | print("working path = \(FileManager.workingPath())")
19 | }
20 |
21 | override func tearDown() {
22 | // Put teardown code here. This method is called after the invocation of each test method in the class.
23 | super.tearDown()
24 | }
25 |
26 | func testTagCheckout() {
27 | runCommand("mkdir checkout-test")
28 |
29 | FileManager.setWorkingPath("checkout-test")
30 |
31 | runCommand("git init")
32 |
33 | var result = Modulo.run(["init", "--app"])
34 | XCTAssertTrue(result == .success)
35 |
36 | result = Modulo.run(["add", "git@github.com:modulo-dm/test-checkout.git", "--version", "v2.0.0", "-u", "-v"])
37 | XCTAssertTrue(result == .success)
38 |
39 | XCTAssertTrue(FileManager.fileExists("modules/test-checkout"))
40 |
41 | let tags = Git().headTagsAtPath("modules/test-checkout")
42 | XCTAssertTrue(tags.contains("v2.0.0"))
43 | }
44 |
45 | func testTagRangeCheckout() {
46 | runCommand("mkdir checkout-test")
47 |
48 | FileManager.setWorkingPath("checkout-test")
49 |
50 | runCommand("git init")
51 |
52 | var result = Modulo.run(["init", "--app"])
53 | XCTAssertTrue(result == .success)
54 |
55 | result = Modulo.run(["add", "git@github.com:modulo-dm/test-checkout.git", "--version", ">0.0.2 <=2.0.1", "-u", "-v"])
56 | XCTAssertTrue(result == .success)
57 |
58 | XCTAssertTrue(FileManager.fileExists("modules/test-checkout"))
59 |
60 | let tags = Git().headTagsAtPath("modules/test-checkout")
61 | XCTAssertTrue(tags.contains("v2.0.1"))
62 | }
63 |
64 | func testTagNonSemverFails() {
65 | runCommand("mkdir checkout-test")
66 |
67 | FileManager.setWorkingPath("checkout-test")
68 |
69 | runCommand("git init")
70 |
71 | var result = Modulo.run(["init", "--app"])
72 | XCTAssertTrue(result == .success)
73 |
74 | result = Modulo.run(["add", "git@github.com:modulo-dm/test-checkout.git", "--version", "nosemver", "-u", "-v"])
75 | XCTAssertTrue(result == .commandError)
76 |
77 | XCTAssertTrue(!FileManager.fileExists("modules/test-checkout"))
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/ModuloKit/Commands/InitCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // InitCommand.swift
3 | // ModuloKit
4 | //
5 | // Created by Brandon Sneed on 6/16/16.
6 | // Copyright © 2016 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | #if NOFRAMEWORKS
11 | #else
12 | import ELCLI
13 | #endif
14 |
15 | open class InitCommand: NSObject, Command {
16 | // Internal properties
17 | open var isModule: Bool = false
18 |
19 | // Protocol conformance
20 | open var name: String { return "init" }
21 | open var shortHelpDescription: String { return "Initialize modulo" }
22 | open var longHelpDescription: String {
23 | return "This command initializes modulo and creates a .modulo file\n" +
24 | "containing module dependency information."
25 | }
26 | open var failOnUnrecognizedOptions: Bool { return true }
27 |
28 | open var verbose: Bool = State.instance.options.alwaysVerbose
29 | open var quiet: Bool = false
30 |
31 | open func configureOptions() {
32 | addOption(["--app"], usage: "init's the working path as an application (default)") { (option, value) in
33 | self.isModule = false
34 | }
35 |
36 | addOption(["--module"], usage: "init's the working path as a module") { (option, value) in
37 | self.isModule = true
38 | }
39 | }
40 |
41 | open func execute(_ otherParams: Array?) -> Int {
42 | //let scm = currentSCM()
43 | let workingPath = FileManager.workingPath()
44 |
45 | // Already nested in a Modules/ directory? Init as a module.
46 | if isValidModuleDirectory(path: workingPath) {
47 | isModule = true
48 | writeln(.stdout, "Initializing as a module, since you're already in the Modules directory ...")
49 | }
50 |
51 | if ModuleSpec.exists() {
52 | exit(.alreadyInitialized)
53 | }
54 |
55 | let specPath = workingPath.appendPathComponent(specFilename)
56 | let spec = ModuleSpec(name: FileManager.directoryName(), module: isModule, sourcePath: nil, dependencies: [], options: OptionsSpec(), path: specPath)
57 | let success = spec.save()
58 |
59 | if !success {
60 | exit(ErrorCode.specNotWritable)
61 | } else {
62 | writeln(.stdout, "Modulo has been initialized.")
63 | }
64 |
65 | return ErrorCode.success.rawValue
66 | }
67 |
68 | open func isValidModuleDirectory(path: String) -> Bool {
69 | let relativeParentPath = path.appendPathComponent("..")
70 | let absolutePath = NSString(string: relativeParentPath).standardizingPath // normalizes relative path segments
71 | let parentDirectoryName = NSString(string: absolutePath).lastPathComponent
72 |
73 | return parentDirectoryName == State.instance.modulePathName
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodableTests/OptionalTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OptionalTests.swift
3 | // ELCodable
4 | //
5 | // Created by Brandon Sneed on 2/23/16.
6 | // Copyright © 2016 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import ELCodable
11 |
12 | struct Data {
13 | var cart: Cart
14 | }
15 |
16 | extension Data: Decodable {
17 | static func decode(json: JSON?) throws -> Data {
18 | return try Data(
19 | cart: json ==> "data"
20 | )
21 | }
22 | }
23 |
24 | struct Cart {
25 | var total: Decimal
26 | var clientTransactionId: String?
27 | var recordSaleTransactionId: String?
28 | var approvalNumber: String?
29 | var authorizerId: String?
30 | }
31 |
32 | extension Cart: Decodable {
33 | static func decode(json: JSON?) throws -> Cart {
34 | return try Cart(
35 | total: json ==> "total",
36 | clientTransactionId: json ==> "clientTransactionId",
37 | recordSaleTransactionId: json ==> "recordSaleTransactionId",
38 | approvalNumber: json ==> "approvalNumber",
39 | authorizerId: json ==> "authorizerId"
40 | )
41 | }
42 | }
43 |
44 | class OptionalTests: XCTestCase {
45 |
46 | override func setUp() {
47 | super.setUp()
48 | // Put setup code here. This method is called before the invocation of each test method in the class.
49 | }
50 |
51 | override func tearDown() {
52 | // Put teardown code here. This method is called after the invocation of each test method in the class.
53 | super.tearDown()
54 | }
55 |
56 | func testBasicOptionals() {
57 | /*guard let json = JSON(bundleClass: ELCodableTests.self, filename: "OptionalTests.json") else {
58 | assertionFailure("the json is missing.")
59 | return
60 | }
61 |
62 | var model: Cart? = nil
63 |
64 | guard let json = JSON(responseJson) else {
65 |
66 | }
67 |
68 | guard let data = json["data"]
69 |
70 | guard let jsonDict = json.object as? NSDictionary else {
71 | assertionFailure("the json is jacked up.")
72 | return
73 | }
74 |
75 | guard let data = jsonDict["data"] as? NSDictionary else {
76 | assertionFailure("the data object is missing")
77 | return
78 | }
79 |
80 | var thrownError: ErrorType? = nil
81 |
82 | do {
83 | model = try Cart.decode(JSON(data))
84 | } catch let error {
85 | thrownError = error
86 | }
87 |
88 | if thrownError != nil {
89 | print(thrownError)
90 | }
91 |
92 | XCTAssertTrue(model != nil, "Cart model is nil!")
93 | XCTAssertTrue(model?.total == Decimal(818.45), "Total doesn't have the right value!")
94 | XCTAssertTrue(model?.clientTransactionId == nil)*/
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/ModuloKitTests/TestAdd.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestAdd.swift
3 | // modulo
4 | //
5 | // Created by Brandon Sneed on 2/1/16.
6 | // Copyright © 2016 Modulo. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import ELCLI
11 | import ELFoundation
12 | @testable import ModuloKit
13 |
14 |
15 | class TestAdd: XCTestCase {
16 | let modulo = Modulo()
17 |
18 | override func setUp() {
19 | super.setUp()
20 | moduloReset()
21 |
22 | print("working path = \(FileManager.workingPath())")
23 | }
24 |
25 | override func tearDown() {
26 | // Put teardown code here. This method is called after the invocation of each test method in the class.
27 | super.tearDown()
28 | }
29 |
30 | func testBasicAddModuleToModule() {
31 | let status = Git().clone("git@github.com:modulo-dm/test-add.git", path: "test-add")
32 | XCTAssertTrue(status == .success)
33 |
34 | FileManager.setWorkingPath("test-add")
35 |
36 | let result = Modulo.run(["add", "git@github.com:modulo-dm/test-add-update.git", "--version", "1.0", "-v"])
37 | XCTAssertTrue(result == .success)
38 |
39 | let spec = ModuleSpec.load(contentsOfFile: specFilename)
40 | XCTAssertTrue(spec!.dependencies.count > 0)
41 | XCTAssertTrue(spec!.dependencyForURL("git@github.com:modulo-dm/test-add-update.git") != nil)
42 |
43 | FileManager.setWorkingPath("..")
44 |
45 | Git().remove("test-add")
46 | }
47 |
48 | func testBasicAddModuleAlreadyExists() {
49 | let status = Git().clone("git@github.com:modulo-dm/test-add.git", path: "test-add")
50 | XCTAssertTrue(status == .success)
51 |
52 | let status2 = Git().clone("git@github.com:modulo-dm/test-init.git", path: "test-init")
53 | XCTAssertTrue(status2 == .success)
54 |
55 | FileManager.setWorkingPath("test-add")
56 |
57 | let result = Modulo.run(["add", "git@github.com:modulo-dm/test-init.git", "--version", "1.0", "-v", "--update"])
58 | XCTAssertTrue(result == .dependencyAlreadyExists)
59 | }
60 |
61 |
62 | func testBasicAddModuleToModuleAndUpdate() {
63 | let status = Git().clone("git@github.com:modulo-dm/test-add.git", path: "test-add")
64 | XCTAssertTrue(status == .success)
65 |
66 | FileManager.setWorkingPath("test-add")
67 |
68 | let result = Modulo.run(["add", "git@github.com:modulo-dm/test-add-update.git", "--version", "1.0", "-v", "--update"])
69 | XCTAssertTrue(result == .success)
70 |
71 | let spec = ModuleSpec.load(contentsOfFile: specFilename)
72 | XCTAssertTrue(spec!.dependencies.count > 0)
73 | XCTAssertTrue(spec!.dependencies[2].repositoryURL == "git@github.com:modulo-dm/test-add-update.git")
74 |
75 | XCTAssertTrue(FileManager.fileExists("../test-add-update/README.md"))
76 | XCTAssertTrue(FileManager.fileExists("../test-dep1/README.md"))
77 | XCTAssertTrue(FileManager.fileExists("../test-dep2/README.md"))
78 |
79 | FileManager.setWorkingPath("..")
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundation.xcodeproj/xcshareddata/xcschemes/ELFoundation_osx.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
45 |
46 |
52 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
70 |
71 |
72 |
73 |
75 |
76 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/Modules/ELFoundation/ELFoundation/Utilities/Synchronization.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Synchronization.swift
3 | // ELFoundation
4 | //
5 | // Created by Brandon Sneed on 2/19/15.
6 | // Copyright (c) 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /**
12 | Mimics @synchronized(x) in Objective-C. Synchronizes around the given object
13 | and executes the supplied closure.
14 |
15 | - parameter lock: Object to lock around.
16 | - parameter closure: Closure to execute inside of the lock.
17 |
18 | Example: synchronized(self) { doSomething() }
19 | */
20 | public func synchronized(_ lock: AnyObject, closure: () -> Void) {
21 | objc_sync_enter(lock)
22 | closure()
23 | objc_sync_exit(lock)
24 | }
25 |
26 | /**
27 | Mimics @synchronized(x) in Objective-C. Synchronizes around the given object
28 | and executes the supplied closure, returning the type T.
29 |
30 | - parameter lock: Object to lock around.
31 | - parameter closure: Closure to execute inside of the lock.
32 | - returns: The result of the closure.
33 |
34 | Example: let running = synchronized(self) { return true }
35 | */
36 | public func synchronized(_ lock: AnyObject, closure: () -> T) -> T {
37 | objc_sync_enter(lock)
38 | let result: T = closure()
39 | objc_sync_exit(lock)
40 | return result
41 | }
42 |
43 | /**
44 | OS Level Spin Lock class. Wraps the OSSpinLock* functions to allow for
45 | synchronization around a specified closure. This is very useful for properties
46 | where get/set need to be thread-safe.
47 | */
48 | final public class Spinlock {
49 | public init() {
50 |
51 | }
52 |
53 | /**
54 | Tries to acquire the lock, and if successful executes the specified closure.
55 |
56 | - parameter closure: Closure to execute inside of the lock.
57 | - returns: False if it failed to acquire the lock, otherwise true.
58 | */
59 | public func tryaround(_ closure: () -> Void) -> Bool {
60 | let held = OSSpinLockTry(&spinlock)
61 | if !held {
62 | closure()
63 | OSSpinLockUnlock(&spinlock)
64 | }
65 | return held
66 | }
67 |
68 | /**
69 | Runs the specified closure within the spin lock.
70 |
71 | - parameter closure: Closure to execute inside of the lock.
72 | */
73 | public func around(_ closure: () -> Void) {
74 | OSSpinLockLock(&spinlock)
75 | closure()
76 | OSSpinLockUnlock(&spinlock)
77 | }
78 |
79 | /**
80 | Runs the specified closure within the spin lock, returning the type T.
81 |
82 | - parameter closure: Closure to execute inside of the lock.
83 | - returns: The result of the closure.
84 | */
85 | public func around(_ closure: () -> T) -> T {
86 | OSSpinLockLock(&spinlock)
87 | let result: T = closure()
88 | OSSpinLockUnlock(&spinlock)
89 | return result
90 | }
91 |
92 | public func lock() {
93 | OSSpinLockLock(&spinlock)
94 | }
95 |
96 | public func trylock() -> Bool {
97 | return OSSpinLockTry(&spinlock)
98 | }
99 |
100 | public func unlock() {
101 | OSSpinLockUnlock(&spinlock)
102 | }
103 |
104 | fileprivate var spinlock: OSSpinLock = OS_SPINLOCK_INIT
105 | }
106 |
--------------------------------------------------------------------------------
/Documentation/modulo-add.1:
--------------------------------------------------------------------------------
1 | .\" generated with Ronn/v0.7.3
2 | .\" http://github.com/rtomayko/ronn/tree/0.7.3
3 | .
4 | .TH "MODULO\-ADD" "1" "July 2017" "Modulo" "Modulo manual"
5 | .
6 | .SH "NAME"
7 | \fBmodulo\-add\fR \- Initialize a project for use with Modulo\.
8 | .
9 | .SH "SYNOPSIS"
10 | \fBmodulo add\fR [\-u] \fIrepo_url\fR
11 | .
12 | .br
13 | \fBmodulo add\fR \-\-tag [\-u] \fIsemver\fR \fIrepo_url\fR
14 | .
15 | .br
16 | \fBmodulo add\fR \-\-branch [\-u] \fIbranchname\fR \fIrepo_url\fR
17 | .
18 | .br
19 | \fBmodulo add\fR \-\-commit [\-u] \fIcommithash\fR \fIrepo_url\fR
20 | .
21 | .br
22 | .
23 | .SH "DESCRIPTION"
24 | This command adds a dependency to the current project\. When no tag/branch/commit is specified, \fBorigin/master\fR is assumed\.
25 | .
26 | .P
27 | No cloning of dependencies, etc\. takes place here unless \fB\-\-update\fR is specified\.
28 | .
29 | .P
30 | Any dependencies that are cloned (even branches) are in a detached\-head state\. This forces the same workflow to be used regardless of the checkout type\.
31 | .
32 | .SH "OPTIONS"
33 | .
34 | .TP
35 | \fB\-\-tag\fR \fIsemver\fR
36 | This option specifies that a semver tag or range should be checked out\. Modulo treats semver as \fBbreaking\.feature\.fix\fR since that is more meaningful to most\.
37 | .
38 | .IP
39 | Modulo\'s semver implementation follows the \fBnpm\fR implementation very closely\. To read more, visit:
40 | .
41 | .IP
42 | https://docs\.npmjs\.com/getting\-started/semantic\-versioning
43 | .
44 | .TP
45 | \fB\-\-branch\fR \fIbranchname\fR
46 | Specify the branch desired on checkedout\. It\'s preferrable to specify the remote, ie: \fBorigin/mybranch\fR\. If omitted, \fBorigin\fR will be the assumed remote\.\'
47 | .
48 | .TP
49 | \fB\-\-commit\fR \fIcommithash\fR
50 | Specify the commit hash to be used on checkout\. This accepts both short and long hashes\.
51 | .
52 | .TP
53 | \fB\-u, \-\-update\fR
54 | Immediately perform an \fBupdate\fR after adding the dependency\. This will clone if necessary, as well as perform any dependency compatibility checks\.
55 | .
56 | .TP
57 | \fB\-v, \-\-verbose\fR
58 | Prints verbose output\. Use this to see what underlying SCM commands are being used and any other important information\.
59 | .
60 | .TP
61 | \fB\-h, \-\-help\fR
62 | Prints the help for this command\.
63 | .
64 | .SH "EXAMPLES"
65 | \fBmodulo add \-\-tag ">=1\.1 < 2\.0\.0" \-\-update git@github\.com/something/yadda\.git\fR
66 | .
67 | .P
68 | This will do the following
69 | .
70 | .br
71 | * Add yadda\.git as a dependency\.
72 | .
73 | .br
74 | * Clone yadda\.git, because \-\-update was specified\.
75 | .
76 | .br
77 | * Checkout the latest tag that is greater than or equal to 1\.1\.0, but less than 2\.0\.0
78 | .
79 | .br
80 | .
81 | .P
82 | \fBmodulo add \-\-branch master git@github\.com/something/yadda\.git\fR
83 | .
84 | .P
85 | This will
86 | .
87 | .br
88 | * Add yadda\.git as a dependency\.
89 | .
90 | .br
91 | * Record that when performing update, the branch \fBorigin/master\fR is to be checked out\.
92 | .
93 | .br
94 | .
95 | .SH "SEE ALSO"
96 | modulo\-layout(1), modulo\-update(1), modulo\-remove(1)
97 | .
98 | .SH "REPORTING BUGS"
99 | Report bugs to the Github Project located at https://github\.com/modulo\-dm/modulo/\. You\'ll be able to see the status and track any issues you create\.
100 | .
101 | .SH "AUTHORS"
102 | .
103 | .nf
104 |
105 | Brandon Sneed
106 | Peat Bakke
107 | .
108 | .fi
109 |
110 |
--------------------------------------------------------------------------------
/ModuloKitTests/TestUpdate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestUpdate.swift
3 | // modulo
4 | //
5 | // Created by Brandon Sneed on 6/27/16.
6 | // Copyright © 2016 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import ELCLI
11 | import ELFoundation
12 | @testable import ModuloKit
13 |
14 |
15 | class TestUpdate: XCTestCase {
16 | let modulo = Modulo()
17 |
18 | override func setUp() {
19 | super.setUp()
20 | moduloReset()
21 | print("working path = \(FileManager.workingPath())")
22 | }
23 |
24 | override func tearDown() {
25 | // Put teardown code here. This method is called after the invocation of each test method in the class.
26 | super.tearDown()
27 | }
28 |
29 | func testUpdateAll() {
30 | let status = Git().clone("git@github.com:modulo-dm/test-add.git", path: "test-add")
31 | XCTAssertTrue(status == .success)
32 |
33 | FileManager.setWorkingPath("test-add")
34 |
35 | let result = Modulo.run(["update", "--all", "-v"])
36 | XCTAssertTrue(result == .success)
37 |
38 | let spec = ModuleSpec.load(contentsOfFile: specFilename)
39 | XCTAssertTrue(spec!.dependencies.count > 0)
40 | XCTAssertTrue(spec!.dependencies[0].repositoryURL == "git@github.com:modulo-dm/test-init.git")
41 |
42 | XCTAssertTrue(FileManager.pathExists("../test-init"))
43 | XCTAssertTrue(FileManager.pathExists("../test-dep1"))
44 | XCTAssertTrue(FileManager.pathExists("../test-dep2"))
45 |
46 | FileManager.setWorkingPath("..")
47 |
48 | Git().remove("test-add")
49 | }
50 |
51 | func testUpdateOneModule() {
52 | let status = Git().clone("git@github.com:modulo-dm/test-add.git", path: "test-add")
53 | XCTAssertTrue(status == .success)
54 |
55 | FileManager.setWorkingPath("test-add")
56 |
57 | let result = Modulo.run(["update", "test-init"])
58 | XCTAssertTrue(result == .success)
59 |
60 | let spec = ModuleSpec.load(contentsOfFile: specFilename)
61 | XCTAssertTrue(spec!.dependencies.count > 0)
62 | XCTAssertTrue(spec!.dependencies[0].repositoryURL == "git@github.com:modulo-dm/test-init.git")
63 |
64 | XCTAssertTrue(FileManager.pathExists("../test-init"))
65 |
66 | FileManager.setWorkingPath("..")
67 |
68 | Git().remove("test-add")
69 | }
70 |
71 | func testUpdatePull() {
72 | let status = Git().clone("git@github.com:modulo-dm/test-add.git", path: "test-add")
73 | XCTAssertTrue(status == .success)
74 |
75 | FileManager.setWorkingPath("test-add")
76 |
77 | var result = Modulo.run(["update", "-v", "--all"])
78 | XCTAssertTrue(result == .success)
79 |
80 | let spec = ModuleSpec.load(contentsOfFile: specFilename)
81 | XCTAssertTrue(spec!.dependencies.count > 0)
82 | XCTAssertTrue(spec!.dependencies[0].repositoryURL == "git@github.com:modulo-dm/test-init.git")
83 |
84 | XCTAssertTrue(FileManager.pathExists("../test-init"))
85 |
86 | // now run it all again and make sure it does a fetch/pull on the branches
87 | State.instance.clear()
88 | result = Modulo.run(["update", "-v", "--all"])
89 | XCTAssertTrue(status == .success)
90 |
91 | FileManager.setWorkingPath("..")
92 |
93 | Git().remove("test-add")
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodable/DecodableExtensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DecodableExtensions.swift
3 | // Codable
4 | //
5 | // Created by Brandon Sneed on 11/4/15.
6 | // Copyright © 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension String: ELDecodable {
12 | public static func decode(_ json: JSON?) throws -> String {
13 | if let value = json?.string {
14 | return value
15 | }
16 | if json != nil {
17 | throw ELDecodeError.undecodable
18 | } else {
19 | throw ELDecodeError.emptyJSON
20 | }
21 | }
22 | }
23 |
24 | extension Float: ELDecodable {
25 | public static func decode(_ json: JSON?) throws -> Float {
26 | if let value = json?.float {
27 | return value
28 | }
29 | throw ELDecodeError.undecodable
30 | }
31 | }
32 |
33 | extension Double: ELDecodable {
34 | public static func decode(_ json: JSON?) throws -> Double {
35 | if let value = json?.double {
36 | return value
37 | }
38 | throw ELDecodeError.undecodable
39 | }
40 | }
41 |
42 | extension Int: ELDecodable {
43 | public static func decode(_ json: JSON?) throws -> Int {
44 | if let value = json?.int {
45 | return value
46 | }
47 | throw ELDecodeError.undecodable
48 | }
49 | }
50 |
51 | extension Int64: ELDecodable {
52 | public static func decode(_ json: JSON?) throws -> Int64 {
53 | if let value = json?.int64 {
54 | return value
55 | }
56 | throw ELDecodeError.undecodable
57 | }
58 | }
59 |
60 | extension UInt: ELDecodable {
61 | public static func decode(_ json: JSON?) throws -> UInt {
62 | if let value = json?.uInt {
63 | return value
64 | }
65 | throw ELDecodeError.undecodable
66 | }
67 | }
68 |
69 | extension UInt64: ELDecodable {
70 | public static func decode(_ json: JSON?) throws -> UInt64 {
71 | if let value = json?.uInt64 {
72 | return value
73 | }
74 | throw ELDecodeError.undecodable
75 | }
76 | }
77 |
78 | extension Bool: ELDecodable {
79 | public static func decode(_ json: JSON?) throws -> Bool {
80 | if let value = json?.bool {
81 | return value
82 | }
83 | throw ELDecodeError.undecodable
84 | }
85 | }
86 |
87 | extension Decimal: ELDecodable {
88 | public static func decode(_ json: JSON?) throws -> Decimal {
89 | if let value = json?.decimal {
90 | return value.decimalValue
91 | }
92 | throw ELDecodeError.undecodable
93 | }
94 | }
95 |
96 | extension Array where Element: ELDecodable {
97 | public static func decode(_ json: JSON?) throws -> [Element] {
98 | guard let items = json?.array else {
99 | throw ELDecodeError.undecodable
100 | }
101 |
102 | var decodedItems = [Element]()
103 |
104 | for item in items {
105 | let decodedItem = try Element.decode(item)
106 | decodedItems.append(decodedItem)
107 | }
108 |
109 | return decodedItems
110 | }
111 | }
112 |
113 | extension Dictionary where Key: ExpressibleByStringLiteral, Value: ELDecodable {
114 | public static func decode(_ json: JSON?) throws -> [String: JSON] {
115 | guard let value = json?.dictionary else {
116 | throw ELDecodeError.undecodable
117 | }
118 |
119 | return value
120 | }
121 | }
122 |
123 |
124 |
--------------------------------------------------------------------------------
/ModuloKit/Commands/AddCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AddCommand.swift
3 | // modulo
4 | //
5 | // Created by Brandon Sneed on 6/17/16.
6 | // Copyright © 2016 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | #if NOFRAMEWORKS
12 | #else
13 | import ELCLI
14 | #endif
15 |
16 | open class AddCommand: NSObject, Command {
17 | // internal properties
18 | fileprivate var version: SemverRange? = nil
19 | fileprivate var repositoryURL: String! = nil
20 | fileprivate var shouldUpdate: Bool = false
21 | fileprivate var unmanaged: Bool = false
22 |
23 | // Protocol conformance
24 | open var name: String { return "add" }
25 | open var shortHelpDescription: String { return "Adds a module dependency" }
26 | open var longHelpDescription: String {
27 | return "Add the given repository as a module to the current project.\n\n" +
28 | "In unmanaged mode, it is up to the user to manage what is checked out.\n" +
29 | "In this case, the update command will simply do a pull.\n\n" +
30 | "More information on version ranges can be found at https://docs.npmjs.com/misc/semver"
31 | }
32 | open var failOnUnrecognizedOptions: Bool { return true }
33 |
34 | open var verbose: Bool = State.instance.options.alwaysVerbose
35 | open var quiet: Bool = false
36 |
37 | open func configureOptions() {
38 | addOptionValue(["--version"], usage: "specify the version or range to use", valueSignature: "") { (option, value) -> Void in
39 | if let value = value {
40 | self.version = SemverRange(value)
41 | }
42 | }
43 |
44 | addOption(["--unmanaged"], usage: "specifies that this module will be unmanaged") { (option, value) in
45 | self.unmanaged = true
46 | }
47 |
48 | addOption(["-u", "--update"], usage: "performs the update command after adding a module") { (option, value) in
49 | self.shouldUpdate = true
50 | }
51 |
52 | addFlaglessOptionValues([""]) { (option, value) -> Void in
53 | self.repositoryURL = value
54 | }
55 | }
56 |
57 | open func execute(_ otherParams: Array?) -> Int {
58 | let actions = Actions()
59 |
60 | if version == nil && unmanaged == false {
61 | writeln(.stderr, "A version or range must be specified via --version, or --unmanaged must be used.")
62 | return ErrorCode.commandError.rawValue
63 | }
64 |
65 | if let version = version {
66 | if version.valid == false {
67 | writeln(.stderr, "The range or version specified is not valid. Please see: https://docs.npmjs.com/misc/semver")
68 | return ErrorCode.commandError.rawValue
69 | }
70 | }
71 |
72 | let result = actions.addDependency(repositoryURL, version: version, unmanaged: unmanaged)
73 | if result == .success {
74 | if shouldUpdate {
75 | writeln(.stdout, "Added \(String(describing: repositoryURL)).")
76 | if let spec = ModuleSpec.workingSpec(), let dep = spec.dependencyForURL(repositoryURL) {
77 | let actions = Actions()
78 | _ = actions.updateDependencies([dep], explicit: true)
79 | }
80 | } else {
81 | writeln(.stdout, "Added \(String(describing: repositoryURL)). Run the `update` command to complete the process.")
82 | }
83 | }
84 |
85 |
86 | return result.rawValue
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/modulo.xcodeproj/xcuserdata/brandonsneed.xcuserdatad/xcschemes/modulo.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/ModuloKitTests/TestGit.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestGit.swift
3 | // modulo
4 | //
5 | // Created by Brandon Sneed on 12/3/16.
6 | // Copyright © 2016 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import ELCLI
11 | import ELFoundation
12 | @testable import ModuloKit
13 |
14 | class TestGit: XCTestCase {
15 |
16 | override func setUp() {
17 | super.setUp()
18 | moduloReset()
19 | print("working path = \(FileManager.workingPath())")
20 | }
21 |
22 | override func tearDown() {
23 | // Put teardown code here. This method is called after the invocation of each test method in the class.
24 | super.tearDown()
25 | }
26 |
27 | func testGettingGitTags() {
28 | let status = Git().clone("git@github.com:modulo-dm/test-checkout.git", path: "test-checkout")
29 | XCTAssertTrue(status == .success)
30 |
31 | let tags = Git().tags("test-checkout").map {
32 | $0.stringValue
33 | }
34 | print(tags)
35 |
36 | Git().remove("test-checkout")
37 | }
38 |
39 | func testGettingBranches() {
40 | let status = Git().clone("git@github.com:modulo-dm/test-checkout.git", path: "test-checkout")
41 | XCTAssertTrue(status == .success)
42 |
43 | let branches = Git().branches("test-checkout")
44 | print(branches)
45 |
46 | Git().remove("test-checkout")
47 | }
48 |
49 | func testAddingToIgnoreFile() {
50 | let status = Git().clone("git@github.com:modulo-dm/test-checkout.git", path: "test-checkout")
51 | XCTAssertTrue(status == .success)
52 |
53 | FileManager.setWorkingPath("test-checkout")
54 |
55 | let localModulesPath = State.instance.modulePathName
56 | let pattern = "testModule"
57 | let textBlob = "\n# Ignore \(pattern) for Modulo.\n\(localModulesPath)/\(pattern)"
58 |
59 | let ignoreFile = "*.*\n*.DS_Store\n*.m\n*.mm" // haha, ignore all the objc's. i kill me.
60 | try! ignoreFile.write(toFile: ".gitignore", atomically: true, encoding: .utf8)
61 |
62 | _ = Git().adjustIgnoreFile(pattern: pattern, removing: false)
63 |
64 | let resultingFile = try! String(contentsOfFile: ".gitignore")
65 |
66 | let found = resultingFile.contains(textBlob)
67 | XCTAssertTrue(found)
68 |
69 | FileManager.setWorkingPath("..")
70 |
71 | Git().remove("test-checkout")
72 | }
73 |
74 | func testRemovingFromIgnoreFile() {
75 | let status = Git().clone("git@github.com:modulo-dm/test-checkout.git", path: "test-checkout")
76 | XCTAssertTrue(status == .success)
77 |
78 | FileManager.setWorkingPath("test-checkout")
79 |
80 | let localModulesPath = State.instance.modulePathName
81 | let pattern = "testModule"
82 | let textBlob = "\n# Ignore \(pattern) for Modulo.\n\(localModulesPath)/\(pattern)"
83 |
84 | let ignoreFile = "*.*\n*.DS_Store\n*.m\n*.mm\n# Ignore testModule for Modulo.\nmodules/testModule"
85 | try! ignoreFile.write(toFile: ".gitignore", atomically: true, encoding: .utf8)
86 |
87 | _ = Git().adjustIgnoreFile(pattern: pattern, removing: true)
88 |
89 | let resultingFile = try! String(contentsOfFile: ".gitignore")
90 |
91 | let found = resultingFile.contains(textBlob)
92 | XCTAssertFalse(found)
93 |
94 | FileManager.setWorkingPath("..")
95 |
96 | Git().remove("test-checkout")
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/Modules/ELCodable/ELCodableTests/NestedErrorTesting.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NestedErrorTesting.swift
3 | // ELCodable
4 | //
5 | // Created by Brandon Sneed on 1/12/16.
6 | // Copyright © 2016 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import ELCodable
11 | import CoreLocation
12 |
13 | // MARK: WMSNGAddress
14 |
15 | struct WMSNGAddress: Equatable {
16 | let street1: String
17 | let street2: String?
18 | let city: String
19 | let state: String
20 | let zip: String
21 | let country: String
22 | }
23 |
24 | func ==(lhs: WMSNGAddress, rhs: WMSNGAddress) -> Bool {
25 | return lhs.street1 == rhs.street1 &&
26 | lhs.street2 == rhs.street2 &&
27 | lhs.city == rhs.city &&
28 | lhs.state == rhs.state &&
29 | lhs.zip == rhs.zip &&
30 | lhs.country == rhs.country
31 | }
32 |
33 | extension WMSNGAddress: Decodable {
34 | static func decode(json: JSON?) throws -> WMSNGAddress {
35 | return try WMSNGAddress(street1: json ==> "street1",
36 | street2: json ==> "street2",
37 | city: json ==> "cityjij",
38 | state: json ==> "state",
39 | zip: json ==> "zip",
40 | country: json ==> "country")
41 | }
42 |
43 | func validate() throws -> WMSNGAddress {
44 | // Possibly validate the data here
45 | return self
46 | }
47 | }
48 |
49 | // MARK: WMSNGStore
50 |
51 | struct WMSNGStore: Equatable {
52 | let storeId: String
53 | let location: CLLocation
54 | let phone: String
55 | let description: String
56 | let address: WMSNGAddress
57 | }
58 |
59 | func ==(lhs: WMSNGStore, rhs: WMSNGStore) -> Bool {
60 | return lhs.storeId == rhs.storeId &&
61 | lhs.location == rhs.location &&
62 | lhs.phone == rhs.phone &&
63 | lhs.description == rhs.description &&
64 | lhs.address == rhs.address
65 | }
66 |
67 | extension WMSNGStore: Decodable {
68 | static func decode(json: JSON?) throws -> WMSNGStore {
69 | let store = try WMSNGStore(storeId: json ==> "storeNumber",
70 | location: CLLocation(latitude: json ==> "latitude", longitude: json ==> "longitude"),
71 | phone: json ==> "phone",
72 | description: json ==> "description",
73 | address: json ==> "address"
74 | )
75 | return store
76 | }
77 |
78 | func validate() throws -> WMSNGStore {
79 | // Possibly validate the data here
80 | return self
81 | }
82 | }
83 |
84 |
85 | class NestedErrorTesting: XCTestCase {
86 |
87 | override func setUp() {
88 | super.setUp()
89 | // Put setup code here. This method is called before the invocation of each test method in the class.
90 | }
91 |
92 | override func tearDown() {
93 | // Put teardown code here. This method is called after the invocation of each test method in the class.
94 | super.tearDown()
95 | }
96 |
97 | func testNestedFailure() {
98 |
99 | let json = JSON(bundleClass: NestedErrorTesting.self, filename: "NestedErrorTesting.json")
100 |
101 | var thrownError: ErrorType? = nil
102 |
103 | do {
104 | let store = try WMSNGStore.decode(json)
105 | print(store)
106 | } catch DecodeError.EmptyJSON {
107 | print("JSON was empty.")
108 | } catch let error {
109 | thrownError = error
110 | }
111 |
112 | XCTAssertTrue(thrownError != nil)
113 | XCTAssertTrue(thrownError.debugDescription == "Optional(ELCodable.DecodeError.NotFound(\"address\"))")
114 | }
115 |
116 | }
117 |
--------------------------------------------------------------------------------
/ModuloKitTests/TestStatus.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestStatus.swift
3 | // modulo
4 | //
5 | // Created by Brandon Sneed on 7/18/16.
6 | // Copyright © 2016 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import ELCLI
11 | import ELFoundation
12 | @testable import ModuloKit
13 |
14 |
15 | class TestStatus: XCTestCase {
16 | let modulo = Modulo()
17 |
18 | override func setUp() {
19 | super.setUp()
20 | moduloReset()
21 | print("working path = \(FileManager.workingPath())")
22 | }
23 |
24 | override func tearDown() {
25 | // Put teardown code here. This method is called after the invocation of each test method in the class.
26 | super.tearDown()
27 | }
28 |
29 | func testStatusDepDirty() {
30 | let status = Git().clone("git@github.com:modulo-dm/test-add.git", path: "test-add")
31 | XCTAssertTrue(status == .success)
32 |
33 | FileManager.setWorkingPath("test-add")
34 |
35 | var result = Modulo.run(["update", "--all", "-v"])
36 | XCTAssertTrue(result == .success)
37 |
38 | touchFile("../test-dep1/blah.txt")
39 |
40 | result = Modulo.run(["status", "-v"])
41 | XCTAssertTrue(result == .dependencyUnclean)
42 |
43 | FileManager.setWorkingPath("..")
44 |
45 | _ = Git().remove("test-add")
46 | }
47 |
48 | func testStatusMainDirty() {
49 | let status = Git().clone("git@github.com:modulo-dm/test-add.git", path: "test-add")
50 | XCTAssertTrue(status == .success)
51 |
52 | FileManager.setWorkingPath("test-add")
53 |
54 | var result = Modulo.run(["update", "--all", "-v"])
55 | XCTAssertTrue(result == .success)
56 |
57 | touchFile("blah.txt")
58 |
59 | result = Modulo.run(["status", "-v"])
60 | XCTAssertTrue(result == .dependencyUnclean)
61 |
62 | FileManager.setWorkingPath("..")
63 |
64 | _ = Git().remove("test-add")
65 | }
66 |
67 | func testStatusMainUnpushed() {
68 | let status = Git().clone("git@github.com:modulo-dm/test-add.git", path: "test-add")
69 | XCTAssertTrue(status == .success)
70 |
71 | FileManager.setWorkingPath("test-add")
72 |
73 | var result = Modulo.run(["update", "--all", "-v"])
74 | XCTAssertTrue(result == .success)
75 |
76 | touchFile("blah.txt")
77 | runCommand("git add blah.txt")
78 | testCommit("test")
79 |
80 | result = Modulo.run(["status", "-v"])
81 | XCTAssertTrue(result == .dependencyUnclean)
82 |
83 | FileManager.setWorkingPath("..")
84 |
85 | _ = Git().remove("test-add")
86 | }
87 |
88 | func testStatusDepUnpushed() {
89 | let status = Git().clone("git@github.com:modulo-dm/test-add.git", path: "test-add")
90 | XCTAssertTrue(status == .success)
91 |
92 | FileManager.setWorkingPath("test-add")
93 |
94 | var result = Modulo.run(["update", "--all", "-v"])
95 | XCTAssertTrue(result == .success)
96 |
97 | FileManager.setWorkingPath("../test-dep1")
98 |
99 | touchFile("blah.txt")
100 | runCommand("git add blah.txt")
101 | testCommit("test")
102 |
103 | FileManager.setWorkingPath("../test-add")
104 |
105 | result = Modulo.run(["status", "-v"])
106 | XCTAssertTrue(result == .dependencyUnclean)
107 |
108 | FileManager.setWorkingPath("..")
109 |
110 | _ = Git().remove("test-add")
111 | }
112 |
113 | }
114 |
--------------------------------------------------------------------------------
/ModuloKit/Commands/DefaultsCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DefaultsCommand.swift
3 | // ModuloKit
4 | //
5 | // Created by Daniel Miedema on 9/25/18.
6 | // Copyright © 2018 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | #if NOFRAMEWORKS
11 | #else
12 | import ELCLI
13 | #endif
14 |
15 | open class DefaultsCommand: NSObject, Command {
16 | // Internal Properties
17 | fileprivate var toggleVerbose: Bool = false
18 | fileprivate var verboseValue: String? = nil
19 | fileprivate var moduleFolderPath: String? = nil
20 | fileprivate var setValue: Bool = false
21 |
22 | // Protocol Conformance
23 | public var name: String { return "defaults" }
24 |
25 | public var shortHelpDescription: String {
26 | return "Set default arguments/configuration properties for this repository"
27 | }
28 |
29 | public var longHelpDescription: String {
30 | return """
31 | Set default argument values for all commands to be run.
32 | This will make changes to the `.modulo` file reflecting the
33 | new defaults that have been set
34 | """
35 | }
36 |
37 | public var failOnUnrecognizedOptions: Bool { return true }
38 |
39 | public var verbose: Bool = State.instance.options.alwaysVerbose
40 | public var quiet: Bool = false
41 |
42 | public func execute(_ otherParams: Array?) -> Int {
43 | guard var spec = ModuleSpec.workingSpec() else {
44 | exit(ErrorCode.notInitialized)
45 | return ErrorCode.notInitialized.rawValue
46 | }
47 |
48 | if setValue {
49 | if toggleVerbose {
50 | let newValue: Bool
51 | switch verboseValue {
52 | case "true":
53 | newValue = true
54 | case "false":
55 | newValue = false
56 | default:
57 | writeln(.stderr, "\(verboseValue ?? "") is not `true` or `false`. Interpretting as `false`.")
58 | newValue = false
59 | }
60 |
61 | spec.options.alwaysVerbose = newValue
62 | State.instance.options.alwaysVerbose = newValue
63 | }
64 | if let moduleFolderPath = moduleFolderPath,
65 | !moduleFolderPath.isEmpty {
66 | spec.options.depdencyInstallationPath = moduleFolderPath
67 | State.instance.options.depdencyInstallationPath = moduleFolderPath
68 | }
69 |
70 | if !toggleVerbose && moduleFolderPath == nil {
71 | writeln(.stderr, """
72 | When `--set` is passed its assumed you want to set a default.
73 | Please specify one of the options
74 | --alwaysVerbose
75 | --moduleFolder
76 | """)
77 | }
78 | spec.save()
79 | } else {
80 | writeln(.stdout, "alwaysVerbose - \(spec.options.alwaysVerbose)")
81 | writeln(.stdout, "depdencyInstallationPath - \(spec.options.depdencyInstallationPath)")
82 | }
83 |
84 | return ErrorCode.success.rawValue
85 | }
86 |
87 | open func configureOptions() {
88 | addOption(["--set"], usage: "set a new value for the given") { (option, value) in
89 | self.setValue = true
90 | }
91 |
92 | addOptionValue(["--alwaysVerbose"],
93 | usage: "specify `verbose` for all commands that are run",
94 | valueSignature: "<[true|false]>") { (option, value) in
95 | self.toggleVerbose = true
96 | self.verboseValue = value
97 | }
98 |
99 | addOptionValue(["--moduleFolder"],
100 | usage: "specify the desired dependency path",
101 | valueSignature: "") { (option, value) in
102 | self.moduleFolderPath = value ?? ""
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/Modules/ELCLI/ELCLI/Output.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Output.swift
3 | // ELCLI
4 | //
5 | // Created by Brandon Sneed on 8/13/15.
6 | // Copyright © 2015 WalmartLabs. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | #if NOFRAMEWORKS
12 | #else
13 | import ELFoundation
14 | #endif
15 |
16 | // FIXME: comparison operators with optionals were removed from the Swift Standard Libary.
17 | // Consider refactoring the code to use the non-optional operators.
18 | fileprivate func < (lhs: T?, rhs: T?) -> Bool {
19 | switch (lhs, rhs) {
20 | case let (l?, r?):
21 | return l < r
22 | case (nil, _?):
23 | return true
24 | default:
25 | return false
26 | }
27 | }
28 |
29 | // FIXME: comparison operators with optionals were removed from the Swift Standard Libary.
30 | // Consider refactoring the code to use the non-optional operators.
31 | fileprivate func > (lhs: T?, rhs: T?) -> Bool {
32 | switch (lhs, rhs) {
33 | case let (l?, r?):
34 | return l > r
35 | default:
36 | return rhs < lhs
37 | }
38 | }
39 |
40 | public enum Output {
41 | case stdin
42 | case stdout
43 | case stderr
44 |
45 | func fileHandle() -> FileHandle {
46 | switch self {
47 | case .stdin:
48 | return FileHandle.standardInput
49 | case .stderr:
50 | return FileHandle.standardError
51 | case .stdout:
52 | fallthrough
53 | default:
54 | return FileHandle.standardOutput
55 | }
56 | }
57 | }
58 |
59 | public func write(_ destination: Output, _ data: String) {
60 | var str = data
61 | var finalDestination = destination
62 | if destination == .stderr {
63 | str = "error: " + data
64 | if isInUnitTest() {
65 | // if we're debugging unit tests, data won't show if it's spit otu to stderr.
66 | finalDestination = .stdout
67 | }
68 | }
69 |
70 | if let outputData = str.data(using: String.Encoding.utf8) {
71 | finalDestination.fileHandle().write(outputData)
72 | }
73 | }
74 |
75 | public func writeln(_ destination: Output, _ data: String) {
76 | write(destination, data + "\n")
77 | }
78 |
79 | public func exitSuccess() {
80 | if isInUnitTest() {
81 | exceptionFailure("")
82 | } else {
83 | exit(0)
84 | }
85 | }
86 |
87 | public func exit(_ data: String, closure: (() -> Void)? = nil) {
88 | writeln(.stderr, data)
89 | if let closure = closure {
90 | closure()
91 | }
92 |
93 | if isInUnitTest() {
94 | exceptionFailure(data)
95 | } else {
96 | exit(1)
97 | }
98 | }
99 |
100 | public func printOption(_ option: Option) {
101 | if option.flags == nil || option.valueSignatures?.count > 1 {
102 | return
103 | }
104 |
105 | var flagData = " "
106 |
107 | if let flags = option.flags {
108 | for index in 0.. 0 {
119 | flagData += " " + sigs[0]
120 | }
121 | }
122 |
123 | flagData = flagData.padBack(26)
124 |
125 | let usageData = option.usage!
126 |
127 | if flagData.count > 26 {
128 | flagData += "\n"
129 | flagData += usageData.padFront(27 + usageData.count)
130 | } else {
131 | flagData += " " + usageData
132 | }
133 |
134 | writeln(.stdout, flagData)
135 |
136 | }
137 |
138 | public func printCommand(_ command: Command) {
139 | if command.name.hasPrefix("-") {
140 | return
141 | }
142 |
143 | var commandData = " "
144 |
145 | commandData += command.name.padBack(14)
146 | commandData += " " + command.shortHelpDescription
147 |
148 | writeln(.stdout, commandData)
149 | }
150 |
--------------------------------------------------------------------------------
/ModuloKit/Commands/UpdateCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UpdateCommand.swift
3 | // modulo
4 | //
5 | // Created by Brandon Sneed on 6/21/16.
6 | // Copyright © 2016 TheHolyGrail. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | #if NOFRAMEWORKS
12 | #else
13 | import ELCLI
14 | #endif
15 |
16 | open class UpdateCommand: NSObject, Command {
17 | // internal properties
18 | fileprivate var updateAll: Bool = true
19 | fileprivate var dependencyName: String! = nil
20 | fileprivate var failSilentlyIfUnused: Bool = false
21 | fileprivate var nonzero: Bool = false
22 | fileprivate var hostname: String? = nil
23 |
24 | // Protocol conformance
25 | open var name: String { return "update" }
26 | open var shortHelpDescription: String { return "Updates module dependencies" }
27 | open var longHelpDescription: String {
28 | return "Updates module dependencies if needed. This command may clone sub dependencies, update the checked out versions, etc."
29 | }
30 | open var failOnUnrecognizedOptions: Bool { return true }
31 |
32 | open var verbose: Bool = State.instance.options.alwaysVerbose
33 | open var quiet: Bool = false
34 |
35 | open func configureOptions() {
36 | addOption(["-a", "--all"], usage: "update all dependencies (default)") { (option, value) in
37 | self.updateAll = true
38 | }
39 |
40 | addOption(["--nonzero"], usage: "return a non-zero result code if clones occurred") { (option, value) in
41 | self.nonzero = true
42 | }
43 |
44 | addOptionValue(["--host"], usage: "checks for host availablility, ie: github.com", valueSignature: "") { (option, value) in
45 | self.hostname = value
46 | }
47 |
48 | addOption(["--meh"], usage: "return success if modulo isn't being used or is uninitialized") { (option, value) in
49 | self.failSilentlyIfUnused = true
50 | }
51 |
52 | addFlaglessOptionValues([""]) { (option, value) -> Void in
53 | self.dependencyName = value
54 | self.updateAll = false
55 | }
56 |
57 | addOption(["--verbose"], usage: "verbose logging on") { (option, value) in
58 | self.verbose = true
59 | }
60 | }
61 |
62 | open func execute(_ otherParams: Array?) -> Int {
63 | let actions = Actions()
64 | actions.scm.verbose = verbose
65 |
66 | if let hostname = hostname {
67 | if canConnect(hostname: hostname) == false {
68 | writeln(.stdout, "Connection to \(hostname) unavailable. Exiting.")
69 | return ErrorCode.success.rawValue
70 | }
71 | }
72 |
73 | var deps = [DependencySpec]()
74 | if updateAll {
75 | if let workingSpec = ModuleSpec.workingSpec() {
76 | deps = workingSpec.dependencies
77 | } else {
78 | return ErrorCode.specNotFound.rawValue
79 | }
80 | } else if dependencyName != nil {
81 | if let dep = ModuleSpec.workingSpec()?.dependencyForName(dependencyName) {
82 | deps.append(dep)
83 | }
84 | } else {
85 | showHelp()
86 | return ErrorCode.commandError.rawValue
87 | }
88 |
89 | if deps.count == 0 {
90 | if failSilentlyIfUnused {
91 | return ErrorCode.success.rawValue
92 | } else {
93 | return ErrorCode.noMatchingDependencies.rawValue
94 | }
95 | } else {
96 | _ = actions.updateDependencies(deps, explicit: true)
97 |
98 | // if we actually cloned something, and the nonzero flag was used,
99 | if nonzero && State.instance.dependenciesWereCloned() {
100 | return 1
101 | }
102 |
103 | return ErrorCode.success.rawValue
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/modulo.xcodeproj/xcuserdata/brandon.xcuserdatad/xcschemes/ModuloKit.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
64 |
65 |
71 |
72 |
73 |
74 |
75 |
76 |
82 |
83 |
89 |
90 |
91 |
92 |
94 |
95 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/modulo.xcodeproj/xcuserdata/brsneed.xcuserdatad/xcschemes/ModuloKit.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
64 |
65 |
71 |
72 |
73 |
74 |
75 |
76 |
82 |
83 |
89 |
90 |
91 |
92 |
94 |
95 |
98 |
99 |
100 |
--------------------------------------------------------------------------------