johnsundell / marathon Goto Github PK
View Code? Open in Web Editor NEW[DEPRECATED] Marathon makes it easy to write, run and manage your Swift scripts ๐
License: MIT License
[DEPRECATED] Marathon makes it easy to write, run and manage your Swift scripts ๐
License: MIT License
Hi John, nice library ๐ . I'm starting to use Marathon, when running marathon create helloWorld "import Foundation; print(\"Hello world\")"
it opens the source file in Xcode, which is handy. But after that, in Finder I only see helloWorld.swift
, how can I open it it Xcode again?
Also, it seems the scheme is duplicated
Running the creation command from the readme:
marathon create helloWorld "import Foundation; print(\"Hello world\")"
Is failing if the run from a folder whose name contains spaces:
Stevens-MacBook-Pro-2:some scripts stevenbarnegren$ marathon create helloWorld "import Foundation; print(\"Hello world\")" ๐ฃ Created script at helloWorld.swift ShellOutError(message: "/bin/bash: line 0: cd: /Users/stevenbarnegren/.marathon/Scripts/Cache/-Users-stevenbarnegren-Desktop-some: No such file or directory", output: "")
The swift file is created, but the script is not able to be run via Marathon. Looking at the error, it looks like it is trying to access the directory, but truncating the name at the space.
From a folder on my desktop, named:
some scripts
fails
test scripts
fails
scripts
succeeds
Hi @JohnSundell!
I want to report this error also if I know that Swift on ARM is not right now a stable environment. So if it's to hard to figure out the problem no worries, you can close this issue :)
The machine is a Raspberry Pi 2 with Ubuntu 16.04.2.
Swift version:
ubuntu@ Marathon (master)$ swift --version
Swift version 3.1 (swift-3.1-RELEASE)
Target: armv7-unknown-linux-gnueabihf
The errors are the same using the Make or the SPM:
Compile Swift Module 'Wrap' (1 sources)
Compile Swift Module 'Unbox' (1 sources)
Compile Swift Module 'Require' (1 sources)
Compile Swift Module 'Files' (1 sources)
Compile Swift Module 'ShellOut' (1 sources)
/home/ubuntu/Marathon/.build/checkouts/wrap.git-1764762263/Sources/Wrap.swift:264:26: error: use of unresolved identifier 'RegularExpression'
let regex = try! RegularExpression(pattern: "(?<=[a-z])([A-Z])|([A-Z])(?=[a-z])", options: [])
^~~~~~~~~~~~~~~~~
Foundation.NSRegularExpression:1:12: note: did you mean 'NSRegularExpression'?
open class NSRegularExpression : Foundation.NSObject, NSCopying, NSCoding {
^
/home/ubuntu/Marathon/.build/checkouts/require.git--488267411/Sources/Require.swift:31:29: error: use of unresolved identifier 'NSException'
let exception = NSException(
^~~~~~~~~~~
SwiftGlibc.exception:1:15: note: did you mean 'exception'?
public struct exception {
^
Foundation.NSExpression:1:12: note: did you mean 'NSExpression'?
open class NSExpression : Foundation.NSObject, NSSecureCoding, NSCopying {
^
Foundation.NSExceptionName:2:15: note: did you mean 'NSExceptionName'?
public struct NSExceptionName : RawRepresentable, Equatable, Hashable, Comparable {
^
<unknown>:0: error: build had 2 command failures
error: exit(1): /opt/swift/swift-3.1/usr/bin/swift-build-tool -f /home/ubuntu/Marathon/.build/release.yaml
Makefile:4: recipe for target 'install' failed
make: *** [install] Error 1
I have no idea why the compiler is "confused" with RegularExpression and NSExpression :(
Thanks in advance!
I think the problem is that the path included a redundant /
when creating like /Users/pixyzehn/Developer//hoge.swift
.
Is that issue in Files
?
pixyzehn โฎ ~/Developer โฎ marathon create hoge
๐ฃ Created script at hoge.swift
โ๏ธ Opening Hoge.xcodeproj/
โน๏ธ Marathon will keep running, in order to commit any changes you make in Xcode back to the original script file
Press any key once you're done
pixyzehn โฎ ~/Developer โฎ marathon list
๐ Scripts
----------
/Users/pixyzehn/Developer//hoge.swift
๐ To remove either a package or the cached data for a script, use 'marathon remove'
pixyzehn โฎ ~/Developer โฎ marathon run hoge
pixyzehn โฎ ~/Developer โฎ marathon list
๐ Scripts
----------
/Users/pixyzehn/Developer//hoge.swift
/Users/pixyzehn/Developer/hoge.swift
๐ To remove either a package or the cached data for a script, use 'marathon remove'
Currently, you need to use either a Git URL or absolute file path in your Marathonfile
. While this covers most usecases, a Marathonfile
should also be able to include relative paths that get expanded whenever the file is evaluated.
When the user starts editing a script (using marathon edit Myscript.swift
), we start syncing the file between the internal copy that Marathon maintains (in order to be able to generate packages for the script) and the original script file (located wherever the user wants).
Currently, this sycning mechanism is done through a simple timer, that every 3 seconds copies the original script file back into Marathon's script folder. This is not ideal for a few reasons:
Before I implemented the syncing this way, I tried two other solutions:
Symlinking the script file
Marathon makes heavy use of symlinks (for example for packages, to "trick" SPM that packages are already compiled, so it won't re-compile them for every script). So my initial idea was to use symlinks for scripts as well. The problem is that Xcode doesn't like symlinks, and would not be able to save the file back (basically it tried to save into the symlink itself, which would cause an error dialog in Xcode). So I abandoned that idea.
Hooking into file system events
The next thing I tried was using GCD to hook into the file system to get notified whenever the file was changed. While this worked really well if the script was edited using an editor like Atom, it didn't work for Xcode, which doesn't seem to generate the same events every time the file is saved.
What we want
So, given the above context, what we want is a more robust syncing solution that fullfils the following requirements:
Perhaps we could hook into the Xcode project itself somehow? Looking for ideas from the community here ๐
> marathon add [email protected]:kareman/FileSmith.git --verbose
๐ Cloning [email protected]:kareman/FileSmith.git...
$ cd "/Users/karemorstol/.marathon/Packages/Temp/" && git clone [email protected]:kareman/FileSmith.git Clone -q
Resolving latest major version for [email protected]:kareman/FileSmith.git...
๐ฅ Could not save file for package 'FileSmith
)
package.dependencies.append(.Package(url: https://github.com/kareman/SwiftShell'
๐ Make sure you have write permissions to the folder '/Users/karemorstol/.marathon/Packages/'
Judging by the error message it doesn't like the slightly unusual Package.swift:
> cat Package.swift
import PackageDescription
let package = Package(
name: "FileSmith"
)
package.dependencies.append(.Package(url: "https://github.com/kareman/SwiftShell", "3.0.0"))
I had no problem adding the SwiftShell framework itself, which has no dependencies.
Hi John,
I can create and run the library now. All are great. Then I add another framework with this command, I run marathon add [email protected]:JohnSundell/Files.git
. I waited for some time but it seems not responding, and there is no Marathonfile
generated.
I'm on macOS 10.12.3
and Swift Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1) Target: x86_64-apple-macosx10.9
Have you considered this to enforce formatting?
pixyzehn โฎ ~/Developer/sandbox-for-marathon โฎ marathon create script --no-open
๐ฃ Created script at script.swift
pixyzehn โฎ ~/Developer/sandbox-for-marathon โฎ cat script.swift
--no-open%
I think it's better to add "import Foundation\n\n"
instead of --no-open
.
I'm a fish
user and I really love the autocompletion in it, so I'm also really happy that Marathon supports this for zsh
.
I've decided that I'll extend Marathon's great user experience to fish
and it's rather easy task, but some thoughts came to my mind during the investigation. Here they are...
First of all, installShellAutocompleteIfNeeded
installs zsh
completions no matter what kind of the shell you're using, so ~/.marathon
looks like this (out of the box), even though I don't have zsh
on my computer:
.marathon/
โโโ Packages
โย ย โโโ Generated
โย ย โโโ Temp
โโโ Scripts
โย ย โโโ Cache
โย ย โโโ Temp
โโโ zsh
โโโ _marathon
I have 2 proposals:
installShellAutocompleteIfNeeded
should check for the shell which user is actually using and install completions only for it..marathon/zsh
to .marathon/autocompletions
to be more generic.I think that second option could be better since those completion files aren't big and they can't make any harm.
Another thing is that Marathon is using custom script from ZshAutocompleteInstaller
to generate a string which is later appended to the file. It's cool that we want to keep everything in Swift, but IMO, at some point this can become a huge pain.
Both fish
and zsh
(and probably more) are using scripts to achieve autocompletion, so why not write them and keep them in repo, or as a dependency?
I'm also thinking about some sort of abstraction layer, so each completion can actually use one set of completions and then generate from this file a proper autocompletion scripts for each shell which Marathon will support. Just thinking in DRY mode right now ๐
Error while compiling:
/Users/luismanuelramirezvargas/Projects/Marathon/Packages/Releases-1.0.6/Sources/Array+Version.swift:10:38: error: same-type requirement makes generic parameter 'Element' non-generic public extension Array where Element == Version { ^ /Users/luismanuelramirezvargas/Projects/Marathon/Packages/Releases-1.0.6/Sources/Array+Version.swift:12:34: error: reference to generic type 'Array' requires arguments in <...> func withoutPreReleases() -> Array { ^ <Any> <unknown>:0: note: generic type 'Array' declared here <unknown>:0: error: build had 1 command failures
Full stacktrace:
$ swift build -c release -Xswiftc -static-stdlib Cloning https://github.com/JohnSundell/Files.git HEAD is now at 284d85d Merge pull request #11 from yageek/feature/currentFolder Resolved version: 1.8.0 Cloning https://github.com/JohnSundell/Unbox.git HEAD is now at ba42e01 Merge pull request #164 from hartbit/set-unboxable-collection Resolved version: 2.4.0 Cloning https://github.com/JohnSundell/Wrap.git HEAD is now at d6b953b Merge pull request #35 from darthpelo/master Resolved version: 2.1.1 Cloning https://github.com/JohnSundell/ShellOut.git HEAD is now at 38cd16d README: Update for new series of commands + path API Resolved version: 1.1.0 Cloning https://github.com/JohnSundell/Require.git HEAD is now at 44d5266 Remove whitespace & improve code formatting Resolved version: 1.0.2 Cloning https://github.com/JohnSundell/Releases.git HEAD is now at 787caab Use HTTPS instead of SSH for cloning dependencies Resolved version: 1.0.6 Compile Swift Module 'Require' (1 sources) Compile Swift Module 'ShellOut' (1 sources) Compile Swift Module 'Wrap' (1 sources) Compile Swift Module 'Unbox' (1 sources) Compile Swift Module 'Files' (1 sources) Compile Swift Module 'Releases' (4 sources) /Users/user/Projects/Marathon/Packages/Releases-1.0.6/Sources/Array+Version.swift:10:38: error: same-type requirement makes generic parameter 'Element' non-generic public extension Array where Element == Version { ^ /Users/user/Projects/Marathon/Packages/Releases-1.0.6/Sources/Array+Version.swift:12:34: error: reference to generic type 'Array' requires arguments in <...> func withoutPreReleases() -> Array { ^ <Any> <unknown>:0: note: generic type 'Array' declared here <unknown>:0: error: build had 1 command failures error: exit(1): /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-build-tool -f /Users/user/Projects/Marathon/.build/release.yaml
An option to the remove
command should be added to quickly clear the cache data for all scripts. This is useful, to not have to go through each and every one and remove them manually. Since it's just cache data, it's not super risky, but it might be worth adding a confirmation step to this one, just to make sure the user really intended to remove all cache data.
Suggested execution:
$ marathon remove -all-script-data
(The reason we're simply not going for -all
here is that I think it's better to reserve that for the future, since it's a bit too general).
Add a package from a given URL to be able to use it from your scripts
๐ Usage: 'marathon add '
โน๏ธ You can also use a 'Marathonfile' to automatically add packages. See https://github.com/johnsundell/marathon for more information
Only a small issue but might be worth mentioning in ReadMe.
Roberts-MacBook-Pro:Marathon robertnash$ make
swift package --enable-prefetching update
Fetching https://github.com/johnsundell/files.git
Fetching https://github.com/johnsundell/unbox.git
Fetching https://github.com/johnsundell/wrap.git
Cloning https://github.com/johnsundell/files.git
Resolving https://github.com/johnsundell/files.git at 1.6.2
Cloning https://github.com/johnsundell/wrap.git
Resolving https://github.com/johnsundell/wrap.git at 2.1.0
Cloning https://github.com/johnsundell/unbox.git
Resolving https://github.com/johnsundell/unbox.git at 2.4.0
swift build --enable-prefetching -c release -Xswiftc -static-stdlib
Compile Swift Module 'Wrap' (1 sources)
Compile Swift Module 'Unbox' (1 sources)
Compile Swift Module 'Files' (1 sources)
Compile Swift Module 'MarathonCore' (24 sources)
Compile Swift Module 'Marathon' (1 sources)
Linking ./.build/release/Marathon
cp -f .build/release/Marathon /usr/local/bin/marathon
cp: /usr/local/bin/marathon: Permission denied
make: *** [install] Error 1
If a script fails to compile because of a missing package, it would be nice to suggest to the user that they run marathon add <package-url>
to add it. Right now, this is the output you get:
๐ฅ Failed to compile script
๐ The following error(s) occured:
- 2:8: no such module 'Files'
It would be nice if, in addition to the above, the following information was included:
๐ You can add Files to Marathon using 'marathon add <url-to-Files>'
marathon add https://github.com/SwiftyJSON/SwiftyJSON.git
it does have a package.swift file and a tag. not sure why it doesn't work.
SwiftyJSON/SwiftyJSON#823
Sometimes you want to write tests for your scripts. For example if you're making something publically available, or if the script goes through many iterations, or if it grows in complexity. Although at some point it'd be better to use the Swift Package Manager directly and just use swift test
to perform tests, it would be very nice if Marathon included lightweight support for running tests using the XCTest
framework.
Proposal: Introducing a test
command
Running marathon test MyScript.swift
will look for a file called MyScriptTests.swift
, and do the following:
swift test
to run the tests.Extension to the create
and edit
commands
We should also extend create
and edit
to support creating a script package that already contains test support. The proposal is to introduce a --test
flag that can be passed to these commands. So for example marathon create MyScript.swift
will create both MyScript.swift
and MyScriptTests.swift
.
Running the following Marathon script in Terminal hangs indefinitely, while completing promptly in Xcode.
print((0...99999).reduce("") { $0 + ",\($1)" })
print("๐ All done!")
I discovered this while attempting to recursively print filenames from a large directory.
Now swift test
takes about 295s in my env. It's time to reduce the time, so we can focus on more essential parts.
Test Suite 'MarathonTests' passed at 2017-04-09 09:07:23.894.
Executed 34 tests, with 0 failures (0 unexpected) in 294.578 (294.580) seconds
Test Suite 'MarathonPackageTests.xctest' passed at 2017-04-09 09:07:23.894.
Executed 34 tests, with 0 failures (0 unexpected) in 294.578 (294.580) seconds
Test Suite 'All tests' passed at 2017-04-09 09:07:23.894.
Executed 34 tests, with 0 failures (0 unexpected) in 294.578 (294.581) seconds
Roberts-MacBook-Pro:Scripts robertnash$ cd ~/Desktop/Folder1/
Roberts-MacBook-Pro:Folder1 robertnash$ marathon create addSuffix
๐ฃ Created script at addSuffix.swift
โ๏ธ Opening Addsuffix.xcodeproj/
โน๏ธ Marathon will keep running, in order to commit any changes you make in Xcode back to the original script file
Press any key once you're done
Roberts-MacBook-Pro:Folder1 robertnash$ marathon run addSuffix "something"
hangs here
Instance method script(at:)
of ScriptManager
should be renamed to script(atPath:)
to match Swift API naming convention as argument name atPath
provides more context than argument type String
.
I'd like to introduce simple two options in the list command,
$ marathon list
๐ฆ Packages
-----------
Files ([email protected]:JohnSundell/Files.git)
SwiftyJSON (https://github.com/SwiftyJSON/SwiftyJSON.git)
๐ Scripts
----------
/Users/pixyzehn/Developer/sandbox-for-marathon/fufufufuf.swift
/Users/pixyzehn/Developer/sandbox-for-marathon/hehe.swift
$ marathon list --packages
๐ฆ Packages
-----------
Files ([email protected]:JohnSundell/Files.git)
SwiftyJSON (https://github.com/SwiftyJSON/SwiftyJSON.git)
$ marathon list --scripts
๐ Scripts
----------
/Users/pixyzehn/Developer/sandbox-for-marathon/fufufufuf.swift
/Users/pixyzehn/Developer/sandbox-for-marathon/hehe.swift
$ marathon list --packages --scripts (or --scripts --packages)
๐ฆ Packages
-----------
Files ([email protected]:JohnSundell/Files.git)
SwiftyJSON (https://github.com/SwiftyJSON/SwiftyJSON.git)
๐ Scripts
----------
/Users/pixyzehn/Developer/sandbox-for-marathon/fufufufuf.swift
/Users/pixyzehn/Developer/sandbox-for-marathon/hehe.swift
Hello,
I like to try TestDrive to install via Marathon, but cannot install. Could you please help me with the issue
/cc @JohnSundell
I was using;
Swift Package Manager
`
seyhunak@MacBook-Pro ~/Projects/Marathon (master)$ swift build -c release -Xswiftc -static-stdlib
Fetching [email protected]:johnsundell/files.git
error: Failed to clone [email protected]:johnsundell/files.git to AbsolutePath:"/Users/seyhunak/Projects/Marathon/.build/repositories/files.git--3794229230550581555"
Marathon Installer via make
seyhunak@MacBook-Pro ~/Projects/Marathon (master)$ sudo make [2.3.1]
swift package --enable-prefetching update
Fetching [email protected]:johnsundell/files.git
Fetching [email protected]:johnsundell/wrap.git
Fetching [email protected]:johnsundell/unbox.git
Fetching [email protected]:johnsundell/shellout.git
Fetching [email protected]:johnsundell/require.git
Fetching [email protected]:johnsundell/releases.git
Fetching [email protected]:johnsundell/files.git
error: Failed to clone [email protected]:johnsundell/files.git to AbsolutePath:"/Users/seyhunak/Projects/Marathon/.build/repositories/files.git--3794229230550581555"
make: *** [install] Error 1
seyhunak@MacBook-Pro ~/Projects/Marathon (master)$
`
@JohnSundell, this looks awesome. Thank you for sharing this.
I use Swift on iOS all the time, but I've only tried setting up a Swift executable with the Swift Package Manager a couple times. I'd just like to ask for your take and recommendation.
Do you think Marathon would work well for managing dependencies not for a short script, but for a Swift server app?
Forgive the very hasty comparison here, but Marathon looks to me like it could serve a similar role to what NPM does on a basic Node.js app: installing dependencies in just a few moments and updating the list of packages automatically.
Thanks again for sharing this awesome work. I'm sure it will help me in my work soon.
I don't know how much effort it would take to make this available via homebrew, but I guess it would be easier to install, update and maintain for less experienced users.
Just tested this out and it seems like you need to be in the destination directory for the script to avoid an error.
I don't have time to dig into this in full detail right now so please feel free to close if I've misunderstood something but it feels like a bug. This is my console log from the installation through to the bug. Hope it's helpful.
Daves-MBP:~ $ cd Desktop
Daves-MBP:Desktop $ git clone [email protected]:JohnSundell/Marathon.git
Cloning into 'Marathon'...
remote: Counting objects: 118, done.
remote: Compressing objects: 100% (12/12), done.
remote: Total 118 (delta 3), reused 0 (delta 0), pack-reused 106
Receiving objects: 100% (118/118), 181.70 KiB | 0 bytes/s, done.
Resolving deltas: 100% (43/43), done.
Daves-MBP:Desktop $ cd Marathon
Daves-MBP:Marathon (master) $ make
swift package update
Cloning https://github.com/johnsundell/files.git
HEAD is now at ac1774c Add @discardableResult to โฆifNeeded methods
Resolved version: 1.5.5
Cloning https://github.com/johnsundell/unbox.git
HEAD is now at ba42e01 Merge pull request #164 from hartbit/set-unboxable-collection
Resolved version: 2.4.0
Cloning https://github.com/johnsundell/wrap.git
HEAD is now at 129142c Use custom verification for set
Resolved version: 2.1.0
swift build -c release -Xswiftc -static-stdlib
Compile Swift Module 'Wrap' (1 sources)
Compile Swift Module 'Files' (1 sources)
Compile Swift Module 'Unbox' (1 sources)
Compile Swift Module 'MarathonCore' (22 sources)
Compile Swift Module 'Marathon' (1 sources)
Linking ./.build/release/Marathon
cp -f .build/release/Marathon /usr/local/bin/marathon
Daves-MBP:Marathon (master) $ marathon create ~/Desktop/script.swift
๐ฅ Failed to create script file named '/Users/dave/Desktop/script.swift'
๐ Make sure you have write permissions to the current folder
Daves-MBP:~ $ cd ~/Desktop
Daves-MBP:Desktop $ marathon create script.swift
๐ฃ Created script script.swift
โ๏ธ Opening Script.xcodeproj/
โน๏ธ Marathon will keep running, in order to commit any changes you make in Xcode back to the original script file
Press any key once you're done
The README mentions
marathon install https://raw.githubusercontent.com/JohnSundell/Marathon-Examples/master/AddSuffix/AddSuffix.swift
Currently this is a 404: https://raw.githubusercontent.com/JohnSundell/Marathon-Examples/master/AddSuffix/AddSuffix.swift
When bash scripting - it's a frequent challenge that there will be error conditions encountered which will cause script to abort.
This script has been well received by people in community to trap a complex script executing multiple commands
https://github.com/niieani/bash-oo-framework#error-handling-with-exceptions-and-throw
http://stackoverflow.com/questions/64786/error-handling-in-bash
#!/bin/bash
source 'lib.trap.sh' // by including this - a complete picture is revealed on error states encountered
echo "doing something wrong now .."
echo "$foo"
exit 0
Naturally this would only make sense when executing other commands from terminal using Marathon.
This may take some time to get right - but would fit nicely into this to help replace bash scripts -> swift.
Similar to #33, it would be nice to make marathon install
have a conveniene feature where you can simply pass the URL of a repo containing a single Swift script that you wish to install.
For example, right now, in order to install Playground, you need to run the following:
$ marathon install https://raw.githubusercontent.com/JohnSundell/Playground/master/Sources/Playground.swift
It would be really nice if you were able to just run:
$ marathon install [email protected]:johnsundell/playground
And Marathon would automatically figure out that you meant to install Sources/Playground.swift
.
marathon create SomeScript
produces a target named Somescript
. Should the default behavior be to capitalize target names while maintaining other capitalized letters? e.g.:
SomeScript
-> SomeScript
instead of Somescript
someScript
-> SomeScript
instead of Somescript
What do you think @JohnSundell?
Personally, to use --no-open
instead of -no-open
looks natural like other CLI tools. What do you think of that?
If you think so, I'd like to replace.
Hey thanks for open sourcing your project!
I wanted to ask for a mechanism to make Marathon additionally search in different paths like ~/scripts/
or $PROJECT_ROOT/Scripts
.
Some use cases are:
My ideas would be:
marathon
or scripts
When running marathon remove --all-packages
, multiple swift package update
commands are performed under the hood, making the removal take longer than needed. Ideally only one update should occur, at the end of the process.
Current behavior:
$ marathon remove --all-packages
๐ Removing Files...
Updating packages...
Removing Releases...
Updating packages...
Removing ShellOut...
Updating packages...
Removing Xgen...
Updating packages...
Updating packages...
๐ Removed all packages
Expected behavior:
$ marathon remove --all-packages
๐ Removing Files...
Removing Releases...
Removing ShellOut...
Removing Xgen...
Updating packages...
๐ Removed all packages
The version of the Swift Package manager bundled with the 3.1 release uses a different folder structure than the one bundled with 3.0. This causes marathon remove packageName
to not fully remove an added package, which in turn causes some of the tests to fail when run on Xcode 8.3. I have a fix in the works which should be in master
soon ๐
Hello @JohnSundell
I wanted to try out marathon, after closely following the installation instructions I run into the following error again and again.
The following info. may be relevant.
I'm on a macOS machine, 10.12.4
And I installed swift using `brew install swift`
Here's the error.
Marathon git/master*
โฏ make
swift package --enable-prefetching update
Fetching [email protected]:johnsundell/wrap.git
Fetching [email protected]:johnsundell/unbox.git
Fetching [email protected]:johnsundell/files.git
Fetching [email protected]:johnsundell/shellout.git
Fetching [email protected]:johnsundell/require.git
Fetching [email protected]:johnsundell/releases.git
Fetching [email protected]:johnsundell/files.git
error: Failed to clone [email protected]:johnsundell/files.git to <AbsolutePath:"/Users/eklavya/Projects/bitworld/SWIFT/Marathon/.build/repositories/files.git--3794229230550581555">
make: *** [install] Error 1
Could you please help me out :)
Hi @JohnSundell I understand why test testAddingAndRemovingRemotePackage
failed on Linux with this error:
<EXPR>:0: error: MarathonTests.AddingAndRemovingRemotePackage : threw error "๐ฅ Cannot remove package 'files' - no such package has been added
๐ Did you mean to remove the cache data for a script? If so, add '.swift' to its path
To list all added packages run 'marathon list'"
The issue is the package name used in the test
// Remove the package
try run(with: ["remove", "files"])
The real name of the package is Files, but on macOS 10.12.4 doesn't matter if we pass the string with the first letter lowercase.
On my virtual machine with Ubuntu 16.04, instead, this difference became an issue. I changed the test in this way and it works:
// Remove the package
#if os(Linux)
try run(with: ["remove", "Files"])
#else
try run(with: ["remove", "files"])
#endif
After that I checked the function func removePackage(named name: String, shouldUpdatePackages: Bool = true) throws -> Package
inside PackageManager.swift
and I think that this is the command that throws the exception
let packageFile = try perform(folder.file(named: name),
orThrow: Error.unknownPackageForRemoval(name))
At this point my question is: how folder.file(named: name)
works? Is it inside the Files
package?
Thanks!
In order to make it easier to work with & share scripts that have dependencies, we should add support for pinning a certain version of a package to a script. The Swift Package Manager already supports this feature, but using it in Marathon requires circumventing the global package cache that Marathon uses to speed things up (to not have to re-clone and re-build each package for all scripts).
For example, the user should be able to use version 1.0
of a given package in one script, and then version 2.0
of that same package in another script, and doing this shouldn't affect the global package version.
Currently a Marathonfile
simply consists of newline separated URLs, so we'll need to add a syntax to define what version of a given dependency that should be used. This syntax is proposed:
https://github.com/johnsundell/unbox.git @ 2.2
https://github.com/johnsundell/[email protected]
Note that it shouldn't matter whether spaces are added around the @
character, both should parse correctly.
If the version suffix is omitted the behavior will be the same as today, the version that Marathon currently has in its package cache will be used.
Similarly, we should allow for the same syntax to be used for inline dependency annotations, like this:
import Unbox // marathon:https://github.com/johnsundell/unbox.git @ 2.2
We also need to support pinning a version to a script from the command line. The proposal here is to introduce a pin
command that pins a given version of a package (that needs to already be added to Marathon) to a script at a given path, like this:
$ marathon pin Unbox 2.2 ~/Scripts/MyUnboxScript.swift
We could also allow the script name to be omitted, if the current folder only contains a single script.
Finally, we need a way to "unpin" a version of a package from a script. This only needs command line support, and could either be done by adding a --remove
argument to the pin
command, like this:
$ marathon pin Unbox ~/Scripts/MyUnboxScript.swift --remove
But to be more clear and consistent with our other commands, the proposal is instead to add a dedicated unpin
command:
$ marathon unpin Unbox ~/Scripts/MyUnboxScript.swift
Like with the pin
command, we could allow the script name to be omitted, if the current folder only contains a single script.
Marathon can now install remote scripts ๐ But one limitation is that it needs to be a "raw" Swift file. That is, if you have a file on GitHub, for example:
https://github.com/JohnSundell/Marathon-Examples/blob/master/AddSuffix/addSuffix.swift
You need to pass its "raw" URL:
https://raw.githubusercontent.com/JohnSundell/Marathon-Examples/master/AddSuffix/addSuffix.swift
Since hosting scripts on GitHub is such a common use case, we should make this more convenient.
The suggestion is to support passing the "non-raw" GitHub URL to marathon install
, which Marathon will then expand into its raw counterpart.
Marathon create was failing for me and I couldn't understand why without debugging the project. I discovered that my ssh key was not added as an identify to my ssh-agent so a pull from source was failing.
This error did not appear in-line in the terminal but it would have been useful if it did. The terminal just hanged actually.
The create command calls upon the following at some point:
func edit(arguments: [String], open: Bool) throws {
do {
let path = try editingPath(from: arguments)
if open {
let relativePath = path.replacingOccurrences(of: folder.path, with: "")
printer.output("โ๏ธ Opening \(relativePath)")
try shellOut(to: "open \"\(path)\"", printer: printer)
if path.hasSuffix(".xcodeproj/") {
printer.output("\nโน๏ธ Marathon will keep running, in order to commit any changes you make in Xcode back to the original script file")
printer.output(" Press the return key once you're done")
startCopyLoop()
_ = FileHandle.standardInput.availableData
try copyChangesToSymlinkedFile()
}
}
} catch {
throw Error.editingFailed(name)
}
}
By lifting the try editingPath function out of the do closure, I was able to push the ShellOut error to the surface.
func edit(arguments: [String], open: Bool) throws {
let path = try editingPath(from: arguments)
do {
...
}
}
And capture it here
do {
try Marathon.run()
} catch let error as ShellOutError {
print(error.message)
print(error.output)
} catch {
print("\(error)")
}
The marathon project is great, but this kind of error erasure happens quite a lot. What is your opinion on printing extraneous errors like this ? Do you have a plan for handling extraneous errors?
Thanks
I run marathon list and I could see that I had packages and scripts installed. Running marathon remove was a little more confusing. I'm not 100% sure what marathon remove actually does.
marathon remove helloWorld
-deletes cached data
marathon remove /path/to/helloWorld.swift
-deletes the script file
Is that right ?
I don't understand 'cached data'. What is getting cached exactly ?
I was expected marathon remove to be the inverse of marathon create. Or maybe it requires an option to do a force remove all maybe
marathon remove -a helloWorld
Running
marathon install https://raw.githubusercontent.com/JohnSundell/Playground/master/Sources/Playground.swift
Output:
๐ Downloading script...
Saving script...
Resolving Marathonfile...
Saving Marathonfile...
Updating packages...
๐ฅ Failed to download script from 'https://raw.githubusercontent.com/JohnSundell/Playground/master/Sources/Playground.swift'
๐ Make sure that the URL is reachable, and that it contains a valid Swift script
Output from marathon list
:
โน๏ธ No packages or script data has been added to Marathon yet
Tried the above marathon install
in the following shells: fish
, bash
, zsh
Running curl https://raw.githubusercontent.com/JohnSundell/Playground/master/Sources/Playground.swift
successfully downloads the file
This is an idea @aciidb0mb3r and me have been discussing over Slack, which I think would be really cool to implement.
Currently, Marathon supports defining dependencies for scripts using a Marathonfile
- which works really well for most usecases. However, sometimes you want to distribute a script just as its .swift
file (and not have to include any additional supporting files). This is where inline dependency resolution comes in.
The suggestion is to enable imports
to be annotated with the URL that the imported package can be found as, so that Marathon can analyze the imports, and add any missing packages (just as it does with a Marathonfile
). Like this:
import Files // [email protected]:JohnSundell/Files.git
print(FileSystem().currentFolder.path)
The reason we use comments instead of something fancy (like an @
sign) is because we want every Marathon script to still be 100% valid Swift, so that it can be run both with and without Marathon.
~/Downloads> marathon add [email protected]:kareman/SwiftShell.git
๐ฅ Could not resolve the latest version for package at '[email protected]:kareman/SwiftShell.git'
๐ Make sure that the package you're trying to add is reachable, and has at least one tagged release
I think this may be the reason:
~/Downloads/Marathon> git ls-remote --tags https://github.com/kareman/SwiftShell
c28ab4b7561a0ae9fe1f653da39ae98ed7cec67e refs/tags/2.0.0
d77285c1520f12d03d28b70ae744cb2b1664d838 refs/tags/2.0.0^{}
7310d2af9312ccab679e3debada2472dbcb127c8 refs/tags/2.0.1
97c49c031ae4d26986d6fa03ccd625d4b026cee0 refs/tags/2.0.1^{}
dc3f92f450d5c3b68a974b93268e8fe474e473bd refs/tags/2.0.2
02b93bc4eccf3552f9f860ee2d2ef597dd778810 refs/tags/2.0.2^{}
37319375302935189ffb89410ba826fa8a86fce9 refs/tags/2.1
7b73ae7be0979907fc339a69bb3a21c5af39ffa7 refs/tags/2.1^{}
417eca4f311fef8a97e33e31c9be38c7a31fc5f0 refs/tags/3.0.0-beta.1
ed371b7e639071a026c0a7e0adb7a2a813f5ff40 refs/tags/3.0.0-beta.1^{}
fa70e419dd6c2fce71bfc6e07bb352186240b3b6 refs/tags/3.0.0-beta.10
d9444645784bcd751526e672bb6e8c933ac2c27c refs/tags/3.0.0-beta.11
e69c3859c0940af2a01f6ecdb2d4b18853b424da refs/tags/3.0.0-beta.12
21a385f198bc2af6b0fede532abb045407b0f95a refs/tags/3.0.0-beta.12^{}
f900b101bc2290490cc1d6f6efcecd381bceecad refs/tags/3.0.0-beta.2
2e27a6d776f22568247360da5c38ce37707bfcf2 refs/tags/3.0.0-beta.2^{}
a67516033e224ce809332e7e2f788ef8b354a7f2 refs/tags/3.0.0-beta.3
22dd184b698f74b43565f8cdd7ca0fd1005cfb3b refs/tags/3.0.0-beta.3^{}
cdefffe73984ce2747a4b549b0fafa16f629b66b refs/tags/3.0.0-beta.4
1a24474a32ae8b6cf66a42ce8910abb37da08256 refs/tags/3.0.0-beta.4^{}
97a769521fa04d1f745c2dd48db74a84814a5b0b refs/tags/3.0.0-beta.5
eea3cd2d61a318f82984598029f2b3339c7a7375 refs/tags/3.0.0-beta.5^{}
7aae88446a0ce92a9e68cc82f8fd4dfed5109619 refs/tags/3.0.0-beta.6
25f64feceb5ebf39607e2ffa89f4aa64e1335ca7 refs/tags/3.0.0-beta.6^{}
31786bb0c2c48be727739d4259ec70c18fef56ca refs/tags/3.0.0-beta.7
5dd2da16f097cb014423d8e486bb10e86830011c refs/tags/3.0.0-beta.7^{}
4145afefd85a51beb57490e7d3d94111d8aa800c refs/tags/3.0.0-beta.8
62780a880aaad2c3e12aa1619c48538b24703c7d refs/tags/3.0.0-beta.9
d1e9688039ee208fea546a3ccf143346db1b657a refs/tags/v0.1
9555306183e7a5c84bc342a76c5b5f9a189a2f17 refs/tags/v0.1^{}
70286ffa67f644f483c5ca50671f94473a6c10e5 refs/tags/v0.2
5564eec6c71fbfc7109e3af802f73158626c5dd8 refs/tags/v0.2^{}
27066b8d2785b823872750dcd07cc06532f9f8b6 refs/tags/v1.0
301bc4b29db848b143b18d92f1e77ec7116f1f7f refs/tags/v1.0^{}
a8bf55096283f959b6397a3055e5b8f50d9550c2 refs/tags/v1.1
a7a68866a19eb41e85083a23025a95e19bbd1dc6 refs/tags/v1.1^{}
616eced7bb9e42805038ce67136c7c4c85f20b18 refs/tags/v2.0b1
12fb5b2a5c85fdc3e3ce86b8d9cb8a92a3b0210a refs/tags/v2.0b1^{}
7560b936769387346a8570e42c5a2a7989de1858 refs/tags/v2.0b2
5ac1b5f6909531444d5798a5f6a3fb937e6577fa refs/tags/v2.0b2^{}
Either because the latest version is a beta version (3.0.0-beta.12), or because the first version tags start with 'v' but not the later ones, and Git sorts them alphabetically instead of chronologically for some reason. I had to stop using 'v' to support Swift package manager if I remember correctly.
This is a just suggestion. I'd like to hear your idea:)
How about marathon uninstall <script-path> [<install-path>]
like this?
It just executes rm -f "/usr/local/bin/<lowercased-name-of-script>"
or rm -f "<install-path>/<lowercased-name-of-script>"
.
It successes only if marathon manages the same script name as the binary.
pixyzehn โฎ ~ โฎ marathon help uninstall
๐ป uninstall
----------
Uninstall a script at a given path as a binary
๐ Usage: 'marathon uninstall <script-path> [<install-path>]'
โน๏ธ Marathon will delete the binary only if Marathon manages the same script name as the binary.
In addition, It's very difficult to select uninstall
emoji ๐ค
I used marathon today to build a cool little tool. It was super fun and marathon made it really easy. When it came time to release my tool to the world, I wasn't really sure how to do that. I ended up using the SPM and the SPM install instructions on marathon's readme for install readme. It worked! After I SPN init'ed and some other things. Am I missing something? Is it easier to deploy a marathon script than what I did? Anyhoo, I'd love to help make the instructions more clear or chat about the topic. Thanks again. I love marathon. Great work John and team!
After significant discussion (see below) we've decided to implement this issue as an export
function. Running marathon export {myScript.swift}
will copy myScript.swift
into the following new folder structure:
MyScript/
Sources/
MyScript.swift
Package.swift
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.