mirror of
https://github.com/git-learning-game/oh-my-git.git
synced 2024-12-22 20:32:38 +01:00
Allow having an arbitrary number of repos in a level
This commit is contained in:
parent
91a57c49d7
commit
065ca2a233
11 changed files with 161 additions and 79 deletions
99
level.gd
99
level.gd
|
@ -4,12 +4,7 @@ class_name Level
|
|||
var slug
|
||||
var description
|
||||
var congrats
|
||||
var start_commands
|
||||
var goal_commands
|
||||
var win_commands
|
||||
|
||||
var _goal_repository_path = game.tmp_prefix_inside+"/repos/goal/"
|
||||
var _active_repository_path = game.tmp_prefix_inside+"/repos/active/"
|
||||
var repos = {}
|
||||
|
||||
# The path is an outer path.
|
||||
func load(path):
|
||||
|
@ -21,41 +16,91 @@ func load(path):
|
|||
# This is an old-style level.
|
||||
description = helpers.read_file(path+"/description", "(no description)")
|
||||
congrats = helpers.read_file(path+"/congrats", "Good job, you solved the level!\n\nFeel free to try a few more things or click 'Next Level'.")
|
||||
start_commands = helpers.read_file(path+"/start", "")
|
||||
goal_commands = helpers.read_file(path+"/goal", "")
|
||||
win_commands = helpers.read_file(path+"/win", "exit 1\n")
|
||||
|
||||
var yours = LevelRepo.new()
|
||||
yours.setup_commands = helpers.read_file(path+"/start", "")
|
||||
#goal_commands = helpers.read_file(path+"/goal", "")
|
||||
yours.win_commands = helpers.read_file(path+"/win", "")
|
||||
|
||||
repos["yours"] = yours
|
||||
elif dir.file_exists(path):
|
||||
# This is a new-style level.
|
||||
var config = helpers.parse(path)
|
||||
|
||||
description = config.get("description", "(no description)")
|
||||
congrats = config.get("congrats", "Good job, you solved the level!\n\nFeel free to try a few more things or click 'Next Level'.")
|
||||
start_commands = config.get("setup", "")
|
||||
goal_commands = ""
|
||||
win_commands = config.get("win", "exit 1\n")
|
||||
|
||||
var keys = config.keys()
|
||||
var repo_setups = []
|
||||
for k in keys:
|
||||
if k.begins_with("setup"):
|
||||
repo_setups.push_back(k)
|
||||
var repo_wins = []
|
||||
for k in keys:
|
||||
if k.begins_with("win"):
|
||||
repo_wins.push_back(k)
|
||||
|
||||
for k in repo_setups:
|
||||
var repo
|
||||
if " " in k:
|
||||
repo = Array(k.split(" "))[1]
|
||||
else:
|
||||
repo = "yours"
|
||||
if not repos.has(repo):
|
||||
repos[repo] = LevelRepo.new()
|
||||
repos[repo].setup_commands = config[k]
|
||||
|
||||
for k in repo_wins:
|
||||
var repo
|
||||
if " " in k:
|
||||
repo = Array(k.split(" "))[1]
|
||||
else:
|
||||
repo = "yours"
|
||||
repos[repo].win_commands = config[k]
|
||||
else:
|
||||
helpers.crash("Level %s does not exist." % path)
|
||||
|
||||
for repo in repos:
|
||||
repos[repo].path = game.tmp_prefix_inside+"repos/%s/" % repo
|
||||
repos[repo].slug = repo
|
||||
|
||||
# Surround all lines indented with four spaces with [code] tags.
|
||||
var monospace_regex = RegEx.new()
|
||||
monospace_regex.compile("\n (.*)\n")
|
||||
description = monospace_regex.sub(description, "\n [code]$1[/code]\n", true)
|
||||
|
||||
func construct():
|
||||
_construct_repo(start_commands +"\n"+ goal_commands, _goal_repository_path)
|
||||
_construct_repo(start_commands, _active_repository_path)
|
||||
|
||||
func _construct_repo(script_content, path):
|
||||
# We're actually destroying stuff here.
|
||||
# Make sure that active_repository is in a temporary directory.
|
||||
helpers.careful_delete(path)
|
||||
|
||||
game.global_shell.run("mkdir " + path)
|
||||
game.global_shell.cd(path)
|
||||
game.global_shell.run("git init")
|
||||
game.global_shell.run("git symbolic-ref HEAD refs/heads/main")
|
||||
game.global_shell.run(script_content)
|
||||
for r in repos:
|
||||
var repo = repos[r]
|
||||
# We're actually destroying stuff here.
|
||||
# Make sure that active_repository is in a temporary directory.
|
||||
helpers.careful_delete(repo.path)
|
||||
|
||||
game.global_shell.run("mkdir " + repo.path)
|
||||
game.global_shell.cd(repo.path)
|
||||
game.global_shell.run("git init")
|
||||
game.global_shell.run("git symbolic-ref HEAD refs/heads/main")
|
||||
|
||||
# Add other repos as remotes.
|
||||
for r2 in repos:
|
||||
if r == r2:
|
||||
continue
|
||||
game.global_shell.run("git remote add %s %s" % [r2, repos[r2].path])
|
||||
|
||||
# Allow receiving a push of the checked-out branch.
|
||||
game.global_shell.run("git config receive.denyCurrentBranch ignore")
|
||||
|
||||
for r in repos:
|
||||
var repo = repos[r]
|
||||
game.global_shell.cd(repo.path)
|
||||
game.global_shell.run(repo.setup_commands)
|
||||
|
||||
func check_win():
|
||||
game.global_shell.cd(_active_repository_path)
|
||||
return game.global_shell.run("function win { %s; }; win 2>/dev/null >/dev/null && echo yes || echo no" % win_commands) == "yes\n"
|
||||
var won = true
|
||||
for r in repos:
|
||||
var repo = repos[r]
|
||||
if repo.win_commands != "":
|
||||
game.global_shell.cd(repo.path)
|
||||
if not game.global_shell.run("function win { %s\n}; win 2>/dev/null >/dev/null && echo yes || echo no" % repo.win_commands) == "yes\n":
|
||||
won = false
|
||||
return won
|
||||
|
|
32
levels/top-down/pull-merge-push
Normal file
32
levels/top-down/pull-merge-push
Normal file
|
@ -0,0 +1,32 @@
|
|||
title = A pull and a conflict
|
||||
author = blinry
|
||||
|
||||
[description]
|
||||
|
||||
You want to push your new commits to the server, but someone has already pushed their own changes.
|
||||
|
||||
In this situation, you need to pull first! Try that here - you'll have to resolve a merge conflict. Push your changes afterwards.
|
||||
|
||||
[congrats]
|
||||
|
||||
Good job! Here's some additional info: banana!
|
||||
|
||||
[setup yours]
|
||||
|
||||
echo fu > file
|
||||
git add .
|
||||
git commit -m "Initial commit"
|
||||
git push
|
||||
|
||||
echo fi > file
|
||||
git commit -a -m "Fi is good"
|
||||
|
||||
[setup origin]
|
||||
|
||||
echo fa > file
|
||||
git add .
|
||||
git commit -a -m "Fa is good"
|
||||
|
||||
[win origin]
|
||||
|
||||
test "$(git rev-parse HEAD^1^)" = "$(git rev-parse HEAD^2^)"
|
30
main.gd
30
main.gd
|
@ -8,8 +8,8 @@ var current_level
|
|||
onready var terminal = $Columns/RightSide/Terminal
|
||||
onready var input = terminal.input
|
||||
onready var output = terminal.output
|
||||
onready var goal_repository = $Columns/Repositories/GoalRepository
|
||||
onready var active_repository = $Columns/Repositories/ActiveRepository
|
||||
onready var repositories_node = $Columns/Repositories
|
||||
var repositories = {}
|
||||
onready var level_select = $Columns/RightSide/TopStuff/Menu/LevelSelect
|
||||
onready var chapter_select = $Columns/RightSide/TopStuff/Menu/ChapterSelect
|
||||
onready var next_level_button = $Columns/RightSide/TopStuff/Menu/NextLevelButton
|
||||
|
@ -57,17 +57,26 @@ func load_level(level_id):
|
|||
AudioServer.set_bus_mute(AudioServer.get_bus_index("Master"), true)
|
||||
|
||||
levels.chapters[current_chapter].levels[current_level].construct()
|
||||
|
||||
var goal_repository_path = game.tmp_prefix_inside+"/repos/goal/"
|
||||
var active_repository_path = game.tmp_prefix_inside+"/repos/active/"
|
||||
|
||||
var level = levels.chapters[current_chapter].levels[current_level]
|
||||
level_description.bbcode_text = level.description
|
||||
level_congrats.bbcode_text = level.congrats
|
||||
level_name.text = level.slug
|
||||
|
||||
goal_repository.path = goal_repository_path
|
||||
active_repository.path = active_repository_path
|
||||
for r in repositories_node.get_children():
|
||||
r.queue_free()
|
||||
repositories = {}
|
||||
|
||||
for r in level.repos:
|
||||
var repo = level.repos[r]
|
||||
var new_repo = preload("res://repository.tscn").instance()
|
||||
new_repo.path = repo.path
|
||||
new_repo.label = repo.slug
|
||||
new_repo.size_flags_horizontal = SIZE_EXPAND_FILL
|
||||
repositories_node.add_child(new_repo)
|
||||
repositories[r] = new_repo
|
||||
|
||||
terminal.repository = repositories[repositories.keys()[0]]
|
||||
terminal.clear()
|
||||
|
||||
# Unmute the audio after a while, so that player can hear pop sounds for
|
||||
|
@ -81,6 +90,7 @@ func load_level(level_id):
|
|||
# FIXME: Need to clean these up when switching levels somehow.
|
||||
|
||||
func reload_level():
|
||||
levels.reload()
|
||||
load_level(current_level)
|
||||
|
||||
func load_next_level():
|
||||
|
@ -104,6 +114,10 @@ func repopulate_chapters():
|
|||
for c in levels.chapters:
|
||||
chapter_select.add_item(c.slug)
|
||||
|
||||
func check_win_condition():
|
||||
func update_repos():
|
||||
for r in repositories:
|
||||
var repo = repositories[r]
|
||||
repo.update_everything()
|
||||
|
||||
if levels.chapters[current_chapter].levels[current_level].check_win():
|
||||
show_win_status()
|
||||
|
|
25
main.tscn
25
main.tscn
|
@ -1,8 +1,7 @@
|
|||
[gd_scene load_steps=10 format=2]
|
||||
[gd_scene load_steps=9 format=2]
|
||||
|
||||
[ext_resource path="res://terminal.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://main.gd" type="Script" id=2]
|
||||
[ext_resource path="res://repository.tscn" type="PackedScene" id=3]
|
||||
[ext_resource path="res://styles/alert_button.tres" type="StyleBox" id=4]
|
||||
[ext_resource path="res://tcp_server.tscn" type="PackedScene" id=5]
|
||||
[ext_resource path="res://styles/theme.tres" type="Theme" id=6]
|
||||
|
@ -65,26 +64,6 @@ __meta__ = {
|
|||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="GoalRepository" parent="Columns/Repositories" instance=ExtResource( 3 )]
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_right = 633.0
|
||||
margin_bottom = 1070.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
label = "Goal"
|
||||
file_browser_active = false
|
||||
|
||||
[node name="ActiveRepository" parent="Columns/Repositories" instance=ExtResource( 3 )]
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = 633.0
|
||||
margin_right = 1267.0
|
||||
margin_bottom = 1070.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
label = "Your repository"
|
||||
|
||||
[node name="RightSide" type="VSplitContainer" parent="Columns"]
|
||||
margin_left = 1279.0
|
||||
margin_right = 1910.0
|
||||
|
@ -192,7 +171,6 @@ margin_top = 541.0
|
|||
margin_right = 631.0
|
||||
margin_bottom = 1070.0
|
||||
size_flags_vertical = 3
|
||||
repository_path = NodePath("../../../Columns/Repositories/ActiveRepository")
|
||||
|
||||
[node name="Test" type="Node2D" parent="."]
|
||||
visible = false
|
||||
|
@ -213,4 +191,5 @@ __meta__ = {
|
|||
[connection signal="button_down" from="Columns/RightSide/TopStuff/Menu/LevelSelect" to="." method="repopulate_levels"]
|
||||
[connection signal="pressed" from="Columns/RightSide/TopStuff/Menu/ReloadButton" to="." method="reload_level"]
|
||||
[connection signal="pressed" from="Columns/RightSide/TopStuff/Menu/NextLevelButton" to="." method="load_next_level"]
|
||||
[connection signal="command_done" from="Columns/RightSide/Terminal" to="." method="update_repos"]
|
||||
[connection signal="text_entered" from="Test/LineEdit" to="Test" method="send"]
|
||||
|
|
|
@ -20,6 +20,11 @@ _global_script_classes=[ {
|
|||
"path": "res://level.gd"
|
||||
}, {
|
||||
"base": "Node",
|
||||
"class": "LevelRepo",
|
||||
"language": "GDScript",
|
||||
"path": "res://level_repo.gd"
|
||||
}, {
|
||||
"base": "Node",
|
||||
"class": "Shell",
|
||||
"language": "GDScript",
|
||||
"path": "res://shell.gd"
|
||||
|
@ -27,6 +32,7 @@ _global_script_classes=[ {
|
|||
_global_script_class_icons={
|
||||
"Chapter": "",
|
||||
"Level": "",
|
||||
"LevelRepo": "",
|
||||
"Shell": ""
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,9 @@ func _ready():
|
|||
set_file_browser_active(file_browser_active)
|
||||
set_simplified_view(simplified_view)
|
||||
set_editable_path(editable_path)
|
||||
set_path(path)
|
||||
|
||||
update_everything()
|
||||
|
||||
func _process(_delta):
|
||||
nodes.rect_pivot_offset = nodes.rect_size / 2
|
||||
|
@ -44,7 +47,8 @@ func there_is_a_git():
|
|||
return shell.run("test -d .git && echo yes || echo no") == "yes\n"
|
||||
|
||||
func update_everything():
|
||||
file_browser.update()
|
||||
if file_browser:
|
||||
file_browser.update()
|
||||
if there_is_a_git():
|
||||
update_head()
|
||||
update_refs()
|
||||
|
@ -52,19 +56,22 @@ func update_everything():
|
|||
update_objects()
|
||||
remove_gone_stuff()
|
||||
else:
|
||||
index.text = ""
|
||||
if index:
|
||||
index.text = ""
|
||||
for o in objects:
|
||||
objects[o].queue_free()
|
||||
objects = {}
|
||||
|
||||
func set_path(new_path):
|
||||
path = new_path
|
||||
path_node.text = path
|
||||
if path_node:
|
||||
path_node.text = path
|
||||
shell.cd(new_path)
|
||||
for o in objects.values():
|
||||
o.queue_free()
|
||||
objects = {}
|
||||
update_everything()
|
||||
if is_inside_tree():
|
||||
update_everything()
|
||||
|
||||
func get_path():
|
||||
return path
|
||||
|
|
|
@ -25,7 +25,7 @@ __meta__ = {
|
|||
|
||||
[node name="RepoVis" type="Control" parent="Rows"]
|
||||
margin_right = 1920.0
|
||||
margin_bottom = 994.0
|
||||
margin_bottom = 925.0
|
||||
mouse_filter = 1
|
||||
size_flags_vertical = 3
|
||||
__meta__ = {
|
||||
|
@ -110,11 +110,11 @@ __meta__ = {
|
|||
[node name="FileBrowser" parent="Rows" instance=ExtResource( 4 )]
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_top = 1006.0
|
||||
margin_top = 937.0
|
||||
margin_right = 1920.0
|
||||
margin_bottom = 1080.0
|
||||
size_flags_vertical = 3
|
||||
size_flags_stretch_ratio = 0.08
|
||||
size_flags_stretch_ratio = 0.16
|
||||
[connection signal="mouse_entered" from="." to="." method="_on_mouse_entered"]
|
||||
[connection signal="mouse_exited" from="." to="." method="_on_mouse_exited"]
|
||||
[connection signal="pressed" from="Rows/RepoVis/Button" to="." method="update_everything"]
|
||||
|
|
|
@ -49,4 +49,3 @@ margin_left = 961.0
|
|||
margin_right = 1910.0
|
||||
margin_bottom = 1070.0
|
||||
size_flags_horizontal = 3
|
||||
repository_path = NodePath("../../Columns/Repository")
|
||||
|
|
19
terminal.gd
19
terminal.gd
|
@ -1,5 +1,7 @@
|
|||
extends Control
|
||||
|
||||
signal command_done
|
||||
|
||||
var thread
|
||||
|
||||
var history_position = 0
|
||||
|
@ -9,8 +11,8 @@ var git_commands_help = []
|
|||
onready var input = $Rows/InputLine/Input
|
||||
onready var output = $Rows/TopHalf/Output
|
||||
onready var completions = $Rows/TopHalf/Completions
|
||||
export(NodePath) var repository_path
|
||||
onready var repository = get_node(repository_path)
|
||||
#export(NodePath) var repository_path
|
||||
var repository
|
||||
onready var command_dropdown = $Rows/InputLine/CommandDropdown
|
||||
onready var main = get_tree().get_root().get_node("Main")
|
||||
|
||||
|
@ -32,13 +34,13 @@ func _ready():
|
|||
helpers.crash("Could not connect TextEditor's hide signal")
|
||||
input.grab_focus()
|
||||
|
||||
var all_git_commands = repository.shell.run("git help -a | grep \"^ \\+[a-z-]\\+ \" -o")
|
||||
var all_git_commands = game.global_shell.run("git help -a | grep \"^ \\+[a-z-]\\+ \" -o")
|
||||
git_commands = Array(all_git_commands.split("\n"))
|
||||
for i in range(git_commands.size()):
|
||||
git_commands[i] = git_commands[i].strip_edges(true, true)
|
||||
git_commands.pop_back()
|
||||
|
||||
var all_git_commands_help = repository.shell.run("git help -a | grep \" [A-Z].\\+$\" -o")
|
||||
var all_git_commands_help = game.global_shell.run("git help -a | grep \" [A-Z].\\+$\" -o")
|
||||
git_commands_help = Array(all_git_commands_help.split("\n"))
|
||||
for i in range(git_commands_help.size()):
|
||||
git_commands_help[i] = git_commands_help[i].strip_edges(true, true)
|
||||
|
@ -95,18 +97,17 @@ func send_command_async(command):
|
|||
func run_command_in_a_thread(command):
|
||||
var o = repository.shell.run(command, false)
|
||||
|
||||
if main:
|
||||
main.check_win_condition()
|
||||
|
||||
input.text = ""
|
||||
input.editable = true
|
||||
|
||||
if o.length() <= 200:
|
||||
if o.length() <= 1000:
|
||||
output.text = output.text + "$ " + command + "\n" + o
|
||||
else:
|
||||
$Pager/Text.text = o
|
||||
$Pager.popup()
|
||||
repository.update_everything()
|
||||
|
||||
emit_signal("command_done")
|
||||
#repository.update_everything()
|
||||
|
||||
func receive_output(text):
|
||||
output.text += text
|
||||
|
|
|
@ -110,7 +110,6 @@ syntax_highlighting = false
|
|||
[node name="TCPServer" parent="." instance=ExtResource( 3 )]
|
||||
|
||||
[node name="Pager" type="WindowDialog" parent="."]
|
||||
visible = true
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = 18.0
|
||||
|
|
|
@ -15,13 +15,13 @@ func _process(_delta):
|
|||
_client_connection = _server.take_connection()
|
||||
var length = _client_connection.get_u8()
|
||||
var filename = _client_connection.get_string(length)
|
||||
filename = filename.replace("%srepos/active/" % game.tmp_prefix_inside, "")
|
||||
filename = filename.replace("%srepos/" % game.tmp_prefix_inside, "")
|
||||
open(filename)
|
||||
|
||||
func open(filename):
|
||||
path = filename
|
||||
|
||||
var fixme_path = game.tmp_prefix_outside+"/repos/active/"
|
||||
var fixme_path = game.tmp_prefix_outside+"repos/"
|
||||
var content = helpers.read_file(fixme_path+filename)
|
||||
text = content
|
||||
|
||||
|
@ -29,7 +29,7 @@ func open(filename):
|
|||
grab_focus()
|
||||
|
||||
func save():
|
||||
var fixme_path = game.tmp_prefix_outside+"/repos/active/"
|
||||
var fixme_path = game.tmp_prefix_outside+"repos/"
|
||||
helpers.write_file(fixme_path+path, text)
|
||||
close()
|
||||
|
||||
|
|
Loading…
Reference in a new issue