10

My goal is to include in a zip file what amounts to a shortcut, instead of telling my customer(s) to open up Terminal and run a shell script.

My deployable essentially looks like this:

$ unzip Deliverable.zip 
$ cd Deliverable; ls
app.jar run.sh

Script in run.sh:

#!/bin/sh
java -jar app.jar

There's a lot more in the directory; suffice to say I need to run the script from the directory Deliverable since I need to access paths relative to it. However, I can't guarantee where a customer is going to open Deliverable.zip (could be home directory, could be right in the Downloads directory, etc.)

I found this that describes how to create a new workflow in Automator, then save it as an application to launch a shell script. I tried to do that to wrap run.sh but it says it can't find run.sh.

Somebody suggested I use applescript and also sent me a link to how to use applescript to switch into the current directory; there's an applescript "action" in automator; so I made a new workflow with that, and saved it as an application. This is what that looks like:

the automator applescript program

The code:

on run {input, parameters}
    tell application "Finder"
        set current_path to container of (path to me) as alias
    end tell

    do shell script "java -jar app.jar" 

    return input
end run

And this is the error I get when I run it:

welcome to 2015

C'mon, this should be pretty simple. What I am doing wrong here?

  • Well I just posted update with a simpler applescript, but see I was beaten to the punch with an answer that should work better for you by grgarside. :-) – markhunte Aug 22 '15 at 15:56
  • The title of this question does not represent the actual question, so I down voted. The question is more narrow: it's about resolving an issue with the error message "PowerPC applications are no longer supported" and this is what should be in the question title. I am actually looking for the answer to how to create an application bundle. The OP knows how to create a bundle but encountered an error. – Jason Apr 9 '18 at 19:45
4
+100

Rename your .sh file to .command and you can cd to the directory that the .command file is located in with the following at the beginning of the file:

cd "$(dirname $BASH_SOURCE)"
7

I can see a couple of things wrong there.

Firstly you have opened a workflow and not an Application.

You should choose Application when you make your selection for the type of Automator file.

enter image description here

And the code you have will not work as you expect, since you have not changed directory. (cd).

In the code as you have it, all it is doing is getting the path as an alias and storing it in the variable current_path and in a format unsuitable for the unix commands.

But you do not use it.

So the current directory will most likely be your home folder

At this stage there is no telling what it is trying to launch.

If I run it as you have it I get.

enter image description here

Which makes sense since I do not have Java installed. But if I did I would not expect it to find the right file.

The Applescript need to look like this.

on run {input, parameters}
    tell application "Finder"
        set current_path to container of (path to me) as alias
    end tell

    do shell script "cd " & quoted form of (POSIX path of current_path) & " ;ls | open -fe"

    return input
end run 

In my example

do shell script "cd " & quoted form of (POSIX path of current_path) & " ;/bin/ls | /usr/bin/open -fe"

I cd to the POSIX path of the alias in the variable current_path

i.e from "alias "Macintosh HD:Applications:"" to "/Applications/"

The quoted form of escapes the path using quotes.

I have used the /bin/ls command and pipe it to the open in TextEdit stdin as a demonstration here so that you can test to see if you are getting to the area you expect.

You would use something like;

do shell script "cd " & quoted form of (POSIX path of current_path) & " ;\"java -jar app.jar\""

update:

A another way is just use pure Applescript.

on run {input, parameters}
    tell application "Finder"
        set current_path to container of (path to me)

        set theFile to (current_path) as alias

        open file "java -jar app.jar" of theFile
    end tell


end run
  • This is very close to a solution; I confirm the ls | open code definitely opens the directory I want, which is great. But when I call open Client.app, I get: LSOpenURLsWithRole() failed with error -10665 for the file <path-to-Client.app> - a few searches for what this error means suggested a permission issue, I checked and +x flags are set. I also tried this, and that didn't work (with same error). – emptyset Aug 22 '15 at 12:06
  • Note that opening Client.app from Finder (double-click) also results in the same PowerPC error pop-up. – emptyset Aug 22 '15 at 12:07
  • @emptyset I call open Client.app Is this the Automator app. From what I understand in the automator you have the applescript code: do shell script "cd " & quoted form of (POSIX path of current_path) & " ;\"java -jar app.jar\"". So where are you using the open command ? which as far as I understand what you are doing, you do not need to use it. The clients will be using double click on the app and the app will run the java – markhunte Aug 22 '15 at 12:56
  • I tested it both ways: from command line: $ open Client.app and by double-clicking. Your version with invoking ls | open -fe works, but when I change it to java -jar app.jar it's giving me that error. – emptyset Aug 22 '15 at 15:23
  • @emptyset try do shell script "cd " & quoted form of (POSIX path of current_path) & " ; " & quoted form of "java -jar app.jar" – markhunte Aug 22 '15 at 15:27
5

Path to Script

In your AppleScript, you need to change the current working directory (cwd) before issuing the java command. Do this with an AppleScript line like:

do shell script "cd " & quoted form of (POSIX path of file_path) & " && java -jar app.jar"

The && is important. If the cd succeeds, the java command will be launched within the right cwd. If cd fails, the java command will not be run.

Problems you will likely encounter include:

  • escaping the POSIX path passed to cd; users will have oddly named folders and spaces in their paths.
  • the cd may fail; wrap up your AppleScript in a try block to catch some errors and warn the user.

