bcify 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
bcify-0.1.0/LICENSE ADDED
@@ -0,0 +1,58 @@
1
+ Server-Lab Open-Control License (SOCL) 1.0
2
+ ====================================
3
+ Copyright (c) 2025 Sourasish Das
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to use,
6
+ copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7
+ the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+ 1. Attribution.
10
+ The original copyright notice and this license text must be retained in
11
+ all copies or substantial portions of the Software. If you distribute
12
+ compiled or packaged forms of the Software, you must include the copyright
13
+ notice and a copy of this license in a file distributed with those forms.
14
+ 2. Open-source grant.
15
+ The rights granted in this license are intended to be open-source in nature:
16
+ recipients may use, study, modify, and redistribute the Software under the
17
+ terms set forth herein.
18
+ 3. Ownership and control.
19
+ Copyright and all intellectual property rights in the Software are and remain
20
+ the exclusive property of the Copyright Owner named above. The Copyright
21
+ Owner retains sole authority to relicense, alter, or otherwise change the
22
+ licensing terms that apply to future distributions of the Software.
23
+ 4. License changes; effective date.
24
+ The Copyright Owner may change or replace this license at any time and
25
+ without notice. Any such change applies only to versions or distributions
26
+ of the Software that the Copyright Owner explicitly distributes after the
27
+ change takes effect. Copies of the Software already distributed by the
28
+ Copyright Owner under a prior version of this license remain governed by
29
+ the terms under which those copies were originally distributed.
30
+ 5. No trademark rights.
31
+ This license does not grant any rights to use the Copyright Owner's trade
32
+ names, trademarks, service marks, or logos.
33
+ 6. No warranty.
34
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE COPYRIGHT OWNER DISCLAIMS ALL
35
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
36
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
37
+ NON-INFRINGEMENT. USE OF THE SOFTWARE IS AT YOUR OWN RISK.
38
+ 7. Limitation of liability.
39
+ IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY CLAIM, DAMAGES OR
40
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
41
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
42
+ DEALINGS IN THE SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43
+ 8. Contributor submissions.
44
+ By submitting a contribution to the project, a contributor grants the
45
+ Copyright Owner a perpetual, irrevocable, worldwide, royalty-free,
46
+ transferable license to use, reproduce, modify, distribute, sublicense,
47
+ and otherwise exploit the contribution as part of the Software.
48
+ 9. Termination.
49
+ This license and the rights granted hereunder will terminate automatically
50
+ if you fail to comply with any term of this license. Termination does not
51
+ affect any rights that were already granted to recipients prior to the
52
+ termination event with respect to copies distributed while the license was
53
+ in effect for that distribution.
54
+ 10. Governing law.
55
+ This license does not select a governing law; legal disputes shall be
56
+ governed by the laws applicable where enforcement is sought, subject to
57
+ applicable conflict-of-law rules.
58
+ [END OF LICENSE]
bcify-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,67 @@
1
+ Metadata-Version: 2.4
2
+ Name: bcify
3
+ Version: 0.1.0
4
+ Summary: Generate Bytecraft .bc scaffolds from existing project repositories.
5
+ Author: Sourasish das
6
+ License: MIT
7
+ Keywords: bytecraft,scaffold,generator,cli
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3 :: Only
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Environment :: Console
13
+ Requires-Python: >=3.10
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Provides-Extra: dev
17
+ Requires-Dist: pytest>=8.0; extra == "dev"
18
+ Dynamic: license-file
19
+
20
+ # Bcify
21
+
22
+ `Bcify` turns an existing project repository into a Bytecraft `.bc` scaffold script.
23
+
24
+ It walks the repo, keeps probable text files, skips binary content, and emits a script
25
+ made of `make-folder` and `make-file` commands that can recreate the text scaffold.
26
+
27
+ ## Install
28
+
29
+ ```bash
30
+ pip install -e .
31
+ ```
32
+
33
+ ## Usage
34
+
35
+ ```bash
36
+ bcify path/to/repo
37
+ bcify path/to/repo --output project.bc
38
+ bcify path/to/repo --root-name cloned-project --include-hidden
39
+ ```
40
+
41
+ By default, `bcify`:
42
+
43
+ - writes `<repo-name>.bc` in the current working directory
44
+ - skips common generated or tool directories like `.git`, `node_modules`, `.venv`, and `dist`
45
+ - ignores files that do not look like text
46
+ - preserves empty text files
47
+
48
+ ## Example
49
+
50
+ ```bash
51
+ bcify ../my-app --output my-app.bc
52
+ ```
53
+
54
+ Example output:
55
+
56
+ ```text
57
+ # Generated by bcify from: ../my-app
58
+ set-working-folder "my-app"
59
+
60
+ make-folder "src"
61
+ make-file "README.md" with ---
62
+ # my-app
63
+ ---
64
+ make-file "src/main.py" with ---
65
+ print("hello")
66
+ ---
67
+ ```
bcify-0.1.0/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # Bcify
2
+
3
+ `Bcify` turns an existing project repository into a Bytecraft `.bc` scaffold script.
4
+
5
+ It walks the repo, keeps probable text files, skips binary content, and emits a script
6
+ made of `make-folder` and `make-file` commands that can recreate the text scaffold.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ pip install -e .
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ```bash
17
+ bcify path/to/repo
18
+ bcify path/to/repo --output project.bc
19
+ bcify path/to/repo --root-name cloned-project --include-hidden
20
+ ```
21
+
22
+ By default, `bcify`:
23
+
24
+ - writes `<repo-name>.bc` in the current working directory
25
+ - skips common generated or tool directories like `.git`, `node_modules`, `.venv`, and `dist`
26
+ - ignores files that do not look like text
27
+ - preserves empty text files
28
+
29
+ ## Example
30
+
31
+ ```bash
32
+ bcify ../my-app --output my-app.bc
33
+ ```
34
+
35
+ Example output:
36
+
37
+ ```text
38
+ # Generated by bcify from: ../my-app
39
+ set-working-folder "my-app"
40
+
41
+ make-folder "src"
42
+ make-file "README.md" with ---
43
+ # my-app
44
+ ---
45
+ make-file "src/main.py" with ---
46
+ print("hello")
47
+ ---
48
+ ```
@@ -0,0 +1,37 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "bcify"
7
+ version = "0.1.0"
8
+ description = "Generate Bytecraft .bc scaffolds from existing project repositories."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ authors = [
12
+ { name = "Sourasish das" }
13
+ ]
14
+ license = { text = "MIT" }
15
+ keywords = ["bytecraft", "scaffold", "generator", "cli"]
16
+ classifiers = [
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3 :: Only",
19
+ "Programming Language :: Python :: 3.10",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Environment :: Console"
22
+ ]
23
+
24
+ [project.scripts]
25
+ bcify = "bcify.cli:main"
26
+
27
+ [project.optional-dependencies]
28
+ dev = ["pytest>=8.0"]
29
+
30
+ [tool.setuptools]
31
+ package-dir = {"" = "src"}
32
+
33
+ [tool.setuptools.packages.find]
34
+ where = ["src"]
35
+
36
+ [tool.pytest.ini_options]
37
+ testpaths = ["tests"]
bcify-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,5 @@
1
+ """Bcify package."""
2
+
3
+ __all__ = ["__version__"]
4
+
5
+ __version__ = "0.1.0"
@@ -0,0 +1,57 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from pathlib import Path
5
+
6
+ from bcify.generator import build_scaffold_script
7
+
8
+
9
+ def build_parser() -> argparse.ArgumentParser:
10
+ parser = argparse.ArgumentParser(
11
+ prog="bcify",
12
+ description="Generate a Bytecraft .bc scaffold from a project repository.",
13
+ )
14
+ parser.add_argument("source", help="Path to the source repository or project folder.")
15
+ parser.add_argument(
16
+ "-o",
17
+ "--output",
18
+ help="Path to the output .bc file. Defaults to <repo-name>.bc in the current directory.",
19
+ )
20
+ parser.add_argument(
21
+ "--root-name",
22
+ help="Folder name used in set-working-folder. Defaults to the source folder name.",
23
+ )
24
+ parser.add_argument(
25
+ "--include-hidden",
26
+ action="store_true",
27
+ help="Include hidden files and directories except default ignored tool folders.",
28
+ )
29
+ return parser
30
+
31
+
32
+ def main() -> int:
33
+ parser = build_parser()
34
+ args = parser.parse_args()
35
+
36
+ source = Path(args.source).expanduser().resolve()
37
+ if not source.exists():
38
+ parser.error(f"Source path does not exist: {source}")
39
+ if not source.is_dir():
40
+ parser.error(f"Source path must be a directory: {source}")
41
+
42
+ output = Path(args.output).expanduser().resolve() if args.output else Path.cwd() / f"{source.name}.bc"
43
+ root_name = args.root_name or source.name
44
+
45
+ script = build_scaffold_script(
46
+ source_dir=source,
47
+ root_name=root_name,
48
+ include_hidden=args.include_hidden,
49
+ )
50
+ output.write_text(script, encoding="utf-8", newline="\n")
51
+
52
+ print(f"Wrote scaffold: {output}")
53
+ return 0
54
+
55
+
56
+ if __name__ == "__main__":
57
+ raise SystemExit(main())
@@ -0,0 +1,149 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from pathlib import Path
5
+
6
+
7
+ DEFAULT_IGNORED_DIRS = {
8
+ ".git",
9
+ ".hg",
10
+ ".svn",
11
+ ".idea",
12
+ ".vscode",
13
+ ".pytest_cache",
14
+ "__pycache__",
15
+ "node_modules",
16
+ ".venv",
17
+ "venv",
18
+ "dist",
19
+ "build",
20
+ "target",
21
+ }
22
+
23
+ DEFAULT_IGNORED_FILES = {
24
+ ".DS_Store",
25
+ "Thumbs.db",
26
+ }
27
+
28
+ TEXT_CHUNK_SIZE = 8192
29
+
30
+
31
+ @dataclass(frozen=True)
32
+ class RepoEntry:
33
+ path: Path
34
+ relative_path: Path
35
+ kind: str
36
+
37
+
38
+ def build_scaffold_script(source_dir: Path, root_name: str, include_hidden: bool = False) -> str:
39
+ entries = collect_repo_entries(source_dir=source_dir, include_hidden=include_hidden)
40
+ lines = [
41
+ f"# Generated by bcify from: {source_dir}",
42
+ '# Non-text files were skipped automatically.',
43
+ f'set-working-folder "{escape_string(root_name)}"',
44
+ "",
45
+ ]
46
+
47
+ for entry in entries:
48
+ relative = entry.relative_path.as_posix()
49
+ if entry.kind == "dir":
50
+ lines.append(f'make-folder "{escape_string(relative)}"')
51
+ continue
52
+
53
+ content = entry.path.read_text(encoding=detect_text_encoding(entry.path))
54
+ lines.extend(
55
+ [
56
+ f'make-file "{escape_string(relative)}" with ---',
57
+ normalize_multiline_content(content),
58
+ "---",
59
+ ]
60
+ )
61
+
62
+ return "\n".join(lines).rstrip() + "\n"
63
+
64
+
65
+ def collect_repo_entries(source_dir: Path, include_hidden: bool = False) -> list[RepoEntry]:
66
+ directories: list[RepoEntry] = []
67
+ files: list[RepoEntry] = []
68
+
69
+ for path in sorted(source_dir.rglob("*")):
70
+ relative = path.relative_to(source_dir)
71
+
72
+ if should_skip_path(relative, path, include_hidden=include_hidden):
73
+ continue
74
+
75
+ if path.is_dir():
76
+ directories.append(RepoEntry(path=path, relative_path=relative, kind="dir"))
77
+ continue
78
+
79
+ if path.is_file() and is_probably_text(path):
80
+ files.append(RepoEntry(path=path, relative_path=relative, kind="file"))
81
+
82
+ return directories + files
83
+
84
+
85
+ def should_skip_path(relative: Path, path: Path, include_hidden: bool) -> bool:
86
+ parts = relative.parts
87
+ if any(part in DEFAULT_IGNORED_DIRS for part in parts):
88
+ return True
89
+
90
+ name = path.name
91
+ if name in DEFAULT_IGNORED_FILES:
92
+ return True
93
+
94
+ if include_hidden:
95
+ return False
96
+
97
+ return any(part.startswith(".") for part in parts)
98
+
99
+
100
+ def is_probably_text(path: Path) -> bool:
101
+ try:
102
+ chunk = path.read_bytes()[:TEXT_CHUNK_SIZE]
103
+ except OSError:
104
+ return False
105
+
106
+ if not chunk:
107
+ return True
108
+
109
+ if b"\x00" in chunk:
110
+ return False
111
+
112
+ try:
113
+ chunk.decode("utf-8")
114
+ return True
115
+ except UnicodeDecodeError:
116
+ pass
117
+
118
+ for encoding in ("utf-16", "utf-16-le", "utf-16-be"):
119
+ try:
120
+ chunk.decode(encoding)
121
+ return True
122
+ except UnicodeDecodeError:
123
+ continue
124
+
125
+ printable = sum(
126
+ byte in b"\t\n\r\f\b" or 32 <= byte <= 126
127
+ for byte in chunk
128
+ )
129
+ return printable / len(chunk) >= 0.85
130
+
131
+
132
+ def detect_text_encoding(path: Path) -> str:
133
+ raw = path.read_bytes()
134
+ for encoding in ("utf-8", "utf-16", "utf-16-le", "utf-16-be"):
135
+ try:
136
+ raw.decode(encoding)
137
+ return encoding
138
+ except UnicodeDecodeError:
139
+ continue
140
+ return "utf-8"
141
+
142
+
143
+ def normalize_multiline_content(content: str) -> str:
144
+ normalized = content.replace("\r\n", "\n").replace("\r", "\n")
145
+ return normalized.rstrip("\n")
146
+
147
+
148
+ def escape_string(value: str) -> str:
149
+ return value.replace("\\", "\\\\").replace('"', '\\"')
@@ -0,0 +1,67 @@
1
+ Metadata-Version: 2.4
2
+ Name: bcify
3
+ Version: 0.1.0
4
+ Summary: Generate Bytecraft .bc scaffolds from existing project repositories.
5
+ Author: Sourasish das
6
+ License: MIT
7
+ Keywords: bytecraft,scaffold,generator,cli
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3 :: Only
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Environment :: Console
13
+ Requires-Python: >=3.10
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Provides-Extra: dev
17
+ Requires-Dist: pytest>=8.0; extra == "dev"
18
+ Dynamic: license-file
19
+
20
+ # Bcify
21
+
22
+ `Bcify` turns an existing project repository into a Bytecraft `.bc` scaffold script.
23
+
24
+ It walks the repo, keeps probable text files, skips binary content, and emits a script
25
+ made of `make-folder` and `make-file` commands that can recreate the text scaffold.
26
+
27
+ ## Install
28
+
29
+ ```bash
30
+ pip install -e .
31
+ ```
32
+
33
+ ## Usage
34
+
35
+ ```bash
36
+ bcify path/to/repo
37
+ bcify path/to/repo --output project.bc
38
+ bcify path/to/repo --root-name cloned-project --include-hidden
39
+ ```
40
+
41
+ By default, `bcify`:
42
+
43
+ - writes `<repo-name>.bc` in the current working directory
44
+ - skips common generated or tool directories like `.git`, `node_modules`, `.venv`, and `dist`
45
+ - ignores files that do not look like text
46
+ - preserves empty text files
47
+
48
+ ## Example
49
+
50
+ ```bash
51
+ bcify ../my-app --output my-app.bc
52
+ ```
53
+
54
+ Example output:
55
+
56
+ ```text
57
+ # Generated by bcify from: ../my-app
58
+ set-working-folder "my-app"
59
+
60
+ make-folder "src"
61
+ make-file "README.md" with ---
62
+ # my-app
63
+ ---
64
+ make-file "src/main.py" with ---
65
+ print("hello")
66
+ ---
67
+ ```
@@ -0,0 +1,13 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/bcify/__init__.py
5
+ src/bcify/cli.py
6
+ src/bcify/generator.py
7
+ src/bcify.egg-info/PKG-INFO
8
+ src/bcify.egg-info/SOURCES.txt
9
+ src/bcify.egg-info/dependency_links.txt
10
+ src/bcify.egg-info/entry_points.txt
11
+ src/bcify.egg-info/requires.txt
12
+ src/bcify.egg-info/top_level.txt
13
+ tests/test_generator.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ bcify = bcify.cli:main
@@ -0,0 +1,3 @@
1
+
2
+ [dev]
3
+ pytest>=8.0
@@ -0,0 +1 @@
1
+ bcify
@@ -0,0 +1,30 @@
1
+ from pathlib import Path
2
+
3
+ from bcify.generator import build_scaffold_script, is_probably_text
4
+
5
+
6
+ def test_build_scaffold_script_skips_binary_and_hidden(tmp_path: Path) -> None:
7
+ project = tmp_path / "sample"
8
+ project.mkdir()
9
+ (project / "src").mkdir()
10
+ (project / ".git").mkdir()
11
+ (project / "README.md").write_text("# Sample\n", encoding="utf-8")
12
+ (project / "src" / "main.py").write_text("print('hi')\n", encoding="utf-8")
13
+ (project / "image.png").write_bytes(b"\x89PNG\r\n\x1a\n\x00\x00binary")
14
+ (project / ".env").write_text("SECRET=test\n", encoding="utf-8")
15
+
16
+ script = build_scaffold_script(project, root_name="sample")
17
+
18
+ assert 'set-working-folder "sample"' in script
19
+ assert 'make-folder "src"' in script
20
+ assert 'make-file "README.md" with ---' in script
21
+ assert 'make-file "src/main.py" with ---' in script
22
+ assert "image.png" not in script
23
+ assert ".env" not in script
24
+
25
+
26
+ def test_empty_file_is_treated_as_text(tmp_path: Path) -> None:
27
+ empty_file = tmp_path / "empty.txt"
28
+ empty_file.write_text("", encoding="utf-8")
29
+
30
+ assert is_probably_text(empty_file) is True