mirror of
https://github.com/danielmiessler/Fabric.git
synced 2026-01-09 22:38:10 -05:00
docs: streamline install process with one-line installer scripts and update documentation
- Add markdown file triggers to GitHub workflow - Update VSCode settings with new spell entries - Simplify README installation with one-line installers - Add bash installer script for Unix systems - Add PowerShell installer script for Windows - Create installer documentation with usage examples - Remove redundant pattern from pattern explanations
This commit is contained in:
@@ -11,6 +11,7 @@ on:
|
|||||||
- "cmd/generate_changelog/incoming/*.txt"
|
- "cmd/generate_changelog/incoming/*.txt"
|
||||||
- "scripts/pattern_descriptions/*.json"
|
- "scripts/pattern_descriptions/*.json"
|
||||||
- "web/static/data/pattern_descriptions.json"
|
- "web/static/data/pattern_descriptions.json"
|
||||||
|
- "**/*.md"
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write # Ensure the workflow has write permissions
|
contents: write # Ensure the workflow has write permissions
|
||||||
|
|||||||
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
@@ -162,6 +162,8 @@
|
|||||||
"unconfigured",
|
"unconfigured",
|
||||||
"unmarshalling",
|
"unmarshalling",
|
||||||
"updatepatterns",
|
"updatepatterns",
|
||||||
|
"useb",
|
||||||
|
"USERPROFILE",
|
||||||
"videoid",
|
"videoid",
|
||||||
"webp",
|
"webp",
|
||||||
"WEBVTT",
|
"WEBVTT",
|
||||||
@@ -176,7 +178,12 @@
|
|||||||
"youtu",
|
"youtu",
|
||||||
"YTDLP"
|
"YTDLP"
|
||||||
],
|
],
|
||||||
"cSpell.ignorePaths": ["go.mod", ".gitignore", "CHANGELOG.md"],
|
"cSpell.ignorePaths": [
|
||||||
|
"go.mod",
|
||||||
|
".gitignore",
|
||||||
|
"CHANGELOG.md",
|
||||||
|
"./scripts/installer/install.*"
|
||||||
|
],
|
||||||
"markdownlint.config": {
|
"markdownlint.config": {
|
||||||
"MD004": false,
|
"MD004": false,
|
||||||
"MD011": false,
|
"MD011": false,
|
||||||
|
|||||||
45
README.md
45
README.md
@@ -118,16 +118,12 @@ Keep in mind that many of these were recorded when Fabric was Python-based, so r
|
|||||||
- [Breaking problems into components](#breaking-problems-into-components)
|
- [Breaking problems into components](#breaking-problems-into-components)
|
||||||
- [Too many prompts](#too-many-prompts)
|
- [Too many prompts](#too-many-prompts)
|
||||||
- [Installation](#installation)
|
- [Installation](#installation)
|
||||||
- [Get Latest Release Binaries](#get-latest-release-binaries)
|
- [One-Line Install (Recommended)](#one-line-install-recommended)
|
||||||
- [Windows](#windows)
|
- [Manual Binary Downloads](#manual-binary-downloads)
|
||||||
- [macOS (arm64)](#macos-arm64)
|
|
||||||
- [macOS (amd64)](#macos-amd64)
|
|
||||||
- [Linux (amd64)](#linux-amd64)
|
|
||||||
- [Linux (arm64)](#linux-arm64)
|
|
||||||
- [Using package managers](#using-package-managers)
|
- [Using package managers](#using-package-managers)
|
||||||
- [macOS (Homebrew)](#macos-homebrew)
|
- [macOS (Homebrew)](#macos-homebrew)
|
||||||
- [Arch Linux (AUR)](#arch-linux-aur)
|
- [Arch Linux (AUR)](#arch-linux-aur)
|
||||||
- [Windows](#windows-1)
|
- [Windows](#windows)
|
||||||
- [From Source](#from-source)
|
- [From Source](#from-source)
|
||||||
- [Docker](#docker)
|
- [Docker](#docker)
|
||||||
- [Environment Variables](#environment-variables)
|
- [Environment Variables](#environment-variables)
|
||||||
@@ -206,38 +202,25 @@ Fabric has Patterns for all sorts of life and work activities, including:
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
To install Fabric, you can use the latest release binaries or install it from the source.
|
### One-Line Install (Recommended)
|
||||||
|
|
||||||
### Get Latest Release Binaries
|
**Unix/Linux/macOS:**
|
||||||
|
|
||||||
#### Windows
|
```bash
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.sh | bash
|
||||||
Via PowerShell, just copy and paste and run the following snippet to install the binary into `{HOME}\.local\bin`. Please make sure that directory is included in your `PATH`.
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
$ErrorActionPreference = "Stop"
|
|
||||||
$LATEST="https://github.com/danielmiessler/fabric/releases/latest/download/fabric-windows-amd64.exe"
|
|
||||||
$DIR="${HOME}\.local\bin"
|
|
||||||
New-Item -Path $DIR -ItemType Directory -Force
|
|
||||||
Invoke-WebRequest -URI "${LATEST}" -outfile "${DIR}\fabric.exe"
|
|
||||||
& "${DIR}\fabric.exe" /version
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### macOS (arm64)
|
**Windows PowerShell:**
|
||||||
|
|
||||||
`curl -L https://github.com/danielmiessler/fabric/releases/latest/download/fabric-darwin-arm64 > fabric && chmod +x fabric && ./fabric --version`
|
```powershell
|
||||||
|
iwr -useb https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.ps1 | iex
|
||||||
|
```
|
||||||
|
|
||||||
#### macOS (amd64)
|
> See [scripts/installer/README.md](./scripts/installer/README.md) for custom installation options and troubleshooting.
|
||||||
|
|
||||||
`curl -L https://github.com/danielmiessler/fabric/releases/latest/download/fabric-darwin-amd64 > fabric && chmod +x fabric && ./fabric --version`
|
### Manual Binary Downloads
|
||||||
|
|
||||||
#### Linux (amd64)
|
The latest release binary archives and their expected SHA256 hashes can be found at <https://github.com/danielmiessler/fabric/releases/latest>
|
||||||
|
|
||||||
`curl -L https://github.com/danielmiessler/fabric/releases/latest/download/fabric-linux-amd64 > fabric && chmod +x fabric && ./fabric --version`
|
|
||||||
|
|
||||||
#### Linux (arm64)
|
|
||||||
|
|
||||||
`curl -L https://github.com/danielmiessler/fabric/releases/latest/download/fabric-linux-arm64 > fabric && chmod +x fabric && ./fabric --version`
|
|
||||||
|
|
||||||
### Using package managers
|
### Using package managers
|
||||||
|
|
||||||
|
|||||||
7
cmd/generate_changelog/incoming/1745.txt
Normal file
7
cmd/generate_changelog/incoming/1745.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
### PR [#1745](https://github.com/danielmiessler/Fabric/pull/1745) by [ksylvan](https://github.com/ksylvan): Fabric Installation Improvements and Automated Release Updates
|
||||||
|
|
||||||
|
- Streamlined install process with one-line installer scripts and updated documentation
|
||||||
|
- Added bash installer script for Unix systems
|
||||||
|
- Added PowerShell installer script for Windows
|
||||||
|
- Created installer documentation with usage examples
|
||||||
|
- Simplified README installation with one-line installers
|
||||||
@@ -178,48 +178,47 @@
|
|||||||
174. **refine_design_document**: Refines a design document based on a design review by analyzing, mapping concepts, and implementing changes using valid Markdown.
|
174. **refine_design_document**: Refines a design document based on a design review by analyzing, mapping concepts, and implementing changes using valid Markdown.
|
||||||
175. **review_design**: Reviews and analyzes architecture design, focusing on clarity, component design, system integrations, security, performance, scalability, and data management.
|
175. **review_design**: Reviews and analyzes architecture design, focusing on clarity, component design, system integrations, security, performance, scalability, and data management.
|
||||||
176. **sanitize_broken_html_to_markdown**: Converts messy HTML into clean, properly formatted Markdown, applying custom styling and ensuring compatibility with Vite.
|
176. **sanitize_broken_html_to_markdown**: Converts messy HTML into clean, properly formatted Markdown, applying custom styling and ensuring compatibility with Vite.
|
||||||
177. **show_fabric_options_markmap**: Visualizes the functionality of the Fabric framework by representing its components, commands, and features based on the provided input.
|
177. **solve_with_cot**: Provides detailed, step-by-step responses with chain of thought reasoning, using structured thinking, reflection, and output sections.
|
||||||
178. **solve_with_cot**: Provides detailed, step-by-step responses with chain of thought reasoning, using structured thinking, reflection, and output sections.
|
178. **suggest_pattern**: Suggests appropriate fabric patterns or commands based on user input, providing clear explanations and options for users.
|
||||||
179. **suggest_pattern**: Suggests appropriate fabric patterns or commands based on user input, providing clear explanations and options for users.
|
179. **summarize**: Summarizes content into a 20-word sentence, main points, and takeaways, formatted with numbered lists in Markdown.
|
||||||
180. **summarize**: Summarizes content into a 20-word sentence, main points, and takeaways, formatted with numbered lists in Markdown.
|
180. **summarize_board_meeting**: Creates formal meeting notes from board meeting transcripts for corporate governance documentation.
|
||||||
181. **summarize_board_meeting**: Creates formal meeting notes from board meeting transcripts for corporate governance documentation.
|
181. **summarize_debate**: Summarizes debates, identifies primary disagreement, extracts arguments, and provides analysis of evidence and argument strength to predict outcomes.
|
||||||
182. **summarize_debate**: Summarizes debates, identifies primary disagreement, extracts arguments, and provides analysis of evidence and argument strength to predict outcomes.
|
182. **summarize_git_changes**: Summarizes recent project updates from the last 7 days, focusing on key changes with enthusiasm.
|
||||||
183. **summarize_git_changes**: Summarizes recent project updates from the last 7 days, focusing on key changes with enthusiasm.
|
183. **summarize_git_diff**: Summarizes and organizes Git diff changes with clear, succinct commit messages and bullet points.
|
||||||
184. **summarize_git_diff**: Summarizes and organizes Git diff changes with clear, succinct commit messages and bullet points.
|
184. **summarize_lecture**: Extracts relevant topics, definitions, and tools from lecture transcripts, providing structured summaries with timestamps and key takeaways.
|
||||||
185. **summarize_lecture**: Extracts relevant topics, definitions, and tools from lecture transcripts, providing structured summaries with timestamps and key takeaways.
|
185. **summarize_legislation**: Summarizes complex political proposals and legislation by analyzing key points, proposed changes, and providing balanced, positive, and cynical characterizations.
|
||||||
186. **summarize_legislation**: Summarizes complex political proposals and legislation by analyzing key points, proposed changes, and providing balanced, positive, and cynical characterizations.
|
186. **summarize_meeting**: Analyzes meeting transcripts to extract a structured summary, including an overview, key points, tasks, decisions, challenges, timeline, references, and next steps.
|
||||||
187. **summarize_meeting**: Analyzes meeting transcripts to extract a structured summary, including an overview, key points, tasks, decisions, challenges, timeline, references, and next steps.
|
187. **summarize_micro**: Summarizes content into a 20-word sentence, 3 main points, and 3 takeaways, formatted in clear, concise Markdown.
|
||||||
188. **summarize_micro**: Summarizes content into a 20-word sentence, 3 main points, and 3 takeaways, formatted in clear, concise Markdown.
|
188. **summarize_newsletter**: Extracts the most meaningful, interesting, and useful content from a newsletter, summarizing key sections such as content, opinions, tools, companies, and follow-up items in clear, structured Markdown.
|
||||||
189. **summarize_newsletter**: Extracts the most meaningful, interesting, and useful content from a newsletter, summarizing key sections such as content, opinions, tools, companies, and follow-up items in clear, structured Markdown.
|
189. **summarize_paper**: Summarizes an academic paper by detailing its title, authors, technical approach, distinctive features, experimental setup, results, advantages, limitations, and conclusion in a clear, structured format using human-readable Markdown.
|
||||||
190. **summarize_paper**: Summarizes an academic paper by detailing its title, authors, technical approach, distinctive features, experimental setup, results, advantages, limitations, and conclusion in a clear, structured format using human-readable Markdown.
|
190. **summarize_prompt**: Summarizes AI chat prompts by describing the primary function, unique approach, and expected output in a concise paragraph. The summary is focused on the prompt's purpose without unnecessary details or formatting.
|
||||||
191. **summarize_prompt**: Summarizes AI chat prompts by describing the primary function, unique approach, and expected output in a concise paragraph. The summary is focused on the prompt's purpose without unnecessary details or formatting.
|
191. **summarize_pull-requests**: Summarizes pull requests for a coding project by providing a summary and listing the top PRs with human-readable descriptions.
|
||||||
192. **summarize_pull-requests**: Summarizes pull requests for a coding project by providing a summary and listing the top PRs with human-readable descriptions.
|
192. **summarize_rpg_session**: Summarizes a role-playing game session by extracting key events, combat stats, character changes, quotes, and more.
|
||||||
193. **summarize_rpg_session**: Summarizes a role-playing game session by extracting key events, combat stats, character changes, quotes, and more.
|
193. **t_analyze_challenge_handling**: Provides 8-16 word bullet points evaluating how well challenges are being addressed, calling out any lack of effort.
|
||||||
194. **t_analyze_challenge_handling**: Provides 8-16 word bullet points evaluating how well challenges are being addressed, calling out any lack of effort.
|
194. **t_check_metrics**: Analyzes deep context from the TELOS file and input instruction, then provides a wisdom-based output while considering metrics and KPIs to assess recent improvements.
|
||||||
195. **t_check_metrics**: Analyzes deep context from the TELOS file and input instruction, then provides a wisdom-based output while considering metrics and KPIs to assess recent improvements.
|
195. **t_create_h3_career**: Summarizes context and produces wisdom-based output by deeply analyzing both the TELOS File and the input instruction, considering the relationship between the two.
|
||||||
196. **t_create_h3_career**: Summarizes context and produces wisdom-based output by deeply analyzing both the TELOS File and the input instruction, considering the relationship between the two.
|
196. **t_create_opening_sentences**: Describes from TELOS file the person's identity, goals, and actions in 4 concise, 32-word bullet points, humbly.
|
||||||
197. **t_create_opening_sentences**: Describes from TELOS file the person's identity, goals, and actions in 4 concise, 32-word bullet points, humbly.
|
197. **t_describe_life_outlook**: Describes from TELOS file a person's life outlook in 5 concise, 16-word bullet points.
|
||||||
198. **t_describe_life_outlook**: Describes from TELOS file a person's life outlook in 5 concise, 16-word bullet points.
|
198. **t_extract_intro_sentences**: Summarizes from TELOS file a person's identity, work, and current projects in 5 concise and grounded bullet points.
|
||||||
199. **t_extract_intro_sentences**: Summarizes from TELOS file a person's identity, work, and current projects in 5 concise and grounded bullet points.
|
199. **t_extract_panel_topics**: Creates 5 panel ideas with titles and descriptions based on deep context from a TELOS file and input.
|
||||||
200. **t_extract_panel_topics**: Creates 5 panel ideas with titles and descriptions based on deep context from a TELOS file and input.
|
200. **t_find_blindspots**: Identify potential blindspots in thinking, frames, or models that may expose the individual to error or risk.
|
||||||
201. **t_find_blindspots**: Identify potential blindspots in thinking, frames, or models that may expose the individual to error or risk.
|
201. **t_find_negative_thinking**: Analyze a TELOS file and input to identify negative thinking in documents or journals, followed by tough love encouragement.
|
||||||
202. **t_find_negative_thinking**: Analyze a TELOS file and input to identify negative thinking in documents or journals, followed by tough love encouragement.
|
202. **t_find_neglected_goals**: Analyze a TELOS file and input instructions to identify goals or projects that have not been worked on recently.
|
||||||
203. **t_find_neglected_goals**: Analyze a TELOS file and input instructions to identify goals or projects that have not been worked on recently.
|
203. **t_give_encouragement**: Analyze a TELOS file and input instructions to evaluate progress, provide encouragement, and offer recommendations for continued effort.
|
||||||
204. **t_give_encouragement**: Analyze a TELOS file and input instructions to evaluate progress, provide encouragement, and offer recommendations for continued effort.
|
204. **t_red_team_thinking**: Analyze a TELOS file and input instructions to red-team thinking, models, and frames, then provide recommendations for improvement.
|
||||||
205. **t_red_team_thinking**: Analyze a TELOS file and input instructions to red-team thinking, models, and frames, then provide recommendations for improvement.
|
205. **t_threat_model_plans**: Analyze a TELOS file and input instructions to create threat models for a life plan and recommend improvements.
|
||||||
206. **t_threat_model_plans**: Analyze a TELOS file and input instructions to create threat models for a life plan and recommend improvements.
|
206. **t_visualize_mission_goals_projects**: Analyze a TELOS file and input instructions to create an ASCII art diagram illustrating the relationship of missions, goals, and projects.
|
||||||
207. **t_visualize_mission_goals_projects**: Analyze a TELOS file and input instructions to create an ASCII art diagram illustrating the relationship of missions, goals, and projects.
|
207. **t_year_in_review**: Analyze a TELOS file to create insights about a person or entity, then summarize accomplishments and visualizations in bullet points.
|
||||||
208. **t_year_in_review**: Analyze a TELOS file to create insights about a person or entity, then summarize accomplishments and visualizations in bullet points.
|
208. **to_flashcards**: Create Anki flashcards from a given text, focusing on concise, optimized questions and answers without external context.
|
||||||
209. **to_flashcards**: Create Anki flashcards from a given text, focusing on concise, optimized questions and answers without external context.
|
209. **transcribe_minutes**: Extracts (from meeting transcription) meeting minutes, identifying actionables, insightful ideas, decisions, challenges, and next steps in a structured format.
|
||||||
210. **transcribe_minutes**: Extracts (from meeting transcription) meeting minutes, identifying actionables, insightful ideas, decisions, challenges, and next steps in a structured format.
|
210. **translate**: Translates sentences or documentation into the specified language code while maintaining the original formatting and tone.
|
||||||
211. **translate**: Translates sentences or documentation into the specified language code while maintaining the original formatting and tone.
|
211. **tweet**: Provides a step-by-step guide on crafting engaging tweets with emojis, covering Twitter basics, account creation, features, and audience targeting.
|
||||||
212. **tweet**: Provides a step-by-step guide on crafting engaging tweets with emojis, covering Twitter basics, account creation, features, and audience targeting.
|
212. **write_essay**: Writes essays in the style of a specified author, embodying their unique voice, vocabulary, and approach. Uses `author_name` variable.
|
||||||
213. **write_essay**: Writes essays in the style of a specified author, embodying their unique voice, vocabulary, and approach. Uses `author_name` variable.
|
213. **write_essay_pg**: Writes concise, clear essays in the style of Paul Graham, focusing on simplicity, clarity, and illumination of the provided topic.
|
||||||
214. **write_essay_pg**: Writes concise, clear essays in the style of Paul Graham, focusing on simplicity, clarity, and illumination of the provided topic.
|
214. **write_hackerone_report**: Generates concise, clear, and reproducible bug bounty reports, detailing vulnerability impact, steps to reproduce, and exploit details for triagers.
|
||||||
215. **write_hackerone_report**: Generates concise, clear, and reproducible bug bounty reports, detailing vulnerability impact, steps to reproduce, and exploit details for triagers.
|
215. **write_latex**: Generates syntactically correct LaTeX code for a new.tex document, ensuring proper formatting and compatibility with pdflatex.
|
||||||
216. **write_latex**: Generates syntactically correct LaTeX code for a new.tex document, ensuring proper formatting and compatibility with pdflatex.
|
216. **write_micro_essay**: Writes concise, clear, and illuminating essays on the given topic in the style of Paul Graham.
|
||||||
217. **write_micro_essay**: Writes concise, clear, and illuminating essays on the given topic in the style of Paul Graham.
|
217. **write_nuclei_template_rule**: Generates Nuclei YAML templates for detecting vulnerabilities using HTTP requests, matchers, extractors, and dynamic data extraction.
|
||||||
218. **write_nuclei_template_rule**: Generates Nuclei YAML templates for detecting vulnerabilities using HTTP requests, matchers, extractors, and dynamic data extraction.
|
218. **write_pull-request**: Drafts detailed pull request descriptions, explaining changes, providing reasoning, and identifying potential bugs from the git diff command output.
|
||||||
219. **write_pull-request**: Drafts detailed pull request descriptions, explaining changes, providing reasoning, and identifying potential bugs from the git diff command output.
|
219. **write_semgrep_rule**: Creates accurate and working Semgrep rules based on input, following syntax guidelines and specific language considerations.
|
||||||
220. **write_semgrep_rule**: Creates accurate and working Semgrep rules based on input, following syntax guidelines and specific language considerations.
|
220. **youtube_summary**: Create concise, timestamped Youtube video summaries that highlight key points.
|
||||||
221. **youtube_summary**: Create concise, timestamped Youtube video summaries that highlight key points.
|
|
||||||
|
|||||||
114
scripts/installer/README.md
Normal file
114
scripts/installer/README.md
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
# Fabric One-Line Installer
|
||||||
|
|
||||||
|
This directory contains the official one-line installer scripts for Fabric.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Unix/Linux/macOS
|
||||||
|
|
||||||
|
Install Fabric with a single command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.sh | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows (PowerShell)
|
||||||
|
|
||||||
|
Install Fabric with a single PowerShell command:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
iwr -useb https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.ps1 | iex
|
||||||
|
```
|
||||||
|
|
||||||
|
## Custom Installation Directory
|
||||||
|
|
||||||
|
### Unix/Linux/macOS
|
||||||
|
|
||||||
|
By default, Fabric is installed to `~/.local/bin`. To install elsewhere:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.sh | INSTALL_DIR=/usr/local/bin bash
|
||||||
|
```
|
||||||
|
|
||||||
|
For system-wide installation (requires sudo):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.sh | sudo INSTALL_DIR=/usr/local/bin bash
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows (PowerShell)
|
||||||
|
|
||||||
|
By default, Fabric is installed to `%USERPROFILE%\.local\bin`. To install elsewhere:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$env:INSTALL_DIR="C:\tools"; iwr -useb https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.ps1 | iex
|
||||||
|
```
|
||||||
|
|
||||||
|
## Supported Systems
|
||||||
|
|
||||||
|
- **Operating Systems**: Darwin (macOS), Linux, Windows
|
||||||
|
- **Architectures**: x86_64, arm64, i386 (Windows only)
|
||||||
|
|
||||||
|
## What It Does
|
||||||
|
|
||||||
|
1. **Detects** your OS and architecture automatically
|
||||||
|
2. **Downloads** the latest Fabric release from GitHub
|
||||||
|
3. **Extracts** only the `fabric` binary (not the full archive)
|
||||||
|
4. **Installs** to your chosen directory (default: `~/.local/bin`)
|
||||||
|
5. **Verifies** the installation works correctly
|
||||||
|
6. **Provides** PATH setup instructions if needed
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- ✅ **Cross-platform** - Unix/Linux/macOS (bash) and Windows (PowerShell)
|
||||||
|
- ✅ **Zero dependencies** - No additional tools required
|
||||||
|
- ✅ **Automatic detection** - OS and architecture
|
||||||
|
- ✅ **Smart extraction** - Only the binary, not extra files
|
||||||
|
- ✅ **Error handling** - Clear messages and graceful failures
|
||||||
|
- ✅ **PATH guidance** - Helps you set up your environment
|
||||||
|
- ✅ **Verification** - Tests the installation before completing
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
### Unix/Linux/macOS
|
||||||
|
|
||||||
|
- `curl` or `wget` for downloading
|
||||||
|
- `tar` for extraction (standard on all Unix systems)
|
||||||
|
- Write permissions to the installation directory
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
- PowerShell (built into Windows)
|
||||||
|
- Write permissions to the installation directory
|
||||||
|
|
||||||
|
## After Installation
|
||||||
|
|
||||||
|
1. **Configure Fabric**: Run `fabric --setup`
|
||||||
|
2. **Add API keys**: Follow the setup prompts
|
||||||
|
3. **Start using**: Try `fabric --help` or `fabric --listpatterns`
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
**Permission denied?**
|
||||||
|
|
||||||
|
- Try with `sudo` for system directories
|
||||||
|
- Or choose a directory you can write to: `INSTALL_DIR=~/bin`
|
||||||
|
|
||||||
|
**Binary not found after install?**
|
||||||
|
|
||||||
|
- Add the install directory to your PATH
|
||||||
|
- The installer provides specific instructions for your shell
|
||||||
|
|
||||||
|
**Download fails?**
|
||||||
|
|
||||||
|
- Check your internet connection
|
||||||
|
- Verify GitHub is accessible from your network
|
||||||
|
|
||||||
|
## Alternative Installation Methods
|
||||||
|
|
||||||
|
If the one-liner doesn't work for you, see the main [Installation Guide](../../README.md#installation) for:
|
||||||
|
|
||||||
|
- Binary downloads
|
||||||
|
- Package managers (Homebrew, winget, AUR)
|
||||||
|
- Docker images
|
||||||
|
- Building from source
|
||||||
253
scripts/installer/install.ps1
Normal file
253
scripts/installer/install.ps1
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
# Fabric Windows Installer Script
|
||||||
|
# Usage: iwr -useb https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.ps1 | iex
|
||||||
|
# Usage with custom directory: $env:INSTALL_DIR="C:\tools"; iwr -useb https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.ps1 | iex
|
||||||
|
|
||||||
|
param(
|
||||||
|
[string]$InstallDir = $env:INSTALL_DIR
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
# Colors for output (Windows Console colors)
|
||||||
|
$Colors = @{
|
||||||
|
Red = "Red"
|
||||||
|
Green = "Green"
|
||||||
|
Yellow = "Yellow"
|
||||||
|
Blue = "Cyan"
|
||||||
|
White = "White"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Print functions
|
||||||
|
function Write-Info {
|
||||||
|
param([string]$Message)
|
||||||
|
Write-Host "[INFO] $Message" -ForegroundColor $Colors.Blue
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-Success {
|
||||||
|
param([string]$Message)
|
||||||
|
Write-Host "[SUCCESS] $Message" -ForegroundColor $Colors.Green
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-Warning {
|
||||||
|
param([string]$Message)
|
||||||
|
Write-Host "[WARNING] $Message" -ForegroundColor $Colors.Yellow
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-Error {
|
||||||
|
param([string]$Message)
|
||||||
|
Write-Host "[ERROR] $Message" -ForegroundColor $Colors.Red
|
||||||
|
}
|
||||||
|
|
||||||
|
# Detect Windows architecture
|
||||||
|
function Get-Architecture {
|
||||||
|
$arch = $env:PROCESSOR_ARCHITECTURE
|
||||||
|
$archAMD64 = $env:PROCESSOR_ARCHITEW6432
|
||||||
|
|
||||||
|
# Check for ARM64
|
||||||
|
if ($arch -eq "ARM64") {
|
||||||
|
return "arm64"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check for x86_64/AMD64
|
||||||
|
if ($arch -eq "AMD64" -or $archAMD64 -eq "AMD64") {
|
||||||
|
return "x86_64"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check for x86 (32-bit)
|
||||||
|
if ($arch -eq "X86") {
|
||||||
|
return "i386"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Error "Unsupported architecture: $arch"
|
||||||
|
Write-Error "This installer supports x86_64, i386, and arm64"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Test if running with appropriate permissions for directory
|
||||||
|
function Test-WritePermission {
|
||||||
|
param([string]$Path)
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!(Test-Path $Path)) {
|
||||||
|
New-Item -Path $Path -ItemType Directory -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
$testFile = Join-Path $Path "fabric_write_test.tmp"
|
||||||
|
"test" | Out-File -FilePath $testFile -Force
|
||||||
|
Remove-Item $testFile -Force
|
||||||
|
return $true
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Download and install Fabric
|
||||||
|
function Install-Fabric {
|
||||||
|
param(
|
||||||
|
[string]$Architecture,
|
||||||
|
[string]$InstallDirectory
|
||||||
|
)
|
||||||
|
|
||||||
|
# Construct download URL
|
||||||
|
$filename = "fabric_Windows_$Architecture.zip"
|
||||||
|
$downloadUrl = "https://github.com/danielmiessler/fabric/releases/latest/download/$filename"
|
||||||
|
|
||||||
|
Write-Info "Downloading Fabric for Windows $Architecture..."
|
||||||
|
Write-Info "URL: $downloadUrl"
|
||||||
|
|
||||||
|
# Create temporary directory
|
||||||
|
$tempDir = Join-Path $env:TEMP "fabric_install_$(Get-Random)"
|
||||||
|
New-Item -Path $tempDir -ItemType Directory -Force | Out-Null
|
||||||
|
$tempFile = Join-Path $tempDir "fabric.zip"
|
||||||
|
|
||||||
|
try {
|
||||||
|
# Download the archive
|
||||||
|
Write-Info "Downloading archive..."
|
||||||
|
Invoke-WebRequest -Uri $downloadUrl -OutFile $tempFile -UseBasicParsing
|
||||||
|
|
||||||
|
Write-Info "Extracting Fabric binary..."
|
||||||
|
|
||||||
|
# Extract the zip file
|
||||||
|
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||||
|
$zip = [System.IO.Compression.ZipFile]::OpenRead($tempFile)
|
||||||
|
|
||||||
|
# Find and extract only fabric.exe
|
||||||
|
$fabricEntry = $zip.Entries | Where-Object { $_.Name -eq "fabric.exe" }
|
||||||
|
if (!$fabricEntry) {
|
||||||
|
Write-Error "fabric.exe not found in the downloaded archive"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create install directory if it doesn't exist
|
||||||
|
if (!(Test-Path $InstallDirectory)) {
|
||||||
|
Write-Info "Creating install directory: $InstallDirectory"
|
||||||
|
New-Item -Path $InstallDirectory -ItemType Directory -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extract fabric.exe to install directory
|
||||||
|
$fabricPath = Join-Path $InstallDirectory "fabric.exe"
|
||||||
|
Write-Info "Installing Fabric to $fabricPath..."
|
||||||
|
|
||||||
|
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($fabricEntry, $fabricPath, $true)
|
||||||
|
$zip.Dispose()
|
||||||
|
|
||||||
|
Write-Success "Fabric installed successfully to $fabricPath"
|
||||||
|
return $fabricPath
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Error "Failed to download or extract Fabric: $($_.Exception.Message)"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
# Clean up
|
||||||
|
if (Test-Path $tempDir) {
|
||||||
|
Remove-Item $tempDir -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if directory is in PATH
|
||||||
|
function Test-InPath {
|
||||||
|
param([string]$Directory)
|
||||||
|
|
||||||
|
$pathDirs = $env:PATH -split ';'
|
||||||
|
return $pathDirs -contains $Directory
|
||||||
|
}
|
||||||
|
|
||||||
|
# Provide PATH setup instructions
|
||||||
|
function Show-PathInstructions {
|
||||||
|
param([string]$InstallDir)
|
||||||
|
|
||||||
|
if (Test-InPath $InstallDir) {
|
||||||
|
Write-Success "✅ $InstallDir is already in your PATH"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Warning "⚠️ $InstallDir is not in your PATH"
|
||||||
|
Write-Info "To use fabric from anywhere, you have a few options:"
|
||||||
|
Write-Info ""
|
||||||
|
Write-Info "Option 1 - Add to PATH for current user (recommended):"
|
||||||
|
Write-Info " `$currentPath = [Environment]::GetEnvironmentVariable('PATH', 'User')"
|
||||||
|
Write-Info " [Environment]::SetEnvironmentVariable('PATH', `"`$currentPath;$InstallDir`", 'User')"
|
||||||
|
Write-Info ""
|
||||||
|
Write-Info "Option 2 - Add to PATH for all users (requires admin):"
|
||||||
|
Write-Info " `$currentPath = [Environment]::GetEnvironmentVariable('PATH', 'Machine')"
|
||||||
|
Write-Info " [Environment]::SetEnvironmentVariable('PATH', `"`$currentPath;$InstallDir`", 'Machine')"
|
||||||
|
Write-Info ""
|
||||||
|
Write-Info "Option 3 - Add to current session only:"
|
||||||
|
Write-Info " `$env:PATH += `";$InstallDir`""
|
||||||
|
Write-Info ""
|
||||||
|
Write-Info "After updating PATH, restart your terminal or run: refreshenv"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Verify installation
|
||||||
|
function Test-Installation {
|
||||||
|
param([string]$FabricPath)
|
||||||
|
|
||||||
|
if (Test-Path $FabricPath) {
|
||||||
|
Write-Info "Verifying installation..."
|
||||||
|
try {
|
||||||
|
$version = & $FabricPath --version 2>$null
|
||||||
|
if ($LASTEXITCODE -eq 0) {
|
||||||
|
Write-Success "Fabric $version is working correctly!"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Warning "Fabric binary exists but --version failed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Warning "Fabric binary exists but could not run --version"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Error "Fabric binary not found at $FabricPath"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main installation function
|
||||||
|
function Main {
|
||||||
|
Write-Info "🚀 Starting Fabric installation..."
|
||||||
|
|
||||||
|
# Detect architecture
|
||||||
|
$arch = Get-Architecture
|
||||||
|
Write-Info "Detected architecture: $arch"
|
||||||
|
|
||||||
|
# Determine install directory
|
||||||
|
if (!$InstallDir) {
|
||||||
|
$InstallDir = Join-Path $env:USERPROFILE ".local\bin"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Info "Install directory: $InstallDir"
|
||||||
|
|
||||||
|
# Check permissions
|
||||||
|
if (!(Test-WritePermission $InstallDir)) {
|
||||||
|
Write-Error "Cannot write to $InstallDir"
|
||||||
|
Write-Error "Try running as Administrator or choose a different directory"
|
||||||
|
Write-Info "Example with custom directory: `$env:INSTALL_DIR=`"C:\tools`"; iwr -useb ... | iex"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install Fabric
|
||||||
|
$fabricPath = Install-Fabric -Architecture $arch -InstallDirectory $InstallDir
|
||||||
|
|
||||||
|
# Verify installation
|
||||||
|
Test-Installation -FabricPath $fabricPath
|
||||||
|
|
||||||
|
# Check PATH and provide instructions
|
||||||
|
Show-PathInstructions -InstallDir $InstallDir
|
||||||
|
|
||||||
|
Write-Info ""
|
||||||
|
Write-Success "🎉 Installation complete!"
|
||||||
|
Write-Info ""
|
||||||
|
Write-Info "Next steps:"
|
||||||
|
Write-Info " 1. Run 'fabric --setup' to configure Fabric"
|
||||||
|
Write-Info " 2. Add your API keys and preferences"
|
||||||
|
Write-Info " 3. Start using Fabric with 'fabric --help'"
|
||||||
|
Write-Info ""
|
||||||
|
Write-Info "Documentation: https://github.com/danielmiessler/fabric"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run main function
|
||||||
|
Main
|
||||||
219
scripts/installer/install.sh
Executable file
219
scripts/installer/install.sh
Executable file
@@ -0,0 +1,219 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Fabric Installer Script
|
||||||
|
# Usage: curl -fsSL https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.sh | bash
|
||||||
|
# Usage with custom directory: curl -fsSL https://raw.githubusercontent.com/danielmiessler/fabric/main/scripts/installer/install.sh | INSTALL_DIR=/usr/local/bin bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Print functions
|
||||||
|
print_info() {
|
||||||
|
printf "${BLUE}[INFO]${NC} %s\n" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_success() {
|
||||||
|
printf "${GREEN}[SUCCESS]${NC} %s\n" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warning() {
|
||||||
|
printf "${YELLOW}[WARNING]${NC} %s\n" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error() {
|
||||||
|
printf "${RED}[ERROR]${NC} %s\n" "$1" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
# Detect OS
|
||||||
|
detect_os() {
|
||||||
|
case "$(uname -s)" in
|
||||||
|
Darwin*)
|
||||||
|
echo "Darwin"
|
||||||
|
;;
|
||||||
|
Linux*)
|
||||||
|
echo "Linux"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
print_error "Unsupported operating system: $(uname -s)"
|
||||||
|
print_error "This installer only supports Darwin (macOS) and Linux"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Detect architecture
|
||||||
|
detect_arch() {
|
||||||
|
case "$(uname -m)" in
|
||||||
|
x86_64|amd64)
|
||||||
|
echo "x86_64"
|
||||||
|
;;
|
||||||
|
arm64|aarch64)
|
||||||
|
echo "arm64"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
print_error "Unsupported architecture: $(uname -m)"
|
||||||
|
print_error "This installer only supports x86_64 and arm64"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if command exists
|
||||||
|
command_exists() {
|
||||||
|
command -v "$1" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Download and extract fabric
|
||||||
|
install_fabric() {
|
||||||
|
local os="$1"
|
||||||
|
local arch="$2"
|
||||||
|
local install_dir="$3"
|
||||||
|
|
||||||
|
# Construct download URL
|
||||||
|
local filename="fabric_${os}_${arch}.tar.gz"
|
||||||
|
local download_url="https://github.com/danielmiessler/fabric/releases/latest/download/${filename}"
|
||||||
|
|
||||||
|
print_info "Downloading Fabric for ${os} ${arch}..."
|
||||||
|
print_info "URL: ${download_url}"
|
||||||
|
|
||||||
|
# Create temporary directory
|
||||||
|
local temp_dir
|
||||||
|
temp_dir=$(mktemp -d)
|
||||||
|
local temp_file="${temp_dir}/fabric.tar.gz"
|
||||||
|
|
||||||
|
# Download the archive
|
||||||
|
if command_exists curl; then
|
||||||
|
if ! curl -fsSL "${download_url}" -o "${temp_file}"; then
|
||||||
|
print_error "Failed to download Fabric"
|
||||||
|
rm -rf "${temp_dir}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
elif command_exists wget; then
|
||||||
|
if ! wget -q "${download_url}" -O "${temp_file}"; then
|
||||||
|
print_error "Failed to download Fabric"
|
||||||
|
rm -rf "${temp_dir}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_error "Neither curl nor wget found. Please install one of them and try again."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_info "Extracting Fabric binary..."
|
||||||
|
|
||||||
|
# Extract only the fabric binary from the archive
|
||||||
|
if ! tar -xzf "${temp_file}" -C "${temp_dir}" fabric; then
|
||||||
|
print_error "Failed to extract Fabric binary"
|
||||||
|
rm -rf "${temp_dir}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create install directory if it doesn't exist
|
||||||
|
if [ ! -d "${install_dir}" ]; then
|
||||||
|
print_info "Creating install directory: ${install_dir}"
|
||||||
|
if ! mkdir -p "${install_dir}"; then
|
||||||
|
print_error "Failed to create install directory: ${install_dir}"
|
||||||
|
print_error "You may need to run with sudo or choose a different directory"
|
||||||
|
rm -rf "${temp_dir}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Move binary to install directory
|
||||||
|
print_info "Installing Fabric to ${install_dir}/fabric..."
|
||||||
|
if ! mv "${temp_dir}/fabric" "${install_dir}/fabric"; then
|
||||||
|
print_error "Failed to install Fabric to ${install_dir}"
|
||||||
|
print_error "You may need to run with sudo or choose a different directory"
|
||||||
|
rm -rf "${temp_dir}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Make sure it's executable
|
||||||
|
chmod +x "${install_dir}/fabric"
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf "${temp_dir}"
|
||||||
|
|
||||||
|
print_success "Fabric installed successfully to ${install_dir}/fabric"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check PATH and provide instructions
|
||||||
|
check_path() {
|
||||||
|
local install_dir="$1"
|
||||||
|
|
||||||
|
if echo "$PATH" | grep -q "${install_dir}"; then
|
||||||
|
print_success "✅ ${install_dir} is already in your PATH"
|
||||||
|
else
|
||||||
|
print_warning "⚠️ ${install_dir} is not in your PATH"
|
||||||
|
print_info "To use fabric from anywhere, add the following to your shell profile:"
|
||||||
|
print_info " export PATH=\"\$PATH:${install_dir}\""
|
||||||
|
print_info ""
|
||||||
|
print_info "For bash, add it to ~/.bashrc or ~/.bash_profile"
|
||||||
|
print_info "For zsh, add it to ~/.zshrc"
|
||||||
|
print_info "For fish, run: fish_add_path ${install_dir}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Verify installation
|
||||||
|
verify_installation() {
|
||||||
|
local install_dir="$1"
|
||||||
|
local fabric_path="${install_dir}/fabric"
|
||||||
|
|
||||||
|
if [ -x "${fabric_path}" ]; then
|
||||||
|
print_info "Verifying installation..."
|
||||||
|
local version
|
||||||
|
if version=$("${fabric_path}" --version 2>/dev/null); then
|
||||||
|
print_success "Fabric ${version} is working correctly!"
|
||||||
|
else
|
||||||
|
print_warning "Fabric binary exists but --version failed"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_error "Fabric binary not found at ${fabric_path}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main installation function
|
||||||
|
main() {
|
||||||
|
print_info "🚀 Starting Fabric installation..."
|
||||||
|
|
||||||
|
# Detect system
|
||||||
|
local os
|
||||||
|
local arch
|
||||||
|
os=$(detect_os)
|
||||||
|
arch=$(detect_arch)
|
||||||
|
|
||||||
|
print_info "Detected system: ${os} ${arch}"
|
||||||
|
|
||||||
|
# Determine install directory
|
||||||
|
local install_dir="${INSTALL_DIR:-${HOME}/.local/bin}"
|
||||||
|
|
||||||
|
print_info "Install directory: ${install_dir}"
|
||||||
|
|
||||||
|
# Install fabric
|
||||||
|
install_fabric "${os}" "${arch}" "${install_dir}"
|
||||||
|
|
||||||
|
# Verify installation
|
||||||
|
verify_installation "${install_dir}"
|
||||||
|
|
||||||
|
# Check PATH
|
||||||
|
check_path "${install_dir}"
|
||||||
|
|
||||||
|
print_info ""
|
||||||
|
print_success "🎉 Installation complete!"
|
||||||
|
print_info ""
|
||||||
|
print_info "Next steps:"
|
||||||
|
print_info " 1. Run 'fabric --setup' to configure Fabric"
|
||||||
|
print_info " 2. Add your API keys and preferences"
|
||||||
|
print_info " 3. Start using Fabric with 'fabric --help'"
|
||||||
|
print_info ""
|
||||||
|
print_info "Documentation: https://github.com/danielmiessler/fabric"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run main function
|
||||||
|
main "$@"
|
||||||
Reference in New Issue
Block a user