Skip to content

Commit

Permalink
✨ Make early access project scope (#330)
Browse files Browse the repository at this point in the history
* project scope early access

* add global default flag

* Remove extra resolve_templates call

* use project's ea setting in query templates

* Add back early access project parameter

---------

Co-authored-by: ayushuk <[email protected]>
Co-authored-by: Ayush Shukla <[email protected]>
  • Loading branch information
3 people authored Feb 18, 2024
1 parent a335b80 commit 30dfe91
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 28 deletions.
5 changes: 4 additions & 1 deletion pros/cli/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,13 @@ def callback(ctx: click.Context, param: click.Parameter, value: str):
if project_path is None:
if allow_none:
return None
else:
elif required:
raise click.UsageError(f'{os.path.abspath(value or ".")} is not inside a PROS project. '
f'Execute this command from within a PROS project or specify it '
f'with --project project/path')
else:
return None

return c.Project(project_path)

def wrapper(f: Union[click.Command, Callable]):
Expand Down
19 changes: 8 additions & 11 deletions pros/cli/conductor.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def fetch(query: c.BaseTemplate):
help="Force apply the template, disregarding if the template is already installed.")
@click.option('--remove-empty-dirs/--no-remove-empty-dirs', 'remove_empty_directories', is_flag=True, default=True,
help='Remove empty directories when removing files')
@click.option('--early-access/--disable-early-access', '--early/--disable-early', '-ea/-dea', 'early_access', '--beta/--disable-beta', default=None,
@click.option('--early-access/--no-early-access', '--early/--no-early', '-ea/-nea', 'early_access', '--beta/--no-beta', default=None,
help='Create a project using the PROS 4 kernel')
@project_option()
@template_query(required=True)
Expand Down Expand Up @@ -145,7 +145,7 @@ def install(ctx: click.Context, **kwargs):
help="Force apply the template, disregarding if the template is already installed.")
@click.option('--remove-empty-dirs/--no-remove-empty-dirs', 'remove_empty_directories', is_flag=True, default=True,
help='Remove empty directories when removing files')
@click.option('--early-access/--disable-early-access', '--early/--disable-early', '-ea/-dea', 'early_access', '--beta/--disable-beta', default=None,
@click.option('--early-access/--no-early-access', '--early/--no-early', '-ea/-nea', 'early_access', '--beta/--no-beta', default=None,
help='Create a project using the PROS 4 kernel')
@project_option()
@template_query(required=False)
Expand Down Expand Up @@ -207,7 +207,7 @@ def uninstall_template(project: c.Project, query: c.BaseTemplate, remove_user: b
help='Compile the project after creation')
@click.option('--build-cache', is_flag=True, default=None, show_default=False,
help='Build compile commands cache after creation. Overrides --compile-after if both are specified.')
@click.option('--early-access/--disable-early-access', '--early/--disable-early', '-ea/-dea', 'early_access', '--beta/--disable-beta', default=None,
@click.option('--early-access/--no-early-access', '--early/--no-early', '-ea/-nea', 'early_access', '--beta/--no-beta', default=None,
help='Create a project using the PROS 4 kernel')
@click.pass_context
@default_options
Expand Down Expand Up @@ -261,12 +261,13 @@ def new_project(ctx: click.Context, path: str, target: str, version: str,
help='Force update all remote depots, ignoring automatic update checks')
@click.option('--limit', type=int, default=15,
help='The maximum number of displayed results for each library')
@click.option('--early-access/--disable-early-access', '--early/--disable-early', '-ea/-dea', 'early_access', '--beta/--disable-beta', default=None,
@click.option('--early-access/--no-early-access', '--early/--no-early', '-ea/-nea', 'early_access', '--beta/--no-beta', default=None,
help='View a list of early access templates')
@template_query(required=False)
@project_option(required=False)
@click.pass_context
@default_options
def query_templates(ctx, query: c.BaseTemplate, allow_offline: bool, allow_online: bool, force_refresh: bool,
def query_templates(ctx, project: Optional[c.Project], query: c.BaseTemplate, allow_offline: bool, allow_online: bool, force_refresh: bool,
limit: int, early_access: bool):
"""
Query local and remote templates based on a spec
Expand All @@ -276,12 +277,10 @@ def query_templates(ctx, query: c.BaseTemplate, allow_offline: bool, allow_onlin
analytics.send("query-templates")
if limit < 0:
limit = 15
if early_access is None and project is not None:
early_access = project.use_early_access
templates = c.Conductor().resolve_templates(query, allow_offline=allow_offline, allow_online=allow_online,
force_refresh=force_refresh, early_access=early_access)
if early_access:
templates += c.Conductor().resolve_templates(query, allow_offline=allow_offline, allow_online=allow_online,
force_refresh=force_refresh, early_access=False)

render_templates = {}
for template in templates:
key = (template.identifier, template.origin)
Expand Down Expand Up @@ -372,7 +371,6 @@ def query_depots(url: bool):
ui.echo(f"Available Depots{' (Add --url for the url)' if not url else ''}:\n")
ui.echo('\n'.join(_conductor.query_depots(url))+"\n")


@conductor.command('reset')
@click.option('--force', is_flag=True, default=False, help='Force reset')
@default_options
Expand All @@ -394,4 +392,3 @@ def reset(force: bool):
os.remove(file)

ui.echo("Conductor was reset")

21 changes: 20 additions & 1 deletion pros/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import pros.cli.misc_commands
import pros.cli.interactive
import pros.cli.user_script
import pros.conductor as c

if sys.platform == 'win32':
kernel32 = ctypes.windll.kernel32
Expand Down Expand Up @@ -99,7 +100,23 @@ def use_analytics(ctx: click.Context, param, value):
ctx.exit(0)
ctx.ensure_object(dict)
analytics.set_use(touse)
ui.echo('Analytics set to : {}'.format(analytics.useAnalytics))
ui.echo(f'Analytics usage set to: {analytics.useAnalytics}')
ctx.exit(0)

def use_early_access(ctx: click.Context, param, value):
if value is None:
return
conductor = c.Conductor()
value = str(value).lower()
if value.startswith("t") or value in ["1", "yes", "y"]:
conductor.use_early_access = True
elif value.startswith("f") or value in ["0", "no", "n"]:
conductor.use_early_access = False
else:
ui.echo('Invalid argument provided for \'--use-early-access\'. Try \'--use-early-access=False\' or \'--use-early-access=True\'')
ctx.exit(0)
conductor.save()
ui.echo(f'Early access set to: {conductor.use_early_access}')
ctx.exit(0)


Expand All @@ -112,6 +129,8 @@ def use_analytics(ctx: click.Context, param, value):
callback=version)
@click.option('--use-analytics', help='Set analytics usage (True/False).', type=str, expose_value=False,
is_eager=True, default=None, callback=use_analytics)
@click.option('--use-early-access', type=str, expose_value=False, is_eager=True, default=None,
help='Create projects with PROS 4 kernel by default', callback=use_early_access)
def cli(ctx):
pros.common.sentry.register()
ctx.call_on_close(after_command)
Expand Down
42 changes: 28 additions & 14 deletions pros/conductor/conductor.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,15 +188,17 @@ def resolve_templates(self, identifier: Union[str, BaseTemplate], allow_online:
results = list() if not unique else set()
kernel_version = kwargs.get('kernel_version', None)
if kwargs.get('early_access', None) is not None:
self.use_early_access = kwargs.get('early_access', False)
use_early_access = kwargs.get('early_access', False)
else:
use_early_access = self.use_early_access
if isinstance(identifier, str):
query = BaseTemplate.create_query(name=identifier, **kwargs)
else:
query = identifier
if allow_offline:
offline_results = list()

if self.use_early_access:
if use_early_access:
offline_results.extend(filter(lambda t: t.satisfies(query, kernel_version=kernel_version), self.early_access_local_templates))

offline_results.extend(filter(lambda t: t.satisfies(query, kernel_version=kernel_version), self.local_templates))
Expand All @@ -208,7 +210,7 @@ def resolve_templates(self, identifier: Union[str, BaseTemplate], allow_online:
if allow_online:
for depot in self.depots.values():
# EarlyAccess depot will only be accessed when the --early-access flag is true
if depot.name != EARLY_ACCESS_NAME or (depot.name == EARLY_ACCESS_NAME and self.use_early_access):
if depot.name != EARLY_ACCESS_NAME or (depot.name == EARLY_ACCESS_NAME and use_early_access):
remote_templates = depot.get_remote_templates(force_check=force_refresh, **kwargs)
online_results = list(filter(lambda t: t.satisfies(query, kernel_version=kernel_version),
remote_templates))
Expand All @@ -219,8 +221,8 @@ def resolve_templates(self, identifier: Union[str, BaseTemplate], allow_online:
results.extend(online_results)
logger(__name__).debug('Saving Conductor config after checking for remote updates')
self.save() # Save self since there may have been some updates from the depots
if len(results) == 0 and not self.use_early_access:

if len(results) == 0 and not use_early_access:
raise dont_send(
InvalidTemplateException(f'{identifier.name} does not support kernel version {kernel_version}'))

Expand Down Expand Up @@ -298,15 +300,16 @@ def apply_template(self, project: Project, identifier: Union[str, BaseTemplate],
if not confirm:
raise dont_send(
InvalidTemplateException(f'Not downgrading'))
elif not self.use_early_access and template.version[0] == '3' and not self.warn_early_access:
elif not project.use_early_access and template.version[0] == '3' and not self.warn_early_access:
confirm = ui.confirm(f'PROS 4 is now in early access. '
f'Please use the --early-access flag if you would like to use it.\n'
f'Do you want to use PROS 4 instead?')
self.warn_early_access = True
if confirm: # use pros 4
self.use_early_access = True
project.use_early_access = True
project.save()
kwargs['version'] = '>=0'
self.save()
kwargs['early_access'] = True
# Recall the function with early access enabled
return self.apply_template(project, identifier, **kwargs)

Expand Down Expand Up @@ -351,14 +354,25 @@ def remove_template(project: Project, identifier: Union[str, BaseTemplate], remo

def new_project(self, path: str, no_default_libs: bool = False, **kwargs) -> Project:
if kwargs.get('early_access', None) is not None:
self.use_early_access = kwargs.get('early_access', False)
use_early_access = kwargs.get('early_access', False)
else:
use_early_access = self.use_early_access
kwargs["early_access"] = use_early_access
if kwargs["version_source"]: # If true, then the user has not specified a version
if not self.use_early_access and self.warn_early_access:
if not use_early_access and self.warn_early_access:
ui.echo(f"PROS 4 is now in early access. "
f"If you would like to use it, use the --early-access flag.")
elif self.use_early_access:
elif not use_early_access and not self.warn_early_access:
confirm = ui.confirm(f'PROS 4 is now in early access. '
f'Please use the --early-access flag if you would like to use it.\n'
f'Do you want to use PROS 4 instead?')
self.warn_early_access = True
if confirm:
use_early_access = True
kwargs['early_access'] = True
elif use_early_access:
ui.echo(f'Early access is enabled. Using PROS 4.')
elif self.use_early_access:
elif use_early_access:
ui.echo(f'Early access is enabled.')

if not is_pathname_valid(str(Path(path).absolute())):
Expand All @@ -367,7 +381,7 @@ def new_project(self, path: str, no_default_libs: bool = False, **kwargs) -> Pro
if Path(path).exists() and Path(path).samefile(os.path.expanduser('~')):
raise dont_send(ValueError('Will not create a project in user home directory'))

proj = Project(path=path, create=True)
proj = Project(path=path, create=True, early_access=use_early_access)
if 'target' in kwargs:
proj.target = kwargs['target']
if 'project_name' in kwargs and kwargs['project_name'] and not kwargs['project_name'].isspace():
Expand All @@ -381,7 +395,7 @@ def new_project(self, path: str, no_default_libs: bool = False, **kwargs) -> Pro
proj.save()

if not no_default_libs:
libraries = self.early_access_libraries if self.use_early_access and (kwargs.get("version", ">").startswith("4") or kwargs.get("version", ">").startswith(">")) else self.default_libraries
libraries = self.early_access_libraries if proj.use_early_access and (kwargs.get("version", ">").startswith("4") or kwargs.get("version", ">").startswith(">")) else self.default_libraries
for library in libraries[proj.target]:
try:
# remove kernel version so that latest template satisfying query is correctly selected
Expand Down
3 changes: 2 additions & 1 deletion pros/conductor/project/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@


class Project(Config):
def __init__(self, path: str = '.', create: bool = False, raise_on_error: bool = True, defaults: dict = None):
def __init__(self, path: str = '.', create: bool = False, raise_on_error: bool = True, defaults: dict = None, early_access: bool = False):
"""
Instantiates a PROS project configuration
:param path: A path to the project, may be the actual project.pros file, any child directory of the project,
Expand All @@ -38,6 +38,7 @@ def __init__(self, path: str = '.', create: bool = False, raise_on_error: bool =
self.templates: Dict[str, Template] = defaults.get('templates', {})
self.upload_options: Dict = defaults.get('upload_options', {})
self.project_name: str = defaults.get('project_name', None)
self.use_early_access = early_access
super(Project, self).__init__(file, error_on_decode=raise_on_error)
if 'kernel' in self.__dict__:
# Add backwards compatibility with PROS CLI 2 projects by adding kernel as a pseudo-template
Expand Down

0 comments on commit 30dfe91

Please sign in to comment.