Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot use TaskInvocation in Depends annotation. #318

Open
Raker22 opened this issue Feb 16, 2018 · 4 comments
Open

Cannot use TaskInvocation in Depends annotation. #318

Raker22 opened this issue Feb 16, 2018 · 4 comments

Comments

@Raker22
Copy link

Raker22 commented Feb 16, 2018

The Depends documentation states that a TaskInvocation can be used instead of a Function or String in order to pass arguments to a dependent task. However, when trying to pass an instance of TaskInvocation to Depends, dart throws an error for it not being a compile-time constant.

error: line 11 pos 10: expression is not a valid compile-time constant @Depends(new TaskInvocation('print'))

When I try to make a constant TaskInvocation dart throws an error because it isn't a const constructor.

error: line 11 pos 39: non-const constructor 'TaskInvocation' cannot be used in const object creation @Depends(const TaskInvocation('print'))

This is my grind.dart file. Am I using this correctly?

import 'package:grinder/grinder.dart';

void main(List<String> args) => grind(args);

@DefaultTask()
void print() {
  log(context.invocation.arguments.arguments.toString());
}

@Task()
@Depends(const TaskInvocation('print'))
void printTest() {

}
@Raker22
Copy link
Author

Raker22 commented Feb 16, 2018

Also, I am using grinder 0.8.1

$ pub deps | grep 'grinder'
|-- grinder 0.8.1

@Raker22
Copy link
Author

Raker22 commented Feb 16, 2018

I've tried to make TaskInvocation and TaskArgs with constant constructors, but, since they have constructor bodies this is proving difficult. An easier solution would be to make another class that has a const constructor and has a method that returns a TaskInvocation.

I think this would fix the problem, but I don't have time to pull down the repo and test it at the moment. It would just require the use of the new class TaskDependecy instead of TaskInvocation when using the Depends annotation.

class TaskDependency {
  final String name;
  final List<String> arguments;

  const TaskDependency(this.name, [this.arguments = const <String>[]]);

  TaskInvocation toTaskInvocation() {
    return new TaskInvocation(this.name, new TaskArgs(this.name, this.arguments));
  }
}

Then in discover_tasks.dart

class TaskDiscovery {
  ...
  AnnotatedTask discoverDeclaration(
      DeclarationMirror decl, Map<DeclarationMirror, AnnotatedTask> cache) {
    ...
    if (annotation != null) {
      ...
      if (dependsAnnotation != null) {
        depends = dependsAnnotation.depends.map((dep) {
          // if (dep is TaskInvocation) return dep; // Impossible to have a const TaskInvocation
          if (dep is TaskDependency) return dep.toTaskInvocation(); // add this line
          if (dep is String) return new TaskInvocation(dep);
          if (dep is Function) {
            ...
          }
          ...
        }).toList();
      }
      ...
    }
    ...
  }
}

@bunopus
Copy link

bunopus commented Jun 24, 2019

Hello, @devoncarew!
I know this issue is here for a while, but it's now blocking our development. Maybe you can help with that?
Thank you in advance

@srawlins
Copy link
Contributor

As a local work-around, there is a neat trick regarding const arguments you can use: declare a new class which implements TaskArgs, and another which implements TaskInvocation, with const constructors:

class _TaskArgs2 implements TaskArgs {
  @override
  final String taskName;
  final Map<String, bool> _flags;
  final Map<String, String> _options;

  const _TaskArgs2(this.taskName,
      {Map<String, bool> flags, Map<String, String> options})
      : _flags = flags,
        _options = options;

  @override
  bool hasFlag(String name) => _flags.containsKey(name);

  @override
  bool getFlag(String name) => _flags[name] ?? false;

  @override
  bool hasOption(String name) => _options.containsKey(name);

  @override
  String getOption(String name) => _options[name];

  @override
  List<String> get arguments => throw UnimplementedError();
}

class _TaskInvocation2 implements TaskInvocation {
  @override
  final String name;
  final TaskArgs _arguments;
  const _TaskInvocation2(this.name, this._arguments);
  @override
  TaskArgs get arguments => _arguments;
}

const _localServerUrlArgs = _TaskArgs2('build', flags: {}, options: {
  'option1': 'one',
  'option2': 'two',
});

@Depends(_TaskInvocation2('build', _localServerUrlArgs))
run() {}

In fact, if a non-breaking solution is preferred for this issue, it may be via subclasses like these.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants