Skip to content

Commit

Permalink
Add flag to choose template
Browse files Browse the repository at this point in the history
This change allows providing a custom template arg flag -t/--template:
```
sinol-make init foo -t [repo link or disk path] [optional subdir]
```
It defaults to the upstream repository and example_package subdir.

Changed the example_package id pattern from `abc` to `__ID__`.
All filenames and file contents are now substituted.

Changed the positional output directory argument to `-o/--output` flag
to help avoid accidents.

Added result directory cleanup on failure.
  • Loading branch information
j4b6ski committed Dec 8, 2024
1 parent 3322119 commit 41b4266
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 31 deletions.
12 changes: 6 additions & 6 deletions example_package/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,20 @@ override_limits:
# Each language can have different extra arguments.

# extra_compilation_args:
# cpp: 'abclib.cpp'
# cpp: '__ID__lib.cpp'

# The arguments can also be in an array:

# extra_compilation_args:
# cpp:
# - 'abclib.cpp'
# - 'abclib2.cpp'
# - '__ID__lib.cpp'
# - '__ID__lib2.cpp'

# Additional files used in compilation can be defined in `extra_compilation_files` key.
# They are copied to the directory where the source code is compiled.
# All languages have the same additional files.

# extra_compilation_files: ['abclib.cpp', 'abclib.py']
# extra_compilation_files: ['__ID__lib.cpp', '__ID__lib.py']


### Keys used by sinol-make:
Expand All @@ -65,7 +65,7 @@ override_limits:
# The names of files in `prog/`, `doc/`, `in/` and `out/` directories have to start with this task id.
# This key is only used by `sinol-make`: running `sinol-make export` creates
# an archive with the proper name, which sio2 uses as the task id.
sinol_task_id: abc
sinol_task_id: __ID__

# sinol-make can behave differently depending on the value of `sinol_contest_type` key.
# Mainly, it affects how points are calculated.
Expand All @@ -76,7 +76,7 @@ sinol_contest_type: oi
# You can specify which tests are static (handwritten). This allows sinol-make to differentiate between
# old and handwritten tests. If this key is not present old tests won't be removed.
# This key is optional and should be a list of tests.
sinol_static_tests: ["abc0.in", "abc0a.in"]
sinol_static_tests: ["__ID__0.in", "__ID__0a.in"]

# sinol-make can check if the solutions run as expected when using `run` command.
# Key `sinol_expected_scores` defines expected scores for each solution on each tests.
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using namespace std;

// Change this function to generate one test for stresstesting.
// The script prog/abcingen.sh in 10 seconds generates
// The script prog/__ID__ingen.sh in 10 seconds generates
// as much tests as possible and compares the outputs
// of the model solution and brute solution.
// The tests shouldn't be very big, but should be able to cover edge cases.
Expand All @@ -12,7 +12,7 @@ void generate_one_stresstest(oi::Random &rng) {
}

