@@ -2482,6 +2482,72 @@ def flat_command(args: argparse.Namespace) -> None:
24822482 sys .stdout .buffer .write (serializer .output )
24832483
24842484
2485+ def server_command (args : argparse .Namespace ) -> None :
2486+ import http .server
2487+ import socketserver
2488+ import hashlib
2489+
2490+ dir = os .path .abspath (args .directory )
2491+ if not os .path .isdir (dir ):
2492+ print (f"Error: { dir } is not a valid directory" )
2493+ sys .exit (1 )
2494+
2495+ scraps = {}
2496+ for root , _ , files in os .walk (dir ):
2497+ for file in files :
2498+ file_path = os .path .join (root , file )
2499+ rel_path = os .path .relpath (file_path , dir )
2500+ if file .startswith ("$" ):
2501+ logger .debug (f"Skipping { rel_path } " )
2502+ continue
2503+ rel_path_without_ext = os .path .splitext (rel_path )[0 ]
2504+ with open (file_path , "r" ) as f :
2505+ try :
2506+ program = parse (tokenize (f .read ()))
2507+ serializer = Serializer ()
2508+ serializer .serialize (program )
2509+ serialized = bytes (serializer .output )
2510+ scraps [rel_path_without_ext ] = serialized
2511+ logger .debug (f"Loaded { rel_path_without_ext } " )
2512+ file_hash = hashlib .sha256 (serialized ).hexdigest ()
2513+ scraps [f"${ file_hash } " ] = serialized
2514+ logger .debug (f"Loaded { rel_path_without_ext } as ${ file_hash } " )
2515+ except Exception as e :
2516+ logger .error (f"Error processing { file_path } : { e } " )
2517+
2518+ keep_serving = True
2519+
2520+ class ScrapHTTPRequestHandler (http .server .SimpleHTTPRequestHandler ):
2521+ def do_QUIT (self ) -> None :
2522+ self .send_response (200 )
2523+ self .end_headers ()
2524+ self .wfile .write (b"Quitting" )
2525+ nonlocal keep_serving
2526+ keep_serving = False
2527+
2528+ def do_GET (self ) -> None :
2529+ path = self .path .lstrip ("/" )
2530+ scrap = scraps .get (path )
2531+ if scrap is not None :
2532+ self .send_response (200 )
2533+ self .send_header ("Content-Type" , "application/scrap; charset=binary" )
2534+ self .send_header ("Content-Disposition" , f'attachment; filename={ json .dumps (f"{ path } .scrap" )} ' )
2535+ self .send_header ("Content-Length" , str (len (scrap )))
2536+ self .end_headers ()
2537+ self .wfile .write (scrap )
2538+ else :
2539+ self .send_response (404 )
2540+ self .send_header ("Content-Type" , "text/plain" )
2541+ self .end_headers ()
2542+ self .wfile .write (b"File not found" )
2543+
2544+ handler = ScrapHTTPRequestHandler
2545+ with socketserver .TCPServer ((args .host , args .port ), handler ) as httpd :
2546+ logger .info (f"Serving { dir } at http://{ args .host } :{ args .port } " )
2547+ while keep_serving :
2548+ httpd .handle_request ()
2549+
2550+
24852551def main () -> None :
24862552 parser = argparse .ArgumentParser (prog = "scrapscript" )
24872553 subparsers = parser .add_subparsers (dest = "command" )
@@ -2521,6 +2587,16 @@ def main() -> None:
25212587 flat = subparsers .add_parser ("flat" )
25222588 flat .set_defaults (func = flat_command )
25232589
2590+ yard = subparsers .add_parser ("yard" )
2591+ yard .set_defaults (func = lambda _ : yard .print_help ())
2592+ yard_subparsers = yard .add_subparsers (dest = "yard_command" )
2593+
2594+ yard_server = yard_subparsers .add_parser ("server" )
2595+ yard_server .set_defaults (func = server_command )
2596+ yard_server .add_argument ("directory" , type = str , nargs = "?" , default = "." , help = "Directory to serve" )
2597+ yard_server .add_argument ("--host" , type = str , default = "127.0.0.1" , help = "Host to bind to" )
2598+ yard_server .add_argument ("--port" , type = int , default = 8080 , help = "Port to listen on" )
2599+
25242600 args = parser .parse_args ()
25252601 if not args .command :
25262602 args .debug = False
0 commit comments