perl

Personally, I would wrap use a short perl script in place of a bash script.

#!/usr/bin/env perl

use strict;
use warnings;
use FindBin qw($Bin); # $Bin is a path to the script's parent folder

`cd "$Bin" && java -jar app.jar`;

There are much better ways to write this perl snippet but this should work.

Automator Application

The best approach is to work through the problems with your Automator approach. @markhunte's answer discusses how to fix the path and create an application. This should get you most of the way.

Also see AppleScript path relative to script location.

appify — create the simplest possible Mac app from a shell script

Alternatively, you can use Thomas Aylott's appify script to bundle your shell script into an OS X application. Mathias Bynen's article walks through how to use the script, how to create simple Mac apps from shell scripts.

#!/bin/bash

if [ "$1" = "-h" -o "$1" = "--help" -o -z "$1" ]; then cat <<EOF
appify v3.0.1 for Mac OS X - http://mths.be/appify
Creates the simplest possible Mac app from a shell script.
Appify takes a shell script as its first argument:
    `basename "$0"` my-script.sh
Note that you cannot rename appified apps. If you want to give your app
a custom name, use the second argument:
    `basename "$0"` my-script.sh "My App"
Copyright (c) Thomas Aylott <http://subtlegradient.com/>
Modified by Mathias Bynens <http://mathiasbynens.be/>
EOF
exit; fi

APPNAME=${2:-$(basename "$1" ".sh")}
DIR="$APPNAME.app/Contents/MacOS"

if [ -a "$APPNAME.app" ]; then
    echo "$PWD/$APPNAME.app already exists :("
    exit 1
fi

mkdir -p "$DIR"
cp "$1" "$DIR/$APPNAME"
chmod +x "$DIR/$APPNAME"

echo "$PWD/$APPNAME.app"

Community contributed improvements to this script are available:

Code Signing

Once you have created your application bundle, it should be code signed. A code signed app will launch without requiring your clients to disable Gatekeeper.

Code sign your application using your Apple Developer ID and the codesign command:

codesign -s <identity> -v <code-path> …

Code signing is a security technology, used in OS X, that allows you to certify that an app was created by you. Once an app is signed, the system can detect any change to the app—whether the change is introduced accidentally or by malicious code.

Learn more about code signing on the Apple Developer site.

  • Thanks for the tip on code signing; I'm looking into that now and testing the appify script! – emptyset Aug 21 '15 at 14:37
  • appify script didn't work; same path issue – emptyset Aug 22 '15 at 11:46
  • @emptyset I have added a path and perl section. It may also be worth separating out the path problem into a new question. If you can fix that, you can use Automator or the appify script. – Graham Miln Aug 22 '15 at 15:08
4

Can you change run.sh to run.command and get the user to double click it?

  • That almost worked! However, it ran the file from the context of the user's home directory (cd ~), which caused it to fail. – emptyset Aug 21 '15 at 14:32
  • 1
    @emptyset Use $BASH_SOURCE, see apple.stackexchange.com/a/201482 – grg Aug 22 '15 at 15:16
4

Use Platypus: "Platypus is an OS X developer tool that creates native Mac applications from interpreted scripts..."

Platypus is an OS X developer tool that creates native Mac applications from interpreted scripts

1

Here is my take on what I understood you are trying to accomplish. The code is long winded on purpose.

All you need to do is copy the code to the Applescript Editor, make any changes you want and save it as an application.

As for the dialog about PowerPC application not supported, I don't know. Can you run it from the command line? I would check that to confirm the app works first.

#
# STEP 1: locate and confirm zip file exists
#
#   This is long winded on purpose. It is meant to save the user some scrolling and 
#   and a click... Isn't this what computers are for to save time? :)
#

# Zip file name 
set zipname to "Deliverable.zip"

# Locate the zip file
set zippath to POSIX path of (choose folder)
log zippath
set qzippath to quoted form of zippath
log qzippath
set zipfile to (zippath & zipname)
set qzipfile to quoted form of (zippath & zipname)
log qzipfile

# Check for the file... Use either test not both :)
try
    # using shell test - case sensetive
    do shell script "test -f " & qzipfile

    # using native test - doesn't like quoted forms and case insensetive...
    POSIX file zipfile as alias
on error
    display dialog "ERROR: Zip file was not found at selected folder." as text ¬
        buttons {"OK"} with icon caution ¬
        with title "Alert"
    return
end try


#
# STEP 2: Zip found. Unzip it
#
try
    # Add " -d Deliverable" at the end to force directory  
    # unzip -o to force overwrite for testing....
    do shell script "cd " & qzippath & "; unzip -o " & zipname
on error eStr
    display dialog "ERROR: Failed to unzip file. Message returned was, " & ¬
        return & return & eStr as text ¬
        buttons {"OK"} with icon caution ¬
        with title "Unzip Error"
    return
end try


#
# STEP 3: Run script 
#
set dpath to (zippath & "Deliverable/")
log dpath
set qdpath to quoted form of dpath
log qdpath
try
    do shell script "cd " & qdpath & ";  sh ./run.sh"
on error eStr
    display dialog "ERROR: Failed to launch script. Message returned was, " & ¬
        return & return & eStr as text ¬
        buttons {"OK"} with icon caution ¬
        with title "Deliverable Script Launch"
    return
end try

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .