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 +17 -0
- lus-0.1.0/PKG-INFO +17 -0
- lus-0.1.0/README.md +33 -0
- lus-0.1.0/lus/LosFile.py +134 -0
- lus-0.1.0/lus/__main__.py +35 -0
- lus-0.1.0/lus.egg-info/PKG-INFO +17 -0
- lus-0.1.0/lus.egg-info/SOURCES.txt +11 -0
- lus-0.1.0/lus.egg-info/dependency_links.txt +1 -0
- lus-0.1.0/lus.egg-info/entry_points.txt +2 -0
- lus-0.1.0/lus.egg-info/requires.txt +1 -0
- lus-0.1.0/lus.egg-info/top_level.txt +1 -0
- lus-0.1.0/setup.cfg +4 -0
- lus-0.1.0/setup.py +20 -0
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
|
+
```
|
lus-0.1.0/lus/LosFile.py
ADDED
|
@@ -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 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ckdl
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
lus
|
lus-0.1.0/setup.cfg
ADDED
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
|
+
)
|