├── Documentation
├── .gitignore
└── Makefile
├── Assets
└── Terminal.png
├── ShellKit.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
├── xcshareddata
│ └── xcschemes
│ │ ├── ShellKit.xcscheme
│ │ ├── ShellKit-Static.xcscheme
│ │ └── ShellKit-Test.xcscheme
└── project.pbxproj
├── .gitignore
├── .travis.yml
├── ShellKit
├── Info.plist
└── Classes
│ └── ShellKit
│ ├── ShellKit.h
│ ├── SKOptionalTask.m
│ ├── SKOptionalTask.h
│ ├── SKObject.m
│ ├── NSDate+ShellKit.m
│ ├── SKObject.h
│ ├── NSDate+ShellKit.h
│ ├── SKRunableObject.h
│ ├── NSString+ShellKit.h
│ ├── SKTaskGroup.h
│ ├── SKTypes.h
│ ├── NSString+ShellKit.m
│ ├── SKTaskGroup.m
│ ├── SKTask.h
│ ├── SKTask.m
│ ├── SKShell.h
│ └── SKShell.m
├── LICENSE
├── README.md
└── ShellKit-Test
└── main.m
/Documentation/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !HeaderDoc-Exclude.txt
3 | !Makefile
4 | !.gitignore
5 |
--------------------------------------------------------------------------------
/Assets/Terminal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/macmade/ShellKit/HEAD/Assets/Terminal.png
--------------------------------------------------------------------------------
/ShellKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Mac Finder
2 | .DS_Store
3 | .Trashes
4 | Icon?
5 |
6 | # Thumbnails
7 | ._*
8 |
9 | # Files that might appear on external disk
10 | .Spotlight-V100
11 | .Trashes
12 |
13 | # Windows
14 | Thumbs.db
15 |
16 | # Xcode
17 | *.pbxuser
18 | *.mode1v3
19 | *.mode2v3
20 | *.perspectivev3
21 | *.xccheckout
22 | *.profraw
23 | !default.pbxuser
24 | !default.mode1v3
25 | !default.mode2v3
26 | !default.perspectivev3
27 | xcuserdata
28 |
29 | # VisualStudio
30 | *.suo
31 | *.sdf
32 | *.opensdf
33 | *.vcxproj.user
34 | *.csproj.user
35 | ipch
36 |
37 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: objective-c
2 | install:
3 | - rvm get head
4 | - gem install xcpretty
5 | script:
6 | - set -o pipefail && xcodebuild -project "ShellKit.xcodeproj" -scheme "ShellKit" build | xcpretty
7 | - set -o pipefail && xcodebuild -project "ShellKit.xcodeproj" -scheme "ShellKit-Static" build | xcpretty
8 | - set -o pipefail && xcodebuild -project "ShellKit.xcodeproj" -scheme "ShellKit-Test" build | xcpretty
9 | - set -o pipefail && xcodebuild -project "ShellKit.xcodeproj" -scheme "ShellKit-Test" install DSTROOT="/" | xcpretty
10 | - /usr/local/bin/ShellKit-Test
11 | notifications:
12 | slack: xs-labs:FXh1yLXNkpcVxKZhZU6icdhI
13 |
--------------------------------------------------------------------------------
/ShellKit/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 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSHumanReadableCopyright
22 | Copyright © 2017 XS-Labs. All rights reserved.
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Jean-David Gadina - www.xs-labs.com / www.digidna.net
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
13 | all 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
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/ShellKit/Classes/ShellKit/ShellKit.h:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | ******************************************************************************/
24 |
25 | /*!
26 | * @file ShellKit.h
27 | * @copyright (c) 2017, Jean-David Gadina - www.xs-labs.com
28 | * @abstarct ShellKit's umbrella header
29 | */
30 |
31 | #import
32 | #import
33 | #import
34 | #import
35 | #import
36 | #import
37 | #import
38 | #import
39 | #import
40 |
--------------------------------------------------------------------------------
/ShellKit/Classes/ShellKit/SKOptionalTask.m:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | ******************************************************************************/
24 |
25 | /*!
26 | * @file SKOptionalTask.m
27 | * @copyright (c) 2017, Jean-David Gadina - www.xs-labs.com
28 | */
29 |
30 | #import
31 |
32 | NS_ASSUME_NONNULL_BEGIN
33 |
34 | @interface SKOptionalTask()
35 |
36 | @end
37 |
38 | NS_ASSUME_NONNULL_END
39 |
40 | @implementation SKOptionalTask
41 |
42 | - ( BOOL )run: ( NSDictionary< NSString *, NSString * > * )variables
43 | {
44 | if( [ super run: variables ] == NO )
45 | {
46 | [ [ SKShell currentShell ] printSuccessMessage: @"Task is marked as optional - Not failing" ];
47 | }
48 |
49 | return YES;
50 | }
51 |
52 | @end
53 |
--------------------------------------------------------------------------------
/ShellKit/Classes/ShellKit/SKOptionalTask.h:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | ******************************************************************************/
24 |
25 | /*!
26 | * @header SKOptionalTask.h
27 | * @copyright (c) 2017, Jean-David Gadina - www.xs-labs.com
28 | */
29 |
30 | #import
31 | #import
32 |
33 | NS_ASSUME_NONNULL_BEGIN
34 |
35 | /*!
36 | * @class SKOptionalTask
37 | * @abstract Represents an optional shell task
38 | * @discussion Optional tasks will succeed regardless of the exit status
39 | * of their command.
40 | * If used in a task group, a faling optional task will not fail
41 | * the whole group.
42 | */
43 | @interface SKOptionalTask: SKTask
44 |
45 | @end
46 |
47 | NS_ASSUME_NONNULL_END
48 |
--------------------------------------------------------------------------------
/ShellKit/Classes/ShellKit/SKObject.m:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | ******************************************************************************/
24 |
25 | /*!
26 | * @file SKObject.m
27 | * @copyright (c) 2017, Jean-David Gadina - www.xs-labs.com
28 | */
29 |
30 | #import
31 |
32 | NS_ASSUME_NONNULL_BEGIN
33 |
34 | @interface SKObject()
35 |
36 | @end
37 |
38 | NS_ASSUME_NONNULL_END
39 |
40 | @implementation SKObject
41 |
42 | - ( NSError * )errorWithDescription: ( NSString * )format, ...
43 | {
44 | NSString * description;
45 | va_list ap;
46 |
47 | va_start( ap, format );
48 |
49 | description = [ [ NSString alloc ] initWithFormat: format arguments: ap ];
50 |
51 | va_end( ap );
52 |
53 | return [ NSError errorWithDomain: [ NSString stringWithFormat: @"com.xs-labs.ShellKit.%@", NSStringFromClass( [ self class ] ) ] code: 0 userInfo: @{ NSLocalizedDescriptionKey : description } ];
54 | }
55 |
56 | @end
57 |
--------------------------------------------------------------------------------
/ShellKit/Classes/ShellKit/NSDate+ShellKit.m:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | ******************************************************************************/
24 |
25 | /*!
26 | * @file NSDate+ShellKit.m
27 | * @copyright (c) 2017, Jean-David Gadina - www.xs-labs.com
28 | */
29 |
30 | #import
31 |
32 | @implementation NSDate( ShellKit )
33 |
34 | - ( nullable NSString * )elapsedTimeStringSinceNow;
35 | {
36 | NSTimeInterval t;
37 | NSString * str;
38 |
39 | t = -[ self timeIntervalSinceNow ];
40 |
41 | if( t < 0 )
42 | {
43 | return nil;
44 | }
45 |
46 | if( t < 1 )
47 | {
48 | str = [ NSString stringWithFormat: @"%lu ms", ( NSUInteger )( t * 1000 ) ];
49 | }
50 | else if( t < 60 )
51 | {
52 | str = [ NSString stringWithFormat: @"%.02f s", t ];
53 | }
54 | else if( t < 3600 )
55 | {
56 | str = [ NSString stringWithFormat: @"%.02f m", t / 60 ];
57 | }
58 | else
59 | {
60 | str = [ NSString stringWithFormat: @"%.02f h", t / 3600 ];
61 | }
62 |
63 | return str;
64 | }
65 |
66 | @end
67 |
--------------------------------------------------------------------------------
/ShellKit/Classes/ShellKit/SKObject.h:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | ******************************************************************************/
24 |
25 | /*!
26 | * @header SKObject.h
27 | * @copyright (c) 2017, Jean-David Gadina - www.xs-labs.com
28 | */
29 |
30 | #import
31 |
32 | NS_ASSUME_NONNULL_BEGIN
33 |
34 | /*!
35 | * @class SKObject
36 | * @abstract Base class for ShellKit objects
37 | */
38 | @interface SKObject: NSObject
39 |
40 | /*!
41 | * @method errorWithDescription:
42 | * @abstract Returns an error object for the class with a custom description
43 | * @discussion The error object will be created with a domain containing the
44 | * class name, eg: `com.xs-labs.ShellKit.SommClass`.
45 | * The message will be set as the error's localized description.
46 | * @param format The error message format
47 | * @param ... Optional parameters for the format string
48 | * @result An error object
49 | */
50 | - ( NSError * )errorWithDescription: ( NSString * )format, ... NS_FORMAT_FUNCTION( 1, 2 );
51 |
52 | @end
53 |
54 | NS_ASSUME_NONNULL_END
55 |
--------------------------------------------------------------------------------
/ShellKit/Classes/ShellKit/NSDate+ShellKit.h:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | ******************************************************************************/
24 |
25 | /*!
26 | * @header NSDate+ShellKit.h
27 | * @copyright (c) 2017, Jean-David Gadina - www.xs-labs.com
28 | */
29 |
30 | #import
31 |
32 | NS_ASSUME_NONNULL_BEGIN
33 |
34 | /*!
35 | * @category NSDate( ShellKit )
36 | * @abstract Additional NSDate methods for ShellKit
37 | */
38 | @interface NSDate( ShellKit )
39 |
40 | /*!
41 | * @property elapsedTimeStringSinceNow
42 | * @abstract Gets a string representing the elapsed time since now
43 | * @discussion If less than a second, the elapsed time will be represented
44 | * in milliseconds (ms). If less that a minute, it will be
45 | * represented in seconds (s). If less than an hour, it will
46 | * be represented in minutes (m). Otherwise, it will be
47 | * represented in hours (h).
48 | * @result A string representing the elasped time
49 | */
50 | @property( atomic, readonly, nullable ) NSString * elapsedTimeStringSinceNow;
51 |
52 | @end
53 |
54 | NS_ASSUME_NONNULL_END
55 |
--------------------------------------------------------------------------------
/ShellKit/Classes/ShellKit/SKRunableObject.h:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | ******************************************************************************/
24 |
25 | /*!
26 | * @header SKRunableObject.h
27 | * @copyright (c) 2017, Jean-David Gadina - www.xs-labs.com
28 | */
29 |
30 | #import
31 |
32 | NS_ASSUME_NONNULL_BEGIN
33 |
34 | /*!
35 | * @protocol SKRunableObject
36 | * @abstract Protocol for runnable objects
37 | * @discussion Represents an object that can be run (like a task).
38 | */
39 | @protocol SKRunableObject< NSObject >
40 |
41 | @required
42 |
43 | /*!
44 | * @property running
45 | * @abstract Set when the runnable object is currently running
46 | */
47 | @property( atomic, readonly ) BOOL running;
48 |
49 | /*!
50 | * @property error
51 | * @abstract An optional error, possibly set after the task has run
52 | */
53 | @property( atomic, readonly, nullable ) NSError * error;
54 |
55 | /*!
56 | * @method run
57 | * @abstract Runs the task (synchronously)
58 | * @result YES if the runnable object has run successfully, otherwise NO
59 | */
60 | - ( BOOL )run;
61 |
62 | /*!
63 | * @method run
64 | * @abstract Runs the task with variables (synchronously)
65 | * @param variables Optional variables
66 | * @result YES if the runnable object has run successfully, otherwise NO
67 | */
68 | - ( BOOL )run: ( nullable NSDictionary< NSString *, NSString * > * )variables;
69 |
70 | @end
71 |
72 | NS_ASSUME_NONNULL_END
73 |
--------------------------------------------------------------------------------
/Documentation/Makefile:
--------------------------------------------------------------------------------
1 | #-------------------------------------------------------------------------------
2 | # The MIT License (MIT)
3 | #
4 | # Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com
5 | #
6 | # Permission is hereby granted, free of charge, to any person obtaining a copy
7 | # of this software and associated documentation files (the "Software"), to deal
8 | # in the Software without restriction, including without limitation the rights
9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | # copies of the Software, and to permit persons to whom the Software is
11 | # furnished to do so, subject to the following conditions:
12 | #
13 | # The above copyright notice and this permission notice shall be included in
14 | # all copies or substantial portions of the Software.
15 | #
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | # THE SOFTWARE.
23 | #-------------------------------------------------------------------------------
24 |
25 |
26 | # Check for the XSDocgen utility
27 | _HAS_XSDOCGEN := $(shell if [ -f "/usr/local/bin/XSDocgen" ]; then echo true; else echo false; fi )
28 |
29 | #-------------------------------------------------------------------------------
30 | # Built-in targets
31 | #-------------------------------------------------------------------------------
32 |
33 | # Declaration for phony targets, to avoid problems with local files
34 | .PHONY: all
35 |
36 | #-------------------------------------------------------------------------------
37 | # Phony targets
38 | #-------------------------------------------------------------------------------
39 |
40 | # Documentation
41 | all:
42 |
43 | ifeq ($(_HAS_XSDOCGEN),true)
44 | @echo $(call _PRINT,XSDoc,universal,Generating the documentation)
45 | @/usr/local/bin/XSDocgen \
46 | @ --clear \
47 | @ --source ../ShellKit \
48 | @ --output . \
49 | @ --project-name "ShellKit" \
50 | @ --project-copyright "XS-Labs © %Y - All Rights Reserved" \
51 | @ --project-version "0.0.0-0" \
52 | @ --project-timezone "Europe/Zurich" \
53 | @ --company-name "XS-Labs" \
54 | @ --company-url "http://www.xs-labs.com/" \
55 | @ --page-home "Pages/Home.inc.php" \
56 | @ --source-root-prefix "/ShellKit/" \
57 | @ --google-analytics "UA-51035898-4" "xs-labs.com" \
58 | @ --google-analytics-display-features
59 | else
60 | @echo $(call _PRINT,XSDoc,universal,Skipping documentation generation - XSDocgen is not installed)
61 | endif
62 |
--------------------------------------------------------------------------------
/ShellKit/Classes/ShellKit/NSString+ShellKit.h:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | ******************************************************************************/
24 |
25 | /*!
26 | * @header NSString+ShellKit.h
27 | * @copyright (c) 2017, Jean-David Gadina - www.xs-labs.com
28 | */
29 |
30 | #import
31 | #import
32 |
33 | /*!
34 | * @category NSString( ShellKit )
35 | * @abstract Additional NSString methods for ShellKit
36 | */
37 | NS_ASSUME_NONNULL_BEGIN
38 |
39 | @interface NSString( ShellKit )
40 |
41 | /*!
42 | * @method stringForShellStatus:
43 | * @abstract Returns an emoji string for a status
44 | * @discussion Status icons can be disabled with the `statusIconsEnabled` of
45 | * `SKShell`.
46 | * @result A string representing the status
47 | * @see SKStatus
48 | * @see SKShell#statusIconsEnabled
49 | */
50 | + ( NSString * )stringForShellStatus: ( SKStatus )status;
51 |
52 | /*!
53 | * @method stringForShellColor:
54 | * @abstract Returns the string used to represent a shell color
55 | * @discussion Colors can be disabled with the `colorsEnabled` property of
56 | * `SKShell`.
57 | * @result A string representing the shell color
58 | * @see SKColor
59 | * @see SKShell#colorsEnabled
60 | */
61 | + ( NSString * )stringForShellColor: ( SKColor )color;
62 |
63 | /*!
64 | * @method stringWithShellColor:
65 | * @abstract Returns a string with a shell color.
66 | * @discussion Colors can be disabled with the `colorsEnabled` property of
67 | * `SKShell`.
68 | * @result The colorized version of the string
69 | * @see SKColor
70 | * @see SKShell#colorsEnabled
71 | */
72 | - ( NSString * )stringWithShellColor: ( SKColor )color;
73 |
74 | @end
75 |
76 | NS_ASSUME_NONNULL_END
77 |
--------------------------------------------------------------------------------
/ShellKit.xcodeproj/xcshareddata/xcschemes/ShellKit.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
35 |
36 |
47 |
48 |
54 |
55 |
56 |
57 |
58 |
59 |
65 |
66 |
72 |
73 |
74 |
75 |
77 |
78 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/ShellKit.xcodeproj/xcshareddata/xcschemes/ShellKit-Static.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
35 |
36 |
47 |
48 |
54 |
55 |
56 |
57 |
58 |
59 |
65 |
66 |
72 |
73 |
74 |
75 |
77 |
78 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/ShellKit/Classes/ShellKit/SKTaskGroup.h:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | ******************************************************************************/
24 |
25 | /*!
26 | * @header SKTaskGroup.h
27 | * @copyright (c) 2017, Jean-David Gadina - www.xs-labs.com
28 | */
29 |
30 | #import
31 | #import
32 | #import
33 |
34 | NS_ASSUME_NONNULL_BEGIN
35 |
36 | /*!
37 | * @class SKTaskGroup
38 | * @abstract Represents a group of tasks that may be run
39 | * @see SKRunableObject
40 | */
41 | @interface SKTaskGroup: SKObject < SKRunableObject >
42 |
43 | /*!
44 | * @property name
45 | * @abstract The name of the task group
46 | */
47 | @property( atomic, readonly ) NSString * name;
48 |
49 | /*!
50 | * @property tasks
51 | * @abstract The tasks contained in the task group
52 | * @see SKRunableObject
53 | */
54 | @property( atomic, readonly ) NSArray< id< SKRunableObject > > * tasks;
55 |
56 | /*!
57 | * @property currentTask
58 | * @abstract The task currently executing
59 | * @discussion This property will be nil if the task group isn't running,
60 | * or if no task is actually executing.
61 | * @see SKRunableObject
62 | */
63 | @property( atomic, readonly, nullable ) id< SKRunableObject > currentTask;
64 |
65 | /*!
66 | * @method taskGroupWithName:tasks:
67 | * @abstract Creates a task group object
68 | * @param name The name of the task group
69 | * @param tasks The tasks to execute when the task group is run
70 | * @result The task group object
71 | * @see SKRunableObject
72 | */
73 | + ( instancetype )taskGroupWithName: ( NSString * )name tasks: ( NSArray< id< SKRunableObject > > * )tasks;
74 |
75 | /*!
76 | * @method initWithName:tasks:
77 | * @abstract Creates a task group object
78 | * @param name The name of the task group
79 | * @param tasks The tasks to execute when the task group is run
80 | * @result The task group object
81 | * @see SKRunableObject
82 | */
83 | - ( instancetype )initWithName: ( NSString * )name tasks: ( NSArray< id< SKRunableObject > > * )tasks NS_DESIGNATED_INITIALIZER;
84 |
85 | @end
86 |
87 | NS_ASSUME_NONNULL_END
88 |
--------------------------------------------------------------------------------
/ShellKit.xcodeproj/xcshareddata/xcschemes/ShellKit-Test.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
40 |
41 |
42 |
43 |
44 |
45 |
60 |
62 |
68 |
69 |
70 |
71 |
72 |
73 |
79 |
81 |
87 |
88 |
89 |
90 |
92 |
93 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/ShellKit/Classes/ShellKit/SKTypes.h:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | ******************************************************************************/
24 |
25 | /*!
26 | * @header SKTypes.h
27 | * @copyright (c) 2017, Jean-David Gadina - www.xs-labs.com
28 | */
29 |
30 | #import
31 |
32 | NS_ASSUME_NONNULL_BEGIN
33 |
34 | /*!
35 | * @typedef SKStatus
36 | * @abstract Defines status icons
37 | */
38 | typedef NS_ENUM( NSInteger, SKStatus )
39 | {
40 | SKStatusNone, /*! No status */
41 | SKStatusSuccess, /*! Sucess status icon */
42 | SKStatusFatal, /*! Fatal error status icon */
43 | SKStatusError, /*! Error status icon */
44 | SKStatusWarning, /*! Warning status icon */
45 | SKStatusInfo, /*! Info status icon */
46 | SKStatusDebug, /*! Debug status icon */
47 | SKStatusBuild, /*! Build status icon */
48 | SKStatusInstall, /*! Install status icon */
49 | SKStatusIdea, /*! Idea status icon */
50 | SKStatusSettings, /*! Settings status icon */
51 | SKStatusSecurity, /*! Security status icon */
52 | SKStatusExecute, /*! Executing status icon */
53 | SKStatusSearch, /*! Search status icon */
54 | SKStatusTarget, /*! Target status icon */
55 | SKStatusComment, /*! Comment status icon */
56 | SKStatusFile, /*! File status icon */
57 | SKStatusFolder, /*! Folder status icon */
58 | SKStatusTrash, /*! Trash status icon */
59 | SKStatusLink, /*! Link status icon */
60 | SKStatusMail, /*! Mail message status icon */
61 | SKStatusAttachement, /*! Message attachmnet status icon */
62 | SKStatusEdit, /*! Edit status icon */
63 | SKStatusPin, /*! Push pin status icon */
64 | SKStatusLock, /*! Lock status icon */
65 | SKStatusRocket, /*! Rocket status icon */
66 | SKStatusFire, /*! Fire status icon */
67 | SKStatusLightning, /*! Lightning status icon */
68 | SKStatusBug /*! Bug status icon */
69 | };
70 |
71 | /*!
72 | * @typedef SKColor
73 | * @abstract Shell color type
74 | */
75 | typedef NS_ENUM( NSInteger, SKColor )
76 | {
77 | SKColorNone, /*! No color (clear) */
78 | SKColorBlack, /*! Black color */
79 | SKColorRed, /*! Red color */
80 | SKColorGreen, /*! Green color */
81 | SKColorYellow, /*! Yellow color */
82 | SKColorBlue, /*! Blue color */
83 | SKColorPurple, /*! Purple color */
84 | SKColorWhite, /*! White color */
85 | SKColorCyan /*! Cyan color */
86 | };
87 |
88 | NS_ASSUME_NONNULL_END
89 |
--------------------------------------------------------------------------------
/ShellKit/Classes/ShellKit/NSString+ShellKit.m:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | ******************************************************************************/
24 |
25 | /*!
26 | * @file NSString+ShellKit.m
27 | * @copyright (c) 2017, Jean-David Gadina - www.xs-labs.com
28 | */
29 |
30 | #import
31 |
32 | #define SK_COLOR_NONE "\x1B[0m"
33 | #define SK_COLOR_BLACK "\x1B[30m"
34 | #define SK_COLOR_RED "\x1B[31m"
35 | #define SK_COLOR_GREEN "\x1B[32m"
36 | #define SK_COLOR_YELLOW "\x1B[33m"
37 | #define SK_COLOR_BLUE "\x1B[34m"
38 | #define SK_COLOR_PURPLE "\x1B[35m"
39 | #define SK_COLOR_CYAN "\x1B[36m"
40 | #define SK_COLOR_WHITE "\x1B[37m"
41 |
42 | @implementation NSString( ShellKit )
43 |
44 | + ( NSString * )stringForShellStatus: ( SKStatus )status
45 | {
46 | if( [ SKShell currentShell ].statusIconsEnabled == NO )
47 | {
48 | return @"";
49 | }
50 |
51 | switch( status )
52 | {
53 | case SKStatusNone: return @"";
54 | case SKStatusSuccess: return @"✅";
55 | case SKStatusFatal: return @"💣";
56 | case SKStatusError: return @"❌";
57 | case SKStatusWarning: return @"⚠️";
58 | case SKStatusInfo: return @"ℹ️";
59 | case SKStatusDebug: return @"🚸";
60 | case SKStatusBuild: return @"🔧";
61 | case SKStatusInstall: return @"📦";
62 | case SKStatusIdea: return @"💡";
63 | case SKStatusSettings: return @"⚙️";
64 | case SKStatusSecurity: return @"🔑";
65 | case SKStatusExecute: return @"🚦";
66 | case SKStatusSearch: return @"🔍";
67 | case SKStatusTarget: return @"🎯";
68 | case SKStatusComment: return @"💬";
69 | case SKStatusFile: return @"📄";
70 | case SKStatusFolder: return @"📁";
71 | case SKStatusTrash: return @"🗑";
72 | case SKStatusLink: return @"🔗";
73 | case SKStatusMail: return @"✉️";
74 | case SKStatusAttachement: return @"📎";
75 | case SKStatusEdit: return @"✏️";
76 | case SKStatusPin: return @"📌";
77 | case SKStatusLock: return @"🔒";
78 | case SKStatusRocket: return @"🚀";
79 | case SKStatusFire: return @"🔥";
80 | case SKStatusLightning: return @"⚡️";
81 | case SKStatusBug: return @"🐛";
82 | }
83 |
84 | return @"";
85 | }
86 |
87 | + ( NSString * )stringForShellColor: ( SKColor )color
88 | {
89 | if
90 | (
91 | [ SKShell currentShell ].supportsColors == NO
92 | || [ SKShell currentShell ].colorsEnabled == NO
93 | )
94 | {
95 | return @"";
96 | }
97 |
98 | switch( color )
99 | {
100 | case SKColorNone: return @SK_COLOR_NONE;
101 | case SKColorBlack: return @SK_COLOR_BLACK;
102 | case SKColorRed: return @SK_COLOR_RED;
103 | case SKColorGreen: return @SK_COLOR_GREEN;
104 | case SKColorYellow: return @SK_COLOR_YELLOW;
105 | case SKColorBlue: return @SK_COLOR_BLUE;
106 | case SKColorPurple: return @SK_COLOR_PURPLE;
107 | case SKColorWhite: return @SK_COLOR_WHITE;
108 | case SKColorCyan: return @SK_COLOR_CYAN;
109 | }
110 | }
111 |
112 | - ( NSString * )stringWithShellColor: ( SKColor )color
113 | {
114 | NSString * str;
115 |
116 | if( self.length == 0 )
117 | {
118 | return @"";
119 | }
120 |
121 | if( [ SKShell currentShell ].supportsColors == NO )
122 | {
123 | return [ self copy ];
124 | }
125 |
126 | str = [ NSString stringForShellColor: color ];
127 | str = [ str stringByAppendingString: self ];
128 | str = [ str stringByAppendingString: [ NSString stringForShellColor: SKColorNone ] ];
129 |
130 | return str;
131 | }
132 |
133 | @end
134 |
--------------------------------------------------------------------------------
/ShellKit/Classes/ShellKit/SKTaskGroup.m:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | ******************************************************************************/
24 |
25 | /*!
26 | * @file SKTaskGroup.m
27 | * @copyright (c) 2017, Jean-David Gadina - www.xs-labs.com
28 | */
29 |
30 | #import
31 |
32 | NS_ASSUME_NONNULL_BEGIN
33 |
34 | @interface SKTaskGroup()
35 |
36 | @property( atomic, readwrite, assign ) BOOL running;
37 | @property( atomic, readwrite, strong, nullable ) NSError * error;
38 | @property( atomic, readwrite, strong ) NSString * name;
39 | @property( atomic, readwrite, strong ) NSArray< id< SKRunableObject > > * tasks;
40 | @property( atomic, readwrite, strong, nullable ) id< SKRunableObject > currentTask;
41 |
42 | @end
43 |
44 | NS_ASSUME_NONNULL_END
45 |
46 | @implementation SKTaskGroup
47 |
48 | + ( instancetype )taskGroupWithName: ( NSString * )name tasks: ( NSArray< id< SKRunableObject > > * )tasks
49 | {
50 | return [ [ self alloc ] initWithName: name tasks: tasks ];
51 | }
52 |
53 | - ( instancetype )init
54 | {
55 | return [ self initWithName: @"" tasks: @[] ];
56 | }
57 |
58 | - ( instancetype )initWithName: ( NSString * )name tasks: ( NSArray< id< SKRunableObject > > * )tasks
59 | {
60 | if( ( self = [ super init ] ) )
61 | {
62 | self.name = name;
63 | self.tasks = tasks;
64 | }
65 |
66 | return self;
67 | }
68 |
69 | #pragma mark - SKRunableObject
70 |
71 | - ( BOOL )run
72 | {
73 | return [ self run: nil ];
74 | }
75 |
76 | - ( BOOL )run: ( nullable NSDictionary< NSString *, NSString * > * )variables
77 | {
78 | id< SKRunableObject > task;
79 | NSDate * date;
80 | NSString * time;
81 | NSUInteger i;
82 |
83 | @synchronized( self )
84 | {
85 | self.running = YES;
86 |
87 | if( self.name.length )
88 | {
89 | [ [ SKShell currentShell ] addPromptPart: self.name ];
90 | }
91 |
92 | if( self.tasks.count == 0 )
93 | {
94 | self.error = [ self errorWithDescription: @"No task defined" ];
95 |
96 | [ [ SKShell currentShell ] printError: self.error ];
97 |
98 | self.running = NO;
99 |
100 | if( self.name.length )
101 | {
102 | [ [ SKShell currentShell ] removeLastPromptPart ];
103 | }
104 |
105 | return NO;
106 | }
107 |
108 | if( self.tasks.count > 1 )
109 | {
110 | [ [ SKShell currentShell ] printMessage: @"Running %lu tasks" status: SKStatusExecute color: SKColorNone, self.tasks.count ];
111 | }
112 |
113 | i = 0;
114 | date = [ NSDate date ];
115 |
116 | for( task in self.tasks )
117 | {
118 | self.currentTask = task;
119 |
120 | [ [ SKShell currentShell ] addPromptPart: [ NSString stringWithFormat: @"#%li", ( unsigned long )++i ] ];
121 |
122 | if( [ task run: variables ] == NO )
123 | {
124 | [ [ SKShell currentShell ] removeLastPromptPart ];
125 |
126 | self.currentTask = nil;
127 | self.error = task.error;
128 |
129 | [ [ SKShell currentShell ] printErrorMessage: @"Failed to execute task group" ];
130 |
131 | self.running = NO;
132 |
133 | if( self.name.length )
134 | {
135 | [ [ SKShell currentShell ] removeLastPromptPart ];
136 | }
137 |
138 | return NO;
139 | }
140 |
141 | [ [ SKShell currentShell ] removeLastPromptPart ];
142 | }
143 |
144 | time = date.elapsedTimeStringSinceNow;
145 | self.currentTask = nil;
146 |
147 | if( self.tasks.count > 1 )
148 | {
149 | if( time )
150 | {
151 | time = [ [ NSString stringWithFormat: @"(%@)", time ] stringWithShellColor: SKColorNone ];
152 |
153 | [ [ SKShell currentShell ] printSuccessMessage: @"%lu tasks completed successfully %@", self.tasks.count, time ];
154 | }
155 | else
156 | {
157 | [ [ SKShell currentShell ] printSuccessMessage: @"%lu tasks completed successfully", self.tasks.count ];
158 | }
159 | }
160 |
161 | self.running = NO;
162 |
163 | if( self.name.length )
164 | {
165 | [ [ SKShell currentShell ] removeLastPromptPart ];
166 | }
167 |
168 | return YES;
169 | }
170 | }
171 |
172 | @end
173 |
--------------------------------------------------------------------------------
/ShellKit/Classes/ShellKit/SKTask.h:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | ******************************************************************************/
24 |
25 | /*!
26 | * @header SKTask.h
27 | * @copyright (c) 2017, Jean-David Gadina - www.xs-labs.com
28 | */
29 |
30 | #import
31 | #import
32 | #import
33 |
34 | NS_ASSUME_NONNULL_BEGIN
35 |
36 | @class SKTask;
37 |
38 | /*!
39 | * @typedef SKTaskOutputType
40 | * @abstract The type of output of a task
41 | * @discussion Used to differenciate output comming from a task's `stdout`
42 | * or `stderr`.
43 | */
44 | typedef NS_ENUM( NSInteger, SKTaskOutputType )
45 | {
46 | SKTaskOutputTypeStandardOutput, /*! `stdout` output type */
47 | SKTaskOutputTypeStandardError /*! `stderr` output type */
48 | };
49 |
50 | /*!
51 | * @protocol SKTaskDelegate
52 | * @abstract Delegate for `SKTask` objects
53 | * @see SKTask
54 | */
55 | @protocol SKTaskDelegate< NSObject >
56 |
57 | @optional
58 |
59 | /*!
60 | * @method taskWillStart:
61 | * @abstract Called when a task is about to be run
62 | * @dicussion This method is optional.
63 | * @param task The task object
64 | * @see SKTask
65 | */
66 | - ( void )taskWillStart: ( SKTask * )task;
67 |
68 | /*!
69 | * @method task:didProduceOutput:
70 | * @abstract Called when a task has produced output on `stdout` or `stderr`
71 | * @dicussion This method is optional.
72 | * Note that the output may not be whole/complete lines, as this
73 | * method, if implemented by the delagete, will be called as
74 | * output is captured.
75 | * @param task The task object
76 | * @param output The produced output string
77 | * @param type The output type
78 | * @see SKTask
79 | * @see SKTaskOutputType
80 | */
81 | - ( void )task: ( SKTask * )task didProduceOutput: ( NSString * )output forType: ( SKTaskOutputType )type;
82 |
83 | /*!
84 | * @method task:didEndWithStatus:
85 | * @abstract Called when a task has finished running
86 | * @dicussion This method is optional.
87 | * @param task The task object
88 | * @param status The task's exit status
89 | * @see SKTask
90 | */
91 | - ( void )task: ( SKTask * )task didEndWithStatus: ( int )status;
92 |
93 | @end
94 |
95 | /*!
96 | * @class SKTask
97 | * @discussion Represents a shell task
98 | * @see SKRunableObject
99 | */
100 | @interface SKTask: SKObject < SKRunableObject >
101 |
102 | /*!
103 | * @property delegate
104 | * @abstract The task's delegate
105 | * @see SKTaskDelegate
106 | */
107 | @property( atomic, readwrite, weak ) id< SKTaskDelegate > delegate;
108 |
109 | /*!
110 | * @method taskWithShellScript:
111 | * @abstract Creates a task from a shell script
112 | * @param script The shell script to execute when the task is run
113 | * @result The task object
114 | */
115 | + ( instancetype )taskWithShellScript: ( NSString * )script;
116 |
117 | /*!
118 | * @method taskWithShellScript:recoverTask:
119 | * @abstract Creates a task from a shell script
120 | * @discussion If a recovery task is passed, it will be executed upon failure.
121 | * If the recovery task then succeed, the primary task will also
122 | * succeed.
123 | * @param script The shell script to execute when the task is run
124 | * @param recover An optional task to execute as recovery if the task fails.
125 | * @result The task object
126 | */
127 | + ( instancetype )taskWithShellScript: ( NSString * )script recoverTask: ( nullable SKTask * )recover;
128 |
129 | /*!
130 | * @method taskWithShellScript:recoverTasks:
131 | * @abstract Creates a task from a shell script
132 | * @discussion If recovery tasks are passed, they will be executed upon
133 | * failure, until one of them succeed.
134 | * If a recovery task then succeed, the primary task will also
135 | * succeed.
136 | * @param script The shell script to execute when the task is run
137 | * @param recover An optional array of tasks to execute as recovery if the task fails.
138 | * @result The task object
139 | */
140 | + ( instancetype )taskWithShellScript: ( NSString * )script recoverTasks: ( nullable NSArray< SKTask * > * )recover;
141 |
142 | /*!
143 | * @method initWithShellScript:
144 | * @abstract Creates a task from a shell script
145 | * @param script The shell script to execute when the task is run
146 | * @result The task object
147 | */
148 | - ( instancetype )initWithShellScript: ( NSString * )script;
149 |
150 | /*!
151 | * @method initWithShellScript:recoverTask:
152 | * @abstract Creates a task from a shell script
153 | * @discussion If a recovery task is passed, it will be executed upon failure.
154 | * If the recovery task then succeed, the primary task will also
155 | * succeed.
156 | * @param script The shell script to execute when the task is run
157 | * @param recover An optional task to execute as recovery if the task fails.
158 | * @result The task object
159 | */
160 | - ( instancetype )initWithShellScript: ( NSString * )script recoverTask: ( nullable SKTask * )recover;
161 |
162 | /*!
163 | * @method initWithShellScript:recoverTasks:
164 | * @abstract Creates a task from a shell script
165 | * @discussion If recovery tasks are passed, they will be executed upon
166 | * failure, until one of them succeed.
167 | * If a recovery task then succeed, the primary task will also
168 | * succeed.
169 | * @param script The shell script to execute when the task is run
170 | * @param recover An optional array of tasks to execute as recovery if the task fails.
171 | * @result The task object
172 | */
173 | - ( instancetype )initWithShellScript: ( NSString * )script recoverTasks: ( nullable NSArray< SKTask * > * )recover NS_DESIGNATED_INITIALIZER;
174 |
175 | @end
176 |
177 | NS_ASSUME_NONNULL_END
178 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ShellKit
2 | ========
3 |
4 | [](https://travis-ci.org/macmade/ShellKit)
5 | [](https://coveralls.io/r/macmade/ShellKit?branch=master)
6 | [](https://github.com/macmade/ShellKit/issues)
7 | 
8 | 
9 | [](https://twitter.com/macmade)
10 | [](https://patreon.com/macmade)
11 | [](https://www.gratipay.com/macmade)
12 | [](https://paypal.me/xslabs)
13 |
14 | About
15 | -----
16 |
17 | Objective-C framework for running shell scripts.
18 |
19 | 
20 |
21 | Documentation
22 | -------------
23 |
24 | Documentation and API reference can be found at: http://doc.xs-labs.com/ShellKit/
25 |
26 | Code Examples
27 | -------------
28 |
29 | `ShellKit` provides a test executable.
30 | For complete examples, please take a look at the [source code](https://github.com/macmade/ShellKit/blob/master/ShellKit-Test/main.m).
31 |
32 | ### Shell informations
33 |
34 | Various shell informations, like paths for commands, can be retrieved using the `SKShell` class:
35 |
36 | ```objc
37 | [ [ SKShell currentShell ] commandIsAvailable: @"xcodebuild" ]
38 |
39 | NSString * path = [ [ SKShell currentShell ] pathForCommand: @"xcodebuild" ]
40 | ```
41 |
42 | ### Running simple commands
43 |
44 | Arbitrary shell commands can be run using the `SKShell` class.
45 | Note that commands are executed using the shell defined in the `SHELL` environment variable, invoked as a login shell.
46 | Data for `stdin` can be provided; `stdout` and `stderr` can be retrieved.
47 |
48 | ```objc
49 | [ [ SKShell currentShell ] runCommand: @"ls -al"
50 | completion: ^( int status, NSString * output, NSString * error )
51 | {
52 | NSLog( @"%i", status );
53 | NSLog( @"%@", output );
54 | NSLog( @"%@", error );
55 | }
56 | ];
57 | ```
58 |
59 | ### Running shell script tasks
60 |
61 | A shell command can by run by using the `SKTask` object:
62 |
63 | ```objc
64 | SKTask * task;
65 |
66 | task = [ SKTask taskWithShellScript: @"ls -al" ];
67 |
68 | [ task run ];
69 | ```
70 |
71 | The task is run synchronously, and its output, if any, will be automatically printed to `stdout`.
72 |
73 | The task will print the executed command prior to running, and print a status message once it's terminated, along with the elapsed time:
74 |
75 | [ ShellKit ]> 🚦 Running task: ls -al
76 | total 536
77 | drwxr-xr-x 5 macmade staff 170 May 11 23:49 .
78 | drwxr-xr-x@ 4 macmade staff 136 May 11 22:18 ..
79 | -rwxr-xr-x 1 macmade staff 124624 May 11 23:49 ShellKit-Test
80 | drwxr-xr-x 7 macmade staff 238 May 11 23:48 ShellKit.framework
81 | -rw-r--r-- 1 macmade staff 143936 May 11 23:48 libShellKit-Static.a
82 | [ ShellKit ]> ✅ Task completed successfully (63 ms)
83 |
84 | A task can have sub-tasks, to try to recover from a failure:
85 |
86 | ```objc
87 | SKTask * task;
88 |
89 | task = [ SKTask taskWithShellScript: @"false" recoverTask: [ SKTask taskWithShellScript: @"true" ] ];
90 |
91 | [ task run ];
92 | ```
93 |
94 | Here, the `false` task will obviously fail, but it will then execute the `true` task, set as recovery.
95 | As `true` will succeed, the `false` task will also succeed:
96 |
97 | [ ShellKit ]> 🚦 Running task: false
98 | [ ShellKit ]> ⚠️ Task failed - Trying to recover...
99 | [ ShellKit ]> 🚦 Running task: true
100 | [ ShellKit ]> ✅ Task completed successfully (66 ms)
101 | [ ShellKit ]> ✅ Task recovered successfully (66 ms)
102 |
103 | ### Optional tasks
104 |
105 | A task can be marked as optional by using the `SKOptionalTask`.
106 | In such a case, the task will succeed, regardless of its exit status:
107 |
108 | ```objc
109 | SKOptionalTask * task;
110 |
111 | task = [ SKOptionalTask taskWithShellScript: @"false" ];
112 |
113 | [ task run ];
114 | ```
115 |
116 | [ ShellKit ]> 🚦 Running task: false
117 | [ ShellKit ]> ❌ Error - Task exited with status 1
118 | [ ShellKit ]> ✅ Task is marked as optional - Not failing
119 |
120 | ### Running task groups
121 |
122 | Multiple tasks can be grouped in a `SKTaskGroup` object:
123 |
124 | ```objc
125 | SKTask * t1;
126 | SKTask * t2;
127 | SKTaskGroup * group;
128 |
129 | t1 = [ SKTask taskWithShellScript: @"true" ];
130 | t2 = [ SKTask taskWithShellScript: @"true" ];
131 | group = [ SKTaskGroup taskGroupWithName: @"task-group" tasks: @[ t1, t2 ] ];
132 |
133 | [ group run ];
134 | ```
135 |
136 | The group will try to run each task.
137 | If a task fails, the whole group will also fail.
138 |
139 | [ ShellKit ]> [ task-group ]> 🚦 Running 2 tasks
140 | [ ShellKit ]> [ task-group ]> [ #1 ]> 🚦 Running task: true
141 | [ ShellKit ]> [ task-group ]> [ #1 ]> ✅ Task completed successfully (64 ms)
142 | [ ShellKit ]> [ task-group ]> [ #2 ]> 🚦 Running task: true
143 | [ ShellKit ]> [ task-group ]> [ #2 ]> ✅ Task completed successfully (65 ms)
144 | [ ShellKit ]> [ task-group ]> ✅ 2 tasks completed successfully (132 ms)
145 |
146 | ### Running task groups within task groups
147 |
148 | A task group may also contain other task groups:
149 |
150 | ```objc
151 | SKTask * t1;
152 | SKTask * t2;
153 | SKTaskGroup * g1;
154 | SKTaskGroup * g2;
155 |
156 | t1 = [ SKTask taskWithShellScript: @"true" ];
157 | t2 = [ SKTask taskWithShellScript: @"true" ];
158 | g1 = [ SKTaskGroup taskGroupWithName: @"child-group" tasks: @[ t1, t2 ] ];
159 | g2 = [ SKTaskGroup taskGroupWithName: @"parent-group" tasks: @[ g1 ] ];
160 |
161 | [ g2 run ];
162 | ```
163 |
164 | The hierarchy of groups will be reflected by the prompt, like:
165 |
166 | [ ShellKit ]> [ parent-group ]> [ #1 ]> [ child-group ]> [ #1 ]> 🚦 Running task: true
167 |
168 | **Note that task groups can also run custom classes, as long as they conform to the `SKRunableObject` protocol.**
169 |
170 | ### Variables substitution
171 |
172 | A task may contain variables, that will be substituted when running.
173 | A variable has the following form:
174 |
175 | %{name}%
176 |
177 | The variable name may contain letters from A to Z (uppercase or lowercase) and numbers from 0 to 9.
178 |
179 | Variables are passed using the `run:` method of `SKTask` and `SKTaskGroup`.
180 |
181 | ```objc
182 | SKTask * task;
183 |
184 | task = [ SKTask taskWithShellScript: @"ls %{args}% %{dir}%" ];
185 |
186 | [ task run: @{ @"args" : @"-al", @"dir" : @"/usr" } ];
187 | ```
188 |
189 | In the example above, the executed script will be: `ls -al /usr`.
190 |
191 | If no value is provided for a variable, the task will fail:
192 |
193 | ```objc
194 | SKTask * task;
195 |
196 | task = [ SKTask taskWithShellScript: @"echo %{hello}% %{foo}% %{bar}%" ];
197 |
198 | [ task run: @{ @"hello" : @"hello, world" } ];
199 | ```
200 |
201 | [ ShellKit ]> 🚦 Running task: echo hello, world %{foo}% %{bar}%
202 | [ ShellKit ]> ⚠️ No value provided value for variable: foo
203 | [ ShellKit ]> ⚠️ No value provided value for variable: bar
204 | [ ShellKit ]> ❌ Error - Script contains unsubstituted variables
205 |
206 | ### Printing messages
207 |
208 | Messages can be printed very easily.
209 | For this purpose, the `SKShell` class provides several methods, like the following one:
210 |
211 |
212 | ```objc
213 | - ( void )printMessage: ( NSString * )format
214 | status: ( SKStatus )status
215 | color: ( SKColor )color,
216 | ...;
217 | ```
218 |
219 | The status represents an optional icon.
220 | Colors can also be used, if the terminal supports it.
221 |
222 | As an example:
223 |
224 | ```objc
225 | [ [ SKShell currentShell ] printMessage: @"hello, %@"
226 | status: SKStatusDebug
227 | color: SKColorCyan,
228 | @"world"
229 | ];
230 | ```
231 |
232 | will produce:
233 |
234 | 🚸 hello, world
235 |
236 | ### Customising prompt
237 |
238 | The prompt can be customised to reflect the hierarchy of the invoked commands.
239 |
240 | For instance:
241 |
242 | ```objc
243 | [ SKShell currentShell ].promptParts = @[ @"foo", @"bar" ];
244 | ```
245 |
246 | Then, every printed message will be prefixed by:
247 |
248 | [ foo ]> [ bar ]> ... message ...
249 |
250 | License
251 | -------
252 |
253 | ShellKit is released under the terms of the MIT license.
254 |
255 | Repository Infos
256 | ----------------
257 |
258 | Owner: Jean-David Gadina - XS-Labs
259 | Web: www.xs-labs.com
260 | Blog: www.noxeos.com
261 | Twitter: @macmade
262 | GitHub: github.com/macmade
263 | LinkedIn: ch.linkedin.com/in/macmade/
264 | StackOverflow: stackoverflow.com/users/182676/macmade
265 |
--------------------------------------------------------------------------------
/ShellKit-Test/main.m:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | ******************************************************************************/
24 |
25 | /*!
26 | * @header main.m
27 | * @copyright (c) 2017, Jean-David Gadina - www.xs-labs.com
28 | */
29 |
30 | #import
31 | #import
32 |
33 | @interface TaskDelegate: NSObject < SKTaskDelegate >
34 |
35 | @end
36 |
37 | void PrintStep( NSString * msg );
38 |
39 | int main( void )
40 | {
41 | @autoreleasepool
42 | {
43 | [ SKShell currentShell ].promptParts = @[ @"ShellKit" ];
44 |
45 | PrintStep( @"Shell infos" );
46 |
47 | {
48 | NSString * shell;
49 | NSString * brew;
50 | NSString * xcodebuild;
51 |
52 | shell = [ SKShell currentShell ].shell;
53 | brew = [ [ SKShell currentShell ] pathForCommand: @"brew" ];
54 | xcodebuild = [ [ SKShell currentShell ] pathForCommand: @"xcodebuild" ];
55 |
56 | assert( shell != nil );
57 |
58 | [ [ SKShell currentShell ] printMessage: @"shell: %@" status: SKStatusSettings, shell ];
59 | [ [ SKShell currentShell ] printMessage: @"brew: %@" status: SKStatusSettings, ( brew ) ? brew : @"--" ];
60 | [ [ SKShell currentShell ] printMessage: @"xcodebuild: %@" status: SKStatusSettings, ( xcodebuild ) ? xcodebuild : @"--" ];
61 | }
62 |
63 | PrintStep( @"Executing commands" );
64 |
65 | {
66 | [ [ SKShell currentShell ] printMessage: @"Executing ls -al" status: SKStatusExecute color: SKColorCyan ];
67 | [ [ SKShell currentShell ] runCommand: @"ls -al" completion: ^( int status, NSString * output, NSString * error )
68 | {
69 | [ [ SKShell currentShell ] printInfoMessage: @"Command exited with status %i", status ];
70 |
71 | if( output.length )
72 | {
73 | [ [ SKShell currentShell ] printInfoMessage: @"Standard output:" ];
74 | [ [ SKShell currentShell ] printMessage: @"%@", output ];
75 | }
76 |
77 | if( error.length )
78 | {
79 | [ [ SKShell currentShell ] printInfoMessage: @"Standard error:" ];
80 | [ [ SKShell currentShell ] printMessage: @"%@", error ];
81 | }
82 | }
83 | ];
84 | }
85 |
86 | PrintStep( @"Simple task" );
87 |
88 | {
89 | SKTask * task;
90 |
91 | task = [ SKTask taskWithShellScript: @"ls -al" ];
92 |
93 | assert( ( [ task run ] == YES ) );
94 | }
95 |
96 | PrintStep( @"Simple task failure" );
97 |
98 | {
99 | SKTask * task;
100 |
101 | task = [ SKTask taskWithShellScript: @"false" ];
102 |
103 | assert( ( [ task run ] == NO ) );
104 | }
105 |
106 | PrintStep( @"Simple task failure with failed recovery" );
107 |
108 | {
109 | SKTask * task;
110 |
111 | task = [ SKTask taskWithShellScript: @"false" recoverTask: [ SKTask taskWithShellScript: @"false" ] ];
112 |
113 | assert( ( [ task run ] == NO ) );
114 | }
115 |
116 | PrintStep( @"Simple task failure with successful recovery (variant 1)" );
117 |
118 | {
119 | SKTask * task;
120 |
121 | task = [ SKTask taskWithShellScript: @"false" recoverTasks: @[ [ SKTask taskWithShellScript: @"false" ], [ SKTask taskWithShellScript: @"true" ] ] ];
122 |
123 | assert( ( [ task run ] == YES ) );
124 | }
125 |
126 | PrintStep( @"Simple task failure with successful recovery (variant 2)" );
127 |
128 | {
129 | SKTask * task;
130 |
131 | task = [ SKTask taskWithShellScript: @"false" recoverTask: [ SKTask taskWithShellScript: @"false" recoverTask: [ SKTask taskWithShellScript: @"true" ] ] ];
132 |
133 | assert( ( [ task run ] == YES ) );
134 | }
135 |
136 | PrintStep( @"Optional task" );
137 |
138 | {
139 | SKOptionalTask * task;
140 |
141 | task = [ SKOptionalTask taskWithShellScript: @"false" ];
142 |
143 | assert( ( [ task run ] == YES ) );
144 | }
145 |
146 | PrintStep( @"Task group" );
147 |
148 | {
149 | SKTask * t1;
150 | SKTask * t2;
151 | SKTaskGroup * group;
152 |
153 | t1 = [ SKTask taskWithShellScript: @"true" ];
154 | t2 = [ SKTask taskWithShellScript: @"true" ];
155 | group = [ SKTaskGroup taskGroupWithName: @"group" tasks: @[ t1, t2 ] ];
156 |
157 | assert( ( [ group run ] == YES ) );
158 | }
159 |
160 | PrintStep( @"Task group failure" );
161 |
162 | {
163 | SKTask * t1;
164 | SKTask * t2;
165 | SKTaskGroup * group;
166 |
167 | t1 = [ SKTask taskWithShellScript: @"true" ];
168 | t2 = [ SKTask taskWithShellScript: @"false" ];
169 | group = [ SKTaskGroup taskGroupWithName: @"group" tasks: @[ t1, t2 ] ];
170 |
171 | assert( ( [ group run ] == NO ) );
172 | }
173 |
174 | PrintStep( @"Task group failure with successful recovery" );
175 |
176 | {
177 | SKTask * t1;
178 | SKTask * t2;
179 | SKTaskGroup * group;
180 |
181 | t1 = [ SKTask taskWithShellScript: @"true" ];
182 | t2 = [ SKTask taskWithShellScript: @"false" recoverTask: t1 ];
183 | group = [ SKTaskGroup taskGroupWithName: @"group" tasks: @[ t1, t2 ] ];
184 |
185 | assert( ( [ group run ] == YES ) );
186 | }
187 |
188 | PrintStep( @"Task groups in task group" );
189 |
190 | {
191 | SKTask * t1;
192 | SKTask * t2;
193 | SKTaskGroup * g1;
194 | SKTaskGroup * g2;
195 | SKTaskGroup * group;
196 |
197 | t1 = [ SKTask taskWithShellScript: @"true" ];
198 | t2 = [ SKTask taskWithShellScript: @"true" ];
199 | g1 = [ SKTaskGroup taskGroupWithName: @"foo" tasks: @[ t1, t2 ] ];
200 | g2 = [ SKTaskGroup taskGroupWithName: @"bar" tasks: @[ t1, t2 ] ];
201 | group = [ SKTaskGroup taskGroupWithName: @"group" tasks: @[ g1, g2 ] ];
202 |
203 | assert( ( [ group run ] == YES ) );
204 | }
205 |
206 | PrintStep( @"Task groups in task group failure" );
207 |
208 | {
209 | SKTask * t1;
210 | SKTask * t2;
211 | SKTask * t3;
212 | SKTaskGroup * g1;
213 | SKTaskGroup * g2;
214 | SKTaskGroup * group;
215 |
216 | t1 = [ SKTask taskWithShellScript: @"true" ];
217 | t2 = [ SKTask taskWithShellScript: @"true" ];
218 | t3 = [ SKTask taskWithShellScript: @"false" ];
219 | g1 = [ SKTaskGroup taskGroupWithName: @"foo" tasks: @[ t1, t2 ] ];
220 | g2 = [ SKTaskGroup taskGroupWithName: @"bar" tasks: @[ t1, t3 ] ];
221 | group = [ SKTaskGroup taskGroupWithName: @"group" tasks: @[ g1, g2 ] ];
222 |
223 | assert( ( [ group run ] == NO ) );
224 | }
225 |
226 | PrintStep( @"Task groups in task group with successful recovery" );
227 |
228 | {
229 | SKTask * t1;
230 | SKTask * t2;
231 | SKTask * t3;
232 | SKTaskGroup * g1;
233 | SKTaskGroup * g2;
234 | SKTaskGroup * group;
235 |
236 | t1 = [ SKTask taskWithShellScript: @"true" ];
237 | t2 = [ SKTask taskWithShellScript: @"true" ];
238 | t3 = [ SKTask taskWithShellScript: @"false" recoverTask: t1 ];
239 | g1 = [ SKTaskGroup taskGroupWithName: @"foo" tasks: @[ t1, t2 ] ];
240 | g2 = [ SKTaskGroup taskGroupWithName: @"bar" tasks: @[ t1, t3 ] ];
241 | group = [ SKTaskGroup taskGroupWithName: @"group" tasks: @[ g1, g2 ] ];
242 |
243 | assert( ( [ group run ] == YES ) );
244 | }
245 |
246 | PrintStep( @"Task arguments" );
247 |
248 | {
249 | SKTask * task;
250 |
251 | task = [ SKTask taskWithShellScript: @"ls %{args}% %{dir}%" ];
252 |
253 | assert( ( [ task run: @{ @"args" : @"-al", @"dir" : @"/usr" } ] == YES ) );
254 | }
255 |
256 | PrintStep( @"Task arguments failure" );
257 |
258 | {
259 | SKTask * task;
260 |
261 | task = [ SKTask taskWithShellScript: @"echo %{hello}% %{foo}% %{bar}%" ];
262 |
263 | assert( ( [ task run: @{ @"hello" : @"hello, world" } ] == NO ) );
264 | }
265 |
266 | PrintStep( @"Task delegate" );
267 |
268 | {
269 | SKTask * task;
270 | TaskDelegate * delegate;
271 |
272 | task = [ SKTask taskWithShellScript: @"ls -al" ];
273 | delegate = [ TaskDelegate new ];
274 | task.delegate = delegate;
275 |
276 | assert( ( [ task run ] == YES ) );
277 |
278 | task.delegate = nil;
279 | }
280 |
281 | [ SKShell currentShell ].prompt = @"";
282 |
283 | [ [ SKShell currentShell ] printMessage: @"" ];
284 | [ [ SKShell currentShell ] printSuccessMessage: @"All examples completed successfully" ];
285 | }
286 |
287 | return EXIT_SUCCESS;
288 | }
289 |
290 | @implementation TaskDelegate
291 |
292 | - ( void )taskWillStart: ( SKTask * )task
293 | {
294 | [ [ SKShell currentShell ] printMessage: @"Task will start: %@" status: SKStatusDebug, task ];
295 | }
296 |
297 | - ( void )task: ( SKTask * )task didEndWithStatus: ( int )status
298 | {
299 | ( void )task;
300 |
301 | [ [ SKShell currentShell ] printMessage: @"Task ended with status: %i" status: SKStatusDebug, status ];
302 | }
303 |
304 | - ( void )task: ( SKTask * )task didProduceOutput: ( NSString * )output forType: ( SKTaskOutputType )type
305 | {
306 | ( void )task;
307 |
308 | if( type == SKTaskOutputTypeStandardOutput )
309 | {
310 | fprintf( stdout, "%s", output.UTF8String );
311 | }
312 | else if( type == SKTaskOutputTypeStandardError )
313 | {
314 | fprintf( stderr, "%s", output.UTF8String );
315 | }
316 | }
317 |
318 | @end
319 |
320 | static NSUInteger step = 0;
321 |
322 | void PrintStep( NSString * msg )
323 | {
324 | NSArray * prompt;
325 |
326 | prompt = [ SKShell currentShell ].promptParts;
327 | [ SKShell currentShell ].prompt = @"";
328 |
329 | [ [ SKShell currentShell ] printMessage: @"" ];
330 | [ [ SKShell currentShell ] printMessage: @"Example %lu: %@" status: SKStatusIdea, ( unsigned long )++step, msg ];
331 | [ [ SKShell currentShell ] printMessage: @"--------------------------------------------------------------------------------" ];
332 |
333 | [ SKShell currentShell ].promptParts = prompt;
334 | }
335 |
--------------------------------------------------------------------------------
/ShellKit/Classes/ShellKit/SKTask.m:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | ******************************************************************************/
24 |
25 | /*!
26 | * @file SKTask.m
27 | * @copyright (c) 2017, Jean-David Gadina - www.xs-labs.com
28 | */
29 |
30 | #import
31 |
32 | NS_ASSUME_NONNULL_BEGIN
33 |
34 | @interface SKTask()
35 |
36 | @property( atomic, readwrite, assign ) BOOL running;
37 | @property( atomic, readwrite, strong, nullable ) NSError * error;
38 | @property( atomic, readwrite, strong ) NSString * script;
39 | @property( atomic, readwrite, strong, nullable ) NSArray< SKTask * > * recover;
40 |
41 | - ( void )dataAvailableForStandardOutput: ( NSNotification * )notification;
42 | - ( void )dataAvailableForStandardError: ( NSNotification * )notification;
43 |
44 | @end
45 |
46 | NS_ASSUME_NONNULL_END
47 |
48 | @implementation SKTask
49 |
50 | + ( instancetype )taskWithShellScript: ( NSString * )script
51 | {
52 | return [ [ self alloc ] initWithShellScript: script ];
53 | }
54 |
55 | + ( instancetype )taskWithShellScript: ( NSString * )script recoverTask: ( nullable SKTask * )recover;
56 | {
57 | return [ [ self alloc ] initWithShellScript: script recoverTask: recover ];
58 | }
59 |
60 | + ( instancetype )taskWithShellScript: ( NSString * )script recoverTasks: ( nullable NSArray< SKTask * > * )recover
61 | {
62 | return [ [ self alloc ] initWithShellScript: script recoverTasks: recover ];
63 | }
64 |
65 | - ( instancetype )init
66 | {
67 | return [ self initWithShellScript: @"" ];
68 | }
69 |
70 | - ( instancetype )initWithShellScript: ( NSString * )script
71 | {
72 | return [ self initWithShellScript: script recoverTask: nil ];
73 | }
74 |
75 | - ( instancetype )initWithShellScript: ( NSString * )script recoverTask: ( nullable SKTask * )recover
76 | {
77 | return [ self initWithShellScript: script recoverTasks: ( recover ) ? @[ recover ] : nil ];
78 | }
79 |
80 | - ( instancetype )initWithShellScript: ( NSString * )script recoverTasks: ( nullable NSArray< SKTask * > * )recover
81 | {
82 | if( ( self = [ super init ] ) )
83 | {
84 | self.script = script;
85 | self.recover = recover;
86 | }
87 |
88 | return self;
89 | }
90 |
91 | - ( void )dealloc
92 | {
93 | [ [ NSNotificationCenter defaultCenter ] removeObserver: self ];
94 | }
95 |
96 | #pragma mark - SKRunableObject
97 |
98 | - ( BOOL )run
99 | {
100 | return [ self run: nil ];
101 | }
102 |
103 | - ( BOOL )run: ( nullable NSDictionary< NSString *, NSString * > * )variables
104 | {
105 | NSTask * task;
106 | NSString * key;
107 | NSString * var;
108 | NSString * script;
109 | NSRegularExpression * regex;
110 | NSArray * matches;
111 | NSTextCheckingResult * match;
112 | NSDate * date;
113 | NSString * time;
114 | id< SKTaskDelegate > delegate;
115 | NSPipe * standardOutput;
116 | NSPipe * standardError;
117 |
118 | @synchronized( self )
119 | {
120 | if( self.script.length == 0 )
121 | {
122 | self.error = [ self errorWithDescription: @"No script defined" ];
123 |
124 | [ [ SKShell currentShell ] printError: self.error ];
125 |
126 | return NO;
127 | }
128 |
129 | script = self.script.copy;
130 |
131 | for( key in variables )
132 | {
133 | var = [ NSString stringWithFormat: @"%%{%@}%%", key ];
134 | script = [ script stringByReplacingOccurrencesOfString: var withString: variables[ key ] ];
135 | }
136 |
137 | self.running = YES;
138 |
139 | [ [ SKShell currentShell ] printMessage: @"Running task: %@" status: SKStatusExecute color: SKColorNone, [ script stringWithShellColor: SKColorCyan ] ];
140 |
141 | regex = [ NSRegularExpression regularExpressionWithPattern: @"%\\{([A-Za-z0-9]+)\\}%" options: NSRegularExpressionCaseInsensitive error: NULL ];
142 | matches = [ regex matchesInString: script options: ( NSMatchingOptions )0 range: NSMakeRange( 0, script.length ) ];
143 |
144 | if( matches.count != 0 )
145 | {
146 | for( match in matches )
147 | {
148 | [ [ SKShell currentShell ] printWarningMessage: @"No value provided value for variable: %@", [ script substringWithRange: [ match rangeAtIndex: 1 ] ] ];
149 | }
150 |
151 | self.error = [ self errorWithDescription: @"Script contains unsubstituted variables" ];
152 |
153 | [ [ SKShell currentShell ] printError: self.error ];
154 |
155 | return NO;
156 | }
157 |
158 | delegate = self.delegate;
159 | task = [ NSTask new ];
160 | task.launchPath = ( [ SKShell currentShell ].shell != nil ) ? [ SKShell currentShell ].shell : @"/bin/sh";
161 | task.arguments =
162 | @[
163 | @"-l",
164 | @"-c",
165 | script
166 | ];
167 |
168 | if( [ delegate respondsToSelector: @selector( task:didProduceOutput:forType: ) ] )
169 | {
170 | standardOutput = [ NSPipe pipe ];
171 | standardError = [ NSPipe pipe ];
172 |
173 | task.standardOutput = standardOutput;
174 | task.standardError = standardError;
175 |
176 | [ [ NSNotificationCenter defaultCenter ] addObserver: self selector: @selector( dataAvailableForStandardOutput: ) name: NSFileHandleDataAvailableNotification object: standardOutput.fileHandleForReading ];
177 | [ [ NSNotificationCenter defaultCenter ] addObserver: self selector: @selector( dataAvailableForStandardError: ) name: NSFileHandleDataAvailableNotification object: standardError.fileHandleForReading ];
178 |
179 | [ standardOutput.fileHandleForReading waitForDataInBackgroundAndNotify ];
180 | [ standardError.fileHandleForReading waitForDataInBackgroundAndNotify ];
181 | }
182 | else
183 | {
184 | standardOutput = nil;
185 | standardError = nil;
186 | }
187 |
188 | if( [ delegate respondsToSelector: @selector( taskWillStart: ) ] )
189 | {
190 | [ delegate taskWillStart: self ];
191 | }
192 |
193 | date = [ NSDate date ];
194 |
195 | [ task launch ];
196 | [ task waitUntilExit ];
197 |
198 | time = date.elapsedTimeStringSinceNow;
199 |
200 | if( [ delegate respondsToSelector: @selector( task:didEndWithStatus: ) ] )
201 | {
202 | [ delegate task: self didEndWithStatus: task.terminationStatus ];
203 | }
204 |
205 | if( standardOutput )
206 | {
207 | [ [ NSNotificationCenter defaultCenter ] removeObserver: self name: NSFileHandleDataAvailableNotification object: standardOutput.fileHandleForReading ];
208 | }
209 |
210 | if( standardError )
211 | {
212 | [ [ NSNotificationCenter defaultCenter ] removeObserver: self name: NSFileHandleDataAvailableNotification object: standardError.fileHandleForReading ];
213 | }
214 |
215 | if( task.terminationStatus != 0 )
216 | {
217 | if( self.recover.count )
218 | {
219 | {
220 | SKTask * recover;
221 | BOOL ret;
222 |
223 | for( recover in self.recover )
224 | {
225 | [ [ SKShell currentShell ] printWarningMessage: @"Task failed - Trying to recover" ];
226 |
227 | ret = [ recover run: variables ];
228 | self.error = recover.error;
229 |
230 | if( ret )
231 | {
232 | time = date.elapsedTimeStringSinceNow;
233 |
234 | if( time )
235 | {
236 | time = [ [ NSString stringWithFormat: @"(%@)", time ] stringWithShellColor: SKColorNone ];
237 |
238 | [ [ SKShell currentShell ] printSuccessMessage: @"Task recovered successfully %@", time ];
239 | }
240 | else
241 | {
242 | [ [ SKShell currentShell ] printSuccessMessage: @"Task recovered successfully" ];
243 | }
244 |
245 | self.running = NO;
246 |
247 | return YES;
248 | }
249 | }
250 |
251 | [ [ SKShell currentShell ] printErrorMessage: @"Task failed to recover" ];
252 |
253 | self.running = NO;
254 |
255 | return NO;
256 | }
257 | }
258 |
259 | self.error = [ self errorWithDescription: @"Task exited with status %li", ( long )( task.terminationStatus ) ];
260 |
261 | [ [ SKShell currentShell ] printError: self.error ];
262 |
263 | self.running = NO;
264 |
265 | return NO;
266 | }
267 |
268 | if( time )
269 | {
270 | time = [ [ NSString stringWithFormat: @"(%@)", time ] stringWithShellColor: SKColorNone ];
271 |
272 | [ [ SKShell currentShell ] printSuccessMessage: @"Task completed successfully %@", time ];
273 | }
274 | else
275 | {
276 | [ [ SKShell currentShell ] printSuccessMessage: @"Task completed successfully" ];
277 | }
278 |
279 | self.running = NO;
280 |
281 | return YES;
282 | }
283 | }
284 |
285 | - ( void )dataAvailableForStandardOutput: ( NSNotification * )notification
286 | {
287 | NSFileHandle * handle;
288 | NSData * data;
289 | NSString * output;
290 | id < SKTaskDelegate > delegate;
291 |
292 | handle = notification.object;
293 | data = handle.availableData;
294 | output = [ [ NSString alloc ] initWithData: data encoding: NSUTF8StringEncoding ];
295 | delegate = self.delegate;
296 |
297 | if( data.length )
298 | {
299 | if( [ delegate respondsToSelector: @selector( task:didProduceOutput:forType: ) ] )
300 | {
301 | [ delegate task: self didProduceOutput: output forType: SKTaskOutputTypeStandardOutput ];
302 | }
303 | else
304 | {
305 | fprintf( stdout, "%s", output.UTF8String );
306 | }
307 |
308 | [ handle waitForDataInBackgroundAndNotify ];
309 | }
310 | }
311 |
312 | - ( void )dataAvailableForStandardError: ( NSNotification * )notification
313 | {
314 | NSFileHandle * handle;
315 | NSData * data;
316 | NSString * output;
317 | id < SKTaskDelegate > delegate;
318 |
319 | handle = notification.object;
320 | data = handle.availableData;
321 | output = [ [ NSString alloc ] initWithData: data encoding: NSUTF8StringEncoding ];
322 | delegate = self.delegate;
323 |
324 | if( data.length )
325 | {
326 | if( [ delegate respondsToSelector: @selector( task:didProduceOutput:forType: ) ] )
327 | {
328 | [ delegate task: self didProduceOutput: output forType: SKTaskOutputTypeStandardError ];
329 | }
330 | else
331 | {
332 | fprintf( stderr, "%s", output.UTF8String );
333 | }
334 |
335 | [ handle waitForDataInBackgroundAndNotify ];
336 | }
337 | }
338 |
339 | @end
340 |
--------------------------------------------------------------------------------
/ShellKit/Classes/ShellKit/SKShell.h:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | ******************************************************************************/
24 |
25 | /*!
26 | * @header SKShell.h
27 | * @copyright (c) 2017, Jean-David Gadina - www.xs-labs.com
28 | */
29 |
30 | #import
31 | #import
32 |
33 | NS_ASSUME_NONNULL_BEGIN
34 |
35 | /*!
36 | * @typedef SKShellCommandCompletion
37 | * @abstract Completion block for a shell command
38 | * @param status The command's exit status
39 | * @param stdandardOutput The command's standard output, if any
40 | * @param standardError The command's standard error, if any
41 | */
42 | typedef void ( ^ SKShellCommandCompletion )( int status, NSString * stdandardOutput, NSString * standardError );
43 |
44 | /*!
45 | * @class SKShell
46 | * @abstract An object representing the current shell
47 | */
48 | @interface SKShell: NSObject
49 |
50 | /*!
51 | * @property supportsColors
52 | * @abstract Set if the current erminal supports color
53 | */
54 | @property( atomic, readonly ) BOOL supportsColors;
55 |
56 | /*!
57 | * @property colorsEnabled
58 | * @abstact Used to enable/disable the use of shell colors
59 | * @discussion Enabled by default. Only applicable if the current terminal
60 | * supports colors.
61 | * @see supportsColors
62 | * @see SKColor
63 | */
64 | @property( atomic, readwrite, assign ) BOOL colorsEnabled;
65 |
66 | /*!
67 | * @property statusIconsEnabled
68 | * @abstact Used to enable/disable the use of status icons
69 | * @discussion Enabled by default. Status icons are reprensented by unicode
70 | * emojis.
71 | * @see SKSTatus
72 | */
73 | @property( atomic, readwrite, assign ) BOOL statusIconsEnabled;
74 |
75 | /*!
76 | * @property prompt
77 | * @abstract Used to get/set the current prompt
78 | * @discussion If a prompt is set, all messages printed with `SKShell` will
79 | * be prefixed by the prompt.
80 | */
81 | @property( atomic, readwrite, strong, nullable ) NSString * prompt;
82 |
83 | /*!
84 | * @property promptParts
85 | * @abstract Used to get/set the promt parts
86 | * @discussion Prompt parts may be set to reflect a hierarchy in the prompt.
87 | * For instance, setting `@[ @"foo", @"bar" ]` as prompt parts will
88 | * result in a `[ foo ]> [ bar ]>` prompt.
89 | */
90 | @property( atomic, readwrite, strong, nullable ) NSArray< NSString * > * promptParts;
91 |
92 | /*!
93 | * @property allowPromptHierarchy
94 | * @abstract Enables/Disables prompt hierarchy
95 | * @discussion Enabled by default. If disabled, setting prompt parts will have
96 | * no effect.
97 | * @see promptParts
98 | */
99 | @property( atomic, readwrite, assign ) BOOL allowPromptHierarchy;
100 |
101 | /*!
102 | * @property shell
103 | * @property The path of the current shell
104 | * @discussion Retrieved using the `SHELL` environment variable.
105 | */
106 | @property( atomic, readonly, nullable ) NSString * shell;
107 |
108 | /*!
109 | * @method currentShell
110 | * @abstract Gets the instance representing the current shell
111 | * @discussion Although a `SKShell` can be instanciated, it is advised
112 | * to alyways use this shared instance.
113 | */
114 | + ( instancetype )currentShell;
115 |
116 | /*!
117 | * @method pathForCommand:
118 | * @abstract Gets the paths of a shell command
119 | * @discussion Commands are found using `which`, invoked through the logn shell.
120 | * @param command The command name
121 | * @result The full path to the command, or nil
122 | */
123 | - ( nullable NSString * )pathForCommand: ( NSString * )command;
124 |
125 | /*!
126 | * @method commandIsAvailable:
127 | * @abstract Checks if a shell command is available
128 | * @discussion Commands are found using `which`, invoked through the logn shell.
129 | * @param command The command name
130 | * @result YES is the command is available, otherwise NO
131 | */
132 | - ( BOOL )commandIsAvailable: ( NSString * )command;
133 |
134 | /*!
135 | * @method runCommand:
136 | * @abstract Executes a shell command synchronously
137 | * @discussion Command can be a complex shell commands.
138 | * @param command The command to execute
139 | * @result YES if the command executed successfully, otherwise NO
140 | */
141 | - ( BOOL )runCommand: ( NSString * )command;
142 |
143 | /*!
144 | * @method runCommand:
145 | * @abstract Executes a shell command synchronously
146 | * @discussion Command can be a complex shell commands.
147 | * @param command The command to execute
148 | * @param input An optional string to use as standard input for the command
149 | * @result YES if the command executed successfully, otherwise NO
150 | */
151 | - ( BOOL )runCommand: ( NSString * )command stdandardInput: ( nullable NSString * )input;
152 |
153 | /*!
154 | * @method runCommand:
155 | * @abstract Executes a shell command synchronously
156 | * @discussion Command can be a complex shell commands.
157 | * @param command The command to execute
158 | * @param completion An optional completion block
159 | * @result YES if the command executed successfully, otherwise NO
160 | * @see SKShellCommandCompletion
161 | */
162 | - ( BOOL )runCommand: ( NSString * )command completion: ( nullable SKShellCommandCompletion )completion;
163 |
164 | /*!
165 | * @method runCommand:
166 | * @abstract Executes a shell command synchronously
167 | * @discussion Command can be a complex shell commands.
168 | * @param command The command to execute
169 | * @param input An optional string to use as standard input for the command
170 | * @param completion An optional completion block
171 | * @result YES if the command executed successfully, otherwise NO
172 | * @see SKShellCommandCompletion
173 | */
174 | - ( BOOL )runCommand: ( NSString * )command stdandardInput: ( nullable NSString * )input completion: ( nullable SKShellCommandCompletion )completion;
175 |
176 | /*!
177 | * @method runCommand:
178 | * @abstract Executes a shell command asynchronously
179 | * @discussion Command can be a complex shell commands.
180 | * @param command The command to execute
181 | */
182 | - ( void )runCommandAsynchronously: ( NSString * )command;
183 |
184 | /*!
185 | * @method runCommand:
186 | * @abstract Executes a shell command asynchronously
187 | * @discussion Command can be a complex shell commands.
188 | * @param command The command to execute
189 | * @param input An optional string to use as standard input for the command
190 | */
191 | - ( void )runCommandAsynchronously: ( NSString * )command stdandardInput: ( nullable NSString * )input;
192 |
193 | /*!
194 | * @method runCommand:
195 | * @abstract Executes a shell command asynchronously
196 | * @discussion Command can be a complex shell commands.
197 | * @param command The command to execute
198 | * @param completion An optional completion block
199 | * @see SKShellCommandCompletion
200 | */
201 | - ( void )runCommandAsynchronously: ( NSString * )command completion: ( nullable SKShellCommandCompletion )completion;
202 |
203 | /*!
204 | * @method runCommand:
205 | * @abstract Executes a shell command asynchronously
206 | * @discussion Command can be a complex shell commands.
207 | * @param command The command to execute
208 | * @param input An optional string to use as standard input for the command
209 | * @param completion An optional completion block
210 | * @see SKShellCommandCompletion
211 | */
212 | - ( void )runCommandAsynchronously: ( NSString * )command stdandardInput: ( nullable NSString * )input completion: ( nullable SKShellCommandCompletion )completion;
213 |
214 | /*!
215 | * @method printError:
216 | * @abstract Prints an error
217 | * @discussion If the `error` param is nil, this method will print a generic
218 | * error message.
219 | * Errors are printed in red if colors are available/enabled and
220 | * with an error sign if status icons are enabled.
221 | * @param error The error object to print
222 | */
223 | - ( void )printError: ( nullable NSError * )error;
224 |
225 | /*!
226 | * @method printErrorMessage:
227 | * @abstract Prints an error message
228 | * @param format The error message format
229 | * @param ... Optional parameters for the format string
230 | * @see printError:
231 | */
232 | - ( void )printErrorMessage: ( NSString * )format, ... NS_FORMAT_FUNCTION( 1, 2 );
233 |
234 | /*!
235 | * @method printWarningMessage:
236 | * @abstract Prints an warning message
237 | * @discussion Warnings are printed in yellow if colors are available/enabled
238 | * and with an warning sign if status icons are enabled.
239 | * @param format The warning message format
240 | * @param ... Optional parameters for the format string
241 | */
242 | - ( void )printWarningMessage: ( NSString * )format, ... NS_FORMAT_FUNCTION( 1, 2 );
243 |
244 | /*!
245 | * @method printSuccessMessage:
246 | * @abstract Prints a success message
247 | * @discussion Success messages are printed in green if colors are
248 | * available/enabled and with a checkmark sign if status icons are
249 | * enabled.
250 | * @param format The success message format
251 | * @param ... Optional parameters for the format string
252 | */
253 | - ( void )printSuccessMessage: ( NSString * )format, ... NS_FORMAT_FUNCTION( 1, 2 );
254 |
255 | /*!
256 | * @method printInfoMessage:
257 | * @abstract Prints an info message
258 | * @discussion Info messages are printed in blue if colors are
259 | * available/enabled and with an info sign if status icons are
260 | * enabled.
261 | * @param format The info message format
262 | * @param ... Optional parameters for the format string
263 | */
264 | - ( void )printInfoMessage: ( NSString * )format, ... NS_FORMAT_FUNCTION( 1, 2 );
265 |
266 | /*!
267 | * @method printMessage:
268 | * @abstract Prints a message
269 | * @param format The message format
270 | * @param ... Optional parameters for the format string
271 | */
272 | - ( void )printMessage: ( NSString * )format, ... NS_FORMAT_FUNCTION( 1, 2 );
273 |
274 | /*!
275 | * @method printMessage:status:
276 | * @abstract Prints a message with a status
277 | * @discussion Statuses will be printed as an emoji, if status icons are
278 | * enabled.
279 | * @param format The message format
280 | * @param status The message status
281 | * @param ... Optional parameters for the format string
282 | * @see SKSTatus
283 | * @see statusIconsEnabled
284 | */
285 | - ( void )printMessage: ( NSString * )format status: ( SKStatus )status, ... NS_FORMAT_FUNCTION( 1, 3 );
286 |
287 | /*!
288 | * @method printMessage:color:
289 | * @abstract Prints a message with a color
290 | * @discussion Colors will only be printed if the terminal supports them and
291 | * if they are enabled.
292 | * @param format The message format
293 | * @param color The message color
294 | * @param ... Optional parameters for the format string
295 | * @see SKColor
296 | * @see supportsColors
297 | * @see colorsEnabled
298 | */
299 | - ( void )printMessage: ( NSString * )format color: ( SKColor )color, ... NS_FORMAT_FUNCTION( 1, 3 );
300 |
301 | /*!
302 | * @method printMessage:color:
303 | * @abstract Prints a message with a color
304 | * @discussion Statuses will be printed as an emoji, if status icons are
305 | * enabled. Colors will only be printed if the terminal supports
306 | * them and if they are enabled.
307 | * @param format The message format
308 | * @param status The message status
309 | * @param color The message color
310 | * @param ... Optional parameters for the format string
311 | * @see SKSTatus
312 | * @see statusIconsEnabled
313 | * @see SKColor
314 | * @see supportsColors
315 | * @see colorsEnabled
316 | */
317 | - ( void )printMessage: ( NSString * )format status: ( SKStatus )status color: ( SKColor )color, ... NS_FORMAT_FUNCTION( 1, 4 );
318 |
319 | /*!
320 | * @method addPromptPart:
321 | * @abstract Adds a part to the current prompt parts
322 | * @discussion Only applicable if the prompt hierarchy is enabled.
323 | * @see promptParts
324 | * @see allowPromptHierarchy
325 | */
326 | - ( void )addPromptPart:( NSString * )part;
327 |
328 | /*!
329 | * @method removeLastPromptPart:
330 | * @abstract Removes the last part of the current prompt parts
331 | * @discussion Only applicable if the prompt hierarchy is enabled.
332 | * @see promptParts
333 | * @see allowPromptHierarchy
334 | */
335 | - ( void )removeLastPromptPart;
336 |
337 | @end
338 |
339 | NS_ASSUME_NONNULL_END
340 |
--------------------------------------------------------------------------------
/ShellKit/Classes/ShellKit/SKShell.m:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | ******************************************************************************/
24 |
25 | /*!
26 | * @file SKShell.m
27 | * @copyright (c) 2017, Jean-David Gadina - www.xs-labs.com
28 | */
29 |
30 | #import
31 | #import
32 | #import
33 |
34 | NS_ASSUME_NONNULL_BEGIN
35 |
36 | @interface SKShell()
37 |
38 | @property( atomic, readwrite, assign ) BOOL observingPrompt;
39 | @property( atomic, readwrite, assign ) BOOL hasPromptParts;
40 | @property( atomic, readwrite, assign ) BOOL supportsColors;
41 | @property( atomic, readwrite, strong ) NSArray< NSString * > * promptStrings;
42 | @property( atomic, readwrite, strong ) dispatch_queue_t dispatchQueue;
43 | @property( atomic, readwrite, strong, nullable ) NSString * shell;
44 |
45 | - ( void )observerPrompt: ( BOOL )observe;
46 |
47 | @end
48 |
49 | NS_ASSUME_NONNULL_END
50 |
51 | @implementation SKShell
52 |
53 | + ( instancetype )currentShell
54 | {
55 | static dispatch_once_t once;
56 | static id instance;
57 |
58 | dispatch_once
59 | (
60 | &once,
61 | ^( void )
62 | {
63 | instance = [ self new ];
64 | }
65 | );
66 |
67 | return instance;
68 | }
69 |
70 | - ( instancetype )init
71 | {
72 | int err;
73 |
74 | if( ( self = [ super init ] ) )
75 | {
76 | self.shell = [ NSProcessInfo processInfo ].environment[ @"SHELL" ];
77 | self.promptStrings = @[];
78 | self.allowPromptHierarchy = YES;
79 | self.dispatchQueue = dispatch_queue_create( "com.xs-labs.ShellKit.SKShell", DISPATCH_QUEUE_CONCURRENT );
80 |
81 | if( setupterm( NULL, 1, &err ) == ERR )
82 | {
83 | self.supportsColors = NO;
84 | }
85 | else
86 | {
87 | self.supportsColors = YES;
88 | }
89 |
90 | self.colorsEnabled = YES;
91 | self.statusIconsEnabled = YES;
92 |
93 | [ self observerPrompt: YES ];
94 | }
95 |
96 | return self;
97 | }
98 |
99 | - ( void )dealloc
100 | {
101 | [ self observerPrompt: NO ];
102 | }
103 |
104 | - ( void )observerPrompt: ( BOOL )observe
105 | {
106 | if( observe && self.observingPrompt == NO )
107 | {
108 | [ self addObserver: self forKeyPath: NSStringFromSelector( @selector( prompt ) ) options: NSKeyValueObservingOptionNew context: NULL ];
109 |
110 | self.observingPrompt = YES;
111 | }
112 | else if( observe == NO && self.observingPrompt )
113 | {
114 | [ self removeObserver: self forKeyPath: NSStringFromSelector( @selector( prompt ) ) ];
115 |
116 | self.observingPrompt = NO;
117 | }
118 | }
119 |
120 | - ( void )observeValueForKeyPath: ( NSString * )keyPath ofObject: ( id )object change: ( NSDictionary * )change context: ( void * )context
121 | {
122 | if( object == self && [ keyPath isEqualToString: NSStringFromSelector( @selector( prompt ) ) ] )
123 | {
124 | @synchronized( self )
125 | {
126 | self.promptStrings = @[];
127 | }
128 | }
129 | else
130 | {
131 | [ super observeValueForKeyPath: keyPath ofObject: object change: change context: context ];
132 | }
133 | }
134 |
135 | - ( nullable NSString * )pathForCommand: ( NSString * )command
136 | {
137 | __block BOOL success;
138 | __block NSString * output;
139 | SKShellCommandCompletion completion;
140 |
141 | completion = ^( int status, NSString * stdandardOutput, NSString * standardError )
142 | {
143 | success = status == EXIT_SUCCESS;
144 | output = stdandardOutput;
145 |
146 | ( void )standardError;
147 | };
148 |
149 | @try
150 | {
151 | if( [ self runCommand: [ NSString stringWithFormat: @"which %@", command ] completion: completion ] == NO )
152 | {
153 | return nil;
154 | }
155 | }
156 | @catch( NSException * exception )
157 | {
158 | ( void )exception;
159 |
160 | return nil;
161 | }
162 |
163 | if( success == NO || output.length == 0 )
164 | {
165 | return nil;
166 | }
167 |
168 | if( output.length == 0 || [ [ NSFileManager defaultManager ] fileExistsAtPath: output ] == NO )
169 | {
170 | return nil;
171 | }
172 |
173 | return output;
174 | }
175 |
176 | - ( BOOL )commandIsAvailable: ( NSString * )command
177 | {
178 | return [ self pathForCommand: command ] != nil;
179 | }
180 |
181 | - ( BOOL )runCommand: ( NSString * )command
182 | {
183 | return [ self runCommand: command stdandardInput: nil ];
184 | }
185 |
186 | - ( BOOL )runCommand: ( NSString * )command stdandardInput: ( nullable NSString * )input
187 | {
188 | return [ self runCommand: command stdandardInput: input completion: NULL ];
189 | }
190 |
191 | - ( BOOL )runCommand: ( NSString * )command completion: ( nullable SKShellCommandCompletion )completion
192 | {
193 | return [ self runCommand: command stdandardInput: nil completion: completion ];
194 | }
195 |
196 | - ( BOOL )runCommand: ( NSString * )command stdandardInput: ( nullable NSString * )input completion: ( nullable void ( ^ )( int status, NSString * stdandardOutput, NSString * standardError ) )completion
197 | {
198 | NSTask * task;
199 | NSPipe * stdinPipe;
200 | NSPipe * stdoutPipe;
201 | NSPipe * stderrPipe;
202 |
203 | if( self.shell.length == NO || [ [ NSFileManager defaultManager ] fileExistsAtPath: self.shell ] == NO )
204 | {
205 | @throw [ NSException exceptionWithName: @"com.xs-labs.ShellKit.SKShellException" reason: @"SHELL environment variable is not defined" userInfo: [ NSProcessInfo processInfo ].environment ];
206 | }
207 |
208 | stdinPipe = [ NSPipe pipe ];
209 | stdoutPipe = [ NSPipe pipe ];
210 | stderrPipe = [ NSPipe pipe ];
211 | task = [ NSTask new ];
212 | task.launchPath = self.shell;
213 | task.arguments = @[ @"-l", @"-c", command ];
214 | task.standardOutput = stdoutPipe;
215 | task.standardError = stderrPipe;
216 |
217 | if( input )
218 | {
219 | task.standardInput = stdinPipe;
220 | }
221 |
222 | [ task launch ];
223 |
224 | if( input )
225 | {
226 | [ stdinPipe.fileHandleForWriting writeData: [ input dataUsingEncoding: NSUTF8StringEncoding ] ];
227 | }
228 |
229 | [ task waitUntilExit ];
230 |
231 | if( completion )
232 | {
233 | {
234 | NSString * output;
235 | NSString * error;
236 |
237 | @try
238 | {
239 | output = [ [ NSString alloc ] initWithData: [ stdoutPipe.fileHandleForReading readDataToEndOfFile ] encoding: NSUTF8StringEncoding ];
240 | }
241 | @catch( NSException * exception )
242 | {
243 | ( void )exception;
244 |
245 | output = nil;
246 | }
247 |
248 | @try
249 | {
250 | error = [ [ NSString alloc ] initWithData: [ stdoutPipe.fileHandleForReading readDataToEndOfFile ] encoding: NSUTF8StringEncoding ];
251 | }
252 | @catch( NSException * exception )
253 | {
254 | ( void )exception;
255 |
256 | error = nil;
257 | }
258 |
259 | output = [ output stringByTrimmingCharactersInSet: [ NSCharacterSet whitespaceAndNewlineCharacterSet ] ];
260 | error = [ error stringByTrimmingCharactersInSet: [ NSCharacterSet whitespaceAndNewlineCharacterSet ] ];
261 |
262 | completion
263 | (
264 | task.terminationStatus,
265 | ( output ) ? output : @"",
266 | ( error ) ? error : @""
267 | );
268 | }
269 | }
270 |
271 | return task.terminationStatus == EXIT_SUCCESS;
272 | }
273 |
274 | - ( void )runCommandAsynchronously: ( NSString * )command;
275 | {
276 | [ self runCommandAsynchronously: command stdandardInput: nil ];
277 | }
278 |
279 | - ( void )runCommandAsynchronously: ( NSString * )command stdandardInput: ( nullable NSString * )input
280 | {
281 | [ self runCommandAsynchronously: command stdandardInput: input completion: NULL ];
282 | }
283 |
284 | - ( void )runCommandAsynchronously: ( NSString * )command completion: ( nullable SKShellCommandCompletion )completion
285 | {
286 | [ self runCommandAsynchronously: command stdandardInput: nil completion: completion ];
287 | }
288 |
289 | - ( void )runCommandAsynchronously: ( NSString * )command stdandardInput: ( nullable NSString * )input completion: ( nullable void ( ^ )( int status, NSString * stdandardOutput, NSString * standardError ) )completion
290 | {
291 | dispatch_async
292 | (
293 | self.dispatchQueue,
294 | ^( void )
295 | {
296 | [ self runCommand: command stdandardInput: input completion: completion ];
297 | }
298 | );
299 | }
300 |
301 | - ( void )printError: ( nullable NSError * )error
302 | {
303 | NSString * message;
304 |
305 | if( error.localizedDescription.length )
306 | {
307 | message = [ NSString stringWithFormat: @"Error - %@", error.localizedDescription ];
308 | }
309 | else
310 | {
311 | message = @"An unknown error occured";
312 | }
313 |
314 | [ self printMessage: @"%@" status: SKStatusError color: SKColorRed, message ];
315 | }
316 |
317 | - ( void )printErrorMessage: ( NSString * )format, ...
318 | {
319 | NSError * error;
320 | NSString * message;
321 | va_list ap;
322 |
323 | va_start( ap, format );
324 |
325 | message = [ [ NSString alloc ] initWithFormat: format arguments: ap ];
326 | error = [ NSError errorWithDomain: NSPOSIXErrorDomain code: 0 userInfo: @{ NSLocalizedDescriptionKey : message } ];
327 |
328 | va_end( ap );
329 |
330 | [ self printError: error ];
331 | }
332 |
333 | - ( void )printWarningMessage: ( NSString * )format, ...
334 | {
335 | NSString * message;
336 | va_list ap;
337 |
338 | va_start( ap, format );
339 |
340 | message = [ [ NSString alloc ] initWithFormat: format arguments: ap ];
341 |
342 | va_end( ap );
343 |
344 | [ self printMessage: @"%@" status: SKStatusWarning color: SKColorYellow, message ];
345 | }
346 |
347 | - ( void )printSuccessMessage: ( NSString * )format, ...
348 | {
349 | NSString * message;
350 | va_list ap;
351 |
352 | va_start( ap, format );
353 |
354 | message = [ [ NSString alloc ] initWithFormat: format arguments: ap ];
355 |
356 | va_end( ap );
357 |
358 | [ self printMessage: @"%@" status: SKStatusSuccess color: SKColorGreen, message ];
359 | }
360 |
361 | - ( void )printInfoMessage: ( NSString * )format, ...
362 | {
363 | NSString * message;
364 | va_list ap;
365 |
366 | va_start( ap, format );
367 |
368 | message = [ [ NSString alloc ] initWithFormat: format arguments: ap ];
369 |
370 | va_end( ap );
371 |
372 | [ self printMessage: @"%@" status: SKStatusInfo color: SKColorBlue, message ];
373 | }
374 |
375 | - ( void )printMessage: ( NSString * )format, ...
376 | {
377 | NSString * message;
378 | va_list ap;
379 |
380 | va_start( ap, format );
381 |
382 | message = [ [ NSString alloc ] initWithFormat: format arguments: ap ];
383 |
384 | va_end( ap );
385 |
386 | [ self printMessage: @"%@" status: SKStatusNone color: SKColorNone, message ];
387 | }
388 |
389 | - ( void )printMessage: ( NSString * )format status: ( SKStatus )status, ...
390 | {
391 | NSString * message;
392 | va_list ap;
393 |
394 | va_start( ap, status );
395 |
396 | message = [ [ NSString alloc ] initWithFormat: format arguments: ap ];
397 |
398 | va_end( ap );
399 |
400 | [ self printMessage: @"%@" status: status color: SKColorNone, message ];
401 | }
402 |
403 | - ( void )printMessage: ( NSString * )format color: ( SKColor )color, ...
404 | {
405 | NSString * message;
406 | va_list ap;
407 |
408 | va_start( ap, color );
409 |
410 | message = [ [ NSString alloc ] initWithFormat: format arguments: ap ];
411 |
412 | va_end( ap );
413 |
414 | [ self printMessage: @"%@" status: SKStatusNone color: color, message ];
415 | }
416 |
417 | - ( void )printMessage: ( NSString * )format status: ( SKStatus )status color: ( SKColor )color, ...
418 | {
419 | NSString * p;
420 | NSString * s;
421 | NSString * message;
422 | va_list ap;
423 |
424 | @synchronized( self )
425 | {
426 | va_start( ap, color );
427 |
428 | message = [ [ NSString alloc ] initWithFormat: format arguments: ap ];
429 |
430 | va_end( ap );
431 |
432 | p = ( self.prompt ) ? self.prompt : @"";
433 | s = [ NSString stringForShellStatus: status ];
434 |
435 | if( s.length > 0 )
436 | {
437 | s = [ s stringByAppendingString: @" " ];
438 | }
439 |
440 | fprintf
441 | (
442 | stdout,
443 | "%s%s%s\n",
444 | p.UTF8String,
445 | s.UTF8String,
446 | [ message stringWithShellColor: color ].UTF8String
447 | );
448 | }
449 | }
450 |
451 | - ( NSArray< NSString * > * )promptParts
452 | {
453 | @synchronized( self )
454 | {
455 | return self.promptStrings.copy;
456 | }
457 | }
458 |
459 | - ( void )setPromptParts: ( NSArray< NSString * > * )parts
460 | {
461 | NSUInteger i;
462 | NSString * part;
463 | NSMutableString * prompt;
464 | SKColor colors[] = { SKColorCyan, SKColorBlue, SKColorPurple };
465 |
466 | @synchronized( self )
467 | {
468 | self.promptStrings = parts.copy;
469 |
470 | if( parts.count == 0 )
471 | {
472 | self.prompt = @"";
473 | }
474 |
475 | prompt = [ NSMutableString new ];
476 | i = 0;
477 |
478 | for( part in parts )
479 | {
480 | part = [ part stringWithShellColor: colors[ i % ( sizeof( colors ) / sizeof( SKColor ) ) ] ];
481 |
482 | [ prompt appendFormat: @"[ %@ ]> ", part ];
483 |
484 | i++;
485 | }
486 |
487 | [ self observerPrompt: NO ];
488 |
489 | self.prompt = prompt;
490 |
491 | [ self observerPrompt: YES ];
492 | }
493 | }
494 |
495 | - ( void )addPromptPart:( NSString * )part
496 | {
497 | if( self.allowPromptHierarchy == NO )
498 | {
499 | return;
500 | }
501 |
502 | self.promptParts = [ self.promptParts arrayByAddingObject: part ];
503 | }
504 |
505 | - ( void )removeLastPromptPart
506 | {
507 | NSMutableArray * parts;
508 |
509 | if( self.allowPromptHierarchy == NO )
510 | {
511 | return;
512 | }
513 |
514 | parts = self.promptParts.mutableCopy;
515 |
516 | if( parts.count )
517 | {
518 | [ parts removeLastObject ];
519 |
520 | self.promptParts = parts;
521 | }
522 | }
523 |
524 | @end
525 |
--------------------------------------------------------------------------------
/ShellKit.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 051DFF491EC55032009A4319 /* NSDate+ShellKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 051DFF471EC55032009A4319 /* NSDate+ShellKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
11 | 051DFF4A1EC55032009A4319 /* NSDate+ShellKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 051DFF481EC55032009A4319 /* NSDate+ShellKit.m */; };
12 | 051DFF4B1EC55040009A4319 /* NSDate+ShellKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 051DFF481EC55032009A4319 /* NSDate+ShellKit.m */; };
13 | 054B003A1EC4E8D20032B500 /* SKObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 054B002D1EC4E8D20032B500 /* SKObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
14 | 054B003C1EC4E8D20032B500 /* SKObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 054B002E1EC4E8D20032B500 /* SKObject.m */; };
15 | 054B003D1EC4E8D20032B500 /* SKObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 054B002E1EC4E8D20032B500 /* SKObject.m */; };
16 | 054B003E1EC4E8D20032B500 /* SKRunableObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 054B002F1EC4E8D20032B500 /* SKRunableObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
17 | 054B00401EC4E8D20032B500 /* SKShell.h in Headers */ = {isa = PBXBuildFile; fileRef = 054B00301EC4E8D20032B500 /* SKShell.h */; settings = {ATTRIBUTES = (Public, ); }; };
18 | 054B00421EC4E8D20032B500 /* SKShell.m in Sources */ = {isa = PBXBuildFile; fileRef = 054B00311EC4E8D20032B500 /* SKShell.m */; };
19 | 054B00431EC4E8D20032B500 /* SKShell.m in Sources */ = {isa = PBXBuildFile; fileRef = 054B00311EC4E8D20032B500 /* SKShell.m */; };
20 | 054B00441EC4E8D20032B500 /* SKTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 054B00321EC4E8D20032B500 /* SKTask.h */; settings = {ATTRIBUTES = (Public, ); }; };
21 | 054B00461EC4E8D20032B500 /* SKTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 054B00331EC4E8D20032B500 /* SKTask.m */; };
22 | 054B00471EC4E8D20032B500 /* SKTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 054B00331EC4E8D20032B500 /* SKTask.m */; };
23 | 054B00481EC4E8D20032B500 /* SKTaskGroup.h in Headers */ = {isa = PBXBuildFile; fileRef = 054B00341EC4E8D20032B500 /* SKTaskGroup.h */; settings = {ATTRIBUTES = (Public, ); }; };
24 | 054B004A1EC4E8D20032B500 /* SKTaskGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 054B00351EC4E8D20032B500 /* SKTaskGroup.m */; };
25 | 054B004B1EC4E8D20032B500 /* SKTaskGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 054B00351EC4E8D20032B500 /* SKTaskGroup.m */; };
26 | 054B004E1EC4EA050032B500 /* NSString+ShellKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 054B004C1EC4EA050032B500 /* NSString+ShellKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
27 | 054B00501EC4EA050032B500 /* NSString+ShellKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 054B004D1EC4EA050032B500 /* NSString+ShellKit.m */; };
28 | 054B00511EC4EA050032B500 /* NSString+ShellKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 054B004D1EC4EA050032B500 /* NSString+ShellKit.m */; };
29 | 054B00541EC4EA950032B500 /* SKTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 054B00521EC4EA950032B500 /* SKTypes.h */; settings = {ATTRIBUTES = (Public, ); }; };
30 | 054B00561EC4ECA60032B500 /* libcurses.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 05C35D8A1EC3D0F500F373E7 /* libcurses.tbd */; };
31 | 058F79171EC5FA53007CFF3A /* ShellKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 058F79161EC5FA53007CFF3A /* ShellKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
32 | 058F79231EC610FE007CFF3A /* SKOptionalTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 058F79211EC610FE007CFF3A /* SKOptionalTask.h */; settings = {ATTRIBUTES = (Public, ); }; };
33 | 058F79241EC610FE007CFF3A /* SKOptionalTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 058F79221EC610FE007CFF3A /* SKOptionalTask.m */; };
34 | 058F79251EC61144007CFF3A /* SKOptionalTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 058F79221EC610FE007CFF3A /* SKOptionalTask.m */; };
35 | 05CF703D1EC4FE2C00A39841 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 05CF703C1EC4FE2C00A39841 /* main.m */; };
36 | 05CF70451EC5003D00A39841 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05CF70441EC5003D00A39841 /* Foundation.framework */; };
37 | 05CF70461EC5004800A39841 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05CF70441EC5003D00A39841 /* Foundation.framework */; };
38 | 05CF70471EC505D200A39841 /* libcurses.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 05C35D8A1EC3D0F500F373E7 /* libcurses.tbd */; };
39 | 05CF70481EC505D700A39841 /* libShellKit-Static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 054BFFFB1EC4E6670032B500 /* libShellKit-Static.a */; };
40 | /* End PBXBuildFile section */
41 |
42 | /* Begin PBXContainerItemProxy section */
43 | 05CF70411EC4FE4600A39841 /* PBXContainerItemProxy */ = {
44 | isa = PBXContainerItemProxy;
45 | containerPortal = 05BD894A1A13FF4700A43CD8 /* Project object */;
46 | proxyType = 1;
47 | remoteGlobalIDString = 054BFFED1EC4E60B0032B500;
48 | remoteInfo = ShellKit;
49 | };
50 | /* End PBXContainerItemProxy section */
51 |
52 | /* Begin PBXCopyFilesBuildPhase section */
53 | 05CF70381EC4FE2C00A39841 /* CopyFiles */ = {
54 | isa = PBXCopyFilesBuildPhase;
55 | buildActionMask = 2147483647;
56 | dstPath = /usr/share/man/man1/;
57 | dstSubfolderSpec = 0;
58 | files = (
59 | );
60 | runOnlyForDeploymentPostprocessing = 1;
61 | };
62 | /* End PBXCopyFilesBuildPhase section */
63 |
64 | /* Begin PBXFileReference section */
65 | 05110D041C1F121C00EE6851 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; };
66 | 05110D051C1F121C00EE6851 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
67 | 051DFF471EC55032009A4319 /* NSDate+ShellKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+ShellKit.h"; sourceTree = ""; };
68 | 051DFF481EC55032009A4319 /* NSDate+ShellKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+ShellKit.m"; sourceTree = ""; };
69 | 054B002D1EC4E8D20032B500 /* SKObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SKObject.h; sourceTree = ""; };
70 | 054B002E1EC4E8D20032B500 /* SKObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SKObject.m; sourceTree = ""; };
71 | 054B002F1EC4E8D20032B500 /* SKRunableObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SKRunableObject.h; sourceTree = ""; };
72 | 054B00301EC4E8D20032B500 /* SKShell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SKShell.h; sourceTree = ""; };
73 | 054B00311EC4E8D20032B500 /* SKShell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SKShell.m; sourceTree = ""; };
74 | 054B00321EC4E8D20032B500 /* SKTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SKTask.h; sourceTree = ""; };
75 | 054B00331EC4E8D20032B500 /* SKTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SKTask.m; sourceTree = ""; };
76 | 054B00341EC4E8D20032B500 /* SKTaskGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SKTaskGroup.h; sourceTree = ""; };
77 | 054B00351EC4E8D20032B500 /* SKTaskGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SKTaskGroup.m; sourceTree = ""; };
78 | 054B004C1EC4EA050032B500 /* NSString+ShellKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+ShellKit.h"; sourceTree = ""; };
79 | 054B004D1EC4EA050032B500 /* NSString+ShellKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+ShellKit.m"; sourceTree = ""; };
80 | 054B00521EC4EA950032B500 /* SKTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SKTypes.h; sourceTree = ""; };
81 | 054BFFEE1EC4E60B0032B500 /* ShellKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ShellKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
82 | 054BFFF11EC4E60B0032B500 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
83 | 054BFFFB1EC4E6670032B500 /* libShellKit-Static.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libShellKit-Static.a"; sourceTree = BUILT_PRODUCTS_DIR; };
84 | 05600C841ECA2D100085BDD1 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; };
85 | 05600C891ECA2F9B0085BDD1 /* Home.inc.php */ = {isa = PBXFileReference; lastKnownFileType = text.script.php; path = Home.inc.php; sourceTree = ""; };
86 | 058F79161EC5FA53007CFF3A /* ShellKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShellKit.h; sourceTree = ""; };
87 | 058F79211EC610FE007CFF3A /* SKOptionalTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SKOptionalTask.h; sourceTree = ""; };
88 | 058F79221EC610FE007CFF3A /* SKOptionalTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SKOptionalTask.m; sourceTree = ""; };
89 | 05C35D8A1EC3D0F500F373E7 /* libcurses.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcurses.tbd; path = usr/lib/libcurses.tbd; sourceTree = SDKROOT; };
90 | 05CF703A1EC4FE2C00A39841 /* ShellKit-Test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "ShellKit-Test"; sourceTree = BUILT_PRODUCTS_DIR; };
91 | 05CF703C1EC4FE2C00A39841 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
92 | 05CF70441EC5003D00A39841 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
93 | 05CFB82C1EC30AF70020A075 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
94 | /* End PBXFileReference section */
95 |
96 | /* Begin PBXFrameworksBuildPhase section */
97 | 054BFFEA1EC4E60B0032B500 /* Frameworks */ = {
98 | isa = PBXFrameworksBuildPhase;
99 | buildActionMask = 2147483647;
100 | files = (
101 | 05CF70451EC5003D00A39841 /* Foundation.framework in Frameworks */,
102 | 054B00561EC4ECA60032B500 /* libcurses.tbd in Frameworks */,
103 | );
104 | runOnlyForDeploymentPostprocessing = 0;
105 | };
106 | 054BFFF81EC4E6670032B500 /* Frameworks */ = {
107 | isa = PBXFrameworksBuildPhase;
108 | buildActionMask = 2147483647;
109 | files = (
110 | );
111 | runOnlyForDeploymentPostprocessing = 0;
112 | };
113 | 05CF70371EC4FE2C00A39841 /* Frameworks */ = {
114 | isa = PBXFrameworksBuildPhase;
115 | buildActionMask = 2147483647;
116 | files = (
117 | 05CF70481EC505D700A39841 /* libShellKit-Static.a in Frameworks */,
118 | 05CF70471EC505D200A39841 /* libcurses.tbd in Frameworks */,
119 | 05CF70461EC5004800A39841 /* Foundation.framework in Frameworks */,
120 | );
121 | runOnlyForDeploymentPostprocessing = 0;
122 | };
123 | /* End PBXFrameworksBuildPhase section */
124 |
125 | /* Begin PBXGroup section */
126 | 050B83E21EB919CB0090EA12 /* Frameworks */ = {
127 | isa = PBXGroup;
128 | children = (
129 | 05CF70441EC5003D00A39841 /* Foundation.framework */,
130 | 05C35D8A1EC3D0F500F373E7 /* libcurses.tbd */,
131 | 05CFB82C1EC30AF70020A075 /* Cocoa.framework */,
132 | );
133 | name = Frameworks;
134 | sourceTree = "";
135 | };
136 | 054B002A1EC4E8D20032B500 /* ShellKit */ = {
137 | isa = PBXGroup;
138 | children = (
139 | 051DFF471EC55032009A4319 /* NSDate+ShellKit.h */,
140 | 051DFF481EC55032009A4319 /* NSDate+ShellKit.m */,
141 | 054B004C1EC4EA050032B500 /* NSString+ShellKit.h */,
142 | 054B004D1EC4EA050032B500 /* NSString+ShellKit.m */,
143 | 058F79161EC5FA53007CFF3A /* ShellKit.h */,
144 | 054B002D1EC4E8D20032B500 /* SKObject.h */,
145 | 054B002E1EC4E8D20032B500 /* SKObject.m */,
146 | 058F79211EC610FE007CFF3A /* SKOptionalTask.h */,
147 | 058F79221EC610FE007CFF3A /* SKOptionalTask.m */,
148 | 054B002F1EC4E8D20032B500 /* SKRunableObject.h */,
149 | 054B00301EC4E8D20032B500 /* SKShell.h */,
150 | 054B00311EC4E8D20032B500 /* SKShell.m */,
151 | 054B00321EC4E8D20032B500 /* SKTask.h */,
152 | 054B00331EC4E8D20032B500 /* SKTask.m */,
153 | 054B00341EC4E8D20032B500 /* SKTaskGroup.h */,
154 | 054B00351EC4E8D20032B500 /* SKTaskGroup.m */,
155 | 054B00521EC4EA950032B500 /* SKTypes.h */,
156 | );
157 | path = ShellKit;
158 | sourceTree = "";
159 | };
160 | 054BFFEF1EC4E60B0032B500 /* ShellKit */ = {
161 | isa = PBXGroup;
162 | children = (
163 | 054BFFF11EC4E60B0032B500 /* Info.plist */,
164 | 054BFFF61EC4E61D0032B500 /* Classes */,
165 | );
166 | path = ShellKit;
167 | sourceTree = "";
168 | };
169 | 054BFFF61EC4E61D0032B500 /* Classes */ = {
170 | isa = PBXGroup;
171 | children = (
172 | 054B002A1EC4E8D20032B500 /* ShellKit */,
173 | );
174 | path = Classes;
175 | sourceTree = "";
176 | };
177 | 05600C811ECA2D100085BDD1 /* Documentation */ = {
178 | isa = PBXGroup;
179 | children = (
180 | 05600C841ECA2D100085BDD1 /* Makefile */,
181 | 05600C881ECA2F9B0085BDD1 /* Pages */,
182 | );
183 | path = Documentation;
184 | sourceTree = "";
185 | };
186 | 05600C881ECA2F9B0085BDD1 /* Pages */ = {
187 | isa = PBXGroup;
188 | children = (
189 | 05600C891ECA2F9B0085BDD1 /* Home.inc.php */,
190 | );
191 | path = Pages;
192 | sourceTree = "";
193 | };
194 | 05BD89491A13FF4700A43CD8 = {
195 | isa = PBXGroup;
196 | children = (
197 | 05110D041C1F121C00EE6851 /* LICENSE */,
198 | 05110D051C1F121C00EE6851 /* README.md */,
199 | 054BFFEF1EC4E60B0032B500 /* ShellKit */,
200 | 05CF703B1EC4FE2C00A39841 /* ShellKit-Test */,
201 | 05600C811ECA2D100085BDD1 /* Documentation */,
202 | 05BD89531A13FF4700A43CD8 /* Products */,
203 | 050B83E21EB919CB0090EA12 /* Frameworks */,
204 | );
205 | sourceTree = "";
206 | };
207 | 05BD89531A13FF4700A43CD8 /* Products */ = {
208 | isa = PBXGroup;
209 | children = (
210 | 054BFFEE1EC4E60B0032B500 /* ShellKit.framework */,
211 | 054BFFFB1EC4E6670032B500 /* libShellKit-Static.a */,
212 | 05CF703A1EC4FE2C00A39841 /* ShellKit-Test */,
213 | );
214 | name = Products;
215 | sourceTree = "";
216 | };
217 | 05CF703B1EC4FE2C00A39841 /* ShellKit-Test */ = {
218 | isa = PBXGroup;
219 | children = (
220 | 05CF703C1EC4FE2C00A39841 /* main.m */,
221 | );
222 | path = "ShellKit-Test";
223 | sourceTree = "";
224 | };
225 | /* End PBXGroup section */
226 |
227 | /* Begin PBXHeadersBuildPhase section */
228 | 054BFFEB1EC4E60B0032B500 /* Headers */ = {
229 | isa = PBXHeadersBuildPhase;
230 | buildActionMask = 2147483647;
231 | files = (
232 | 054B00401EC4E8D20032B500 /* SKShell.h in Headers */,
233 | 054B00441EC4E8D20032B500 /* SKTask.h in Headers */,
234 | 054B003A1EC4E8D20032B500 /* SKObject.h in Headers */,
235 | 054B003E1EC4E8D20032B500 /* SKRunableObject.h in Headers */,
236 | 054B004E1EC4EA050032B500 /* NSString+ShellKit.h in Headers */,
237 | 058F79231EC610FE007CFF3A /* SKOptionalTask.h in Headers */,
238 | 054B00541EC4EA950032B500 /* SKTypes.h in Headers */,
239 | 051DFF491EC55032009A4319 /* NSDate+ShellKit.h in Headers */,
240 | 058F79171EC5FA53007CFF3A /* ShellKit.h in Headers */,
241 | 054B00481EC4E8D20032B500 /* SKTaskGroup.h in Headers */,
242 | );
243 | runOnlyForDeploymentPostprocessing = 0;
244 | };
245 | 054BFFF91EC4E6670032B500 /* Headers */ = {
246 | isa = PBXHeadersBuildPhase;
247 | buildActionMask = 2147483647;
248 | files = (
249 | );
250 | runOnlyForDeploymentPostprocessing = 0;
251 | };
252 | /* End PBXHeadersBuildPhase section */
253 |
254 | /* Begin PBXNativeTarget section */
255 | 054BFFED1EC4E60B0032B500 /* ShellKit */ = {
256 | isa = PBXNativeTarget;
257 | buildConfigurationList = 054BFFF31EC4E60B0032B500 /* Build configuration list for PBXNativeTarget "ShellKit" */;
258 | buildPhases = (
259 | 054BFFE91EC4E60B0032B500 /* Sources */,
260 | 054BFFEA1EC4E60B0032B500 /* Frameworks */,
261 | 054BFFEB1EC4E60B0032B500 /* Headers */,
262 | 054BFFEC1EC4E60B0032B500 /* Resources */,
263 | );
264 | buildRules = (
265 | );
266 | dependencies = (
267 | );
268 | name = ShellKit;
269 | productName = ShellKit;
270 | productReference = 054BFFEE1EC4E60B0032B500 /* ShellKit.framework */;
271 | productType = "com.apple.product-type.framework";
272 | };
273 | 054BFFFA1EC4E6670032B500 /* ShellKit-Static */ = {
274 | isa = PBXNativeTarget;
275 | buildConfigurationList = 054B00011EC4E6670032B500 /* Build configuration list for PBXNativeTarget "ShellKit-Static" */;
276 | buildPhases = (
277 | 054BFFF71EC4E6670032B500 /* Sources */,
278 | 054BFFF81EC4E6670032B500 /* Frameworks */,
279 | 054BFFF91EC4E6670032B500 /* Headers */,
280 | );
281 | buildRules = (
282 | );
283 | dependencies = (
284 | );
285 | name = "ShellKit-Static";
286 | productName = "ShellKit-Static";
287 | productReference = 054BFFFB1EC4E6670032B500 /* libShellKit-Static.a */;
288 | productType = "com.apple.product-type.library.static";
289 | };
290 | 05CF70391EC4FE2C00A39841 /* ShellKit-Test */ = {
291 | isa = PBXNativeTarget;
292 | buildConfigurationList = 05CF70401EC4FE2C00A39841 /* Build configuration list for PBXNativeTarget "ShellKit-Test" */;
293 | buildPhases = (
294 | 05CF70361EC4FE2C00A39841 /* Sources */,
295 | 05CF70371EC4FE2C00A39841 /* Frameworks */,
296 | 05CF70381EC4FE2C00A39841 /* CopyFiles */,
297 | );
298 | buildRules = (
299 | );
300 | dependencies = (
301 | 05CF70421EC4FE4600A39841 /* PBXTargetDependency */,
302 | );
303 | name = "ShellKit-Test";
304 | productName = "ShellKit-Test";
305 | productReference = 05CF703A1EC4FE2C00A39841 /* ShellKit-Test */;
306 | productType = "com.apple.product-type.tool";
307 | };
308 | /* End PBXNativeTarget section */
309 |
310 | /* Begin PBXProject section */
311 | 05BD894A1A13FF4700A43CD8 /* Project object */ = {
312 | isa = PBXProject;
313 | attributes = {
314 | LastUpgradeCheck = 0900;
315 | ORGANIZATIONNAME = "XS-Labs";
316 | TargetAttributes = {
317 | 054BFFED1EC4E60B0032B500 = {
318 | CreatedOnToolsVersion = 8.3.1;
319 | LastSwiftMigration = 0900;
320 | ProvisioningStyle = Automatic;
321 | };
322 | 054BFFFA1EC4E6670032B500 = {
323 | CreatedOnToolsVersion = 8.3.1;
324 | LastSwiftMigration = 0900;
325 | ProvisioningStyle = Automatic;
326 | };
327 | 05CF70391EC4FE2C00A39841 = {
328 | CreatedOnToolsVersion = 8.3.1;
329 | ProvisioningStyle = Automatic;
330 | };
331 | };
332 | };
333 | buildConfigurationList = 05BD894D1A13FF4700A43CD8 /* Build configuration list for PBXProject "ShellKit" */;
334 | compatibilityVersion = "Xcode 3.2";
335 | developmentRegion = English;
336 | hasScannedForEncodings = 0;
337 | knownRegions = (
338 | en,
339 | );
340 | mainGroup = 05BD89491A13FF4700A43CD8;
341 | productRefGroup = 05BD89531A13FF4700A43CD8 /* Products */;
342 | projectDirPath = "";
343 | projectRoot = "";
344 | targets = (
345 | 054BFFED1EC4E60B0032B500 /* ShellKit */,
346 | 054BFFFA1EC4E6670032B500 /* ShellKit-Static */,
347 | 05CF70391EC4FE2C00A39841 /* ShellKit-Test */,
348 | );
349 | };
350 | /* End PBXProject section */
351 |
352 | /* Begin PBXResourcesBuildPhase section */
353 | 054BFFEC1EC4E60B0032B500 /* Resources */ = {
354 | isa = PBXResourcesBuildPhase;
355 | buildActionMask = 2147483647;
356 | files = (
357 | );
358 | runOnlyForDeploymentPostprocessing = 0;
359 | };
360 | /* End PBXResourcesBuildPhase section */
361 |
362 | /* Begin PBXSourcesBuildPhase section */
363 | 054BFFE91EC4E60B0032B500 /* Sources */ = {
364 | isa = PBXSourcesBuildPhase;
365 | buildActionMask = 2147483647;
366 | files = (
367 | 054B00501EC4EA050032B500 /* NSString+ShellKit.m in Sources */,
368 | 054B00421EC4E8D20032B500 /* SKShell.m in Sources */,
369 | 058F79241EC610FE007CFF3A /* SKOptionalTask.m in Sources */,
370 | 054B004A1EC4E8D20032B500 /* SKTaskGroup.m in Sources */,
371 | 051DFF4A1EC55032009A4319 /* NSDate+ShellKit.m in Sources */,
372 | 054B003C1EC4E8D20032B500 /* SKObject.m in Sources */,
373 | 054B00461EC4E8D20032B500 /* SKTask.m in Sources */,
374 | );
375 | runOnlyForDeploymentPostprocessing = 0;
376 | };
377 | 054BFFF71EC4E6670032B500 /* Sources */ = {
378 | isa = PBXSourcesBuildPhase;
379 | buildActionMask = 2147483647;
380 | files = (
381 | 054B00511EC4EA050032B500 /* NSString+ShellKit.m in Sources */,
382 | 054B00431EC4E8D20032B500 /* SKShell.m in Sources */,
383 | 058F79251EC61144007CFF3A /* SKOptionalTask.m in Sources */,
384 | 054B004B1EC4E8D20032B500 /* SKTaskGroup.m in Sources */,
385 | 051DFF4B1EC55040009A4319 /* NSDate+ShellKit.m in Sources */,
386 | 054B003D1EC4E8D20032B500 /* SKObject.m in Sources */,
387 | 054B00471EC4E8D20032B500 /* SKTask.m in Sources */,
388 | );
389 | runOnlyForDeploymentPostprocessing = 0;
390 | };
391 | 05CF70361EC4FE2C00A39841 /* Sources */ = {
392 | isa = PBXSourcesBuildPhase;
393 | buildActionMask = 2147483647;
394 | files = (
395 | 05CF703D1EC4FE2C00A39841 /* main.m in Sources */,
396 | );
397 | runOnlyForDeploymentPostprocessing = 0;
398 | };
399 | /* End PBXSourcesBuildPhase section */
400 |
401 | /* Begin PBXTargetDependency section */
402 | 05CF70421EC4FE4600A39841 /* PBXTargetDependency */ = {
403 | isa = PBXTargetDependency;
404 | target = 054BFFED1EC4E60B0032B500 /* ShellKit */;
405 | targetProxy = 05CF70411EC4FE4600A39841 /* PBXContainerItemProxy */;
406 | };
407 | /* End PBXTargetDependency section */
408 |
409 | /* Begin XCBuildConfiguration section */
410 | 054B00021EC4E6670032B500 /* Debug */ = {
411 | isa = XCBuildConfiguration;
412 | buildSettings = {
413 | CLANG_ENABLE_MODULES = YES;
414 | CODE_SIGN_IDENTITY = "-";
415 | EXECUTABLE_PREFIX = lib;
416 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
417 | PRODUCT_NAME = "$(TARGET_NAME)";
418 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
419 | SWIFT_VERSION = 3.0;
420 | };
421 | name = Debug;
422 | };
423 | 054B00031EC4E6670032B500 /* Release */ = {
424 | isa = XCBuildConfiguration;
425 | buildSettings = {
426 | CLANG_ENABLE_MODULES = YES;
427 | CODE_SIGN_IDENTITY = "-";
428 | EXECUTABLE_PREFIX = lib;
429 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
430 | PRODUCT_NAME = "$(TARGET_NAME)";
431 | SWIFT_VERSION = 3.0;
432 | };
433 | name = Release;
434 | };
435 | 054BFFF41EC4E60B0032B500 /* Debug */ = {
436 | isa = XCBuildConfiguration;
437 | buildSettings = {
438 | CLANG_ENABLE_MODULES = YES;
439 | CODE_SIGN_IDENTITY = "-";
440 | CURRENT_PROJECT_VERSION = 1;
441 | DEFINES_MODULE = YES;
442 | DYLIB_COMPATIBILITY_VERSION = 1;
443 | DYLIB_CURRENT_VERSION = 1;
444 | DYLIB_INSTALL_NAME_BASE = "@rpath";
445 | FRAMEWORK_VERSION = A;
446 | INFOPLIST_FILE = ShellKit/Info.plist;
447 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
448 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
449 | PRODUCT_BUNDLE_IDENTIFIER = "com.xs-labs.ShellKit";
450 | PRODUCT_NAME = "$(TARGET_NAME)";
451 | VERSIONING_SYSTEM = "apple-generic";
452 | VERSION_INFO_PREFIX = "";
453 | };
454 | name = Debug;
455 | };
456 | 054BFFF51EC4E60B0032B500 /* Release */ = {
457 | isa = XCBuildConfiguration;
458 | buildSettings = {
459 | CLANG_ENABLE_MODULES = YES;
460 | CODE_SIGN_IDENTITY = "-";
461 | CURRENT_PROJECT_VERSION = 1;
462 | DEFINES_MODULE = YES;
463 | DYLIB_COMPATIBILITY_VERSION = 1;
464 | DYLIB_CURRENT_VERSION = 1;
465 | DYLIB_INSTALL_NAME_BASE = "@rpath";
466 | FRAMEWORK_VERSION = A;
467 | INFOPLIST_FILE = ShellKit/Info.plist;
468 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
469 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
470 | PRODUCT_BUNDLE_IDENTIFIER = "com.xs-labs.ShellKit";
471 | PRODUCT_NAME = "$(TARGET_NAME)";
472 | VERSIONING_SYSTEM = "apple-generic";
473 | VERSION_INFO_PREFIX = "";
474 | };
475 | name = Release;
476 | };
477 | 05BD89571A13FF4700A43CD8 /* Debug */ = {
478 | isa = XCBuildConfiguration;
479 | buildSettings = {
480 | ALWAYS_SEARCH_USER_PATHS = NO;
481 | CLANG_ANALYZER_DEADCODE_DEADSTORES = YES;
482 | CLANG_ANALYZER_GCD = YES;
483 | CLANG_ANALYZER_LOCALIZABILITY_EMPTY_CONTEXT = YES;
484 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
485 | CLANG_ANALYZER_MEMORY_MANAGEMENT = YES;
486 | CLANG_ANALYZER_NONNULL = YES;
487 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
488 | CLANG_ANALYZER_OBJC_ATSYNC = YES;
489 | CLANG_ANALYZER_OBJC_COLLECTIONS = YES;
490 | CLANG_ANALYZER_OBJC_DEALLOC = YES;
491 | CLANG_ANALYZER_OBJC_GENERICS = YES;
492 | CLANG_ANALYZER_OBJC_INCOMP_METHOD_TYPES = YES;
493 | CLANG_ANALYZER_OBJC_NSCFERROR = YES;
494 | CLANG_ANALYZER_OBJC_RETAIN_COUNT = YES;
495 | CLANG_ANALYZER_OBJC_SELF_INIT = YES;
496 | CLANG_ANALYZER_OBJC_UNUSED_IVARS = YES;
497 | CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
498 | CLANG_ANALYZER_SECURITY_INSECUREAPI_GETPW_GETS = YES;
499 | CLANG_ANALYZER_SECURITY_INSECUREAPI_MKSTEMP = YES;
500 | CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
501 | CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
502 | CLANG_ANALYZER_SECURITY_INSECUREAPI_UNCHECKEDRETURN = YES;
503 | CLANG_ANALYZER_SECURITY_INSECUREAPI_VFORK = YES;
504 | CLANG_ANALYZER_SECURITY_KEYCHAIN_API = YES;
505 | CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
506 | CLANG_CXX_LIBRARY = "libc++";
507 | CLANG_ENABLE_MODULES = NO;
508 | CLANG_ENABLE_OBJC_ARC = YES;
509 | CLANG_STATIC_ANALYZER_MODE = deep;
510 | CLANG_STATIC_ANALYZER_MODE_ON_ANALYZE_ACTION = deep;
511 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_INTEGER = YES;
512 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES;
513 | CLANG_WARN_ASSIGN_ENUM = YES;
514 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES_ERROR;
515 | CLANG_WARN_BOOL_CONVERSION = YES;
516 | CLANG_WARN_COMMA = YES_ERROR;
517 | CLANG_WARN_CONSTANT_CONVERSION = YES;
518 | CLANG_WARN_CXX0X_EXTENSIONS = YES;
519 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
520 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
521 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
522 | CLANG_WARN_EMPTY_BODY = YES;
523 | CLANG_WARN_ENUM_CONVERSION = YES;
524 | CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
525 | CLANG_WARN_INFINITE_RECURSION = YES;
526 | CLANG_WARN_INT_CONVERSION = YES;
527 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES_ERROR;
528 | CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
529 | CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
530 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
531 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
532 | CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = NO;
533 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES;
534 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
535 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
536 | CLANG_WARN_STRICT_PROTOTYPES = YES_ERROR;
537 | CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
538 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
539 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
540 | CLANG_WARN_UNREACHABLE_CODE = YES;
541 | CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
542 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
543 | CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
544 | COMBINE_HIDPI_IMAGES = YES;
545 | COPY_PHASE_STRIP = NO;
546 | DEBUG_INFORMATION_FORMAT = dwarf;
547 | ENABLE_STRICT_OBJC_MSGSEND = YES;
548 | ENABLE_TESTABILITY = YES;
549 | GCC_C_LANGUAGE_STANDARD = c11;
550 | GCC_DYNAMIC_NO_PIC = NO;
551 | GCC_ENABLE_CPP_EXCEPTIONS = YES;
552 | GCC_ENABLE_CPP_RTTI = YES;
553 | GCC_NO_COMMON_BLOCKS = YES;
554 | GCC_OPTIMIZATION_LEVEL = 0;
555 | GCC_PREPROCESSOR_DEFINITIONS = (
556 | "DEBUG=1",
557 | "$(inherited)",
558 | );
559 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
560 | GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
561 | GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
562 | GCC_TREAT_WARNINGS_AS_ERRORS = YES;
563 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
564 | GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
565 | GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES;
566 | GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
567 | GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
568 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
569 | GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES;
570 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
571 | GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = YES;
572 | GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
573 | GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
574 | GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
575 | GCC_WARN_INHIBIT_ALL_WARNINGS = NO;
576 | GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
577 | GCC_WARN_MISSING_PARENTHESES = YES;
578 | GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
579 | GCC_WARN_PEDANTIC = YES;
580 | GCC_WARN_SHADOW = YES;
581 | GCC_WARN_SIGN_COMPARE = YES;
582 | GCC_WARN_STRICT_SELECTOR_MATCH = YES;
583 | GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
584 | GCC_WARN_UNDECLARED_SELECTOR = YES;
585 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
586 | GCC_WARN_UNKNOWN_PRAGMAS = YES;
587 | GCC_WARN_UNUSED_FUNCTION = YES;
588 | GCC_WARN_UNUSED_LABEL = YES;
589 | GCC_WARN_UNUSED_PARAMETER = YES;
590 | GCC_WARN_UNUSED_VALUE = YES;
591 | GCC_WARN_UNUSED_VARIABLE = YES;
592 | LLVM_LTO = YES_THIN;
593 | MACOSX_DEPLOYMENT_TARGET = 10.9;
594 | ONLY_ACTIVE_ARCH = YES;
595 | RUN_CLANG_STATIC_ANALYZER = YES;
596 | SDKROOT = macosx;
597 | SKIP_INSTALL = YES;
598 | SWIFT_DISABLE_SAFETY_CHECKS = NO;
599 | SWIFT_ENFORCE_EXCLUSIVE_ACCESS = full;
600 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
601 | SWIFT_SUPPRESS_WARNINGS = NO;
602 | SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
603 | SWIFT_VERSION = 3.0;
604 | };
605 | name = Debug;
606 | };
607 | 05BD89581A13FF4700A43CD8 /* Release */ = {
608 | isa = XCBuildConfiguration;
609 | buildSettings = {
610 | ALWAYS_SEARCH_USER_PATHS = NO;
611 | CLANG_ANALYZER_DEADCODE_DEADSTORES = YES;
612 | CLANG_ANALYZER_GCD = YES;
613 | CLANG_ANALYZER_LOCALIZABILITY_EMPTY_CONTEXT = YES;
614 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
615 | CLANG_ANALYZER_MEMORY_MANAGEMENT = YES;
616 | CLANG_ANALYZER_NONNULL = YES;
617 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
618 | CLANG_ANALYZER_OBJC_ATSYNC = YES;
619 | CLANG_ANALYZER_OBJC_COLLECTIONS = YES;
620 | CLANG_ANALYZER_OBJC_DEALLOC = YES;
621 | CLANG_ANALYZER_OBJC_GENERICS = YES;
622 | CLANG_ANALYZER_OBJC_INCOMP_METHOD_TYPES = YES;
623 | CLANG_ANALYZER_OBJC_NSCFERROR = YES;
624 | CLANG_ANALYZER_OBJC_RETAIN_COUNT = YES;
625 | CLANG_ANALYZER_OBJC_SELF_INIT = YES;
626 | CLANG_ANALYZER_OBJC_UNUSED_IVARS = YES;
627 | CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
628 | CLANG_ANALYZER_SECURITY_INSECUREAPI_GETPW_GETS = YES;
629 | CLANG_ANALYZER_SECURITY_INSECUREAPI_MKSTEMP = YES;
630 | CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
631 | CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
632 | CLANG_ANALYZER_SECURITY_INSECUREAPI_UNCHECKEDRETURN = YES;
633 | CLANG_ANALYZER_SECURITY_INSECUREAPI_VFORK = YES;
634 | CLANG_ANALYZER_SECURITY_KEYCHAIN_API = YES;
635 | CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
636 | CLANG_CXX_LIBRARY = "libc++";
637 | CLANG_ENABLE_MODULES = NO;
638 | CLANG_ENABLE_OBJC_ARC = YES;
639 | CLANG_STATIC_ANALYZER_MODE = deep;
640 | CLANG_STATIC_ANALYZER_MODE_ON_ANALYZE_ACTION = deep;
641 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_INTEGER = YES;
642 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES;
643 | CLANG_WARN_ASSIGN_ENUM = YES;
644 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES_ERROR;
645 | CLANG_WARN_BOOL_CONVERSION = YES;
646 | CLANG_WARN_COMMA = YES_ERROR;
647 | CLANG_WARN_CONSTANT_CONVERSION = YES;
648 | CLANG_WARN_CXX0X_EXTENSIONS = YES;
649 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
650 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
651 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
652 | CLANG_WARN_EMPTY_BODY = YES;
653 | CLANG_WARN_ENUM_CONVERSION = YES;
654 | CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
655 | CLANG_WARN_INFINITE_RECURSION = YES;
656 | CLANG_WARN_INT_CONVERSION = YES;
657 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES_ERROR;
658 | CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
659 | CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
660 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
661 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
662 | CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = NO;
663 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES;
664 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
665 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
666 | CLANG_WARN_STRICT_PROTOTYPES = YES_ERROR;
667 | CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
668 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
669 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
670 | CLANG_WARN_UNREACHABLE_CODE = YES;
671 | CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
672 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
673 | CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
674 | COMBINE_HIDPI_IMAGES = YES;
675 | COPY_PHASE_STRIP = YES;
676 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
677 | ENABLE_NS_ASSERTIONS = NO;
678 | ENABLE_STRICT_OBJC_MSGSEND = YES;
679 | GCC_C_LANGUAGE_STANDARD = c11;
680 | GCC_ENABLE_CPP_EXCEPTIONS = YES;
681 | GCC_ENABLE_CPP_RTTI = YES;
682 | GCC_NO_COMMON_BLOCKS = YES;
683 | GCC_OPTIMIZATION_LEVEL = s;
684 | GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
685 | GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
686 | GCC_TREAT_WARNINGS_AS_ERRORS = YES;
687 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
688 | GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
689 | GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES;
690 | GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
691 | GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
692 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
693 | GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES;
694 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
695 | GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = YES;
696 | GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
697 | GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
698 | GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
699 | GCC_WARN_INHIBIT_ALL_WARNINGS = NO;
700 | GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
701 | GCC_WARN_MISSING_PARENTHESES = YES;
702 | GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
703 | GCC_WARN_PEDANTIC = YES;
704 | GCC_WARN_SHADOW = YES;
705 | GCC_WARN_SIGN_COMPARE = YES;
706 | GCC_WARN_STRICT_SELECTOR_MATCH = YES;
707 | GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
708 | GCC_WARN_UNDECLARED_SELECTOR = YES;
709 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
710 | GCC_WARN_UNKNOWN_PRAGMAS = YES;
711 | GCC_WARN_UNUSED_FUNCTION = YES;
712 | GCC_WARN_UNUSED_LABEL = YES;
713 | GCC_WARN_UNUSED_PARAMETER = YES;
714 | GCC_WARN_UNUSED_VALUE = YES;
715 | GCC_WARN_UNUSED_VARIABLE = YES;
716 | LLVM_LTO = YES_THIN;
717 | MACOSX_DEPLOYMENT_TARGET = 10.9;
718 | RUN_CLANG_STATIC_ANALYZER = YES;
719 | SDKROOT = macosx;
720 | SKIP_INSTALL = YES;
721 | SWIFT_DISABLE_SAFETY_CHECKS = NO;
722 | SWIFT_ENFORCE_EXCLUSIVE_ACCESS = full;
723 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
724 | SWIFT_SUPPRESS_WARNINGS = NO;
725 | SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
726 | SWIFT_VERSION = 3.0;
727 | };
728 | name = Release;
729 | };
730 | 05CF703E1EC4FE2C00A39841 /* Debug */ = {
731 | isa = XCBuildConfiguration;
732 | buildSettings = {
733 | CODE_SIGN_IDENTITY = "-";
734 | OTHER_LDFLAGS = (
735 | "-ObjC",
736 | "-all_load",
737 | );
738 | PRODUCT_NAME = "$(TARGET_NAME)";
739 | SKIP_INSTALL = NO;
740 | };
741 | name = Debug;
742 | };
743 | 05CF703F1EC4FE2C00A39841 /* Release */ = {
744 | isa = XCBuildConfiguration;
745 | buildSettings = {
746 | CODE_SIGN_IDENTITY = "-";
747 | OTHER_LDFLAGS = (
748 | "-ObjC",
749 | "-all_load",
750 | );
751 | PRODUCT_NAME = "$(TARGET_NAME)";
752 | SKIP_INSTALL = NO;
753 | };
754 | name = Release;
755 | };
756 | /* End XCBuildConfiguration section */
757 |
758 | /* Begin XCConfigurationList section */
759 | 054B00011EC4E6670032B500 /* Build configuration list for PBXNativeTarget "ShellKit-Static" */ = {
760 | isa = XCConfigurationList;
761 | buildConfigurations = (
762 | 054B00021EC4E6670032B500 /* Debug */,
763 | 054B00031EC4E6670032B500 /* Release */,
764 | );
765 | defaultConfigurationIsVisible = 0;
766 | defaultConfigurationName = Release;
767 | };
768 | 054BFFF31EC4E60B0032B500 /* Build configuration list for PBXNativeTarget "ShellKit" */ = {
769 | isa = XCConfigurationList;
770 | buildConfigurations = (
771 | 054BFFF41EC4E60B0032B500 /* Debug */,
772 | 054BFFF51EC4E60B0032B500 /* Release */,
773 | );
774 | defaultConfigurationIsVisible = 0;
775 | defaultConfigurationName = Release;
776 | };
777 | 05BD894D1A13FF4700A43CD8 /* Build configuration list for PBXProject "ShellKit" */ = {
778 | isa = XCConfigurationList;
779 | buildConfigurations = (
780 | 05BD89571A13FF4700A43CD8 /* Debug */,
781 | 05BD89581A13FF4700A43CD8 /* Release */,
782 | );
783 | defaultConfigurationIsVisible = 0;
784 | defaultConfigurationName = Release;
785 | };
786 | 05CF70401EC4FE2C00A39841 /* Build configuration list for PBXNativeTarget "ShellKit-Test" */ = {
787 | isa = XCConfigurationList;
788 | buildConfigurations = (
789 | 05CF703E1EC4FE2C00A39841 /* Debug */,
790 | 05CF703F1EC4FE2C00A39841 /* Release */,
791 | );
792 | defaultConfigurationIsVisible = 0;
793 | defaultConfigurationName = Release;
794 | };
795 | /* End XCConfigurationList section */
796 | };
797 | rootObject = 05BD894A1A13FF4700A43CD8 /* Project object */;
798 | }
799 |
--------------------------------------------------------------------------------