@@ -158,6 +158,8 @@ def galaxy_config(ctx, runnables, **kwds):
158
158
c = docker_galaxy_config
159
159
elif kwds .get ("external" , False ):
160
160
c = external_galaxy_config
161
+ elif kwds .get ("uvx_galaxy" , False ):
162
+ c = uvx_galaxy_config
161
163
log_thread = None
162
164
e = threading .Event ()
163
165
try :
@@ -1421,7 +1423,286 @@ def _ensure_directory(path):
1421
1423
os .makedirs (path )
1422
1424
1423
1425
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
+
1424
1703
__all__ = (
1425
1704
"DATABASE_LOCATION_TEMPLATE" ,
1426
1705
"galaxy_config" ,
1706
+ "UvxGalaxyConfig" ,
1707
+ "uvx_galaxy_config" ,
1427
1708
)
0 commit comments