2
0

Main.hx 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068
  1. /*
  2. * Copyright (C)2005-2012 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. */
  22. package tools.haxelib;
  23. import haxe.zip.Reader;
  24. import sys.io.File;
  25. import sys.io.Process;
  26. import haxe.ds.Option;
  27. enum Answer {
  28. Yes;
  29. No;
  30. Always;
  31. }
  32. class SiteProxy extends haxe.remoting.Proxy<tools.haxelib.SiteApi> {
  33. }
  34. class Progress extends haxe.io.Output {
  35. var o : haxe.io.Output;
  36. var cur : Int;
  37. var max : Int;
  38. var start : Float;
  39. public function new(o) {
  40. this.o = o;
  41. cur = 0;
  42. start = haxe.Timer.stamp();
  43. }
  44. function bytes(n) {
  45. cur += n;
  46. if( max == null )
  47. Sys.print(cur+" bytes\r");
  48. else
  49. Sys.print(cur+"/"+max+" ("+Std.int((cur*100.0)/max)+"%)\r");
  50. }
  51. public override function writeByte(c) {
  52. o.writeByte(c);
  53. bytes(1);
  54. }
  55. public override function writeBytes(s,p,l) {
  56. var r = o.writeBytes(s,p,l);
  57. bytes(r);
  58. return r;
  59. }
  60. public override function close() {
  61. super.close();
  62. o.close();
  63. var time = haxe.Timer.stamp() - start;
  64. var speed = (cur / time) / 1024;
  65. time = Std.int(time * 10) / 10;
  66. speed = Std.int(speed * 10) / 10;
  67. Sys.print("Download complete : "+cur+" bytes in "+time+"s ("+speed+"KB/s)\n");
  68. }
  69. public override function prepare(m) {
  70. max = m;
  71. }
  72. }
  73. class ProgressIn extends haxe.io.Input {
  74. var i : haxe.io.Input;
  75. var pos : Int;
  76. var tot : Int;
  77. public function new( i, tot ) {
  78. this.i = i;
  79. this.pos = 0;
  80. this.tot = tot;
  81. }
  82. public override function readByte() {
  83. var c = i.readByte();
  84. doRead(1);
  85. return c;
  86. }
  87. public override function readBytes(buf,pos,len) {
  88. var k = i.readBytes(buf,pos,len);
  89. doRead(k);
  90. return k;
  91. }
  92. function doRead( nbytes : Int ) {
  93. pos += nbytes;
  94. Sys.print( Std.int((pos * 100.0) / tot) + "%\r" );
  95. }
  96. }
  97. class Main {
  98. static var VERSION = SemVer.ofString('3.0.0-rc.2');
  99. static var REPNAME = "lib";
  100. static var SERVER = {
  101. host : "lib.haxe.org",
  102. port : 80,
  103. dir : "",
  104. url : "index.n",
  105. apiVersion : VERSION.major+"."+VERSION.minor,
  106. };
  107. var argcur : Int;
  108. var args : Array<String>;
  109. var commands : List<{ name : String, doc : String, f : Void -> Void, net : Bool }>;
  110. var siteUrl : String;
  111. var site : SiteProxy;
  112. function new() {
  113. args = Sys.args();
  114. commands = new List();
  115. addCommand("install", install, "install a given library");
  116. addCommand("list", list, "list all installed libraries", false);
  117. addCommand("upgrade", upgrade, "upgrade all installed libraries");
  118. addCommand("update", update, "update a single library");
  119. addCommand("updateself", updateSelf, "update haxelib itself");
  120. addCommand("remove", remove, "remove a given library/version", false);
  121. addCommand("set", set, "set the current version for a library", false);
  122. addCommand("search", search, "list libraries matching a word");
  123. addCommand("info", info, "list informations on a given library");
  124. addCommand("user", user, "list informations on a given user");
  125. addCommand("register", register, "register a new user");
  126. addCommand("submit", submit, "submit or update a library package");
  127. addCommand("setup", setup, "set the haxelib repository path", false);
  128. addCommand("config", config, "print the repository path", false);
  129. addCommand("path", path, "give paths to libraries", false);
  130. addCommand("run", run, "run the specified library with parameters", false);
  131. addCommand("local", local, "install the specified package locally", false);
  132. addCommand("dev", dev, "set the development directory for a given library", false);
  133. addCommand("git", git, "uses git repository as library");
  134. addCommand("proxy", proxy, "setup the Http proxy");
  135. initSite();
  136. }
  137. function initSite() {
  138. siteUrl = "http://" + SERVER.host + ":" + SERVER.port + "/" + SERVER.dir;
  139. site = new SiteProxy(haxe.remoting.HttpConnection.urlConnect(siteUrl + "api/" + SERVER.apiVersion + "/" + SERVER.url).api);
  140. }
  141. function param( name, ?passwd ) {
  142. if( args.length > argcur )
  143. return args[argcur++];
  144. Sys.print(name+" : ");
  145. if( passwd ) {
  146. var s = new StringBuf();
  147. var c;
  148. while( (c = Sys.getChar(false)) != 13 )
  149. s.addChar(c);
  150. print("");
  151. return s.toString();
  152. }
  153. return Sys.stdin().readLine();
  154. }
  155. function ask( question ) {
  156. while( true ) {
  157. Sys.print(question+" [y/n/a] ? ");
  158. switch( Sys.stdin().readLine() ) {
  159. case "n": return No;
  160. case "y": return Yes;
  161. case "a": return Always;
  162. }
  163. }
  164. return null;
  165. }
  166. function paramOpt() {
  167. if( args.length > argcur )
  168. return args[argcur++];
  169. return null;
  170. }
  171. function addCommand( name, f, doc, ?net = true ) {
  172. commands.add({ name : name, doc : doc, f : f, net : net });
  173. }
  174. function usage() {
  175. print("Haxe Library Manager " + VERSION + " - (c)2006-2013 Haxe Foundation");
  176. print(" Usage : haxelib [command] [options]");
  177. print(" Commands :");
  178. for( c in commands )
  179. print(" "+c.name+" : "+c.doc);
  180. Sys.exit(1);
  181. }
  182. function process() {
  183. var debug = false;
  184. argcur = 0;
  185. while( true ) {
  186. var a = args[argcur++];
  187. if( a == null )
  188. break;
  189. switch( a ) {
  190. case "-debug":
  191. debug = true;
  192. case "-notimeout":
  193. haxe.remoting.HttpConnection.TIMEOUT = 0;
  194. case "-R":
  195. var path = args[argcur++];
  196. var r = ~/^(http:\/\/)?([^:\/]+)(:[0-9]+)?\/?(.*)$/;
  197. if( !r.match(path) )
  198. throw "Invalid repository format '"+path+"'";
  199. SERVER.host = r.matched(2);
  200. if( r.matched(3) != null )
  201. SERVER.port = Std.parseInt(r.matched(3).substr(1));
  202. SERVER.dir = r.matched(4);
  203. initSite();
  204. default:
  205. argcur--;
  206. break;
  207. }
  208. }
  209. var cmd = args[argcur++];
  210. if( cmd == null )
  211. usage();
  212. for( c in commands )
  213. if( c.name == cmd ) {
  214. try {
  215. if( c.net ) loadProxy();
  216. c.f();
  217. } catch( e : Dynamic ) {
  218. if( e == "std@host_resolve" ) {
  219. print("Host "+SERVER.host+" was not found");
  220. print("Please ensure that your internet connection is on");
  221. print("If you don't have an internet connection or if you are behing a proxy");
  222. print("please download manually the file from http://lib.haxe.org/files");
  223. print("and run 'haxelib local <file>' to install the Library.");
  224. print("You can also setup the proxy with 'haxelib proxy'.");
  225. Sys.exit(1);
  226. }
  227. if( e == "Blocked" ) {
  228. print("Http connection timeout. Try running haxelib -notimeout <command> to disable timeout");
  229. Sys.exit(1);
  230. }
  231. if( debug )
  232. neko.Lib.rethrow(e);
  233. print(Std.string(e));
  234. Sys.exit(1);
  235. }
  236. return;
  237. }
  238. print("Unknown command "+cmd);
  239. usage();
  240. }
  241. // ---- COMMANDS --------------------
  242. function search() {
  243. var word = param("Search word");
  244. var l = site.search(word);
  245. for( s in l )
  246. print(s.name);
  247. print(l.length+" libraries found");
  248. }
  249. function info() {
  250. var prj = param("Library name");
  251. var inf = site.infos(prj);
  252. print("Name: "+inf.name);
  253. print("Tags: "+inf.tags.join(", "));
  254. print("Desc: "+inf.desc);
  255. print("Website: "+inf.website);
  256. print("License: "+inf.license);
  257. print("Owner: "+inf.owner);
  258. print("Version: "+inf.curversion);
  259. print("Releases: ");
  260. if( inf.versions.length == 0 )
  261. print(" (no version released yet)");
  262. for( v in inf.versions )
  263. print(" "+v.date+" "+v.name+" : "+v.comments);
  264. }
  265. function user() {
  266. var uname = param("User name");
  267. var inf = site.user(uname);
  268. print("Id: "+inf.name);
  269. print("Name: "+inf.fullname);
  270. print("Mail: "+inf.email);
  271. print("Libraries: ");
  272. if( inf.projects.length == 0 )
  273. print(" (no libraries)");
  274. for( p in inf.projects )
  275. print(" "+p);
  276. }
  277. function register() {
  278. doRegister(param("User"));
  279. print("Registration successful");
  280. }
  281. function doRegister(name) {
  282. var email = param("Email");
  283. var fullname = param("Fullname");
  284. var pass = param("Password",true);
  285. var pass2 = param("Confirm",true);
  286. if( pass != pass2 )
  287. throw "Password does not match";
  288. pass = haxe.crypto.Md5.encode(pass);
  289. site.register(name,pass,email,fullname);
  290. return pass;
  291. }
  292. function submit() {
  293. var file = param("Package");
  294. var data = sys.io.File.getBytes(file);
  295. var zip = Reader.readZip(new haxe.io.BytesInput(data));
  296. var infos = Data.readInfos(zip,true);
  297. var user = infos.developers.first();
  298. var password;
  299. if( site.isNewUser(user) ) {
  300. print("This is your first submission as '"+user+"'");
  301. print("Please enter the following informations for registration");
  302. password = doRegister(user);
  303. } else {
  304. if( infos.developers.length > 1 )
  305. user = param("User");
  306. password = haxe.crypto.Md5.encode(param("Password",true));
  307. if( !site.checkPassword(user,password) )
  308. throw "Invalid password for "+user;
  309. }
  310. site.checkDeveloper(infos.project,user);
  311. // check dependencies validity
  312. for( d in infos.dependencies ) {
  313. var infos = site.infos(d.project);
  314. if( d.version == "" )
  315. continue;
  316. var found = false;
  317. for( v in infos.versions )
  318. if( v.name == d.version ) {
  319. found = true;
  320. break;
  321. }
  322. if( !found )
  323. throw "Library "+d.project+" does not have version "+d.version;
  324. }
  325. // check if this version already exists
  326. var sinfos = try site.infos(infos.project) catch( _ : Dynamic ) null;
  327. if( sinfos != null )
  328. for( v in sinfos.versions )
  329. if( v.name == infos.version.toString() && ask("You're about to overwrite existing version '"+v.name+"', please confirm") == No )
  330. throw "Aborted";
  331. // query a submit id that will identify the file
  332. var id = site.getSubmitId();
  333. // directly send the file data over Http
  334. var h = new haxe.Http("http://"+SERVER.host+":"+SERVER.port+"/"+SERVER.url);
  335. h.onError = function(e) { throw e; };
  336. h.onData = print;
  337. h.fileTransfert("file",id,new ProgressIn(new haxe.io.BytesInput(data),data.length),data.length);
  338. print("Sending data.... ");
  339. h.request(true);
  340. // processing might take some time, make sure we wait
  341. print("Processing file.... ");
  342. haxe.remoting.HttpConnection.TIMEOUT = 1000;
  343. // ask the server to register the sent file
  344. var msg = site.processSubmit(id,user,password);
  345. print(msg);
  346. }
  347. function install() {
  348. var prj = param("Library name");
  349. if( sys.FileSystem.exists(prj) && !sys.FileSystem.isDirectory(prj) ) {
  350. if( !StringTools.endsWith(prj,".zip") )
  351. throw "Local file to install must be a zip";
  352. doInstallFile(prj,true,true);
  353. return;
  354. }
  355. var inf = site.infos(prj);
  356. if( inf.curversion == null )
  357. throw "This library has not yet released a version";
  358. var reqversion = paramOpt();
  359. var version = if( reqversion != null ) reqversion else inf.curversion;
  360. var found = false;
  361. for( v in inf.versions )
  362. if( v.name == version ) {
  363. found = true;
  364. break;
  365. }
  366. if( !found )
  367. throw "No such version "+version;
  368. doInstall(inf.name,version,version == inf.curversion);
  369. }
  370. function doInstall( project, version, setcurrent ) {
  371. var rep = getRepository();
  372. // check if exists already
  373. if( sys.FileSystem.exists(rep+Data.safe(project)+"/"+Data.safe(version)) ) {
  374. print("You already have "+project+" version "+version+" installed");
  375. setCurrent(project,version,true);
  376. return;
  377. }
  378. // download to temporary file
  379. var filename = Data.fileName(project,version);
  380. var filepath = rep+filename;
  381. var out = sys.io.File.write(filepath,true);
  382. var progress = new Progress(out);
  383. var h = new haxe.Http(siteUrl+Data.REPOSITORY+"/"+filename);
  384. h.onError = function(e) {
  385. progress.close();
  386. sys.FileSystem.deleteFile(filepath);
  387. throw e;
  388. };
  389. print("Downloading "+filename+"...");
  390. h.customRequest(false,progress);
  391. doInstallFile(filepath, setcurrent);
  392. site.postInstall(project, version);
  393. }
  394. function doInstallFile(filepath,setcurrent,?nodelete) {
  395. // read zip content
  396. var f = sys.io.File.read(filepath,true);
  397. var zip = Reader.readZip(f);
  398. f.close();
  399. var infos = Data.readInfos(zip,false);
  400. // create directories
  401. var pdir = getRepository() + Data.safe(infos.project);
  402. safeDir(pdir);
  403. pdir += "/";
  404. var target = pdir + Data.safe(infos.version.toString());
  405. safeDir(target);
  406. target += "/";
  407. // locate haxelib.xml base path
  408. var basepath = Data.locateBasePath(zip);
  409. // unzip content
  410. for( zipfile in zip ) {
  411. var n = zipfile.fileName;
  412. if( StringTools.startsWith(n,basepath) ) {
  413. // remove basepath
  414. n = n.substr(basepath.length,n.length-basepath.length);
  415. if( n.charAt(0) == "/" || n.charAt(0) == "\\" || n.split("..").length > 1 )
  416. throw "Invalid filename : "+n;
  417. var dirs = ~/[\/\\]/g.split(n);
  418. var path = "";
  419. var file = dirs.pop();
  420. for( d in dirs ) {
  421. path += d;
  422. safeDir(target+path);
  423. path += "/";
  424. }
  425. if( file == "" ) {
  426. if( path != "" ) print(" Created "+path);
  427. continue; // was just a directory
  428. }
  429. path += file;
  430. print(" Install "+path);
  431. var data = Reader.unzip(zipfile);
  432. sys.io.File.saveBytes(target+path,data);
  433. }
  434. }
  435. // set current version
  436. if( setcurrent || !sys.FileSystem.exists(pdir+".current") ) {
  437. sys.io.File.saveContent(pdir + ".current", infos.version.toString());
  438. print(" Current version is now "+infos.version);
  439. }
  440. // end
  441. if( !nodelete )
  442. sys.FileSystem.deleteFile(filepath);
  443. print("Done");
  444. // process dependencies
  445. for( d in infos.dependencies ) {
  446. print("Installing dependency "+d.project+" "+d.version);
  447. if( d.version == "" )
  448. d.version = site.infos(d.project).curversion;
  449. doInstall(d.project,d.version,false);
  450. }
  451. }
  452. function safeDir( dir ) {
  453. if( sys.FileSystem.exists(dir) ) {
  454. if( !sys.FileSystem.isDirectory(dir) )
  455. throw ("A file is preventing "+dir+" to be created");
  456. return false;
  457. }
  458. try {
  459. sys.FileSystem.createDirectory(dir);
  460. } catch( e : Dynamic ) {
  461. throw "You don't have enough user rights to create the directory "+dir;
  462. }
  463. return true;
  464. }
  465. function safeDelete( file ) {
  466. try {
  467. sys.FileSystem.deleteFile(file);
  468. return true;
  469. } catch (e:Dynamic) {
  470. if( Sys.systemName() == "Windows") {
  471. try {
  472. Sys.command("attrib -R \"" +file+ "\"");
  473. sys.FileSystem.deleteFile(file);
  474. return true;
  475. } catch (e:Dynamic) {
  476. }
  477. }
  478. return false;
  479. }
  480. }
  481. function getRepository( ?setup : Bool ) {
  482. var win = Sys.systemName() == "Windows";
  483. var haxepath = Sys.getEnv("HAXEPATH");
  484. if( haxepath != null ) {
  485. var last = haxepath.charAt(haxepath.length - 1);
  486. if( last != "/" && last != "\\" )
  487. haxepath += "/";
  488. }
  489. var config_file;
  490. if( win )
  491. config_file = Sys.getEnv("HOMEDRIVE") + Sys.getEnv("HOMEPATH");
  492. else
  493. config_file = Sys.getEnv("HOME");
  494. config_file += "/.haxelib";
  495. var rep = try
  496. sys.io.File.getContent(config_file)
  497. catch( e : Dynamic ) try
  498. sys.io.File.getContent("/etc/.haxelib")
  499. catch( e : Dynamic ) {
  500. if( setup ) {
  501. (win ? haxepath : "/usr/lib/haxe/")+REPNAME;
  502. } else if( win ) {
  503. // Windows have a default directory (no need for setup)
  504. if( haxepath == null )
  505. throw "HAXEPATH environment variable not defined, please run haxesetup.exe first";
  506. var rep = haxepath+REPNAME;
  507. try {
  508. safeDir(rep);
  509. } catch( e : Dynamic ) {
  510. throw "The directory defined by HAXEPATH does not exist, please run haxesetup.exe again";
  511. }
  512. return rep+"\\";
  513. } else
  514. throw "This is the first time you are runing haxelib. Please run haxelib setup first";
  515. }
  516. rep = StringTools.trim(rep);
  517. if( setup ) {
  518. if( args.length <= argcur ) {
  519. print("Please enter haxelib repository path with write access");
  520. print("Hit enter for default (" + rep + ")");
  521. }
  522. var line = param("Path");
  523. if( line != "" )
  524. rep = line;
  525. if( !sys.FileSystem.exists(rep) ) {
  526. try {
  527. sys.FileSystem.createDirectory(rep);
  528. } catch( e : Dynamic ) {
  529. print("Failed to create directory '"+rep+"' ("+Std.string(e)+"), maybe you need appropriate user rights");
  530. print("Check also that the parent directory exists");
  531. Sys.exit(1);
  532. }
  533. }
  534. rep = try sys.FileSystem.fullPath(rep) catch( e : Dynamic ) rep;
  535. sys.io.File.saveContent(config_file, rep);
  536. } else if( !sys.FileSystem.exists(rep) )
  537. throw "haxelib Repository "+rep+" does not exists. Please run haxelib setup again";
  538. return rep+"/";
  539. }
  540. function setup() {
  541. var path = getRepository(true);
  542. print("haxelib repository is now "+path);
  543. }
  544. function config() {
  545. print(getRepository());
  546. }
  547. function getCurrent( dir ) {
  548. return StringTools.trim(sys.io.File.getContent(dir + "/.current"));
  549. }
  550. function getDev( dir ) {
  551. return StringTools.trim(sys.io.File.getContent(dir + "/.dev"));
  552. }
  553. function list() {
  554. var rep = getRepository();
  555. for( p in sys.FileSystem.readDirectory(rep) ) {
  556. if( p.charAt(0) == "." )
  557. continue;
  558. var versions = new Array();
  559. var current = getCurrent(rep + p);
  560. var dev = try StringTools.trim(sys.io.File.getContent(rep+p+"/.dev")) catch( e : Dynamic ) null;
  561. for( v in sys.FileSystem.readDirectory(rep+p) ) {
  562. if( v.charAt(0) == "." )
  563. continue;
  564. v = Data.unsafe(v);
  565. if( dev == null && v == current )
  566. v = "["+v+"]";
  567. versions.push(v);
  568. }
  569. if( dev != null )
  570. versions.push("[dev:"+dev+"]");
  571. print(Data.unsafe(p) + ": "+versions.join(" "));
  572. }
  573. }
  574. function upgrade() {
  575. var state = { rep : getRepository(), prompt : true, updated : false };
  576. for( p in sys.FileSystem.readDirectory(state.rep) ) {
  577. if( p.charAt(0) == "." || !sys.FileSystem.isDirectory(state.rep+"/"+p) )
  578. continue;
  579. var p = Data.unsafe(p);
  580. print("Checking " + p);
  581. doUpdate(p,state);
  582. }
  583. if( state.updated )
  584. print("Done");
  585. else
  586. print("All libraries are up-to-date");
  587. }
  588. function doUpdate( p : String, state ) {
  589. var rep = state.rep;
  590. if( sys.FileSystem.exists(rep + "/" + p + "/git") && sys.FileSystem.isDirectory(rep + "/" + p + "/git") ) {
  591. checkGit();
  592. var oldCwd = Sys.getCwd();
  593. Sys.setCwd(rep + "/" + p + "/git");
  594. Sys.command("git pull");
  595. // TODO: update haxelib.xml version?
  596. Sys.setCwd(oldCwd);
  597. state.updated = true;
  598. } else {
  599. var inf = try site.infos(p) catch( e : Dynamic ) { Sys.println(e); return; };
  600. if( !sys.FileSystem.exists(rep+Data.safe(p)+"/"+Data.safe(inf.curversion)) ) {
  601. if( state.prompt )
  602. switch ask("Upgrade "+p+" to "+inf.curversion) {
  603. case Yes:
  604. case Always: state.prompt = false;
  605. case No:
  606. return;
  607. }
  608. doInstall(p,inf.curversion,true);
  609. state.updated = true;
  610. } else
  611. setCurrent(p, inf.curversion, true);
  612. }
  613. }
  614. function updateByName(prj:String) {
  615. var state = { rep : getRepository(), prompt : false, updated : false };
  616. doUpdate(prj,state);
  617. return state.updated;
  618. }
  619. function update() {
  620. var prj = param('Library');
  621. if (!updateByName(prj))
  622. print(prj + " is up to date");
  623. }
  624. function updateSelf() {
  625. function tryBuild() {
  626. var p = new Process('haxe', ['-neko', 'test.n', '-lib', 'haxelib_client', '-main', 'tools.haxelib.Main', '--no-output']);
  627. return
  628. if (p.exitCode() == 0) None;
  629. else Some(p.stderr.readAll().toString());
  630. }
  631. if (!updateByName('haxelib_client'))
  632. print("haxelib is up to date");
  633. switch tryBuild() {
  634. case None:
  635. var haxepath = Sys.getEnv("HAXEPATH"),
  636. win = Sys.systemName() == "Windows";
  637. if (haxepath == null)
  638. throw 'HAXEPATH environment variable not defined';
  639. else
  640. haxepath +=
  641. switch (haxepath.charAt(haxepath.length - 1)) {
  642. case '/', '\\': '';
  643. default: '/';
  644. }
  645. if (win) {
  646. var file = '$haxepath/haxelib.n';
  647. var p = new Process(
  648. 'haxe',
  649. [
  650. '-neko', file,
  651. '-lib', 'haxelib_client',
  652. '-main', 'tools.haxelib.Main',
  653. ]
  654. );
  655. if (p.exitCode() == 0) {
  656. var p = new Process('nekotools', ['boot', file]);
  657. if (p.exitCode() != 0)
  658. throw 'Error booting haxelib :' + p.stderr.readAll().toString();
  659. }
  660. else throw 'Error rebuilding haxelib: ' + p.stderr.readAll().toString();
  661. }
  662. else {
  663. var p = new Process('haxelib', ['path', 'haxelib_client']);
  664. if (p.exitCode() == 0) {
  665. var args = [];
  666. for (arg in p.stdout.readAll().toString().split('\n')) {
  667. arg = StringTools.trim(arg);
  668. if (arg.charAt(0) == '-')
  669. args.push(arg);
  670. else if (arg.length > 0)
  671. args.push('-cp "$arg"');
  672. };
  673. var file = '$haxepath/haxelib.sh';
  674. try File.saveContent(
  675. file,
  676. '#!\nhaxe --run -main tools.haxelib.Main '+args.join(' ')
  677. )
  678. catch (e:Dynamic)
  679. throw 'Error writing file $file. Please ensure you have write permissions. Error message ' + Std.string(e);
  680. }
  681. else throw p.stdout.readAll();
  682. }
  683. case Some(error):
  684. throw 'Error compiling haxelib client: $error';
  685. }
  686. }
  687. function deleteRec(dir) {
  688. for( p in sys.FileSystem.readDirectory(dir) ) {
  689. var path = dir+"/"+p;
  690. if( sys.FileSystem.isDirectory(path) )
  691. deleteRec(path);
  692. else
  693. safeDelete(path);
  694. }
  695. sys.FileSystem.deleteDirectory(dir);
  696. }
  697. function remove() {
  698. var prj = param("Library");
  699. var version = paramOpt();
  700. var rep = getRepository();
  701. var pdir = rep + Data.safe(prj);
  702. if( version == null ) {
  703. if( !sys.FileSystem.exists(pdir) )
  704. throw "Library "+prj+" is not installed";
  705. deleteRec(pdir);
  706. print("Library "+prj+" removed");
  707. return;
  708. }
  709. var vdir = pdir + "/" + Data.safe(version);
  710. if( !sys.FileSystem.exists(vdir) )
  711. throw "Library "+prj+" does not have version "+version+" installed";
  712. var cur = getCurrent(pdir);
  713. if( cur == version )
  714. throw "Can't remove current version of library "+prj;
  715. deleteRec(vdir);
  716. print("Library "+prj+" version "+version+" removed");
  717. }
  718. function set() {
  719. var prj = param("Library");
  720. var version = param("Version");
  721. setCurrent(prj,version,false);
  722. }
  723. function setCurrent( prj : String, version : String, doAsk : Bool ) {
  724. var pdir = getRepository() + Data.safe(prj);
  725. var vdir = pdir + "/" + Data.safe(version);
  726. if( !sys.FileSystem.exists(vdir) )
  727. throw "Library "+prj+" version "+version+" is not installed";
  728. if( getCurrent(pdir) == version )
  729. return;
  730. if( doAsk && ask("Set "+prj+" to version "+version) == No )
  731. return;
  732. sys.io.File.saveContent(pdir+"/.current",version);
  733. print("Library "+prj+" current version is now "+version);
  734. }
  735. function checkRec( prj : String, version : String, l : List<{ project : String, version : String }> ) {
  736. var pdir = getRepository() + Data.safe(prj);
  737. if( !sys.FileSystem.exists(pdir) )
  738. throw "Library "+prj+" is not installed : run 'haxelib install "+prj+"'";
  739. var version = if( version != null ) version else getCurrent(pdir);
  740. var vdir = pdir + "/" + Data.safe(version);
  741. if( StringTools.endsWith(vdir, "dev") )
  742. vdir = getDev(pdir);
  743. if( !sys.FileSystem.exists(vdir) )
  744. throw "Library "+prj+" version "+version+" is not installed";
  745. for( p in l )
  746. if( p.project == prj ) {
  747. if( p.version == version )
  748. return;
  749. throw "Library "+prj+" has two version included "+version+" and "+p.version;
  750. }
  751. l.add({ project : prj, version : version });
  752. var json = try sys.io.File.getContent(vdir+"/"+Data.JSON) catch( e : Dynamic ) null;
  753. if( json == null )
  754. return; // ignore missing haxelib.json, assume no dependencies
  755. var inf = Data.readData(json,false);
  756. for( d in inf.dependencies )
  757. checkRec(d.project,if( d.version == "" ) null else d.version,l);
  758. }
  759. function path() {
  760. var list = new List();
  761. while( argcur < args.length ) {
  762. var a = args[argcur++].split(":");
  763. checkRec(a[0],a[1],list);
  764. }
  765. var rep = getRepository();
  766. for( d in list ) {
  767. var pdir = Data.safe(d.project)+"/"+Data.safe(d.version)+"/";
  768. var dir = rep + pdir;
  769. try {
  770. dir = getDev(rep+Data.safe(d.project));
  771. if( dir.length == 0 || (dir.charAt(dir.length-1) != '/' && dir.charAt(dir.length-1) != '\\') )
  772. dir += "/";
  773. pdir = dir;
  774. } catch( e : Dynamic ) {
  775. }
  776. var ndir = dir + "ndll";
  777. if( sys.FileSystem.exists(ndir) ) {
  778. var sysdir = ndir+"/"+Sys.systemName();
  779. var is64 = neko.Lib.load("std", "sys_is64", 0)();
  780. if( is64 ) sysdir += "64";
  781. if( !sys.FileSystem.exists(sysdir) )
  782. throw "Library "+d.project+" version "+d.version+" does not have a neko dll for your system";
  783. Sys.println("-L "+pdir+"ndll/");
  784. }
  785. try {
  786. var f = sys.io.File.getContent(dir + "extraParams.hxml");
  787. Sys.println(StringTools.trim(f));
  788. } catch( e : Dynamic ) {
  789. }
  790. Sys.println(dir);
  791. Sys.println("-D "+d.project);
  792. }
  793. }
  794. function dev() {
  795. var rep = getRepository();
  796. var project = param("Library");
  797. var dir = paramOpt();
  798. var proj = rep + Data.safe(project);
  799. if( !sys.FileSystem.exists(proj) ) {
  800. sys.FileSystem.createDirectory(proj);
  801. sys.io.File.saveContent(proj + "/.current", "dev");
  802. }
  803. var devfile = proj+"/.dev";
  804. if( dir == null ) {
  805. if( sys.FileSystem.exists(devfile) )
  806. sys.FileSystem.deleteFile(devfile);
  807. print("Development directory disabled");
  808. } else {
  809. try {
  810. sys.io.File.saveContent(devfile, dir);
  811. print("Development directory set to "+dir);
  812. }
  813. catch (e:Dynamic) {
  814. print("Could not write to " +proj + "/.dev");
  815. }
  816. }
  817. }
  818. function checkGit() {
  819. var gitExists = function()
  820. try { command("git", []); return true; } catch (e:Dynamic) return false;
  821. if( gitExists() )
  822. return;
  823. // if we have already msys git/cmd in our PATH
  824. var match = ~/(.*)git([\\|\/])cmd$/ ;
  825. for (path in Sys.getEnv("PATH").split(";")) {
  826. if (match.match(path.toLowerCase()))
  827. {
  828. var newPath = match.matched(1) + "git" +match.matched(2) + "bin";
  829. Sys.putEnv("PATH", Sys.getEnv("PATH") + ";" +newPath);
  830. }
  831. }
  832. if( gitExists() )
  833. return;
  834. // look at a few default paths
  835. for( path in ["C:\\Program Files (x86)\\Git\\bin","C:\\Progra~1\\Git\\bin"] )
  836. if( sys.FileSystem.exists(path) ) {
  837. Sys.putEnv("PATH", Sys.getEnv("PATH") + ";" +path);
  838. if( gitExists() )
  839. return;
  840. }
  841. print("Could not execute git, please make sure it is installed and available in your PATH.");
  842. }
  843. function git() {
  844. var libName = param("Library name");
  845. var rep = getRepository();
  846. var libPath = rep + Data.safe(libName) + "/git";
  847. if( sys.FileSystem.exists(libPath) ) {
  848. var state = { rep : rep, prompt : false, updated : false };
  849. doUpdate(libName,state);
  850. if( !state.updated )
  851. print("You already have a git version of "+libName+" installed");
  852. return;
  853. }
  854. var gitPath = param("Git path");
  855. var subDir = paramOpt();
  856. var match = ~/@([0-9]+)/;
  857. var rev = if (match.match(gitPath) && match.matchedRight() == "")
  858. {
  859. gitPath = match.matchedLeft();
  860. match.matched(1);
  861. }
  862. else
  863. null;
  864. print("Installing " +libName + " from " +gitPath);
  865. checkGit();
  866. if( Sys.command("git clone \"" +gitPath + "\" \"" +libPath + "\"") != 0 ) {
  867. print("Could not clone git repository");
  868. return;
  869. }
  870. Sys.setCwd(libPath);
  871. if (rev != null) {
  872. var ret = command("git", ["checkout", rev]);
  873. if (ret.code != 0)
  874. {
  875. print("Could not checkout revision: " +ret.out);
  876. // TODO: We might have to get rid of the cloned repository here
  877. return;
  878. }
  879. }
  880. var revision = command("git", ["rev-parse", "HEAD"]).out;
  881. var devPath = libPath + (subDir == null ? "" : "/" + subDir);
  882. if (!sys.FileSystem.exists(devPath +"/haxelib.xml"))
  883. {
  884. var haxelib = "<project name='" +libName + "' url='" +gitPath + "' license='BSD'>"
  885. +"<description></description>"
  886. +"<version name='" +revision + "'>Updated from git.</version>"
  887. +"</project>";
  888. sys.io.File.saveContent(devPath +"/haxelib.xml", haxelib);
  889. }
  890. Sys.setCwd(libPath + "/../");
  891. sys.io.File.saveContent(".current", "dev");
  892. sys.io.File.saveContent(".dev", devPath);
  893. print("Done");
  894. }
  895. function run() {
  896. var rep = getRepository();
  897. var project = param("Library");
  898. var temp = project.split(":");
  899. project = temp[0];
  900. var pdir = rep + Data.safe(project);
  901. if( !sys.FileSystem.exists(pdir) )
  902. throw "Library "+project+" is not installed";
  903. pdir += "/";
  904. var version = temp[1] != null ? temp[1] : getCurrent(pdir);
  905. var dev = try getDev(pdir) catch ( e : Dynamic ) null;
  906. var vdir = dev!=null ? dev : pdir + Data.safe(version);
  907. var rdir = vdir + "/run.n";
  908. if( !sys.FileSystem.exists(rdir) )
  909. throw "Library "+project+" version "+version+" does not have a run script";
  910. args.push(Sys.getCwd());
  911. Sys.setCwd(vdir);
  912. var cmd = "neko run.n";
  913. for( i in argcur...args.length )
  914. cmd += " "+escapeArg(args[i]);
  915. Sys.exit(Sys.command(cmd));
  916. }
  917. function escapeArg( a : String ) {
  918. if( a.indexOf(" ") == -1 )
  919. return a;
  920. return '"'+a+'"';
  921. }
  922. function local() {
  923. var file = param("Package");
  924. doInstallFile(file,true,true);
  925. }
  926. function command( cmd:String, args:Array<String> ) {
  927. var p = new sys.io.Process(cmd, args);
  928. var code = p.exitCode();
  929. return { code:code, out: code == 0 ? p.stdout.readAll().toString() : p.stderr.readAll().toString() };
  930. }
  931. function proxy() {
  932. var rep = getRepository();
  933. var host = param("Proxy host");
  934. if( host == "" ) {
  935. if( sys.FileSystem.exists(rep + "/.proxy") ) {
  936. sys.FileSystem.deleteFile(rep + "/.proxy");
  937. print("Proxy disabled");
  938. } else
  939. print("No proxy specified");
  940. return;
  941. }
  942. var port = Std.parseInt(param("Proxy port"));
  943. var authName = param("Proxy user login");
  944. var authPass = authName == "" ? "" : param("Proxy user pass");
  945. var proxy = {
  946. host : host,
  947. port : port,
  948. auth : authName == "" ? null : { user : authName, pass : authPass },
  949. };
  950. haxe.Http.PROXY = proxy;
  951. print("Testing proxy...");
  952. try haxe.Http.requestUrl("http://www.google.com") catch( e : Dynamic ) {
  953. print("Proxy connection failed");
  954. return;
  955. }
  956. sys.io.File.saveContent(rep + "/.proxy", haxe.Serializer.run(proxy));
  957. print("Proxy setup done");
  958. }
  959. function loadProxy() {
  960. var rep = getRepository();
  961. try haxe.Http.PROXY = haxe.Unserializer.run(sys.io.File.getContent(rep + "/.proxy")) catch( e : Dynamic ) { };
  962. }
  963. // ----------------------------------
  964. static function print(str) {
  965. Sys.print(str+"\n");
  966. }
  967. static function main() {
  968. new Main().process();
  969. }
  970. }