{"id":29285922,"url":"https://github.com/byteface/sharpshooter","last_synced_at":"2025-09-01T05:36:10.740Z","repository":{"id":57466655,"uuid":"408236339","full_name":"byteface/sharpshooter","owner":"byteface","description":"A shorthand for creating files and folders. (A parser could be written in any language)","archived":false,"fork":false,"pushed_at":"2021-12-20T20:37:13.000Z","size":471,"stargazers_count":11,"open_issues_count":19,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-04T20:56:12.052Z","etag":null,"topics":["cli","command-line","command-line-tool","python","python3"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/byteface.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-09-19T21:03:39.000Z","updated_at":"2024-12-25T22:29:08.000Z","dependencies_parsed_at":"2022-09-19T08:41:39.160Z","dependency_job_id":null,"html_url":"https://github.com/byteface/sharpshooter","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/byteface/sharpshooter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/byteface%2Fsharpshooter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/byteface%2Fsharpshooter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/byteface%2Fsharpshooter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/byteface%2Fsharpshooter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/byteface","download_url":"https://codeload.github.com/byteface/sharpshooter/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/byteface%2Fsharpshooter/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263826447,"owners_count":23516763,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","command-line","command-line-tool","python","python3"],"created_at":"2025-07-05T23:38:54.961Z","updated_at":"2025-07-05T23:38:59.681Z","avatar_url":"https://github.com/byteface.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🌳 tree (sharpshooter)\n\n[![PyPI version](https://badge.fury.io/py/sharpshooter.svg)](https://badge.fury.io/py/sharpshooter.svg) \n[![Downloads](https://pepy.tech/badge/sharpshooter)](https://pepy.tech/project/sharpshooter)\n[![Python version](https://img.shields.io/pypi/pyversions/sharpshooter.svg?style=flat)](https://img.shields.io/pypi/pyversions/sharpshooter.svg?style=flat)\n[![Python package](https://github.com/byteface/sharpshooter/actions/workflows/python-package.yml/badge.svg?branch=master)](https://github.com/byteface/sharpshooter/actions/workflows/python-package.yml)\n\nShorthand templates for creating (or destroying) file-systems.\n\ntree could be written for any language.\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://github.com/byteface/sharpshooter/raw/master/tty.gif?raw=true\"/\u003e\u003c/p\u003e\n\n## install\n\n```bash\npython3 -m pip install sharpshooter --upgrade  # for just sharpshooter\npython3 -m pip install sharpshooter[jinja2]  # sharpshooter with jinja2 cli extension\n```\n\n## CLI quick start\n\n```bash\ncd /path/to/some/folder\nsharpshooter -c hello\n# now open and edit the created hello.tree file in any text editor of your choice\n# i.e sudo vim hello.tree\nsharpshooter -t hello.tree  # run -t to test\nsharpshooter -f hello.tree  # or -f to create folders/files specified hello.tree\nsharpshooter --mock  # creates a sharpshooter.tree file of the current working directory\n```\n\n## intro\n\nTo create a plain empty file just type a word i.e.\n\n```\nfile\n```\n\nto create or access a dir use a slash /\n\n```\n/dir\n```\n\nTo create a file inside a dir use a 4 spaces (or tab)\n\n```\n/dir\n    file\n```\n\nputting it all together…\n\n```\n/dir\n    file\n    /plugins\n    /mail\n        /vendor\n        index.html\n            /something # this one will fail\n        file.py\n        file.py\n```\n\n### / (slash) Creating a tree\n\n```python\nfrom sharpshooter import tree\n\ntree('''\n/dir\n    file\n    /plugins\n        /mail\n            /vendor\n            index.html\n            file.py\n        file2.py\n''')\n```\n\ntree doesn't wait to be told. Your files are now there.\n\n### - (minus) deleting a tree\n\ntree can also remove dirs and files. You guessed it. With the the - minus symbol\n\n```python\ntree = '''\n/dir\n    /plugins\n         -mail\n'''\n```\n\ntree will not ask twice. Your files are gone.\n\nBut be mindful this example would also 'create' the dir and plugins folders if they didn't exist. Because tree by nature creates by default.\n\nTo read info about a file or folder without creation use colon ':' to indicate read-only.\n\n```python\ntree = '''\n:/dir\n    :/plugins\n        -mail\n'''\n```\n\nMore on colons : later.\n\n###### WARNING - be careful using minus. tree could destroy your entire filesytem if used incorrectly\n\n### \\# (hash) comments\n\nUse # to comment out a line or instruction.\n\n```python\ns = '''\n/:dir\n    file# some ignored text here\n    /plugins\n        /mail\n'''\n```\n\n###### WARNING - the # symbol is ignored if it comes after the \u003c, $ or \u003e symbols. (see why further down)\n\n### : (colon) read only\n\nTo read info about a file or folder, without creating any, use a colon ':'\n\nYou can then format the tree with an f-string to get the result which produces similir output as 'ls -al' on nix systems i.e.\n\n```python\ntest = tree('''\n:README.md\n''')\nprint(f\"{test}\")\n# -rw-r--r-- byteface staff 2100 21 Sep 07:58 README.md\n```\n\nor for a directory...\n\n```python\ntest = tree('''\n:venv\n''')\nprint(f\"{test}\")\n# drwxr-xr-x byteface staff 192 Mon Sep 20 10:18:44 2021 venv\n```\n\nNotice the little 'd' at the front lets you know it's a directory. Just like in a terminal.\n\nyou can safely change change order of colon and plus i.e. will still work.\n\n```python\ntree('''\n:/dont\n    :/make\n        :this\n''')\n```\n\nbut i prefer to use the colon right before the file or folder name .i.e.\n\n```python\ntree('''\n/:dont\n    /:make\n        :this\n''')\n```\n\nup to you.\n\n### test mode\n\nIf you are feeling unsure. Try tree in test mode.\n\nIt will log what it would do to the console but won't actually create any files or folders.\n\nYou just have to past test=True to the tree function. i.e\n\n```python\nmytree = '''\n/somedir\n    /anotherdir\n        someotherfile.png\n    file.txt\n    file2.gif\n'''\n\ntree(mytree, test=True)  # notice how we set test=True\n\n```\n\nNow check the console and if you feel confident set test=False and run the code again.\n\n### ~ (tilde) users home direcory\n\nusers home path is supported.\n\n```python\ns1 = \"\"\"\n:/~\n    test.png\n    /somedir\n        somescript.py\n\"\"\"\ntree(s1, test=True)\ntree(s1, test=False)\n```\n\n### \u003c (lt) write to a file\n\n\u003c This symbol can be used to write a string to a file.\n\n```python\nmystring = \"\"\"\n/somedir\n    somescript.py \u003c print('hello world!')\n    some.txt \u003c hello world!\n    script.sh \u003c echo 'hello world'\n\"\"\"\ntree(mystring)\n```\n\nyou can use \\n to add more than one line to a file.\n\n```python\nmystring = \"\"\"\n/somedir\n    somepage.md \u003c # heading \\n## another heading \\n### and another heading\n\"\"\"\ntree(mystring)\n```\n\n###### WARNING - the comment # symbols are ignored after the \u003c so they can be succesfully written to files. (i.e. .md files)\n\n### $ (dollar) pass to the shell\n\nAnything after the $ symbol is passed to the shell and the result is written to the file.\n\n```python\nmystring = \"\"\"\n/somedir\n    test.txt $ cowsay moo\n\"\"\"\ntree(mystring)\n```\n\n###### WARNING - comments # symbol is ignored after the $ so don't use comments on these lines or they could be sent to the terminal\n\n### \u003e (gt) pass to windows cmd\n\nbash commands won't work on windows. Instead use the \u003e symbol for windows commands\n\nAnything after the \u003e symbol is passed to cmd with the result written to the file.\n\n```python\nmystring = \"\"\"\n/somedir\n    test.txt $ ls -al\n    test.txt \u003e dir\n\"\"\"\ntree(mystring)\n```\n\n###### WARNING - comments # symbol is ignored after the \u003e so don't use comments on these lines or they could be sent to cmd\n\n\n### ? (question)\n\nA question will take user input. It can be used in place of a filename.\n\n```python\nmystring = \"\"\"\n/somedir\n    somefile.txt\n    ?\n    anotherfile.txt ?\n    /?\n        info.txt\n\"\"\"\ntree(mystring)\n```\n\nIn this example a prompt would ask for a filename inbetween creating somefile.txt and anotherfile.txt.\n\nThen a multi-line prompt would ask for content to be input for anotherfile.txt.\n\nLastly a prompt would ask for the folder name to be created before putting info.txt in it.\n\n###### WARNING - comments # symbol is ignored after the \u003e so don't use comments on these lines or they could be sent to cmd\n\n\n### \\#[name] labels\n\nA label is a way to store multiple trees in a single file.\n\nBy using square brackets after a # symbol you can label a tree. i.e.\n\n```\n#[mylabel]\n/dir\n    file\n```\n\nYou can now pass the label to the tree function.\n\n```bash\nsharpshooter --test myconfig.tree -l mylabel  # use --label to only parse part of a .tree file\n```\n\n## Anything else?\n\n- you can now have spaces in filenames.\n\n- tips: use with a proxy server and range requests to write partials to files.\n\nTo see planned features/goals see TODO.md\n\n## CLI\n\nThere's several commands you can pass to sharpshooter on the command line.\n\n```bash\npython3 -m sharpshooter --help  # shows available commands. also uses -h\n```\n\n```bash\nsharpshooter --version  # shows the current version. also uses -v\n```\n\n```bash\nsharpshooter --create someconfigname  # creates a helloworld.tree file. also uses -c\n```\n\n```bash\nsharpshooter --file myconfig.tree  # parses a .tree file and executes it. also uses -f\n```\n\n```bash\nsharpshooter --test anotherconfig.tree  # parses a .tree file in test mode. also uses -t\n```\n\n```bash\nsharpshooter --mock  # makes a sharpshooter.tree file based on the current working directory. also uses -m\n# sharpshooter --mock 1  # pass optional depth as int\n```\n\n```bash\nsharpshooter --dir  # set the current working directory. use with other commands. also uses -d\n#i.e. python -m sharpshooter -d tests -f test.tree\n```\n\n```bash\nsharpshooter --pretty 0 # prints a pretty tree of the cwd. also uses -p\n\n# i.e\n# ├── refs\n# │   ├── heads\n# │   │   ├── question\n# │   │   ├── master\n# │   │   └── anytree\n# │   ├── tags\n# │   └── remotes\n# │       └── origin\n# │           └── master\n\n# takes optional parameter for depth : int\n\n```\n\nThere's an optional feature that requires jinja2:\n\n```bash\npython -m pip install jinja2  # make sure you have jinja2 installed\nsharpshooter --jinja myconfig.tree arg1=test # parses a .tree but runs through jinja first. also uses -j\n```\n\n- (note. jinja2 is not part of sharpshooter so you need to install it yourself. its an optional CLI dependency)\n- (note. jinja2 has no test mode yet so be careful)\n\n\n## NOTES\n\nI came up with the idea while mucking around with a lexer.\n\nhttps://www.dabeaz.com/ply/\n\nhttps://github.com/dabeaz/ply\n\nremember it executes from where your python thinks is the current dir.\nIf you're unsure set it first. i.e.\n\n```bash\nimport os\nos.chdir(os.path.dirname(os.path.abspath(__file__)))\n```\n\nFor your information, tree is the language and sharpshooter is an implementation.\n\npretty is available on the tree class as a static method.\n\n```\nfrom sharpshooter import tree\ntree.pretty(tree_string)\n```\n\n## Contributing\n\nIf you think you can write a sharpshooter parser in another language then please do and i'll link to your repo.\n\nTo dev on this one locally just pull the repo and do...\n\n```bash\ncd /sharpshooter\npython3 -m venv venv\n. venv/bin/activate  # lnux, # windows: venv\\Scripts\\activate \npip install -r requirements.txt \npython -m sharpshooter -d tests -f test.tree  # to use code version without installing\nmake test  # to run tests\n```\n\nOr run and write some tests, there's a few to get started in the Makefile.\n\nYou can install your own version using...\n\n```bash\npython3 -m pip install -e .\n```\n\nThere's several test.tree files in the /tests you can tweak and run through the CLI.\n\nIt creates a tmp folder you can delete and rerun to experiment. i.e.\n\n```\n/tmp\n    /hello\n        world.txt \u003c y tho!\n        page.html \u003c \u003chtml\u003ey tho!\u003c/html\u003e\n    /this # some comment\n        /is\n            cool.txt $ cowsay cool\n            cool.txt \u003e dir\n            test.md \u003c # heading \\n## another heading \\n### and another heading\n    page.html $ curl -s https://www.google.com\n    page2.htm $ curl -s https://www.fileformat.info/info/charset/UTF-32/list.htm\n    /partial\n        star.html $ curl -s -r 32-35 https://raw.githubusercontent.com/byteface/domonic/master/docs/_templates/sidebarintro.html\n    files.txt $ find .\n```\n\n## DISCLAIMER / known bugs\n\nUse 4 spaces not tabs.\n\nThis is a work in progress. It creates and destroys files on your hard drive. So be careful.\n\nDON'T leave trailing negative space on lines. I use space to change dirs.\n\ncomments won't work on lines with bash/windows commands or when writing to file. this is so you can write # symbols to the file.\n\nfilenames with special chars #?\u003e\u003c$ at start or end may cause issues until escaping them is sorted.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbyteface%2Fsharpshooter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbyteface%2Fsharpshooter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbyteface%2Fsharpshooter/lists"}