// Change this function to create a test with the given name.
// The lists of tests to generate needs to be written in prog/abcingen.sh
// The lists of tests to generate needs to be written in prog/__ID__ingen.sh
void generate_proper_test(string test_name, oi::Random &rng) {
if (test_name == "0a")
cout << "0 1" << endl;
Expand All @@ -34,7 +34,7 @@ int main(int argc, char *argv[]) {
return 0;
}
if (argc != 2) {
cerr << "Run prog/abcingen.sh to stresstest and create proper tests." << endl;
cerr << "Run prog/__ID__ingen.sh to stresstest and create proper tests." << endl;
exit(1);
}
string test_name = argv[1];
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
75 changes: 53 additions & 22 deletions src/sinol_make/commands/init/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ class Command(BaseCommand):
Class for "init"
"""

TEMPLATE_ID='__ID__'
DEFAULT_TEMPLATE = 'https://github.com/sio2project/sinol-make.git'
DEFAULT_SUBDIR = 'example_package'

def get_name(self):
return "init"

Expand All @@ -23,21 +27,35 @@ def configure_subparser(self, subparser: argparse.ArgumentParser):
description='Create package from predefined template with given id.'
)
parser.add_argument('task_id', type=str, help='id of the task to create')
parser.add_argument('directory', type=str, nargs='?',
parser.add_argument('-o', '--output', type=str,
help='destination directory to copy the template into, defaults to task_id')
parser.add_argument('-f', '--force', action='store_true',
help='overwrite files in destination directory if they already exist')
parser.add_argument('-t', '--template', nargs='+', default=[self.DEFAULT_TEMPLATE, self.DEFAULT_SUBDIR],
help='specify template repository or directory, optionally subdirectory after space'
f' (default: {self.DEFAULT_TEMPLATE} {self.DEFAULT_SUBDIR})')
parser.add_argument('-v', '--verbose', action='store_true')
return parser

def download_template(self):
repo = 'https://github.com/sio2project/sinol-make.git'
package_dir = 'sinol-make/example_package'
template = self.template[0]
subdir = self.template[1] if len(self.template) > 1 else ''

self.used_tmpdir = tempfile.TemporaryDirectory()
tmp_dir = self.used_tmpdir.name
ret = subprocess.run(['git', 'clone', '-q', '--depth', '1', repo], cwd=tmp_dir)
if ret.returncode != 0:
util.exit_with_error("Could not access repository. Please try again.")
path = os.path.join(tmp_dir, package_dir)

is_url = template.startswith("https://") or template.startswith("git@")
print(('Cloning' if is_url else 'Copying') + ' template ' +
(f'{subdir} from {template}' if subdir else f'{template}'))
if is_url:
ret = subprocess.run(['git', 'clone', '-v' if self.verbose else '-q', '--depth', '1', template, tmp_dir])
if ret.returncode != 0:
util.exit_with_error("Could not access repository. Please try again.")
path = os.path.join(tmp_dir, subdir)
else:
path = os.path.join(tmp_dir, 'template')
shutil.copytree(os.path.join(os.getcwd(), template, subdir), path)

if os.path.exists(os.path.join(path, '.git')):
shutil.rmtree(os.path.join(path, '.git'))
return path
Expand All @@ -55,22 +73,31 @@ def move_folder(self):
raise
for file in files:
dest_filename = file
if file[:3] == 'abc':
dest_filename = self.task_id + file[3:]
if file[:len(self.TEMPLATE_ID)] == self.TEMPLATE_ID:
dest_filename = self.task_id + file[len(self.TEMPLATE_ID):]
shutil.move(os.path.join(root, file), os.path.join(mapping[root], dest_filename))

def update_config(self):
with open(os.path.join(os.getcwd(), 'config.yml')) as config:
config_data = config.read()
config_data = config_data.replace('sinol_task_id: abc', f'sinol_task_id: {self.task_id}')
def update_task_id(self):
for root, dirs, files in os.walk(os.getcwd()):
for file in files:
path = os.path.join(os.getcwd(), root, file)
with open(path) as file:
try:
file_data = file.read()
except UnicodeDecodeError:
# ignore non-text files
continue
file_data = file_data.replace(self.TEMPLATE_ID, self.task_id)

with open(os.path.join(os.getcwd(), 'config.yml'), 'w') as config:
config.write(config_data)
with open(path, 'w') as file:
file.write(file_data)

def run(self, args: argparse.Namespace):
self.task_id = args.task_id
self.force = args.force
destination = args.directory or self.task_id
self.template = args.template
self.verbose = args.verbose
destination = args.output or self.task_id
if not os.path.isabs(destination):
destination = os.path.join(os.getcwd(), destination)
try:
Expand All @@ -80,13 +107,17 @@ def run(self, args: argparse.Namespace):
util.exit_with_error(f"Destination {destination} already exists. "
f"Provide a different task id or directory name, "
f"or use the --force flag to overwrite.")
os.chdir(destination)
try:
self.template_dir = self.download_template()

self.template_dir = self.download_template()
os.chdir(destination)

self.move_folder()
self.update_config()
self.move_folder()
self.update_task_id()

self.used_tmpdir.cleanup()
self.used_tmpdir.cleanup()

print(util.info(f'Successfully created task "{self.task_id}"'))
print(util.info(f'Successfully created task "{self.task_id}"'))
except:
shutil.rmtree(destination)
raise

0 comments on commit 41b4266

Please sign in to comment.