Skip to content

Commit

Permalink
Merge pull request #351 from betwixt-labs/chord-changes
Browse files Browse the repository at this point in the history
feat(extensions): General Availability
  • Loading branch information
andrewmd5 authored Sep 27, 2024
2 parents 3142efb + df6b89c commit 4c81283
Show file tree
Hide file tree
Showing 39 changed files with 2,017 additions and 398 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -295,3 +295,5 @@ go.work
dist
*.chord
playground/src/bebopc/bebopc.bin
*.tgz
extensions/edks/typescript/javy-cli
2 changes: 1 addition & 1 deletion Core/Exceptions/Exceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ public MultipleDecoratorsException(string identifier, Span span, string? hint =
class InvalidDecoratorUsageException : SpanException
{
public InvalidDecoratorUsageException(string identifier, string reason, Span span, string? hint = null)
: base($"Decorator '{identifier}' cannot be applied to this target: {reason}." + (string.IsNullOrWhiteSpace(hint) ? "" : $" (Hint: {hint})"), span, 141)
: base(reason + (string.IsNullOrWhiteSpace(hint) ? "" : $" (Hint: {hint})"), span, 141)
{ }
}
class DecoratorValidationException : SpanException
Expand Down
26 changes: 23 additions & 3 deletions Core/Meta/BebopSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,11 @@ private readonly List<SpanException> ValidateDefinitionDecorators(List<SchemaDec
{
if (!decorator.IsUsableOn())
{
validationErrors.Add(new InvalidDecoratorUsageException(decorator.Identifier, $"Decorator '{decorator.Identifier}' cannot be applied to {definition.Name.ToLowerInvariant()} '{definition.Name}'", decorator.Span));
validationErrors.Add(new InvalidDecoratorUsageException(decorator.Identifier,
$"Invalid usage of decorator '{decorator.Identifier}' on '{definition.Name}'. " +
$"This decorator can only be applied to {decorator.GetValidTargetsString()}.",
decorator.Span
));
}
if (!decorator.Definition.TryValidate(out var reason, decorator))
{
Expand Down Expand Up @@ -165,8 +169,24 @@ private static List<SpanException> ValidateFieldDecorators(List<SchemaDecorator>

if (!decorator.IsUsableOn())
{
var hint = parent is StructDefinition && decorator.Identifier == "deprecated" ? "deprecated decorator cannot be applied to struct fields" : "";
validationErrors.Add(new InvalidDecoratorUsageException(decorator.Identifier, $"Decorator '{decorator.Identifier}' cannot be applied to '{parent.Name}.{field.Name}'", decorator.Span, hint));
string validTargets = decorator.GetValidTargetsString();
string currentTarget = $"field '{parent.Name}.{field.Name}'";
string baseMessage = $"Invalid usage of decorator '{decorator.Identifier}' on {currentTarget}.";
string targetMessage = $"This decorator can only be applied to {validTargets}.";

string hint = "";
if (parent is StructDefinition && decorator.Identifier.Equals("deprecated", StringComparison.OrdinalIgnoreCase))
{
hint = "Note: The 'deprecated' decorator cannot be applied to struct fields.";
}

string fullMessage = string.Join(" ", new[] { baseMessage, targetMessage, hint }.Where(s => !string.IsNullOrEmpty(s)));

validationErrors.Add(new InvalidDecoratorUsageException(
decorator.Identifier,
fullMessage,
decorator.Span
));
}
if (!decorator.Definition.TryValidate(out var reason, decorator))
{
Expand Down
133 changes: 128 additions & 5 deletions Core/Meta/Decorators/SchemaDecorator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,142 @@ public bool TryGetValue(string parameter, [NotNullWhen(true)] out string? value)

public bool IsUsableOn()
{
if (Definition.Targets is DecoratorTargets.All)
if (Definition.Targets == DecoratorTargets.All)
{
if (Target.HasFlag(DecoratorTargets.Struct | DecoratorTargets.Field) && Identifier.Equals("deprecated", StringComparison.OrdinalIgnoreCase))
// Handle special case for 'deprecated' decorator
if (Target.HasFlag(DecoratorTargets.Struct | DecoratorTargets.Field) &&
Identifier.Equals("deprecated", StringComparison.OrdinalIgnoreCase))
{
return false;
}
return true;
}

if (Target == Definition.Targets)
// Separate container and member flags from Definition.Targets
var definitionContainerFlags = Definition.Targets & (DecoratorTargets.Enum | DecoratorTargets.Message | DecoratorTargets.Struct | DecoratorTargets.Union | DecoratorTargets.Service);
var definitionMemberFlags = Definition.Targets & (DecoratorTargets.Field | DecoratorTargets.Method);

// Separate container and member flags from Target
var targetContainerFlags = Target & (DecoratorTargets.Enum | DecoratorTargets.Message | DecoratorTargets.Struct | DecoratorTargets.Union | DecoratorTargets.Service);
var targetMemberFlags = Target & (DecoratorTargets.Field | DecoratorTargets.Method);

if (definitionContainerFlags != DecoratorTargets.None)
{
return true;
// Definition specifies container types
if (definitionMemberFlags != DecoratorTargets.None)
{
// Definition specifies container and member types
// Check if Target includes both the container and member types
if ((targetContainerFlags & definitionContainerFlags) != DecoratorTargets.None &&
(targetMemberFlags & definitionMemberFlags) != DecoratorTargets.None)
{
return true;
}
}
else
{
// Definition only specifies container types
// Check if Target includes the container type
if ((targetContainerFlags & definitionContainerFlags) != DecoratorTargets.None)
{
return true;
}
}
}
else if (definitionMemberFlags != DecoratorTargets.None)
{
// Definition only specifies member types
// Check if Target includes the member type
if ((targetMemberFlags & definitionMemberFlags) != DecoratorTargets.None)
{
return true;
}
}

return false;
}

public string GetValidTargetsString()
{
if (Definition.Targets == DecoratorTargets.All)
{
return "all targets";
}

var containerTargets = new List<string>();
var memberTargets = new List<string>();

bool hasEnum = Definition.Targets.HasFlag(DecoratorTargets.Enum);
bool hasMessage = Definition.Targets.HasFlag(DecoratorTargets.Message);
bool hasStruct = Definition.Targets.HasFlag(DecoratorTargets.Struct);
bool hasUnion = Definition.Targets.HasFlag(DecoratorTargets.Union);
bool hasService = Definition.Targets.HasFlag(DecoratorTargets.Service);
bool hasField = Definition.Targets.HasFlag(DecoratorTargets.Field);
bool hasMethod = Definition.Targets.HasFlag(DecoratorTargets.Method);

if (hasEnum && !hasField && !hasMethod) containerTargets.Add("enums");
if (hasMessage && !hasField && !hasMethod) containerTargets.Add("messages");
if (hasStruct && !hasField && !hasMethod) containerTargets.Add("structs");
if (hasUnion && !hasField && !hasMethod) containerTargets.Add("unions");
if (hasService && !hasField && !hasMethod) containerTargets.Add("services");

if (hasField)
{
var fieldContainers = new List<string>();
if (hasEnum) fieldContainers.Add("enums");
if (hasMessage) fieldContainers.Add("messages");
if (hasStruct) fieldContainers.Add("structs");
if (hasUnion) fieldContainers.Add("unions");

if (fieldContainers.Count > 0)
{
memberTargets.Add($"fields of {FormatTargetList(fieldContainers)}");
}
else
{
memberTargets.Add("fields");
}
}

if (hasMethod)
{
var methodContainers = new List<string>();
if (hasMessage) methodContainers.Add("messages");
if (hasService) methodContainers.Add("services");

if (methodContainers.Count > 0)
{
memberTargets.Add($"methods of {FormatTargetList(methodContainers)}");
}
else
{
memberTargets.Add("methods");
}
}

var allTargets = containerTargets.Concat(memberTargets).ToList();

if (allTargets.Count == 0)
{
return "no targets";
}
else
{
return FormatTargetList(allTargets);
}
}

private static string FormatTargetList(List<string> targets)
{
if (targets.Count == 1)
{
return targets[0];
}
else
{
string lastTarget = targets[targets.Count - 1];
targets.RemoveAt(targets.Count - 1);
return string.Join(", ", targets) + " and " + lastTarget;
}
return Definition.Targets.HasFlag(Target);
}
}
76 changes: 43 additions & 33 deletions Tools/bash/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -269,13 +269,13 @@ ${ERROR_UTF8}
EOABORT
)"
fi

}

fetch_release_url() {
fetch_release_urls() {
local target_os_name="$1"
local target_os_arch="$2"
readonly target="bebopc-${target_os_name}-${target_os_arch}.zip"
readonly bebopc_target="bebopc-${target_os_name}-${target_os_arch}.zip"
readonly chordc_target="chordc-${target_os_name}-${target_os_arch}.zip"
local exit_code=1
if result=$(
if [[ -x "$(which wget)" ]]; then
Expand All @@ -284,10 +284,12 @@ fetch_release_url() {
curl -fL "${BEBOP_RELEASE_URL}" 2>&1
fi
); then
local release_url
release_url="$(echo "$result" | grep -E 'browser_download_url' | grep "${target}" | cut -d '"' -f 4)"
if [[ -n "$release_url" ]]; then
echo "$release_url"
local bebopc_url
local chordc_url
bebopc_url="$(echo "$result" | grep -E 'browser_download_url' | grep "${bebopc_target}" | cut -d '"' -f 4)"
chordc_url="$(echo "$result" | grep -E 'browser_download_url' | grep "${chordc_target}" | cut -d '"' -f 4)"
if [[ -n "$bebopc_url" && -n "$chordc_url" ]]; then
echo "$bebopc_url $chordc_url"
exit 0
fi
else
Expand All @@ -300,11 +302,10 @@ fetch_release_url() {
abort "$(
cat <<EOABORT
${ERROR_UTF8}
- ${tty_red}Unable to locate release artifact for bebopc${tty_reset} ${tty_underline}${tty_white}$BEBOPC_VERSION${tty_reset} (exit code ${exit_code}):
- ${tty_red}Unable to locate release artifacts for bebopc and chordc${tty_reset} ${tty_underline}${tty_white}$BEBOPC_VERSION${tty_reset} (exit code ${exit_code}):
- $error_message
EOABORT
)"

}

extract() {
Expand All @@ -314,7 +315,7 @@ extract() {
abort "$(
cat <<EOABORT
${ERROR_UTF8}
- ${tty_red}Failed to install bebopc to ${BEBOPC_PREFIX}/bin${tty_reset}:
- ${tty_red}Failed to install to ${BEBOPC_PREFIX}/bin${tty_reset}:
- ${result}
EOABORT
)"
Expand Down Expand Up @@ -416,48 +417,57 @@ else
echo "- ${BEBOPC_PREFIX}/bin/bebopc"
fi

point "${UNICORN_UTF8} Downloading and installing bebopc (${BEBOPC_VERSION})..."
point "${UNICORN_UTF8} Downloading and installing Bebop (${BEBOPC_VERSION})..."
(
echo -ne "- ${tty_bold}Locating releases${tty_reset} "

echo -ne "- ${tty_bold}Locating release${tty_reset} "

if ! release_url=$(fetch_release_url "$os" "$os_arch"); then
# should be the error if fetch_release_url failed
abort "$release_url"
if ! release_urls=$(fetch_release_urls "$os" "$os_arch"); then
# should be the error if fetch_release_urls failed
abort "$release_urls"
fi

read -r bebopc_url chordc_url <<<"$release_urls"

echo -e "${SUCCESS_UTF8}"

echo -ne "- ${tty_bold}Creating temp file${tty_reset} "
echo -ne "- ${tty_bold}Creating temp files${tty_reset} "

temp_file=$(mktemp)
readonly temp_file
# Bail out if the temp file wasn't created successfully.
if [ ! -e "$temp_file" ]; then
bebopc_temp_file=$(mktemp)
chordc_temp_file=$(mktemp)
readonly bebopc_temp_file chordc_temp_file
# Bail out if the temp files weren't created successfully.
if [ ! -e "$bebopc_temp_file" ] || [ ! -e "$chordc_temp_file" ]; then
abort "$(
cat <<EOABORT
${ERROR_UTF8}
${tty_red}Failed to create temporary file${tty_reset}
${tty_red}Failed to create temporary files${tty_reset}
EOABORT
)"
fi

echo -e "${SUCCESS_UTF8}"
echo -ne "- ${tty_bold}Downloading${tty_reset} "
echo -ne "- ${tty_bold}Downloading bebopc${tty_reset} "

download "${bebopc_url}" "${bebopc_temp_file}"

echo -e "${SUCCESS_UTF8}"
echo -ne "- ${tty_bold}Downloading chordc${tty_reset} "

download "${release_url}" "${temp_file}"
download "${chordc_url}" "${chordc_temp_file}"

echo -e "${SUCCESS_UTF8}"
echo -ne "- ${tty_bold}Installing bebopc "
echo -ne "- ${tty_bold}Installing bebopc and chordc "

extract "${temp_file}" "${BEBOPC_PREFIX}/bin"
extract "${bebopc_temp_file}" "${BEBOPC_PREFIX}/bin"
extract "${chordc_temp_file}" "${BEBOPC_PREFIX}/bin"

BEBOPC_PATH="${BEBOPC_PREFIX}/bin/bebopc"
if [ ! -f "${BEBOPC_PATH}" ]; then
CHORDC_PATH="${BEBOPC_PREFIX}/bin/chordc"
if [ ! -f "${BEBOPC_PATH}" ] || [ ! -f "${CHORDC_PATH}" ]; then
abort "$(
cat <<EOABORT
${ERROR_UTF8}
${tty_red}Could not locate \`${BEBOPC_PATH}\` after installation${tty_reset}
${tty_red}Could not locate \`${BEBOPC_PATH}\` or \`${CHORDC_PATH}\` after installation${tty_reset}
EOABORT
)"
fi
Expand All @@ -466,7 +476,7 @@ EOABORT

if [[ ":${PATH}:" != *":${BEBOPC_PREFIX}/bin:"* ]]; then
warn "${tty_underline}${tty_white}${BEBOPC_PREFIX}/bin${tty_reset} is not in your ${tty_underline}${tty_white}PATH${tty_reset}.
Instructions on how to configure your shell for bebopc
Instructions on how to configure your shell for bebopc and chordc
can be found in the 'Next steps' section below."
fi

Expand Down Expand Up @@ -500,17 +510,17 @@ EOS

point "${HAPPY_UTF8} Next steps:"
readonly additional_shellenv_commands="export PATH=\$PATH:$BEBOPC_PREFIX/bin"
echo "- Run this command in your terminal to add bebopc to your ${tty_underline}${tty_white}PATH${tty_reset}:"
echo "- Run this command in your terminal to add bebopc and chordc to your ${tty_underline}${tty_white}PATH${tty_reset}:"
printf "${tty_bold}${tty_white} echo '%s' >> ${shell_profile}${tty_reset}\n" "${additional_shellenv_commands[@]}"
printf "${tty_bold}${tty_white} %s${tty_reset}\n" "${additional_shellenv_commands[@]}"
if [[ ! -x "$BEBOPC_PATH" ]]; then
printf "${tty_bold}${tty_white} %s${tty_reset}\n" "sudo chmod +x ${BEBOPC_PATH}"
if [[ ! -x "$BEBOPC_PATH" ]] || [[ ! -x "$CHORDC_PATH" ]]; then
printf "${tty_bold}${tty_white} %s${tty_reset}\n" "sudo chmod +x ${BEBOPC_PATH} ${CHORDC_PATH}"
fi

cat <<EOS
- Run ${tty_bold}bebopc --help${tty_reset} to get started
- Further documentation:
${tty_underline}${tty_white}https://github.com/betwixt-labs/bebop/wiki${tty_reset}
${tty_underline}${tty_white}https://docs.bebop.sh${tty_reset}
EOS

) ||
Expand Down
Loading

0 comments on commit 4c81283

Please sign in to comment.