@@ -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 } 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+ 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