What's a Hook?
Hooks let you extend CodeKit to handle any kind of file. You provide a custom command in either Bash or AppleScript, then tell CodeKit which files should trigger that command. Your command becomes another processing step for files of that type.
Adding a Hook
As shown above, open the Project Settings area, then choose the Hooks category. Click the button to add a Hook. Customize the name, choose the type of script your Hook will run (AppleScript or Bash), then define the rules for file-matching.
Use the Rule Editor to tell CodeKit which files should trigger this Hook. The "Path From Disk Root" option refers to a file's full input path, starting at the root of your drive:
Assuming "project" is the folder you've added to CodeKit, then the "Path From Project Root" would be:
All matching operators are case-insensitive and ignore diacritic marks (é and e are the same.)
Wildcards are not supported in any operator other than Matches RegEx. Invalid RegEx will cause your Hook to fail. CodeKit uses ICU V3 RegEx Syntax. RegEx is slower than other matching operators and should be used only as a last resort.
If you use Begins With, keep in mind that input and output paths start with a leading slash. Likewise, if you use the Is operator, you must provide a full, matching string.
If a file triggers more than one Hook, the Hooks are run in top-down order. Drag Hooks up or down in Project Settings to change that order.
If your Hook targets filetypes for which CodeKit has built-in processing, your Hook always runs after CodeKit's built-in steps complete.
Hooks Do Not Run On Copy
Your Hook will only run on files that have their Output Action set to Process/Compile. If the Output Action is set to Copy or Ignore, Hooks do not run. For details, see Setting Output Paths & Actions.
If your Hook targets a type of file that is not one of CodeKit's built-in languages, you should read Adding Custom Languages To CodeKit.
Determining Changed Files
If your Hook is a Bash script, you can use two special environment variables to determine which file triggered the Hook:
- $CK_INPUT_PATH will be the input path of the changed file.
- $CK_OUTPUT_PATH will be the full output path, as specified in CodeKit.
The screenshot above shows these variables in action. In this Hook, handlebars is called to compile the changed file at $CK_INPUT_PATH and it's told to write the output to $CK_OUTPUT_PATH.
NOTE: Trigger Files
The paths in these variables may not be those of the file that was actually saved. For example, if parent.scss imports child.scss and you save child.scss in your editor, CodeKit will compile parent.scss and that's the path you'll find in the environment variables. (Unless you have enabled an output file for child.scss, in which case CodeKit would compile both files and run any matching Hook twice.)
Getting The Project's Root Folder
You can use the environment variable $CK_PROJECT_ROOT to get the project's root folder. (In CodeKit 3.0.5 and above.)
For example, if you've installed custom NPM packages in your project and want to call one of them in a Hook, you might write:
$CK_PROJECT_ROOT/node_modules/myModule doStuff --optionA
Hook output appears in CodeKit's log entry for the affected file, just like output from CodeKit's built-in processing steps.
If your Hook exits with a non-zero code, the entry will be marked as an error and CodeKit will log whatever your Hook writes to StdErr. If your Hook exits with code 0, CodeKit will log whatever it writes to StdOut.
Note: You can also use CodeKit's Scripting API to log something at any time.
Hooks cannot be interactive. That is, your script cannot have prompts that require human input. Additionally, your script must be able to run under the privileges of the current user—sudo is prohibited.
Imagine that you have a shared CodeKit project and an evil co-worker adds this Hook: rm -rf ~/Documents. Your co-worker commits his changes, you pull, and CodeKit syncs the project. Are you about to delete your Documents folder next time you save?
No. CodeKit automatically detects when a Hook's source code has changed since you last saw it. When this happens, you'll see an alert and the app will automatically disable the new/changed Hooks. Once you verify that the source code for each Hook is safe, you can manually re-enable them by checking the box pictured.
That said, there is no safety net to protect you from yourself. CodeKit will run exactly what you tell it to run, every time the criteria you specify are met. So if YOU add the Hook that deletes your Documents folder...I hope you have a backup.
Performance & Stability
Keep Hooks short and simple. Remember that each Hook will be run once for every matching file. Malformed Hooks can crash CodeKit, so be sure to double-check your code.
If your Hook is a Bash script, CodeKit runs it on a background thread. AppleScript Hooks must run on the main thread because AppleScript is not thread-safe. CodeKit's UI may become unresponsive while your Hook completes. CodeKit caches the compiled version of each AppleScript Hook after it runs the first time. Subsequent runs should be significantly faster than the initial one.
WARNING: Hooks Run In Parallel
CodeKit compiles many files at once during builds. This means it's likely that your Hook will run simultaneously on different threads for different files. Write your Hooks with this in mind.
For example, if you create a Hook that always writes to a single file, like ~/Documents/log.txt, that will likely cause problems because five instances of your Hook will be competing for access to that file from five different threads. This may slow down compiling or it may, in the worst case, corrupt data or cause a crash.
Parallel programming is hard. Welcome to my world.