#define _POSIX_C_SOURCE 200809L
#include "macoraone.h"
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/stat.h>
#include <unistd.h>
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
#define R "\033[0m"
#define G "\033[32m"
#define Y "\033[33m"
#define B "\033[34m"
#define C "\033[36m"
#define ROOT ".macoraone"
#define PROJECT_ROOT "MacoraOne"
#define TEMPLATE "https://github.com/dominexmacedon-docs/NativeFlexi-android.git"
static void info(const char*f,...){va_list a;va_start(a,f);printf("%s[MacoraOne]%s ",C,R);vprintf(f,a);printf("\n");va_end(a);}
static void good(const char*f,...){va_list a;va_start(a,f);printf("%s[OK]%s ",G,R);vprintf(f,a);printf("\n");va_end(a);}
static void warnx(const char*f,...){va_list a;va_start(a,f);printf("%s[WARN]%s ",Y,R);vprintf(f,a);printf("\n");va_end(a);}
static void bad(const char*f,...){va_list a;va_start(a,f);fprintf(stderr,"\033[31m[ERROR]%s ",R);vfprintf(stderr,f,a);fprintf(stderr,"\n");va_end(a);}
static const char*home(void){const char*p=getenv("HOME");return p&&*p?p:".";}
static void root(char*o,size_t n){const char*p=getenv("MACORAONE_HOME");if(p&&*p)snprintf(o,n,"%s",p);else snprintf(o,n,"%s/%s",home(),ROOT);}
static void dirs(char*c,size_t n,char*p,size_t m){char r[PATH_MAX];root(r,sizeof(r));snprintf(c,n,"%s/components",r);snprintf(p,m,"%s/%s/projects",home(),PROJECT_ROOT);}
int macora_exists(const char*p){struct stat s;return p&&stat(p,&s)==0;}
int macora_is_directory(const char*p){struct stat s;return p&&stat(p,&s)==0&&S_ISDIR(s.st_mode);}
int macora_mkdir_p(const char*x){char b[PATH_MAX],*p;if(!x||!*x)return -1;if(macora_is_directory(x))return 0;snprintf(b,sizeof(b),"%s",x);for(p=b+1;*p;p++)if(*p=='/'){*p=0;if(*b&&mkdir(b,0755)&&errno!=EEXIST)return -1;*p='/';}return mkdir(b,0755)==0||errno==EEXIST?0:-1;}
int macora_run(const char*c,int v){if(v)printf("%s>%s %s\n",B,R,c);fflush(stdout);return system(c);}
int macora_command(const char*c,char*o,size_t n){FILE*f;size_t u=0;if(!o||!n)return -1;o[0]=0;f=popen(c,"r");if(!f)return -1;while(u+1<n&&fgets(o+u,(int)(n-u),f))u=strlen(o);if(pclose(f)!=0)return -1;while(u&&(o[u-1]=='\n'||o[u-1]=='\r'))o[--u]=0;return 0;}
static void q(const char*s,char*d,size_t n){size_t u=0;if(!n)return;d[u++]='\'';while(s&&*s&&u+5<n){if(*s=='\''){memcpy(d+u,"'\\''",4);u+=4;}else d[u++]=*s;s++;}if(u+1<n)d[u++]='\'';d[u]=0;}
int macora_remove_tree(const char*p){char a[PATH_MAX*2],c[PATH_MAX*2+32];if(!p||!macora_exists(p))return 0;q(p,a,sizeof(a));snprintf(c,sizeof(c),"rm -rf -- %s",a);return macora_run(c,0);}
int macora_copy_tree(const char*s,const char*d){char a[PATH_MAX*2],b[PATH_MAX*2],c[PATH_MAX*4+64];if(!macora_is_directory(s)||macora_mkdir_p(d))return -1;q(s,a,sizeof(a));q(d,b,sizeof(b));snprintf(c,sizeof(c),"cp -a %s/. %s/",a,b);return macora_run(c,1);}
int macora_validate_name(const char*n){const unsigned char*p;if(!n||!*n||strlen(n)>100||!strcmp(n,".")||!strcmp(n,".."))return 0;for(p=(const unsigned char*)n;*p;p++)if(!(isalnum(*p)||*p=='-'||*p=='_'||*p=='.'))return 0;return 1;}
int macora_open_url(const char*u){char a[2048],c[4096];q(u,a,sizeof(a));snprintf(c,sizeof(c),"xdg-open %s >/dev/null 2>&1 || sensible-browser %s >/dev/null 2>&1",a,a);return macora_run(c,0);}
static int have(const char*n){char c[256];snprintf(c,sizeof(c),"command -v %s >/dev/null 2>&1",n);return system(c)==0;}
static int logged(void){return system("gh auth status >/dev/null 2>&1")==0;}
int macora_authenticate(void){char a[16];if(!have("gh")){bad("GitHub CLI 'gh' is required.");return -1;}if(logged())return 0;printf("Do you have a GitHub account? [Y/n]: ");fflush(stdout);if(!fgets(a,sizeof(a),stdin))return -1;if(tolower((unsigned char)a[0])=='n'){macora_open_url("https://github.com/signup");info("Create the account, then run this command again.");return -1;}info("Starting GitHub browser authorization. MacoraOne never asks for your GitHub password.");if(macora_run("gh auth login --hostname github.com --git-protocol https --web",1)||!logged()){bad("GitHub browser authorization was not completed.");return -1;}good("GitHub authorization completed.");return 0;}
static int clone_clean(const char*u,const char*d){char a[2048],b[PATH_MAX*2],c[PATH_MAX*2+4096];if(macora_exists(d)&&macora_remove_tree(d))return -1;q(u,a,sizeof(a));q(d,b,sizeof(b));snprintf(c,sizeof(c),"git clone --depth 1 %s %s",a,b);return macora_run(c,1);}
int macora_install(void){const MacoraRepository x[]={{"greenServeFE-build","https://github.com/dominexmacedon-docs/greenServeFE-build.git"},{"greenServeFE-","https://github.com/dominexmacedon-docs/greenServeFE-.git"},{"CMLL-build","https://github.com/dominexmacedon-docs/CMLL-build.git"},{"CMLL","https://github.com/dominexmacedon-docs/CMLL.git"},{"NativeFlexi","https://github.com/dominexmacedon-docs/NativeFlexi.git"},{"NativeFlexi-android",TEMPLATE}};char co[PATH_MAX],pr[PATH_MAX],d[PATH_MAX],r[PATH_MAX];size_t i;if(!have("git")){bad("git is required.");return 1;}dirs(co,sizeof(co),pr,sizeof(pr));root(r,sizeof(r));if(macora_mkdir_p(r)||macora_mkdir_p(co)||macora_mkdir_p(pr))return 1;for(i=0;i<sizeof(x)/sizeof(x[0]);i++){snprintf(d,sizeof(d),"%s/%s",co,x[i].name);if(clone_clean(x[i].url,d)){bad("Could not install %s.",x[i].name);return 1;}good("Installed %s.",x[i].name);}good("MacoraOne components refreshed at %s.",r);return 0;}
int macora_uninstall(void){char r[PATH_MAX];root(r,sizeof(r));if(macora_remove_tree(r)){bad("Could not remove %s.",r);return 1;}good("MacoraOne managed data removed.");return 0;}
static const char*folder(MacoraLanguage l){return l==MACORAONE_KOTLIN?"NativeFlexi-kotlin":"NativeFlexi-java";}
static const char*workflow(MacoraLanguage l){return l==MACORAONE_KOTLIN?"android-kotlin.yml":"android-java.yml";}
static int choose(MacoraLanguage*l){char a[32];printf("Choose Android implementation:\n  1) Kotlin based\n  2) Java based\nChoice [1/2]: ");fflush(stdout);if(!fgets(a,sizeof(a),stdin))return -1;if(a[0]=='1'||!strncasecmp(a,"kotlin",6)){*l=MACORAONE_KOTLIN;return 0;}if(a[0]=='2'||!strncasecmp(a,"java",4)){*l=MACORAONE_JAVA;return 0;}bad("Invalid language selection.");return -1;}
static int marker_write(const char*d,MacoraLanguage l){char p[PATH_MAX];FILE*f;snprintf(p,sizeof(p),"%s/.macoraone-language",d);f=fopen(p,"w");if(!f)return -1;fprintf(f,"%s\n",l==MACORAONE_KOTLIN?"kotlin":"java");fclose(f);return 0;}
static int marker_read(const char*d,MacoraLanguage*l){char p[PATH_MAX],v[32];FILE*f;snprintf(p,sizeof(p),"%s/.macoraone-language",d);f=fopen(p,"r");if(!f||!fgets(v,sizeof(v),f)){if(f)fclose(f);return -1;}fclose(f);if(!strncmp(v,"kotlin",6))*l=MACORAONE_KOTLIN;else if(!strncmp(v,"java",4))*l=MACORAONE_JAVA;else return -1;return 0;}
static int rename_project(const char*d,const char*n){char a[PATH_MAX*2],c[PATH_MAX*4+1024];q(d,a,sizeof(a));snprintf(c,sizeof(c),"find %s -type f \\( -name '*.gradle' -o -name '*.gradle.kts' -o -name '*.kts' -o -name '*.java' -o -name '*.kt' -o -name '*.xml' -o -name '*.properties' -o -name '*.md' -o -name '*.json' \\) -exec sed -i -e 's/NativeFlexi-android/%s/g' -e 's/NativeFlexi-kotlin/%s/g' -e 's/NativeFlexi-java/%s/g' -e 's/NativeFlexi/%s/g' {} +",a,n,n,n,n);return macora_run(c,0);}
static int workflow_copy(const char*t,const char*d,MacoraLanguage l,const char*n){char s[PATH_MAX],w[PATH_MAX],dst[PATH_MAX],a[PATH_MAX*2],b[PATH_MAX*2],c[PATH_MAX*4+2048];snprintf(s,sizeof(s),"%s/.github/workflows/%s",t,workflow(l));snprintf(w,sizeof(w),"%s/.github/workflows",d);snprintf(dst,sizeof(dst),"%s/%s",w,workflow(l));if(macora_mkdir_p(w))return -1;q(s,a,sizeof(a));q(dst,b,sizeof(b));if(l==MACORAONE_KOTLIN)snprintf(c,sizeof(c),"cp %s %s && sed -i -e 's|working-directory: NativeFlexi-kotlin|working-directory: .|g' -e 's|NativeFlexi-kotlin/app|app|g' -e 's|NativeFlexi-kotlin|%s|g' -e 's|NativeFlexi-android|%s|g' -e 's|NativeFlexi|%s|g' %s",a,b,n,n,n,b);else snprintf(c,sizeof(c),"cp %s %s && sed -i -e 's|working-directory: NativeFlexi-java|working-directory: .|g' -e 's|NativeFlexi-java/app|app|g' -e 's|NativeFlexi-java|%s|g' -e 's|NativeFlexi-android|%s|g' -e 's|NativeFlexi|%s|g' %s",a,b,n,n,n,b);return macora_run(c,0);}
static int git_identity(const char*app){char login[256],uid[256],email[512],c[PATH_MAX+2048],qapp[PATH_MAX*2],qname[512],qemail[1024];if(macora_command("gh api user -q .login",login,sizeof(login))||!login[0]){bad("Could not determine the authenticated GitHub user with gh api user.");return -1;}if(macora_command("gh api user -q .id",uid,sizeof(uid))||!uid[0]){bad("Could not determine the authenticated GitHub user ID.");return -1;}snprintf(email,sizeof(email),"%s+%s@users.noreply.github.com",uid,login);q(app,qapp,sizeof(qapp));q(login,qname,sizeof(qname));q(email,qemail,sizeof(qemail));snprintf(c,sizeof(c),"git -C %s config user.name %s && git -C %s config user.email %s",qapp,qname,qapp,qemail);if(macora_run(c,1))return -1;good("Configured local Git identity for %s.",login);return 0;}
int macora_create(const char*n){char co[PATH_MAX],pr[PATH_MAX],t[PATH_MAX],app[PATH_MAX],sel[PATH_MAX],other[PATH_MAX],c[PATH_MAX*3+2048],login[256];MacoraLanguage l;if(!macora_validate_name(n)){bad("Invalid AppName.");return 1;}if(macora_authenticate()||choose(&l))return 1;dirs(co,sizeof(co),pr,sizeof(pr));if(macora_mkdir_p(pr))return 1;snprintf(t,sizeof(t),"%s/NativeFlexi-android",co);info("Refreshing NativeFlexi-android template.");if(clone_clean(TEMPLATE,t)){bad("Template download failed.");return 1;}snprintf(app,sizeof(app),"%s/%s",pr,n);if(macora_exists(app)&&macora_remove_tree(app))return 1;if(macora_mkdir_p(app))return 1;snprintf(sel,sizeof(sel),"%s/%s",t,folder(l));if(!macora_is_directory(sel)){bad("Template is missing %s.",folder(l));macora_remove_tree(app);return 1;}info("Copying selected %s template.",l==MACORAONE_KOTLIN?"Kotlin":"Java");if(macora_copy_tree(sel,app)){bad("Could not copy selected Android template.");macora_remove_tree(app);return 1;}if(workflow_copy(t,app,l,n)){bad("Could not copy selected workflow.");macora_remove_tree(app);return 1;}snprintf(other,sizeof(other),"%s/%s",app,l==MACORAONE_KOTLIN?"NativeFlexi-java":"NativeFlexi-kotlin");if(macora_exists(other))macora_remove_tree(other);if(rename_project(app,n))warnx("Some NativeFlexi names could not be renamed.");if(marker_write(app,l))return 1;char qa[PATH_MAX*2];q(app,qa,sizeof(qa));snprintf(c,sizeof(c),"git -C %s init",qa);if(macora_run(c,1))return 1;if(git_identity(app))return 1;snprintf(c,sizeof(c),"git -C %s branch -M main && git -C %s add -A && git -C %s commit -m 'Create Android app'",qa,qa,qa);if(macora_run(c,1))return 1;info("Creating GitHub repository '%s'.",n);char qn[512],qremote[PATH_MAX*2];q(n,qn,sizeof(qn));q(app,qremote,sizeof(qremote));snprintf(c,sizeof(c),"gh repo create %s --public --source %s --remote origin --push",qn,qremote);if(macora_run(c,1))warnx("GitHub repository creation/push did not complete. The local project remains available.");else {if(macora_command("gh api user -q .login",login,sizeof(login))==0&&login[0])good("Created https://github.com/%s/%s",login,n);else good("Created GitHub repository %s.",n);}info("Local project: %s",app);return 0;}
static int valid_repo(const char*r){const char*p;if(!r||!*r||strlen(r)>200)return 0;for(p=(const char*)r;*p;p++)if(!(isalnum((unsigned char)*p)||*p=='-'||*p=='_'||*p=='.'||*p=='/'))return 0;if(strstr(r,"//")||r[0]=='/'||r[strlen(r)-1]=='/')return 0;return 1;}
int macora_push(const char*a,const char*r){char co[PATH_MAX],pr[PATH_MAX],app[PATH_MAX],c[PATH_MAX*2+2048],qr[2048],qapp[PATH_MAX*2];if(!macora_validate_name(a)||!valid_repo(r)){bad("Invalid AppName or repository name.");return 1;}if(macora_authenticate())return 1;dirs(co,sizeof(co),pr,sizeof(pr));snprintf(app,sizeof(app),"%s/%s",pr,a);if(!macora_is_directory(app)){bad("AppName does not exist: %s",app);return 1;}q(app,qapp,sizeof(qapp));q(r,qr,sizeof(qr));snprintf(c,sizeof(c),"git -C %s add -A && (git -C %s commit -m 'Update application' || true) && git -C %s branch -M main && (git -C %s remote set-url origin 'https://github.com/%s.git' 2>/dev/null || git -C %s remote add origin 'https://github.com/%s.git') && git -C %s push --force origin main",qapp,qapp,qapp,qapp,r,qapp,r,qapp);return macora_run(c,1)?1:(good("Push completed."),0);}
static int latest(const char*r,const char*w,char*id,size_t n){char c[4096],qr[2048],qw[512],candidate[64];int i;q(r,qr,sizeof(qr));q(w,qw,sizeof(qw));for(i=0;i<15;i++){snprintf(c,sizeof(c),"gh run list --repo %s --workflow %s --limit 1 --json databaseId -q '.[0].databaseId'",qr,qw);if(macora_command(c,candidate,sizeof(candidate))==0&&candidate[0]){snprintf(id,n,"%s",candidate);return 0;}sleep(2);}return -1;}
static int build_status(const char*r,const char*id,char*status,size_t n){char c[4096],qr[2048],qid[256];q(r,qr,sizeof(qr));q(id,qid,sizeof(qid));snprintf(c,sizeof(c),"gh run view %s --repo %s --json status,conclusion -q '.status+\"|\"+(.conclusion // \"\")'",qid,qr);return macora_command(c,status,n);}
static int build_steps(const char*r,const char*id,char*steps,size_t n){char c[8192],qr[2048],qid[256];q(r,qr,sizeof(qr));q(id,qid,sizeof(qid));snprintf(c,sizeof(c),"gh run view %s --repo %s --json jobs --jq '.jobs[] | .steps[]? | [.name,.status,(.conclusion // \"\")] | @tsv'",qid,qr);return macora_command(c,steps,n);}
static void show_steps(const char*data,char*seen[],int*count){char buf[16384],*line,*a,*b,*d,*next;snprintf(buf,sizeof(buf),"%s",data);line=buf;while(line&&*line){next=strchr(line,'\\n');if(next)*next=0;a=strchr(line,'\\t');if(!a){line=next?next+1:NULL;continue;}*a++=0;b=strchr(a,'\\t');if(!b){line=next?next+1:NULL;continue;}*b++=0;d=b;char key[512];snprintf(key,sizeof(key),"%s\\t%s\\t%s",line,a,d);int known=0;for(int i=0;i<*count;i++)if(!strcmp(seen[i],key)){known=1;break;}if(!known&&*count<128){seen[*count]=strdup(key);(*count)++;if(!strcmp(d,"success"))printf("\033[32m[OK]\033[0m %s\\n",line);else if(!strcmp(d,"failure")||!strcmp(d,"cancelled")||!strcmp(d,"timed_out"))printf("\033[31m[ERROR]\033[0m %s — %s\\n",line,d);else if(!strcmp(a,"in_progress"))printf("\033[36m[RUN]\033[0m %s\\n",line);else if(!strcmp(a,"queued")||!strcmp(a,"waiting"))printf("\033[33m[WAIT]\033[0m %s\\n",line);}line=next?next+1:NULL;}}
static int build_failure(const char*r,const char*id){char c[8192],qr[2048],qid[256],out[8192],*line,*sep,*sep2;int found=0;q(r,qr,sizeof(qr));q(id,qid,sizeof(qid));snprintf(c,sizeof(c),"gh run view %s --repo %s --json jobs --jq '.jobs[] | [.name,.conclusion,([.steps[]? | select(.conclusion==\"failure\") | .name] | join(\", \"))] | @tsv'",qid,qr);if(macora_command(c,out,sizeof(out))!=0||!out[0]){bad("The Android build failed, but no failed-step details were available.");return 1;}line=out;while(line&&*line){char*next=strchr(line,'\n');if(next)*next=0;sep=strchr(line,'\t');if(!sep){line=next?next+1:NULL;continue;}*sep=0;sep2=strchr(sep+1,'\t');if(sep2)*sep2=0;printf("\033[31m[BUILD ERROR]\033[0m %s",line);if(sep2&&sep2[1])printf(" — failed step: %s",sep2+1);printf("\n");found=1;line=next?next+1:NULL;}if(!found)bad("The Android build failed. Check the build details from MacoraOne.");return 1;}
static int wait_build(const char*r,const char*id){char status[256],steps[16384],*seen[128]={0};int seen_count=0,i;if(build_steps(r,id,steps,sizeof(steps))==0&&steps[0])show_steps(steps,seen,&seen_count);for(i=0;i<120;i++){if(build_status(r,id,status,sizeof(status))){bad("Could not read the GitHub build status.");goto done;}if(build_steps(r,id,steps,sizeof(steps))==0&&steps[0])show_steps(steps,seen,&seen_count);if(!strncmp(status,"queued",6)||!strncmp(status,"requested",9)){info("Build queued. Waiting for Android runner.");}else if(!strncmp(status,"in_progress",11)){/* Step states above provide the progress display. */}else if(!strncmp(status,"completed",9)){if(strstr(status,"|success")){good("GitHub build finished successfully.");goto success;}if(strstr(status,"|cancelled")){bad("Android build was cancelled.");goto done;}if(strstr(status,"|timed_out")){bad("Android build timed out.");goto done;}build_failure(r,id);goto done;}sleep(3);}bad("Android build did not finish within the MacoraOne wait period.");goto done;success:for(i=0;i<seen_count;i++)free(seen[i]);return 0;done:for(i=0;i<seen_count;i++)free(seen[i]);return 1;}
int macora_build(const char*a,const char*mode){char co[PATH_MAX],pr[PATH_MAX],app[PATH_MAX],repo[1024],wf[128],id[64],art[2048],c[8192],qapp[PATH_MAX*2],qrepo[2048],qwf[512];MacoraLanguage l;if(!macora_validate_name(a)||macora_authenticate())return 1;dirs(co,sizeof(co),pr,sizeof(pr));snprintf(app,sizeof(app),"%s/%s",pr,a);if(!macora_is_directory(app)||marker_read(app,&l)){bad("Cannot find AppName or determine Java/Kotlin selection.");return 1;}q(app,qapp,sizeof(qapp));snprintf(c,sizeof(c),"git -C %s remote get-url origin",qapp);if(macora_command(c,repo,sizeof(repo)))return 1;char*p=strstr(repo,"github.com/");if(!p){bad("AppName origin is not GitHub.");return 1;}memmove(repo,p+11,strlen(p+11)+1);p=strrchr(repo,'.');if(p&&!strcmp(p,".git"))*p=0;if(!valid_repo(repo)){bad("AppName origin is not a valid GitHub repository.");return 1;}snprintf(wf,sizeof(wf),"%s",workflow(l));q(repo,qrepo,sizeof(qrepo));q(wf,qwf,sizeof(qwf));if(!mode||!(!strcmp(mode,"all")||!strcmp(mode,"debug")||!strcmp(mode,"release"))){bad("Build type must be all, debug, or release.");return 1;}info("Triggering %s for %s (%s build).",wf,repo,mode);char qm[256];q(mode,qm,sizeof(qm));snprintf(c,sizeof(c),"gh workflow run %s --repo %s --ref main -f build_type=%s",qwf,qrepo,qm);if(macora_run(c,1))return 1;sleep(2);if(latest(repo,wf,id,sizeof(id))||!id[0]){bad("Could not find the dispatched workflow run.");return 1;}info("MacoraOne is interpreting the GitHub build status.");if(wait_build(repo,id))return 1;snprintf(art,sizeof(art),"https://github.com/%s/actions/runs/%s/artifacts",repo,id);good("Android build completed successfully.");info("Artifact URL: %s",art);macora_open_url(art);return 0;}
void macora_help(const char*p){printf("MacoraOne %s\n",MACORAONE_VERSION);printf("Usage:\n  %s --help\n  %s --version\n  %s install [package[@version]]\n  %s install package version\n  %s uninstall [package]\n  %s list\n  %s list-available\n  %s create AppName\n  %s push AppName reponame\n  %s build AppName [all|debug|release]\n",p,p,p,p,p,p,p,p,p,p);}
void macora_version(void){printf("%s %s\n",MACORAONE_NAME,MACORAONE_VERSION);}
int main(int argc,char**argv){if(argc<2){macora_help(argv[0]);return 0;}if(!strcmp(argv[1],"--help")||!strcmp(argv[1],"-h")){macora_help(argv[0]);return 0;}if(!strcmp(argv[1],"--version")||!strcmp(argv[1],"-v")){macora_version();return 0;}if(!strcmp(argv[1],"install")){if(argc==2)return macora_authenticate()?1:macora_install();if(argc==3){char pkg[128],*at;snprintf(pkg,sizeof(pkg),"%s",argv[2]);at=strchr(pkg,'@');if(at){*at++=0;if(!*at){bad("Version after @ cannot be empty.");return 1;}return macora_package_install(pkg,at);}return macora_package_install(pkg,NULL);}if(argc==4)return macora_package_install(argv[2],argv[3]);bad("Usage: %s install [package[@version]] or install package version",argv[0]);return 1;}if(!strcmp(argv[1],"uninstall")){if(argc==2)return macora_uninstall();if(argc==3)return macora_package_uninstall(argv[2]);bad("Usage: %s uninstall [package]",argv[0]);return 1;}if(!strcmp(argv[1],"list")){return argc==2?macora_package_list():(bad("Usage: %s list",argv[0]),1);}if(!strcmp(argv[1],"list-available")){return argc==2?macora_package_available():(bad("Usage: %s list-available",argv[0]),1);}if(!strcmp(argv[1],"create")){if(argc!=3){bad("Usage: %s create AppName",argv[0]);return 1;}return macora_create(argv[2]);}if(!strcmp(argv[1],"push")){if(argc!=4){bad("Usage: %s push AppName reponame",argv[0]);return 1;}return macora_push(argv[2],argv[3]);}if(!strcmp(argv[1],"build")){if(argc<3||argc>4){bad("Usage: %s build AppName [all|debug|release]",argv[0]);return 1;}return macora_build(argv[2],argc==4?argv[3]:"all");}bad("Unknown command: %s",argv[1]);macora_help(argv[0]);return 1;}
