lus 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.

Potentially problematic release.


This version of lus might be problematic. Click here for more details.

lus-0.1.0/LICENSE.txt ADDED
@@ -0,0 +1,17 @@
1
+ Copyright (c) 2025 Jan Niklas Hasse
2
+
3
+ This software is provided 'as-is', without any express or implied
4
+ warranty. In no event will the authors be held liable for any damages
5
+ arising from the use of this software.
6
+
7
+ Permission is granted to anyone to use this software for any purpose,
8
+ including commercial applications, and to alter it and redistribute it
9
+ freely, subject to the following restrictions:
10
+
11
+ 1. The origin of this software must not be misrepresented; you must not
12
+ claim that you wrote the original software. If you use this software
13
+ in a product, an acknowledgment in the product documentation would be
14
+ appreciated but is not required.
15
+ 2. Altered source versions must be plainly marked as such, and must not be
16
+ misrepresented as being the original software.
17
+ 3. This notice may not be removed or altered from any source distribution.
lus-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,17 @@
1
+ Metadata-Version: 2.4
2
+ Name: lus
3
+ Version: 0.1.0
4
+ Summary: A simple task-runner using KDL for configuration
5
+ Home-page: https://bixense.com/lus
6
+ Download-URL: https://github.com/jhasse/lus/archive/v0.1.0.tar.gz
7
+ Author: Jan Niklas Hasse
8
+ Author-email: jhasse@bixense.com
9
+ License-File: LICENSE.txt
10
+ Requires-Dist: ckdl
11
+ Dynamic: author
12
+ Dynamic: author-email
13
+ Dynamic: download-url
14
+ Dynamic: home-page
15
+ Dynamic: license-file
16
+ Dynamic: requires-dist
17
+ Dynamic: summary
lus-0.1.0/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # lus
2
+
3
+ `lus` is a task runner similar to [just](https://just.systems). It's key differentiators are:
4
+
5
+ * No DSL, `lus` uses the existing [KDL](https://kdl.dev)
6
+ * Runs tasks directly without a shell
7
+ * Comes with a simple built-in shell, so it works out-of-the-box on Windows
8
+ * Less features
9
+
10
+ ```kdl
11
+ b {
12
+ $ lus build
13
+ }
14
+
15
+ $ host="$(uname -a)"
16
+
17
+ // build main
18
+ build {
19
+ $ cc *.a -o main
20
+ }
21
+
22
+ // test everything
23
+ test-all {
24
+ $ lus build
25
+ $ "./test" --all
26
+ }
27
+
28
+ // run a specific test
29
+ test {
30
+ $ lus build
31
+ $ "./test" --test $args
32
+ }
33
+ ```
@@ -0,0 +1,134 @@
1
+ import os
2
+ import shlex
3
+ import subprocess
4
+ import sys
5
+ import ckdl
6
+
7
+
8
+ class LosFile:
9
+ def __init__(self, content: str):
10
+ self.main_lus_kdl = ckdl.parse(content).nodes
11
+ self.print_commands = False
12
+ self.local_variables = {}
13
+
14
+ self.check_args(self.main_lus_kdl, sys.argv[1:], True)
15
+
16
+ def print_command(self, args: list[str]):
17
+ if self.print_commands:
18
+ print(f"\x1b[1;34m$ {shlex.join(args)}\x1b[0m")
19
+
20
+ def run(self, args: list[str], properties: dict[str, str]):
21
+ if args[0] == "exit":
22
+ raise SystemExit(args[1])
23
+ elif args[0] == "cd":
24
+ self.print_command(args)
25
+ os.chdir(args[1])
26
+ elif args[0] == "test":
27
+ if args[1] == "-f" or args[1] == "-d":
28
+ exists = os.path.exists(args[2])
29
+ if (
30
+ not exists
31
+ or (args[1] == "-f" and not os.path.isfile(args[2]))
32
+ or (args[1] == "-d" and not os.path.isdir(args[2]))
33
+ ):
34
+ if len(args) > 3 and args[3] == "||":
35
+ self.run(args[4:], properties)
36
+ else:
37
+ raise SystemExit(1)
38
+ else:
39
+ raise NotImplementedError(f"test {args[1]} not implemented")
40
+ elif args[0] == "lus":
41
+ old_cwd = os.getcwd()
42
+ # print_command(args)
43
+ try:
44
+ self.check_args(self.main_lus_kdl, args[1:], True)
45
+ except SystemExit as e:
46
+ if e.code != 0:
47
+ raise SystemExit(e.code)
48
+ finally:
49
+ os.chdir(old_cwd)
50
+ elif args[0] == "export":
51
+ self.print_command(args + [f"{k}={v}" for k, v in properties.items()])
52
+ os.environ.update(properties)
53
+ elif args[0] == "set":
54
+ global print_commands
55
+ if args[1] == "-x":
56
+ print_commands = True
57
+ elif args[1] == "+x":
58
+ print_commands = False
59
+ else:
60
+ raise NotImplementedError(f"set {args[1]} not implemented")
61
+ elif "/" in args[0] and not os.path.isabs(args[0]):
62
+ self.print_command(args)
63
+ subprocess.check_call([os.path.join(os.getcwd(), args[0])] + args[1:])
64
+ else:
65
+ self.print_command(args)
66
+ subprocess.check_call(args)
67
+
68
+ def check_args(self, nodes, args: list[str], check_if_args_handled: bool):
69
+ # Flags for this subcommand, i.e. ["--release"]
70
+ flags = []
71
+
72
+ # Everything after the last flag. For example, if the command is `lus build --release foo bar
73
+ # -v`, then this will contain `["foo", "bar", "-v"]`.
74
+ remaining_args_without_flags = []
75
+
76
+ for arg in args:
77
+ if len(remaining_args_without_flags) == 0 and arg.startswith("-"):
78
+ flags.append(arg)
79
+ else:
80
+ remaining_args_without_flags.append(arg)
81
+ remaining_args = args
82
+
83
+ subcommand = (
84
+ remaining_args_without_flags[0]
85
+ if remaining_args_without_flags
86
+ else "default"
87
+ )
88
+
89
+ for i, child in enumerate(nodes):
90
+ if child.name == "$":
91
+ if len(child.args) > 0:
92
+ cmd = []
93
+ for arg in child.args:
94
+ if arg == "$args":
95
+ cmd.extend(remaining_args)
96
+ remaining_args = []
97
+ elif arg == "$subcommand":
98
+ cmd.append(subcommand)
99
+ else:
100
+ cmd.append(arg)
101
+ self.run(cmd, child.properties)
102
+ else:
103
+ self.local_variables.update(child.properties)
104
+ elif child.name == subcommand:
105
+ try:
106
+ remaining_args.remove(subcommand)
107
+ except ValueError as e:
108
+ if subcommand != "default":
109
+ raise e
110
+ self.check_args(child.children, remaining_args, i == len(nodes) - 1)
111
+ remaining_args = []
112
+ elif child.name in flags:
113
+ remaining_args.remove(child.name)
114
+ self.check_args(child.children, remaining_args_without_flags, False)
115
+ if check_if_args_handled and len(remaining_args) > 0:
116
+ available_subcommands = [
117
+ child.name
118
+ for child in nodes
119
+ if len(child.name) > 0
120
+ and child.name != "$"
121
+ and child.name[0] != "-"
122
+ and child.name != "default"
123
+ ]
124
+ if len(available_subcommands) == 0:
125
+ print(
126
+ f"\x1b[1;31merror:\x1b[0m Unexpected argument: {shlex.join(remaining_args)}"
127
+ )
128
+ else:
129
+ print(
130
+ f"\x1b[1;31merror:\x1b[0m Unknown subcommand {shlex.quote(subcommand)} not one of:"
131
+ )
132
+ for available_subcommand in available_subcommands:
133
+ print(f" \x1b[1;34m{available_subcommand}\x1b[0m")
134
+ raise SystemExit(1)
@@ -0,0 +1,35 @@
1
+ import subprocess
2
+ import sys
3
+ import ckdl
4
+ import os
5
+
6
+ from .LosFile import LosFile
7
+
8
+ try:
9
+ MAX_DEPTH = 50
10
+ current_filesystem = os.stat(".").st_dev
11
+ for i in range(MAX_DEPTH):
12
+ try:
13
+ with open("lus.kdl", "r") as f:
14
+ content = f.read()
15
+ except FileNotFoundError as e:
16
+ if current_filesystem != os.stat("..").st_dev:
17
+ raise e
18
+ cwd = os.getcwd()
19
+ os.chdir("..")
20
+ if cwd == os.getcwd():
21
+ raise e
22
+ else:
23
+ break
24
+
25
+ file = LosFile(content)
26
+ except subprocess.CalledProcessError as e:
27
+ sys.exit(e.returncode)
28
+ except FileNotFoundError as e:
29
+ print(f"\x1b[1;31merror:\x1b[0m {e.strerror}: {e.filename}", file=sys.stderr)
30
+ sys.exit(1)
31
+ except KeyboardInterrupt:
32
+ sys.exit(130)
33
+ except ckdl.ParseError as e:
34
+ print(f"\x1b[1;31merror:\x1b[0m {e}", file=sys.stderr)
35
+ sys.exit(1)
@@ -0,0 +1,17 @@
1
+ Metadata-Version: 2.4
2
+ Name: lus
3
+ Version: 0.1.0
4
+ Summary: A simple task-runner using KDL for configuration
5
+ Home-page: https://bixense.com/lus
6
+ Download-URL: https://github.com/jhasse/lus/archive/v0.1.0.tar.gz
7
+ Author: Jan Niklas Hasse
8
+ Author-email: jhasse@bixense.com
9
+ License-File: LICENSE.txt
10
+ Requires-Dist: ckdl
11
+ Dynamic: author
12
+ Dynamic: author-email
13
+ Dynamic: download-url
14
+ Dynamic: home-page
15
+ Dynamic: license-file
16
+ Dynamic: requires-dist
17
+ Dynamic: summary
@@ -0,0 +1,11 @@
1
+ LICENSE.txt
2
+ README.md
3
+ setup.py
4
+ lus/LosFile.py
5
+ lus/__main__.py
6
+ lus.egg-info/PKG-INFO
7
+ lus.egg-info/SOURCES.txt
8
+ lus.egg-info/dependency_links.txt
9
+ lus.egg-info/entry_points.txt
10
+ lus.egg-info/requires.txt
11
+ lus.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ lus = lus:__main__
@@ -0,0 +1 @@
1
+ ckdl
@@ -0,0 +1 @@
1
+ lus
lus-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
lus-0.1.0/setup.py ADDED
@@ -0,0 +1,20 @@
1
+ from setuptools import setup
2
+
3
+ VERSION='0.1.0' # also see __init__.py
4
+
5
+ setup(
6
+ name='lus',
7
+ version=VERSION,
8
+ author="Jan Niklas Hasse",
9
+ author_email="jhasse@bixense.com",
10
+ url="https://bixense.com/lus",
11
+ download_url='https://github.com/jhasse/lus/archive/v{}.tar.gz'.format(VERSION),
12
+ description="A simple task-runner using KDL for configuration",
13
+ packages=['lus'],
14
+ entry_points={
15
+ 'console_scripts': ['lus = lus:__main__'],
16
+ },
17
+ install_requires=[
18
+ 'ckdl',
19
+ ],
20
+ )