Skip to content

Commit

Permalink
Improved CLI and docs to explaoin graphviz dependency, bumped version
Browse files Browse the repository at this point in the history
  • Loading branch information
beveradb committed Mar 6, 2024
1 parent 2e17d5b commit ff81b27
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 32 deletions.
54 changes: 37 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,21 @@ logo-diagram-generator -c examples/full.example.yml -o examples -n full.example
pip install logo-diagram-generator
```

2. **Prepare Your Configuration**
2. **Install Graphviz**

Create a `config.yml` file based on the provided `config.yml.example`. This file should list all the tools in your ecosystem, categorized appropriately. For example:
This tool uses [Graphviz](https://graphviz.org/) to render the graph, so you need the graphviz binaries installed on your system for this to work.

Depending whether you're installing in a conda environment, or directly on your Mac or Linux system, one of these commands should be what you need:
- conda install graphviz
- brew install graphviz
- sudo apt-get install graphviz
3. **Prepare Your Configuration**
Create a `config.yml` file for your own diagram by copying one of the provided examples. `examples/minimal.example.yml` is a simple one to start with.
Edit your config file to list all the tools in your ecosystem, with category groupings as you see fit. The minimum viable config would be one central tool and one group:
```yaml
ecosystem:
Expand All @@ -40,33 +52,41 @@ logo-diagram-generator -c examples/full.example.yml -o examples -n full.example
- name: Rancher
```
If a tool has a different alias on VectorLogoZone or you want to download a logo from a specific URL, set the `alias` or `svgURL` value in the config respectively.

See `config.yml.example` for more configuration examples!
See `examples/full.example.yml` for more configuration examples - these become more relevant when you need to tweak the styles or layout of the diagram after your first run.
3. **Download Logos and Generate Diagram**
4. **Download Logos and Generate Diagram**
With your configuration ready, use the `logo-diagram-generator` CLI to download logos and generate your ecosystem diagram:
With your configuration ready, run the `logo-diagram-generator` CLI in the same directory as your `config.yml` file, and it will download logos (with interactive input if it isn't able to find one on the first try) and generate your ecosystem diagram:

```bash
logo-diagram-generator download-logos -c config.yml
logo-diagram-generator generate -c config.yml
logo-diagram-generator
```

This will download the necessary logos and produce an SVG file named `diagram_logos.svg` in your current directory.

Both commands offer customization options for paths and output names, use `--help` to see all available CLI parameters.
For further customization options for paths and output names, use `--help` to see all available CLI parameters:

```bash
usage: logo-diagram-generator [-h] [-d] [--log_level LOG_LEVEL] [-n NAME] [-c CONFIG] [-l LOGOS_DIR] [-s SKIP_DOWNLOAD] [-o OUTPUT_DIR]
Generate SVG diagrams of a tech ecosystem, using logos from each tool organised into groups around a central logo.
options:
-h, --help show this help message and exit
-d, --debug enable debug logging, equivalent to --log_level=debug
--log_level LOG_LEVEL log level, e.g. info, debug, warning (default: info)
-n NAME, --name NAME Base name for the output SVG files.
-c CONFIG, --config CONFIG Path to the configuration file.
-l LOGOS_DIR, --logos_dir LOGOS_DIR Directory where logos are stored.
-s SKIP_DOWNLOAD, --skip_download SKIP_DOWNLOAD Skip downloading logos before generating.
-o OUTPUT_DIR, --output_dir OUTPUT_DIR Directory for the output SVG diagram.
```

## Customizing Your Diagram

- **Configuration File**: Modify `config.yml` to add, remove, or categorize tools as needed. Each tool can have a `name`, `label`, and optionally an `alias` or `svgURL` for custom logo URLs.
- **Logo Download**: If the automatic logo download doesn't find a logo for a tool, you can manually place an SVG file in the `logos` directory. The file name should match the tool's name in the configuration file.
- **Diagram Appearance**: The appearance of the generated diagram can be customized by modifying the `config.yml` file or by using different CLI options.

## Troubleshooting

- **Missing Logos**: Ensure all tools in your `config.yml` have either a valid `svgURL` or a corresponding SVG file in the `logos` directory.
- **CLI Errors**: Check the output of the CLI commands for any error messages. Most issues can be resolved by ensuring the configuration file is correctly formatted and all dependencies are installed.
- **Logo Download**: If the automatic logo download doesn't find a logo for a tool, you can specify the URL interactively or manually place an SVG file in the `logos` directory. The file name should match the tool's name in the configuration file, in lowercase.
- **Diagram Appearance**: The appearance of the generated diagram can be customized by modifying the `config.yml` file. See the example configs and Graphviz documentation for more info.

## Contributing

Expand Down
1 change: 1 addition & 0 deletions examples/full.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ ecosystem:
- alias: istioio
label: Istio
name: Istio
positionAdjustX: 20
- alias: corednsio
label: CoreDNS
name: CoreDNS
Expand Down
17 changes: 13 additions & 4 deletions logo_diagram_generator/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,32 @@

def main():
parser = argparse.ArgumentParser(
description="Generate SVG diagrams of a tech ecosystem, using logos from each tool organised into groups around a central logo."
description="Generate SVG diagrams of a tech ecosystem, using logos from each tool organised into groups around a central logo.",
formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, max_help_position=80),
)
parser.add_argument("-d", "--debug", action="store_true", help="enable debug logging, equivalent to --log_level=debug")
parser.add_argument("--log_level", default="info", help="log level, e.g. info, debug, warning (default: %(default)s)")

parser.add_argument("-n", "--name", default="diagram", help="Base name for the output SVG files.")
parser.add_argument("-c", "--config", default="config.yml", help="Path to the configuration file.")
parser.add_argument("-l", "--logos_dir", default="logos", help="Directory where logos are stored.")
parser.add_argument("-d", "--skip_download", default=False, help="Skip downloading logos before generating.")
parser.add_argument("-s", "--skip_download", default=False, help="Skip downloading logos before generating.")
parser.add_argument(
"-o",
"--output_dir",
default=os.getcwd(),
help="Directory for the output SVG diagram.",
)

logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s")

args = parser.parse_args()

if args.debug:
log_level = logging.DEBUG
else:
log_level = getattr(logging, args.log_level.upper())

logging.basicConfig(format="%(asctime)s.%(msecs)03d - %(levelname)s - %(module)s - %(message)s", datefmt="%Y-%m-%d %H:%M:%S", level=log_level)

logging.info(f"Checking logos directory exists: {args.logos_dir}")
utils.ensure_directory_exists(args.logos_dir)

Expand Down
17 changes: 7 additions & 10 deletions logo_diagram_generator/generate_diagram.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ def embed_logos_in_diagram(diagram_name, diagram_svg_path, output_svg_path, conf
diagram_graph_node = find_svg_element_by_id(diagram_svg_dom.documentElement, diagram_name)

if tool_node is not None:
logging.debug(f"Found node in diagram for tool: {tool_label}")
logging.info(f"Found node in diagram for tool: {tool_label}, processing and embedding logo SVG")

ellipse_node = tool_node.getElementsByTagName("ellipse")[0]
cx = ellipse_node.getAttribute("cx")
Expand All @@ -171,34 +171,31 @@ def embed_logos_in_diagram(diagram_name, diagram_svg_path, output_svg_path, conf
with open(logo_svg_path, "r") as file:
logo_svg_content = file.read()

logging.debug(f"Performing find/replace to add {tool_name_slug}- prefix to generic classes, IDs, and hrefs")
class_search_1 = re.search(r'class="st\d+"', logo_svg_content)
if class_search_1:
logging.warning(f"Found class attribute {class_search_1.group()} in tool SVG: {tool_label}")

logging.debug(f"Adding {tool_name_slug}- prefix to any usages of generic class name")
logging.debug(f"Adding {tool_name_slug}- prefix to generic class {class_search_1.group()}")
logo_svg_content = re.sub(r"(st\d+)", f"{tool_name_slug}-\\1", logo_svg_content)

class_search_2 = re.search(r'class="cls-\d+"', logo_svg_content)
if class_search_2:
logging.warning(f"Found class attribute {class_search_2.group()} in tool SVG: {tool_label}")

logging.debug(f"Adding {tool_name_slug}- prefix to any usages of generic class name")
logging.debug(f"Adding {tool_name_slug}- prefix to generic class {class_search_2.group()}")
logo_svg_content = re.sub(r"(cls-\d+)", f"{tool_name_slug}-\\1", logo_svg_content)

id_search = re.findall(r'id="([^"]+)"', logo_svg_content)
href_search = re.findall(r'xlink:href="#([^"]+)"', logo_svg_content)

for id_match in id_search:
logging.debug(f"Found ID {id_match} in tool SVG: {tool_label}")
logging.debug(f"Adding {tool_name_slug}- prefix to ID {id_match}")
logo_svg_content = re.sub(f'id="{id_match}"', f'id="{tool_name_slug}-{id_match}"', logo_svg_content)

for href_match in href_search:
logging.debug(f"Found href #{href_match} in tool SVG: {tool_label}")
logging.debug(f"Adding {tool_name_slug}- prefix to href #{href_match}")
logo_svg_content = re.sub(f'xlink:href="#{href_match}"', f'xlink:href="#{tool_name_slug}-{href_match}"', logo_svg_content)

css_url_search = re.findall(r"url\(#([^)]+)\)", logo_svg_content)
for css_url_match in css_url_search:
logging.debug(f"Found CSS URL reference #{css_url_match} in tool SVG: {tool_label}")
logging.debug(f"Adding {tool_name_slug}- prefix to CSS URL reference #{css_url_match}")
logo_svg_content = re.sub(f"url\(#{css_url_match}\)", f"url(#{tool_name_slug}-{css_url_match})", logo_svg_content)

logo_svg_dom = xml.dom.minidom.parseString(logo_svg_content)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "logo-diagram-generator"
version = "0.1.1"
version = "0.1.2"
description = "Generate SVG diagrams of a (tech) ecosystem, using logos from each tool organised into groups around a central logo"
authors = ["Andrew Beveridge <[email protected]>"]
license = "MIT"
Expand Down

0 comments on commit ff81b27

Please sign in to comment.