@@ -158,6 +158,8 @@ def galaxy_config(ctx, runnables, **kwds):
158158        c  =  docker_galaxy_config 
159159    elif  kwds .get ("external" , False ):
160160        c  =  external_galaxy_config 
161+     elif  kwds .get ("uvx_galaxy" , False ):
162+         c  =  uvx_galaxy_config 
161163    log_thread  =  None 
162164    e  =  threading .Event ()
163165    try :
@@ -1421,7 +1423,286 @@ def _ensure_directory(path):
14211423        os .makedirs (path )
14221424
14231425
1426+ class  UvxGalaxyConfig (BaseManagedGalaxyConfig ):
1427+     """A uvx-managed implementation of :class:`GalaxyConfig`.""" 
1428+ 
1429+     def  __init__ (
1430+         self ,
1431+         ctx ,
1432+         config_directory ,
1433+         env ,
1434+         test_data_dir ,
1435+         port ,
1436+         server_name ,
1437+         master_api_key ,
1438+         runnables ,
1439+         kwds ,
1440+     ):
1441+         super ().__init__ (
1442+             ctx ,
1443+             config_directory ,
1444+             env ,
1445+             test_data_dir ,
1446+             port ,
1447+             server_name ,
1448+             master_api_key ,
1449+             runnables ,
1450+             kwds ,
1451+         )
1452+         # Use config directory as placeholder for galaxy_root since uvx manages Galaxy 
1453+         self .galaxy_root  =  config_directory 
1454+ 
1455+     @property  
1456+     def  host (self ):
1457+         """Host for uvx Galaxy instance.""" 
1458+         return  self ._kwds .get ("host" , "127.0.0.1" )
1459+ 
1460+     @property  
1461+     def  galaxy_config_file (self ):
1462+         """Path to galaxy configuration file.""" 
1463+         return  self .env .get ("GALAXY_CONFIG_FILE" , os .path .join (self .config_directory , "galaxy.yml" ))
1464+ 
1465+     def  kill (self ):
1466+         """Kill uvx Galaxy process.""" 
1467+         if  self ._ctx .verbose :
1468+             shell (["ps" , "ax" ])
1469+             exists  =  os .path .exists (self .pid_file )
1470+             print (f"Killing pid file [{ self .pid_file }  )
1471+             print (f"pid_file exists? [{ exists }  )
1472+             if  exists :
1473+                 with  open (self .pid_file ) as  f :
1474+                     print (f"pid_file contents are [{ f .read ()}  )
1475+ 
1476+         # Kill process using existing utility 
1477+         kill_pid_file (self .pid_file )
1478+ 
1479+     def  startup_command (self , ctx , ** kwds ):
1480+         """Return a shell command used to startup this uvx Galaxy instance.""" 
1481+         daemon  =  kwds .get ("daemon" , False )
1482+         uvx_cmd  =  self ._build_uvx_command (** kwds )
1483+ 
1484+         if  daemon :
1485+             # Use shell background execution for daemon mode - return as single string for shell execution 
1486+             return  f"nohup { shell_join (uvx_cmd )} { self .log_file } { self .pid_file }  
1487+         else :
1488+             # Direct foreground execution 
1489+             return  shell_join (uvx_cmd )
1490+ 
1491+     def  _build_uvx_command (self , ** kwds ):
1492+         """Build uvx galaxy command with appropriate flags.""" 
1493+         cmd  =  ["uvx" , "galaxy" ]
1494+ 
1495+         # Only pass config file - host and port are configured in galaxy.yml 
1496+         cmd .extend (["-c" , self .galaxy_config_file ])
1497+ 
1498+         return  cmd 
1499+ 
1500+     @property  
1501+     def  log_file (self ):
1502+         """Log file used when planemo serves this uvx Galaxy instance.""" 
1503+         file_name  =  f"{ self .server_name }  
1504+         return  os .path .join (self .config_directory , file_name )
1505+ 
1506+     @property  
1507+     def  pid_file (self ):
1508+         """PID file for uvx Galaxy process.""" 
1509+         pid_file_name  =  f"{ self .server_name }  
1510+         return  os .path .join (self .config_directory , pid_file_name )
1511+ 
1512+     @property  
1513+     def  log_contents (self ):
1514+         """Return contents of log file.""" 
1515+         if  not  os .path .exists (self .log_file ):
1516+             return  "" 
1517+         with  open (self .log_file ) as  f :
1518+             return  f .read ()
1519+ 
1520+     def  cleanup (self ):
1521+         """Clean up uvx Galaxy configuration.""" 
1522+         shutil .rmtree (self .config_directory , CLEANUP_IGNORE_ERRORS )
1523+ 
1524+     @property  
1525+     def  default_use_path_paste (self ):
1526+         """Default path paste setting for uvx Galaxy.""" 
1527+         return  self .user_is_admin 
1528+ 
1529+     def  _install_galaxy (self ):
1530+         """Override to skip Galaxy installation - uvx manages this.""" 
1531+         # No-op for uvx since it manages Galaxy installation 
1532+         return  True 
1533+ 
1534+     def  _ensure_galaxy_repository_available (self ):
1535+         """Override to skip repository cloning - not needed for uvx.""" 
1536+         # No-op for uvx since no repository is needed 
1537+         return  True 
1538+ 
1539+ 
1540+ @contextlib .contextmanager  
1541+ def  uvx_galaxy_config (ctx , runnables , for_tests = False , ** kwds ):
1542+     """Set up a ``UvxGalaxyConfig`` in an auto-cleaned context.""" 
1543+     test_data_dir  =  _find_test_data (runnables , ** kwds )
1544+ 
1545+     with  _config_directory (ctx , ** kwds ) as  config_directory :
1546+ 
1547+         def  config_join (* args ):
1548+             return  os .path .join (config_directory , * args )
1549+ 
1550+         server_name  =  "main" 
1551+ 
1552+         # Ensure dependency resolvers are configured 
1553+         ensure_dependency_resolvers_conf_configured (ctx , kwds , os .path .join (config_directory , "resolvers_conf.xml" ))
1554+ 
1555+         # Handle basic galaxy configuration without installation 
1556+         galaxy_root  =  config_directory   # Use config directory as galaxy root for uvx 
1557+         # Skip refgenie config for uvx since Galaxy is managed by uvx 
1558+ 
1559+         # Setup tool paths (but don't require galaxy_root) 
1560+         all_tool_paths  =  _all_tool_paths (runnables , galaxy_root = None , extra_tools = kwds .get ("extra_tools" ))
1561+         kwds ["all_in_one_handling" ] =  True 
1562+         _handle_job_config_file (config_directory , server_name , test_data_dir , all_tool_paths , kwds )
1563+         _handle_file_sources (config_directory , test_data_dir , kwds )
1564+ 
1565+         # Basic paths setup 
1566+         file_path  =  kwds .get ("file_path" ) or  config_join ("files" )
1567+         _ensure_directory (file_path )
1568+ 
1569+         tool_dependency_dir  =  kwds .get ("tool_dependency_dir" ) or  config_join ("deps" )
1570+         _ensure_directory (tool_dependency_dir )
1571+ 
1572+         shed_tool_conf  =  kwds .get ("shed_tool_conf" ) or  config_join ("shed_tools_conf.xml" )
1573+         empty_tool_conf  =  config_join ("empty_tool_conf.xml" )
1574+         tool_conf  =  config_join ("tool_conf.xml" )
1575+         shed_data_manager_config_file  =  config_join ("shed_data_manager_conf.xml" )
1576+ 
1577+         shed_tool_path  =  kwds .get ("shed_tool_path" ) or  config_join ("shed_tools" )
1578+         _ensure_directory (shed_tool_path )
1579+ 
1580+         sheds_config_path  =  _configure_sheds_config_file (ctx , config_directory , runnables , ** kwds )
1581+ 
1582+         database_location  =  config_join ("galaxy.sqlite" )
1583+         master_api_key  =  _get_master_api_key (kwds )
1584+         dependency_dir  =  os .path .join (config_directory , "deps" )
1585+         _ensure_directory (dependency_dir )
1586+         port  =  _get_port (kwds )
1587+ 
1588+         # Template args for file generation 
1589+         # Use fallback for tool shed URL if none configured 
1590+         shed_target_url  =  tool_shed_url (ctx , ** kwds ) or  MAIN_TOOLSHED_URL 
1591+ 
1592+         template_args  =  dict (
1593+             shed_tool_path = shed_tool_path ,
1594+             shed_tool_conf = shed_tool_conf ,
1595+             shed_data_manager_config_file = shed_data_manager_config_file ,
1596+             test_data_dir = test_data_dir ,
1597+             shed_target_url = shed_target_url ,
1598+             dependency_dir = dependency_dir ,
1599+             file_path = file_path ,
1600+             temp_directory = config_directory ,
1601+         )
1602+ 
1603+         # Galaxy properties 
1604+         properties  =  _shared_galaxy_properties (config_directory , kwds , for_tests = for_tests )
1605+         properties .update (
1606+             dict (
1607+                 server_name = server_name ,
1608+                 host = kwds .get ("host" , "127.0.0.1" ),
1609+                 port = str (port ),
1610+                 enable_celery_tasks = "true" ,
1611+                 ftp_upload_dir_template = "${ftp_upload_dir}" ,
1612+                 ftp_upload_purge = "false" ,
1613+                 ftp_upload_dir = test_data_dir  or  os .path .abspath ("." ),
1614+                 ftp_upload_site = "Test Data" ,
1615+                 check_upload_content = "false" ,
1616+                 tool_dependency_dir = dependency_dir ,
1617+                 file_path = file_path ,
1618+                 new_file_path = "${temp_directory}/tmp" ,
1619+                 tool_config_file = f"{ tool_conf } { shed_tool_conf }  ,
1620+                 tool_sheds_config_file = sheds_config_path ,
1621+                 manage_dependency_relationships = "false" ,
1622+                 job_working_directory = "${temp_directory}/job_working_directory" ,
1623+                 template_cache_path = "${temp_directory}/compiled_templates" ,
1624+                 citation_cache_type = "file" ,
1625+                 citation_cache_data_dir = "${temp_directory}/citations/data" ,
1626+                 citation_cache_lock_dir = "${temp_directory}/citations/lock" ,
1627+                 database_auto_migrate = "true" ,
1628+                 enable_beta_tool_formats = "true" ,
1629+                 id_secret = "${id_secret}" ,
1630+                 log_level = "DEBUG"  if  ctx .verbose  else  "INFO" ,
1631+                 debug = "true"  if  ctx .verbose  else  "false" ,
1632+                 watch_tools = "auto" ,
1633+                 default_job_shell = "/bin/bash" ,
1634+                 integrated_tool_panel_config = ("${temp_directory}/integrated_tool_panel_conf.xml" ),
1635+                 migrated_tools_config = empty_tool_conf ,
1636+                 test_data_dir = test_data_dir ,
1637+                 shed_data_manager_config_file = shed_data_manager_config_file ,
1638+                 outputs_to_working_directory = "true" ,
1639+                 object_store_store_by = "uuid" ,
1640+             )
1641+         )
1642+ 
1643+         _handle_container_resolution (ctx , kwds , properties )
1644+         properties ["database_connection" ] =  _database_connection (database_location , ** kwds )
1645+ 
1646+         if  kwds .get ("mulled_containers" , False ):
1647+             properties ["mulled_channels" ] =  kwds .get ("conda_ensure_channels" , "" )
1648+ 
1649+         _handle_kwd_overrides (properties , kwds )
1650+ 
1651+         # Build environment 
1652+         env  =  _build_env_for_galaxy (properties , template_args )
1653+         env ["PLANEMO" ] =  "1" 
1654+         env ["GALAXY_DEVELOPMENT_ENVIRONMENT" ] =  "1" 
1655+ 
1656+         # Write configuration files (but skip Galaxy installation) 
1657+         # Assume uvx Galaxy is modern (>= 22.01) and write YAML config directly 
1658+         env ["GALAXY_CONFIG_FILE" ] =  config_join ("galaxy.yml" )
1659+         env ["GRAVITY_STATE_DIR" ] =  config_join ("gravity" )
1660+         with  NamedTemporaryFile (suffix = ".sock" , delete = True ) as  nt :
1661+             env ["SUPERVISORD_SOCKET" ] =  nt .name 
1662+         write_file (
1663+             env ["GALAXY_CONFIG_FILE" ],
1664+             json .dumps (
1665+                 {
1666+                     "galaxy" : properties ,
1667+                     "gravity" : {
1668+                         "galaxy_root" : galaxy_root ,
1669+                         "gunicorn" : {
1670+                             "bind" : f"{ kwds .get ('host' , 'localhost' )} { port }  ,
1671+                             "preload" : False ,
1672+                         },
1673+                         "gx-it-proxy" : {
1674+                             "enable" : False ,
1675+                         },
1676+                     },
1677+                 },
1678+                 indent = 2 ,
1679+             ),
1680+         )
1681+ 
1682+         # Write tool configurations 
1683+         tool_definition  =  _tool_conf_entry_for (all_tool_paths )
1684+         write_file (tool_conf , _sub (TOOL_CONF_TEMPLATE , dict (tool_definition = tool_definition )))
1685+ 
1686+         shed_tool_conf_contents  =  _sub (SHED_TOOL_CONF_TEMPLATE , template_args )
1687+         write_file (shed_tool_conf , shed_tool_conf_contents , force = False )
1688+         write_file (shed_data_manager_config_file , SHED_DATA_MANAGER_CONF_TEMPLATE )
1689+ 
1690+         yield  UvxGalaxyConfig (
1691+             ctx ,
1692+             config_directory ,
1693+             env ,
1694+             test_data_dir ,
1695+             port ,
1696+             server_name ,
1697+             master_api_key ,
1698+             runnables ,
1699+             kwds ,
1700+         )
1701+ 
1702+ 
14241703__all__  =  (
14251704    "DATABASE_LOCATION_TEMPLATE" ,
14261705    "galaxy_config" ,
1706+     "UvxGalaxyConfig" ,
1707+     "uvx_galaxy_config" ,
14271708)
0 commit comments