@@ -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,289 @@ 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 } 2>&1 & echo $! > { 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 } .log"
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 } .pid"
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+ try :
1591+ shed_target_url = tool_shed_url (ctx , ** kwds ) or MAIN_TOOLSHED_URL
1592+ except :
1593+ shed_target_url = MAIN_TOOLSHED_URL
1594+
1595+ template_args = dict (
1596+ shed_tool_path = shed_tool_path ,
1597+ shed_tool_conf = shed_tool_conf ,
1598+ shed_data_manager_config_file = shed_data_manager_config_file ,
1599+ test_data_dir = test_data_dir ,
1600+ shed_target_url = shed_target_url ,
1601+ dependency_dir = dependency_dir ,
1602+ file_path = file_path ,
1603+ temp_directory = config_directory ,
1604+ )
1605+
1606+ # Galaxy properties
1607+ properties = _shared_galaxy_properties (config_directory , kwds , for_tests = for_tests )
1608+ properties .update (
1609+ dict (
1610+ server_name = server_name ,
1611+ host = kwds .get ("host" , "127.0.0.1" ),
1612+ port = str (port ),
1613+ enable_celery_tasks = "true" ,
1614+ ftp_upload_dir_template = "${ftp_upload_dir}" ,
1615+ ftp_upload_purge = "false" ,
1616+ ftp_upload_dir = test_data_dir or os .path .abspath ("." ),
1617+ ftp_upload_site = "Test Data" ,
1618+ check_upload_content = "false" ,
1619+ tool_dependency_dir = dependency_dir ,
1620+ file_path = file_path ,
1621+ new_file_path = "${temp_directory}/tmp" ,
1622+ tool_config_file = f"{ tool_conf } ,{ shed_tool_conf } " ,
1623+ tool_sheds_config_file = sheds_config_path ,
1624+ manage_dependency_relationships = "false" ,
1625+ job_working_directory = "${temp_directory}/job_working_directory" ,
1626+ template_cache_path = "${temp_directory}/compiled_templates" ,
1627+ citation_cache_type = "file" ,
1628+ citation_cache_data_dir = "${temp_directory}/citations/data" ,
1629+ citation_cache_lock_dir = "${temp_directory}/citations/lock" ,
1630+ database_auto_migrate = "true" ,
1631+ enable_beta_tool_formats = "true" ,
1632+ id_secret = "${id_secret}" ,
1633+ log_level = "DEBUG" if ctx .verbose else "INFO" ,
1634+ debug = "true" if ctx .verbose else "false" ,
1635+ watch_tools = "auto" ,
1636+ default_job_shell = "/bin/bash" ,
1637+ integrated_tool_panel_config = ("${temp_directory}/integrated_tool_panel_conf.xml" ),
1638+ migrated_tools_config = empty_tool_conf ,
1639+ test_data_dir = test_data_dir ,
1640+ shed_data_manager_config_file = shed_data_manager_config_file ,
1641+ outputs_to_working_directory = "true" ,
1642+ object_store_store_by = "uuid" ,
1643+ )
1644+ )
1645+
1646+ _handle_container_resolution (ctx , kwds , properties )
1647+ properties ["database_connection" ] = _database_connection (database_location , ** kwds )
1648+
1649+ if kwds .get ("mulled_containers" , False ):
1650+ properties ["mulled_channels" ] = kwds .get ("conda_ensure_channels" , "" )
1651+
1652+ _handle_kwd_overrides (properties , kwds )
1653+
1654+ # Build environment
1655+ env = _build_env_for_galaxy (properties , template_args )
1656+ env ["PLANEMO" ] = "1"
1657+ env ["GALAXY_DEVELOPMENT_ENVIRONMENT" ] = "1"
1658+
1659+ # Write configuration files (but skip Galaxy installation)
1660+ # Assume uvx Galaxy is modern (>= 22.01) and write YAML config directly
1661+ env ["GALAXY_CONFIG_FILE" ] = config_join ("galaxy.yml" )
1662+ env ["GRAVITY_STATE_DIR" ] = config_join ("gravity" )
1663+ with NamedTemporaryFile (suffix = ".sock" , delete = True ) as nt :
1664+ env ["SUPERVISORD_SOCKET" ] = nt .name
1665+ write_file (
1666+ env ["GALAXY_CONFIG_FILE" ],
1667+ json .dumps (
1668+ {
1669+ "galaxy" : properties ,
1670+ "gravity" : {
1671+ "galaxy_root" : galaxy_root ,
1672+ "gunicorn" : {
1673+ "bind" : f"{ kwds .get ('host' , 'localhost' )} :{ port } " ,
1674+ "preload" : False ,
1675+ },
1676+ "gx-it-proxy" : {
1677+ "enable" : False ,
1678+ },
1679+ },
1680+ },
1681+ indent = 2 ,
1682+ ),
1683+ )
1684+
1685+ # Write tool configurations
1686+ tool_definition = _tool_conf_entry_for (all_tool_paths )
1687+ write_file (tool_conf , _sub (TOOL_CONF_TEMPLATE , dict (tool_definition = tool_definition )))
1688+
1689+ shed_tool_conf_contents = _sub (SHED_TOOL_CONF_TEMPLATE , template_args )
1690+ write_file (shed_tool_conf , shed_tool_conf_contents , force = False )
1691+ write_file (shed_data_manager_config_file , SHED_DATA_MANAGER_CONF_TEMPLATE )
1692+
1693+ yield UvxGalaxyConfig (
1694+ ctx ,
1695+ config_directory ,
1696+ env ,
1697+ test_data_dir ,
1698+ port ,
1699+ server_name ,
1700+ master_api_key ,
1701+ runnables ,
1702+ kwds ,
1703+ )
1704+
1705+
14241706__all__ = (
14251707 "DATABASE_LOCATION_TEMPLATE" ,
14261708 "galaxy_config" ,
1709+ "UvxGalaxyConfig" ,
1710+ "uvx_galaxy_config" ,
14271711)
0 commit comments