all: Use protobuf to generate config structs (fixes #6734) (#6900)

This commit is contained in:
Audrius Butkevicius
2020-08-25 08:11:14 +02:00
committed by GitHub
parent 5b953033c7
commit d507d932b8
84 changed files with 3807 additions and 542 deletions
+24
View File
@@ -0,0 +1,24 @@
syntax = "proto2";
package ext;
import "google/protobuf/descriptor.proto";
option go_package = "github.com/syncthing/syncthing/proto/ext";
extend google.protobuf.MessageOptions {
optional bool xml_tags = 74001;
}
extend google.protobuf.FieldOptions {
optional string xml = 75005;
optional string json = 75006;
optional string default = 75007;
optional bool restart = 75008;
optional bool device_id = 75009;
optional string goname = 75010;
}
extend google.protobuf.EnumValueOptions {
optional string enumgoname = 76010;
}
+131
View File
@@ -0,0 +1,131 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: ext.proto
package ext
import (
fmt "fmt"
proto "github.com/gogo/protobuf/proto"
descriptor "github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
var E_XmlTags = &proto.ExtensionDesc{
ExtendedType: (*descriptor.MessageOptions)(nil),
ExtensionType: (*bool)(nil),
Field: 74001,
Name: "ext.xml_tags",
Tag: "varint,74001,opt,name=xml_tags",
Filename: "ext.proto",
}
var E_Xml = &proto.ExtensionDesc{
ExtendedType: (*descriptor.FieldOptions)(nil),
ExtensionType: (*string)(nil),
Field: 75005,
Name: "ext.xml",
Tag: "bytes,75005,opt,name=xml",
Filename: "ext.proto",
}
var E_Json = &proto.ExtensionDesc{
ExtendedType: (*descriptor.FieldOptions)(nil),
ExtensionType: (*string)(nil),
Field: 75006,
Name: "ext.json",
Tag: "bytes,75006,opt,name=json",
Filename: "ext.proto",
}
var E_Default = &proto.ExtensionDesc{
ExtendedType: (*descriptor.FieldOptions)(nil),
ExtensionType: (*string)(nil),
Field: 75007,
Name: "ext.default",
Tag: "bytes,75007,opt,name=default",
Filename: "ext.proto",
}
var E_Restart = &proto.ExtensionDesc{
ExtendedType: (*descriptor.FieldOptions)(nil),
ExtensionType: (*bool)(nil),
Field: 75008,
Name: "ext.restart",
Tag: "varint,75008,opt,name=restart",
Filename: "ext.proto",
}
var E_DeviceId = &proto.ExtensionDesc{
ExtendedType: (*descriptor.FieldOptions)(nil),
ExtensionType: (*bool)(nil),
Field: 75009,
Name: "ext.device_id",
Tag: "varint,75009,opt,name=device_id",
Filename: "ext.proto",
}
var E_Goname = &proto.ExtensionDesc{
ExtendedType: (*descriptor.FieldOptions)(nil),
ExtensionType: (*string)(nil),
Field: 75010,
Name: "ext.goname",
Tag: "bytes,75010,opt,name=goname",
Filename: "ext.proto",
}
var E_Enumgoname = &proto.ExtensionDesc{
ExtendedType: (*descriptor.EnumValueOptions)(nil),
ExtensionType: (*string)(nil),
Field: 76010,
Name: "ext.enumgoname",
Tag: "bytes,76010,opt,name=enumgoname",
Filename: "ext.proto",
}
func init() {
proto.RegisterExtension(E_XmlTags)
proto.RegisterExtension(E_Xml)
proto.RegisterExtension(E_Json)
proto.RegisterExtension(E_Default)
proto.RegisterExtension(E_Restart)
proto.RegisterExtension(E_DeviceId)
proto.RegisterExtension(E_Goname)
proto.RegisterExtension(E_Enumgoname)
}
func init() { proto.RegisterFile("ext.proto", fileDescriptor_95fe6908ffcf64d3) }
var fileDescriptor_95fe6908ffcf64d3 = []byte{
// 305 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0xd1, 0x3d, 0x4b, 0x03, 0x31,
0x18, 0xc0, 0x71, 0x8e, 0x16, 0xdb, 0x66, 0xec, 0x24, 0x82, 0xb5, 0x6e, 0x9d, 0xee, 0x10, 0x41,
0x31, 0x74, 0x52, 0x14, 0x1c, 0x44, 0x28, 0xe2, 0xe0, 0x52, 0xd2, 0xcb, 0xd3, 0x34, 0x92, 0x97,
0x72, 0x49, 0x24, 0x6e, 0xea, 0x37, 0xf0, 0x2b, 0x39, 0x69, 0x27, 0xfd, 0x06, 0xd2, 0xd1, 0xef,
0xe0, 0x0b, 0x77, 0x97, 0x93, 0x42, 0x87, 0xdb, 0x42, 0xf8, 0xff, 0x1e, 0x12, 0x1e, 0xd4, 0x01,
0x6f, 0xe3, 0x79, 0xa6, 0xad, 0xee, 0x36, 0xc0, 0xdb, 0xad, 0x3e, 0xd3, 0x9a, 0x09, 0x48, 0x8a,
0xab, 0x89, 0x9b, 0x26, 0x14, 0x4c, 0x9a, 0xf1, 0xb9, 0xd5, 0x59, 0x99, 0xe1, 0x21, 0x6a, 0x7b,
0x29, 0xc6, 0x96, 0x30, 0xd3, 0xdd, 0x89, 0xcb, 0x3c, 0xae, 0xf2, 0xf8, 0x02, 0x8c, 0x21, 0x0c,
0x2e, 0xe7, 0x96, 0x6b, 0x65, 0x36, 0x9f, 0x5f, 0x9a, 0xfd, 0x68, 0xd0, 0x1e, 0xb5, 0xbc, 0x14,
0x57, 0x84, 0x19, 0xbc, 0x87, 0x1a, 0x5e, 0x8a, 0xee, 0xf6, 0x1a, 0x3c, 0xe3, 0x20, 0x68, 0xc5,
0xbe, 0xdf, 0x72, 0xd6, 0x19, 0xe5, 0x2d, 0xde, 0x47, 0xcd, 0x5b, 0xa3, 0x55, 0x9d, 0xf9, 0x09,
0xa6, 0x88, 0xf1, 0x11, 0x6a, 0x51, 0x98, 0x12, 0x27, 0x6c, 0x9d, 0xfb, 0x0d, 0xae, 0xea, 0x73,
0x9a, 0x81, 0xb1, 0x24, 0xab, 0xa5, 0x0f, 0x8b, 0xf0, 0xbb, 0xd0, 0xe3, 0x21, 0xea, 0x50, 0xb8,
0xe3, 0x29, 0x8c, 0x39, 0xad, 0xc3, 0x8f, 0x01, 0xb7, 0x4b, 0x71, 0x4e, 0xf1, 0x21, 0xda, 0x60,
0x5a, 0x11, 0x09, 0x75, 0xf4, 0x69, 0x51, 0x3e, 0x39, 0xe4, 0xf8, 0x04, 0x21, 0x50, 0x4e, 0x06,
0xbc, 0xbb, 0x86, 0x4f, 0x95, 0x93, 0xd7, 0x44, 0xb8, 0xff, 0xb5, 0x7c, 0x7d, 0x94, 0x03, 0x56,
0xd8, 0xf1, 0xc1, 0xeb, 0xb2, 0x17, 0xbd, 0x2f, 0x7b, 0xd1, 0xe7, 0xb2, 0x17, 0xdd, 0x0c, 0x18,
0xb7, 0x33, 0x37, 0x89, 0x53, 0x2d, 0x13, 0x73, 0xaf, 0x52, 0x3b, 0xe3, 0x8a, 0xad, 0x9c, 0x8a,
0xd9, 0x09, 0x78, 0xfb, 0x17, 0x00, 0x00, 0xff, 0xff, 0xcd, 0x40, 0x4c, 0x73, 0x42, 0x02, 0x00,
0x00,
}
+55
View File
@@ -0,0 +1,55 @@
// Copyright (C) 2020 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
//+build ignore
package main
import (
"log"
"os"
"os/exec"
"path/filepath"
)
//go:generate go run scripts/protofmt.go .
// First generate extensions using standard proto compiler.
//go:generate protoc -I ../ -I . --gogofast_out=Mgoogle/protobuf/descriptor.proto=github.com/gogo/protobuf/protoc-gen-gogo/descriptor,paths=source_relative:ext ext.proto
// Then build our vanity compiler that uses the new extensions
//go:generate go build -o scripts/protoc-gen-gosyncthing scripts/protoc_plugin.go
// Inception, go generate calls the script itself that then deals with generation.
// This is only done because go:generate does not support wildcards in paths.
//go:generate go run generate.go lib/config lib/fs
// Use the standard compiler here. We can revisit this later, but we don't plan on exposing this via any APIs.
//go:generate protoc -I ../ -I . --gogofast_out=paths=source_relative:.. lib/protocol/bep.proto
func main() {
for _, path := range os.Args[1:] {
matches, err := filepath.Glob(filepath.Join(path, "*proto"))
if err != nil {
log.Fatal(err)
}
log.Println(path, "returned:", matches)
args := []string{
"-I", "..",
"-I", ".",
"--plugin=protoc-gen-gosyncthing=scripts/protoc-gen-gosyncthing",
"--gosyncthing_out=paths=source_relative:..",
}
args = append(args, matches...)
cmd := exec.Command("protoc", args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Fatal("Failed generating", path)
}
}
}
+14
View File
@@ -0,0 +1,14 @@
syntax = "proto3";
package config;
import "repos/protobuf/gogoproto/gogo.proto";
import "ext.proto";
enum AuthMode {
option (gogoproto.goproto_enum_stringer) = false;
AUTH_MODE_STATIC = 0;
AUTH_MODE_LDAP = 1 [(ext.enumgoname) = "AuthModeLDAP"];
}
+9
View File
@@ -0,0 +1,9 @@
syntax = "proto3";
package config;
enum BlockPullOrder {
BLOCK_PULL_ORDER_STANDARD = 0;
BLOCK_PULL_ORDER_RANDOM = 1;
BLOCK_PULL_ORDER_IN_ORDER = 2;
}
+23
View File
@@ -0,0 +1,23 @@
syntax = "proto3";
package config;
import "lib/config/folderconfiguration.proto";
import "lib/config/deviceconfiguration.proto";
import "lib/config/guiconfiguration.proto";
import "lib/config/ldapconfiguration.proto";
import "lib/config/optionsconfiguration.proto";
import "lib/config/observed.proto";
import "ext.proto";
message Configuration {
int32 version = 1 [(ext.xml) = "version,attr"];
repeated FolderConfiguration folders = 2;
repeated DeviceConfiguration devices = 3;
GUIConfiguration gui = 4 [(ext.goname) = "GUI"];
LDAPConfiguration ldap = 5 [(ext.goname) = "LDAP"];
OptionsConfiguration options = 6;
repeated ObservedDevice ignored_devices = 7 [(ext.json) = "remoteIgnoredDevices", (ext.xml) = "remoteIgnoredDevice"];
repeated ObservedDevice pending_devices = 8;
}
@@ -0,0 +1,27 @@
syntax = "proto3";
package config;
import "lib/protocol/bep.proto";
import "lib/config/observed.proto";
import "ext.proto";
message DeviceConfiguration {
bytes device_id = 1 [(ext.goname) = "DeviceID", (ext.xml) = "id,attr", (ext.json) = "deviceID", (ext.device_id) = true];
string name = 2 [(ext.xml) = "name,attr,omitempty"];
repeated string addresses = 3 [(ext.xml) = "address,omitempty", (ext.default) = "dynamic"];
protocol.Compression compression = 4 [(ext.xml) = "compression,attr"];
string cert_name = 5 [(ext.xml) = "certName,attr,omitempty"];
bool introducer = 6 [(ext.xml) = "introducer,attr"];
bool skip_introduction_removals = 7 [(ext.xml) = "skipIntroductionRemovals,attr"];
bytes introduced_by = 8 [(ext.xml) = "introducedBy,attr", (ext.device_id) = true];
bool paused = 9;
repeated string allowed_networks = 10 [(ext.xml) = "allowedNetwork,omitempty"];
bool auto_accept_folders = 11;
int32 max_send_kbps = 12;
int32 max_recv_kbps = 13;
repeated ObservedFolder ignored_folders = 14;
repeated ObservedFolder pending_folders = 15;
int32 max_request_kib = 16 [(ext.goname) = "MaxRequestKiB", (ext.xml) = "maxRequestKiB", (ext.json) = "maxRequestKiB"];
}
@@ -0,0 +1,61 @@
syntax = "proto3";
package config;
import "lib/config/foldertype.proto";
import "lib/config/size.proto";
import "lib/config/pullorder.proto";
import "lib/config/versioningconfiguration.proto";
import "lib/config/blockpullorder.proto";
import "lib/fs/types.proto";
import "lib/fs/copyrangemethod.proto";
import "ext.proto";
message FolderDeviceConfiguration {
bytes device_id = 1 [(ext.goname) = "DeviceID", (ext.xml) = "id,attr", (ext.json) = "deviceID", (ext.device_id) = true];
bytes introduced_by = 2 [(ext.xml) = "introducedBy,attr", (ext.device_id) = true];
}
message FolderConfiguration {
string id = 1 [(ext.goname) = "ID", (ext.xml) = "id,attr"];
string label = 2 [(ext.xml) = "label,attr", (ext.restart) = false];
fs.FilesystemType filesystem_type = 3;
string path = 4 [(ext.xml) = "path,attr"];
FolderType type = 5 [(ext.xml) = "type,attr"];
repeated FolderDeviceConfiguration devices = 6;
int32 rescan_interval_s = 7 [(ext.xml) = "rescanIntervalS,attr", (ext.default) = "3600"];
bool fs_watcher_enabled = 8 [(ext.goname) = "FSWatcherEnabled", (ext.xml) = "fsWatcherEnabled,attr", (ext.default) = "true"];
int32 fs_watcher_delay_s = 9 [(ext.goname) = "FSWatcherDelayS", (ext.xml) = "fsWatcherDelayS,attr", (ext.default) = "10"];
bool ignore_perms = 10 [(ext.xml) = "ignorePerms,attr"];
bool auto_normalize = 11 [(ext.xml) = "autoNormalize,attr", (ext.default) = "true"];
Size min_disk_free = 12;
VersioningConfiguration versioning = 13;
int32 copiers = 14;
int32 puller_max_pending_kib = 15 [(ext.goname) = "PullerMaxPendingKiB", (ext.xml) = "pullerMaxPendingKiB", (ext.json) = "pullerMaxPendingKiB"];
int32 hashers = 16;
PullOrder order = 17;
bool ignore_delete = 18;
int32 scan_progress_interval_s = 19;
int32 puller_pause_s = 20;
int32 max_conflicts = 21 [(ext.default) = "-1"];
bool disable_sparse_files = 22;
bool disable_temp_indexes = 23;
bool paused = 24;
int32 weak_hash_threshold_pct = 25;
string marker_name = 26;
bool copy_ownership_from_parent = 27;
int32 mod_time_window_s = 28 [(ext.goname) = "RawModTimeWindowS"];
int32 max_concurrent_writes = 29 [(ext.default) = "2"];
bool disable_fsync = 30;
BlockPullOrder block_pull_order = 31;
fs.CopyRangeMethod copy_range_method = 32 [(ext.default) = "standard"];
bool case_sensitive_fs = 33 [(ext.goname) = "CaseSensitiveFS", (ext.xml) = "caseSensitiveFS", (ext.json) = "caseSensitiveFS"];
bool follow_junctions = 34 [(ext.goname) = "JunctionsAsDirs", (ext.xml) = "junctionsAsDirs", (ext.json) = "junctionsAsDirs"];
// Legacy deprecated
bool read_only = 9000 [deprecated=true, (ext.xml) = "ro,attr,omitempty"];
double min_disk_free_pct = 9001 [deprecated=true];
int32 pullers = 9002 [deprecated=true];
}
+9
View File
@@ -0,0 +1,9 @@
syntax = "proto3";
package config;
enum FolderType {
FOLDER_TYPE_SEND_RECEIVE = 0;
FOLDER_TYPE_SEND_ONLY = 1;
FOLDER_TYPE_RECEIVE_ONLY = 2;
}
+23
View File
@@ -0,0 +1,23 @@
syntax = "proto3";
package config;
import "lib/config/authmode.proto";
import "ext.proto";
message GUIConfiguration {
bool enabled = 1 [(ext.xml) = "enabled,attr", (ext.default) = "true"];
string address = 2 [(ext.goname) = "RawAddress", (ext.default) = "127.0.0.1:8384"];
string unix_socket_permissions = 3 [(ext.goname) = "RawUnixSocketPermissions", (ext.xml) = "unixSocketPermissions,omitempty"];
string user = 4 [(ext.xml) = "user,omitempty"];
string password = 5 [(ext.xml) = "password,omitempty"];
AuthMode auth_mode = 6 [(ext.xml) = "authMode,omitempty"];
bool use_tls = 7 [(ext.goname) = "RawUseTLS", (ext.xml) = "tls,attr", (ext.json) = "useTLS"];
string api_key = 8 [(ext.goname) = "APIKey", (ext.xml) = "apikey,omitempty"];
bool insecure_admin_access = 9 [(ext.xml) = "insecureAdminAccess,omitempty"];
string theme = 10 [(ext.default) = "default"];
bool debugging = 11 [(ext.xml) = "debugging,attr"];
bool insecure_skip_host_check = 12 [(ext.xml) = "insecureSkipHostcheck,omitempty", (ext.json) = "insecureSkipHostcheck"];
bool insecure_allow_frame_loading = 13 [(ext.xml) = "insecureAllowFrameLoading,omitempty"];
}
+17
View File
@@ -0,0 +1,17 @@
syntax = "proto3";
package config;
import "lib/config/ldaptransport.proto";
import "ext.proto";
message LDAPConfiguration {
string address = 1 [(ext.xml) = "address,omitempty"];
string bind_dn = 2 [(ext.goname) = "BindDN", (ext.xml) = "bindDN,omitempty", (ext.json) = "bindDN"];
LDAPTransport transport = 3 [(ext.xml) = "transport,omitempty"];
bool insecure_skip_verify = 4 [(ext.xml) = "insecureSkipVerify,omitempty", (ext.default) = "false"];
string search_base_dn = 5 [(ext.goname) = "SearchBaseDN", (ext.xml) = "searchBaseDN,omitempty", (ext.json) = "searchBaseDN"];
string search_filter = 6 [(ext.xml) = "searchFilter,omitempty"];
}
+15
View File
@@ -0,0 +1,15 @@
syntax = "proto3";
package config;
import "repos/protobuf/gogoproto/gogo.proto";
import "ext.proto";
enum LDAPTransport {
option (gogoproto.goproto_enum_stringer) = false;
LDAP_TRANSPORT_PLAIN = 0 [(ext.enumgoname) = "LDAPTransportPlain"];
LDAP_TRANSPORT_TLS = 2 [(ext.enumgoname) = "LDAPTransportTLS"];
LDAP_TRANSPORT_START_TLS = 3 [(ext.enumgoname) = "LDAPTransportStartTLS"];
}
+20
View File
@@ -0,0 +1,20 @@
syntax = "proto3";
package config;
import "google/protobuf/timestamp.proto";
import "ext.proto";
message ObservedFolder {
google.protobuf.Timestamp time = 1 [(ext.xml) = "time,attr"];
string id = 2 [(ext.goname) = "ID", (ext.xml) = "id,attr"];
string label = 3 [(ext.xml) = "label,attr"];
}
message ObservedDevice {
google.protobuf.Timestamp time = 1 [(ext.xml) = "time,attr"];
bytes id = 2 [(ext.goname) = "ID", (ext.json) = "deviceID", (ext.xml) = "id,attr", (ext.device_id) = true];
string name = 3 [(ext.xml) = "name,attr"];
string address = 4 [(ext.xml) = "address,attr"];
}
@@ -0,0 +1,66 @@
syntax = "proto3";
package config;
import "lib/config/tuning.proto";
import "lib/config/size.proto";
import "ext.proto";
message OptionsConfiguration {
repeated string listen_addresses = 1 [(ext.goname) = "RawListenAddresses", (ext.default) = "default"];
repeated string global_discovery_servers = 2 [(ext.goname) = "RawGlobalAnnServers", (ext.xml) = "globalAnnounceServer", (ext.json) = "globalAnnounceServers", (ext.default) = "default"];
bool global_discovery_enabled = 3 [(ext.goname) = "GlobalAnnEnabled", (ext.xml) = "globalAnnounceEnabled", (ext.json) = "globalAnnounceEnabled", (ext.default) = "true"];
bool local_discovery_enabled = 4 [(ext.goname) = "LocalAnnEnabled", (ext.xml) = "localAnnounceEnabled", (ext.json) = "localAnnounceEnabled", (ext.default) = "true"];
int32 local_announce_port = 5 [(ext.goname) = "LocalAnnPort", (ext.xml) = "localAnnouncePort", (ext.json) = "localAnnouncePort", (ext.default) = "21027"];
string local_announce_multicast_address = 6 [(ext.goname) = "LocalAnnMCAddr", (ext.xml) = "localAnnounceMCAddr", (ext.json) = "localAnnounceMCAddr", (ext.default) = "[ff12::8384]:21027"];
int32 max_send_kbps = 7;
int32 max_recv_kbps = 8;
int32 reconnection_interval_s = 9 [(ext.goname) = "ReconnectIntervalS", (ext.default) = "60"];
bool relays_enabled = 10 [(ext.default) = "true"];
int32 relays_reconnect_interval_m = 11 [(ext.goname) = "RelayReconnectIntervalM", (ext.xml) = "relayReconnectIntervalM", (ext.json) = "relayReconnectIntervalM", (ext.default) = "10"];
bool start_browser = 12 [(ext.default) = "true"];
bool nat_traversal_enabled = 14 [(ext.goname) = "NATEnabled", (ext.xml) = "natEnabled", (ext.json) = "natEnabled", (ext.default) = "true"];
int32 nat_traversal_lease_m = 15 [(ext.goname) = "NATLeaseM", (ext.xml) = "natLeaseMinutes", (ext.json) = "natLeaseMinutes", (ext.default) = "60"];
int32 nat_traversal_renewal_m = 16 [(ext.goname) = "NATRenewalM", (ext.xml) = "natRenewalMinutes", (ext.json) = "natRenewalMinutes", (ext.default) = "30"];
int32 nat_traversal_timeout_s = 17 [(ext.goname) = "NATTimeoutS", (ext.xml) = "natTimeoutSeconds", (ext.json) = "natTimeoutSeconds", (ext.default) = "10"];
int32 usage_reporting_accepted = 18 [(ext.goname) = "URAccepted", (ext.xml) = "urAccepted", (ext.json) = "urAccepted"];
int32 usage_reporting_seen = 19 [(ext.goname) = "URSeen", (ext.xml) = "urSeen", (ext.json) = "urSeen"];
string usage_reporting_unique_id = 20 [(ext.goname) = "URUniqueID", (ext.xml) = "urUniqueID", (ext.json) = "urUniqueId"];
string usage_reporting_url = 21 [(ext.goname) = "URURL", (ext.xml) = "urURL", (ext.json) = "urURL", (ext.default) = "https://data.syncthing.net/newdata"];
bool usage_reporting_post_insecurely = 22 [(ext.goname) = "URPostInsecurely", (ext.xml) = "urPostInsecurely", (ext.json) = "urPostInsecurely", (ext.default) = "false"];
int32 usage_reporting_initial_delay_s = 23 [(ext.goname) = "URInitialDelayS", (ext.xml) = "urInitialDelayS", (ext.json) = "urInitialDelayS", (ext.default) = "1800"];
bool restart_on_wakeup = 24 [(ext.default) = "true"];
int32 auto_upgrade_interval_h = 25 [(ext.default) = "12"];
bool upgrade_to_pre_releases = 26;
int32 keep_temporaries_h = 27 [(ext.default) = "24"];
bool cache_ignored_files = 28 [(ext.default) = "false"];
int32 progress_update_interval_s = 29 [(ext.default) = "5"];
bool limit_bandwidth_in_lan = 30 [(ext.default) = "false"];
Size min_home_disk_free = 31 [(ext.default) = "1 %"];
string releases_url = 32 [(ext.goname) = "ReleasesURL", (ext.xml) = "releasesURL", (ext.json) = "releasesURL", (ext.default) = "https://upgrades.syncthing.net/meta.json"];
repeated string always_local_nets = 33;
bool overwrite_remote_device_names_on_connect = 34 [(ext.goname) = "OverwriteRemoteDevNames", (ext.default) = "false"];
int32 temp_index_min_blocks = 35 [(ext.default) = "10"];
repeated string unacked_notification_ids = 36 [(ext.goname) = "UnackedNotificationIDs", (ext.xml) = "unackedNotificationID", (ext.json) = "unackedNotificationIDs"];
int32 traffic_class = 37;
string default_folder_path = 38 [(ext.default) = "~"];
bool set_low_priority = 39 [(ext.default) = "true"];
int32 max_folder_concurrency = 40 [(ext.goname) = "RawMaxFolderConcurrency"];
string crash_reporting_url = 41 [(ext.goname) = "CRURL", (ext.xml) = "crashReportingURL", (ext.json) = "crURL", (ext.default) = "https://crash.syncthing.net/newcrash"];
bool crash_reporting_enabled = 42 [(ext.goname) = "CREnabled", (ext.default) = "true"];
int32 stun_keepalive_start_s = 43 [(ext.default) = "180"];
int32 stun_keepalive_min_s = 44 [(ext.default) = "20"];
repeated string stun_servers = 45 [(ext.goname) = "RawStunServers", (ext.default) = "default"];
Tuning database_tuning = 46 [(ext.restart) = true];
int32 max_concurrent_incoming_request_kib = 47 [(ext.goname) = "RawMaxCIRequestKiB", (ext.xml) = "maxConcurrentIncomingRequestKiB", (ext.json) = "maxConcurrentIncomingRequestKiB"];
// Legacy deprecated
bool upnp_enabled = 9000 [deprecated = true, (ext.goname) = "DeprecatedUPnPEnabled"];
int32 upnp_lease_m = 9001 [deprecated = true, (ext.goname) = "DeprecatedUPnPLeaseM", (ext.xml) = "upnpLeaseMinutes,omitempty"];
int32 upnp_renewal_m = 9002 [deprecated = true, (ext.goname) = "DeprecatedUPnPRenewalM", (ext.xml) = "upnpRenewalMinutes,omitempty"];
int32 upnp_timeout_s = 9003 [deprecated = true, (ext.goname) = "DeprecatedUPnPTimeoutS", (ext.xml) = "upnpTimeoutSeconds,omitempty"];
repeated string relay_servers = 9004 [deprecated = true];
double min_home_disk_free_pct = 9005 [deprecated = true];
int32 max_concurrent_scans = 9006 [deprecated = true];
}
+16
View File
@@ -0,0 +1,16 @@
syntax = "proto3";
package config;
import "repos/protobuf/gogoproto/gogo.proto";
enum PullOrder {
option (gogoproto.goproto_enum_stringer) = false;
PULL_ORDER_RANDOM = 0;
PULL_ORDER_ALPHABETIC = 1;
PULL_ORDER_SMALLEST_FIRST = 2;
PULL_ORDER_LARGEST_FIRST = 3;
PULL_ORDER_OLDEST_FIRST = 4;
PULL_ORDER_NEWEST_FIRST = 5;
}
+14
View File
@@ -0,0 +1,14 @@
syntax = "proto3";
package config;
import "repos/protobuf/gogoproto/gogo.proto";
import "ext.proto";
message Size {
option (gogoproto.goproto_stringer) = false;
double value = 1 [(ext.xml) = ",chardata"];
string unit = 2 [(ext.xml) = "unit,attr"];
}
+13
View File
@@ -0,0 +1,13 @@
syntax = "proto3";
package config;
import "repos/protobuf/gogoproto/gogo.proto";
enum Tuning {
option (gogoproto.goproto_enum_stringer) = false;
TUNING_AUTO = 0;
TUNING_SMALL = 1;
TUNING_LARGE = 2;
}
@@ -0,0 +1,14 @@
syntax = "proto3";
package config;
import "ext.proto";
// VersioningConfiguration is used in the code and for JSON serialization
message VersioningConfiguration {
option (ext.xml_tags) = false;
string type = 1;
map<string, string> parameters = 2 [(ext.goname) = "Params", (ext.json) = "params"];
int32 cleanup_interval_s = 3 [(ext.default) = "3600"];
}
+12
View File
@@ -0,0 +1,12 @@
syntax = "proto3";
package fs;
enum CopyRangeMethod {
COPY_RANGE_METHOD_STANDARD = 0;
COPY_RANGE_METHOD_IOCTL = 1;
COPY_RANGE_METHOD_COPY_FILE_RANGE = 2;
COPY_RANGE_METHOD_SEND_FILE = 3;
COPY_RANGE_METHOD_DUPLICATE_EXTENTS = 4;
COPY_RANGE_METHOD_ALL_WITH_FALLBACK = 5;
}
+8
View File
@@ -0,0 +1,8 @@
syntax = "proto3";
package fs;
enum FilesystemType {
FILESYSTEM_TYPE_BASIC = 0;
FILESYSTEM_TYPE_FAKE = 1;
}
+214
View File
@@ -0,0 +1,214 @@
syntax = "proto3";
package protocol;
import "repos/protobuf/gogoproto/gogo.proto";
option (gogoproto.goproto_getters_all) = false;
option (gogoproto.sizer_all) = false;
option (gogoproto.protosizer_all) = true;
option (gogoproto.goproto_enum_stringer_all) = true;
option (gogoproto.goproto_enum_prefix_all) = false;
option (gogoproto.goproto_unkeyed_all) = false;
option (gogoproto.goproto_unrecognized_all) = false;
option (gogoproto.goproto_sizecache_all) = false;
// --- Pre-auth ---
message Hello {
string device_name = 1;
string client_name = 2;
string client_version = 3;
}
// --- Header ---
message Header {
MessageType type = 1;
MessageCompression compression = 2;
}
enum MessageType {
CLUSTER_CONFIG = 0 [(gogoproto.enumvalue_customname) = "messageTypeClusterConfig"];
INDEX = 1 [(gogoproto.enumvalue_customname) = "messageTypeIndex"];
INDEX_UPDATE = 2 [(gogoproto.enumvalue_customname) = "messageTypeIndexUpdate"];
REQUEST = 3 [(gogoproto.enumvalue_customname) = "messageTypeRequest"];
RESPONSE = 4 [(gogoproto.enumvalue_customname) = "messageTypeResponse"];
DOWNLOAD_PROGRESS = 5 [(gogoproto.enumvalue_customname) = "messageTypeDownloadProgress"];
PING = 6 [(gogoproto.enumvalue_customname) = "messageTypePing"];
CLOSE = 7 [(gogoproto.enumvalue_customname) = "messageTypeClose"];
}
enum MessageCompression {
NONE = 0 [(gogoproto.enumvalue_customname) = "MessageCompressionNone"];
LZ4 = 1 [(gogoproto.enumvalue_customname) = "MessageCompressionLZ4"];
}
// --- Actual messages ---
// Cluster Config
message ClusterConfig {
repeated Folder folders = 1 [(gogoproto.nullable) = false];
}
message Folder {
string id = 1 [(gogoproto.customname) = "ID"];
string label = 2;
bool read_only = 3;
bool ignore_permissions = 4;
bool ignore_delete = 5;
bool disable_temp_indexes = 6;
bool paused = 7;
repeated Device devices = 16 [(gogoproto.nullable) = false];
}
message Device {
bytes id = 1 [(gogoproto.customname) = "ID", (gogoproto.customtype) = "DeviceID", (gogoproto.nullable) = false];
string name = 2;
repeated string addresses = 3;
Compression compression = 4;
string cert_name = 5;
int64 max_sequence = 6;
bool introducer = 7;
uint64 index_id = 8 [(gogoproto.customname) = "IndexID", (gogoproto.customtype) = "IndexID", (gogoproto.nullable) = false];
bool skip_introduction_removals = 9;
}
enum Compression {
METADATA = 0 [(gogoproto.enumvalue_customname) = "CompressMetadata"];
NEVER = 1 [(gogoproto.enumvalue_customname) = "CompressNever"];
ALWAYS = 2 [(gogoproto.enumvalue_customname) = "CompressAlways"];
}
// Index and Index Update
message Index {
string folder = 1;
repeated FileInfo files = 2 [(gogoproto.nullable) = false];
}
message IndexUpdate {
string folder = 1;
repeated FileInfo files = 2 [(gogoproto.nullable) = false];
}
message FileInfo {
option (gogoproto.goproto_stringer) = false;
// The field ordering here optimizes for struct size / alignment --
// large types come before smaller ones.
string name = 1;
int64 size = 3;
int64 modified_s = 5;
uint64 modified_by = 12 [(gogoproto.customtype) = "ShortID", (gogoproto.nullable) = false];
Vector version = 9 [(gogoproto.nullable) = false];
int64 sequence = 10;
repeated BlockInfo blocks = 16 [(gogoproto.nullable) = false];
string symlink_target = 17;
bytes blocks_hash = 18;
FileInfoType type = 2;
uint32 permissions = 4;
int32 modified_ns = 11;
int32 block_size = 13 [(gogoproto.customname) = "RawBlockSize"];
// The local_flags fields stores flags that are relevant to the local
// host only. It is not part of the protocol, doesn't get sent or
// received (we make sure to zero it), nonetheless we need it on our
// struct and to be able to serialize it to/from the database.
uint32 local_flags = 1000;
// The version_hash is an implementation detail and not part of the wire
// format.
bytes version_hash = 1001;
bool deleted = 6;
bool invalid = 7 [(gogoproto.customname) = "RawInvalid"];
bool no_permissions = 8;
}
enum FileInfoType {
FILE = 0 [(gogoproto.enumvalue_customname) = "FileInfoTypeFile"];
DIRECTORY = 1 [(gogoproto.enumvalue_customname) = "FileInfoTypeDirectory"];
SYMLINK_FILE = 2 [(gogoproto.enumvalue_customname) = "FileInfoTypeDeprecatedSymlinkFile", deprecated = true];
SYMLINK_DIRECTORY = 3 [(gogoproto.enumvalue_customname) = "FileInfoTypeDeprecatedSymlinkDirectory", deprecated = true];
SYMLINK = 4 [(gogoproto.enumvalue_customname) = "FileInfoTypeSymlink"];
}
message BlockInfo {
option (gogoproto.goproto_stringer) = false;
bytes hash = 3;
int64 offset = 1;
int32 size = 2;
uint32 weak_hash = 4;
}
message Vector {
repeated Counter counters = 1 [(gogoproto.nullable) = false];
}
message Counter {
uint64 id = 1 [(gogoproto.customname) = "ID", (gogoproto.customtype) = "ShortID", (gogoproto.nullable) = false];
uint64 value = 2;
}
// Request
message Request {
int32 id = 1 [(gogoproto.customname) = "ID"];
string folder = 2;
string name = 3;
int64 offset = 4;
int32 size = 5;
bytes hash = 6;
bool from_temporary = 7;
uint32 weak_hash = 8;
}
// Response
message Response {
int32 id = 1 [(gogoproto.customname) = "ID"];
bytes data = 2;
ErrorCode code = 3;
}
enum ErrorCode {
NO_ERROR = 0 [(gogoproto.enumvalue_customname) = "ErrorCodeNoError"];
GENERIC = 1 [(gogoproto.enumvalue_customname) = "ErrorCodeGeneric"];
NO_SUCH_FILE = 2 [(gogoproto.enumvalue_customname) = "ErrorCodeNoSuchFile"];
INVALID_FILE = 3 [(gogoproto.enumvalue_customname) = "ErrorCodeInvalidFile"];
}
// DownloadProgress
message DownloadProgress {
string folder = 1;
repeated FileDownloadProgressUpdate updates = 2 [(gogoproto.nullable) = false];
}
message FileDownloadProgressUpdate {
FileDownloadProgressUpdateType update_type = 1;
string name = 2;
Vector version = 3 [(gogoproto.nullable) = false];
repeated int32 block_indexes = 4 [packed=false];
int32 block_size = 5;
}
enum FileDownloadProgressUpdateType {
APPEND = 0 [(gogoproto.enumvalue_customname) = "UpdateTypeAppend"];
FORGET = 1 [(gogoproto.enumvalue_customname) = "UpdateTypeForget"];
}
// Ping
message Ping {
}
// Close
message Close {
string reason = 1;
}
+68
View File
@@ -0,0 +1,68 @@
// Copyright (C) 2020 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
//+build ignore
package main
import (
"encoding/csv"
"fmt"
"os"
"path/filepath"
"reflect"
"strings"
"github.com/syncthing/syncthing/lib/config"
)
func main() {
new, err := os.Create("tags.csv")
if err != nil {
panic(err)
}
fmt.Println(filepath.Abs(new.Name()))
w := csv.NewWriter(new)
w.Write([]string{
"path", "json", "xml", "default", "restart",
})
walk(w, "", &config.Configuration{})
w.Flush()
new.Close()
}
func walk(w *csv.Writer, prefix string, data interface{}) {
s := reflect.ValueOf(data).Elem()
t := s.Type()
for i := 0; i < s.NumField(); i++ {
f := s.Field(i)
ft := t.Field(i)
for f.Kind() == reflect.Ptr {
f = f.Elem()
}
pfx := prefix + "." + s.Type().Field(i).Name
if f.Kind() == reflect.Slice {
slc := reflect.MakeSlice(f.Type(), 1, 1)
f = slc.Index(0)
pfx = prefix + "." + s.Type().Field(i).Name + "[]"
}
if f.Kind() == reflect.Struct && strings.HasPrefix(f.Type().PkgPath(), "github.com/syncthing/syncthing") {
walk(w, pfx, f.Addr().Interface())
} else {
jsonTag := ft.Tag.Get("json")
xmlTag := ft.Tag.Get("xml")
defaultTag := ft.Tag.Get("default")
restartTag := ft.Tag.Get("restart")
w.Write([]string{
strings.ToLower(pfx), jsonTag, xmlTag, defaultTag, restartTag,
})
}
}
}
+291
View File
@@ -0,0 +1,291 @@
// Copyright (C) 2020 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
//+build ignore
package main
import (
"fmt"
"path/filepath"
"strings"
"unicode"
"github.com/syncthing/syncthing/proto/ext"
"github.com/gogo/protobuf/gogoproto"
"github.com/gogo/protobuf/proto"
"github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
"github.com/gogo/protobuf/vanity"
"github.com/gogo/protobuf/vanity/command"
)
func main() {
req := command.Read()
files := req.GetProtoFile()
files = vanity.FilterFiles(files, vanity.NotGoogleProtobufDescriptorProto)
vanity.ForEachFile(files, vanity.TurnOffGoGettersAll)
vanity.ForEachFile(files, TurnOnProtoSizerAll)
vanity.ForEachFile(files, vanity.TurnOffGoEnumPrefixAll)
vanity.ForEachFile(files, vanity.TurnOffGoUnrecognizedAll)
vanity.ForEachFile(files, vanity.TurnOffGoUnkeyedAll)
vanity.ForEachFile(files, vanity.TurnOffGoSizecacheAll)
vanity.ForEachFile(files, vanity.TurnOffGoEnumStringerAll)
vanity.ForEachEnumInFiles(files, HandleCustomEnumExtensions)
vanity.ForEachFile(files, SetPackagePrefix("github.com/syncthing/syncthing"))
vanity.ForEachMessageInFiles(files, HandleCustomExtensions)
vanity.ForEachFieldInFilesExcludingExtensions(files, TurnOffNullableForMessages)
resp := command.Generate(req)
command.Write(resp)
}
func TurnOnProtoSizerAll(file *descriptor.FileDescriptorProto) {
vanity.SetBoolFileOption(gogoproto.E_ProtosizerAll, true)(file)
}
func TurnOffNullableForMessages(field *descriptor.FieldDescriptorProto) {
if !vanity.FieldHasBoolExtension(field, gogoproto.E_Nullable) {
_, hasCustomType := GetFieldStringExtension(field, gogoproto.E_Customtype)
if field.IsMessage() || hasCustomType {
vanity.SetBoolFieldOption(gogoproto.E_Nullable, false)(field)
}
}
}
func HandleCustomEnumExtensions(enum *descriptor.EnumDescriptorProto) {
for _, field := range enum.Value {
if field == nil {
continue
}
if field.Options == nil {
field.Options = &descriptor.EnumValueOptions{}
}
customName := gogoproto.GetEnumValueCustomName(field)
if customName != "" {
continue
}
if v, ok := GetEnumValueStringExtension(field, ext.E_Enumgoname); ok {
SetEnumValueStringFieldOption(field, gogoproto.E_EnumvalueCustomname, v)
} else {
SetEnumValueStringFieldOption(field, gogoproto.E_EnumvalueCustomname, toCamelCase(*field.Name, true))
}
}
}
func SetPackagePrefix(prefix string) func(file *descriptor.FileDescriptorProto) {
return func(file *descriptor.FileDescriptorProto) {
if file.Options.GoPackage == nil {
pkg, _ := filepath.Split(file.GetName())
fullPkg := prefix + "/" + strings.TrimSuffix(pkg, "/")
file.Options.GoPackage = &fullPkg
}
}
}
func toCamelCase(input string, firstUpper bool) string {
runes := []rune(strings.ToLower(input))
outputRunes := make([]rune, 0, len(runes))
nextUpper := false
for i, rune := range runes {
if rune == '_' {
nextUpper = true
continue
}
if (firstUpper && i == 0) || nextUpper {
rune = unicode.ToUpper(rune)
nextUpper = false
}
outputRunes = append(outputRunes, rune)
}
return string(outputRunes)
}
func SetStringFieldOption(field *descriptor.FieldDescriptorProto, extension *proto.ExtensionDesc, value string) {
if _, ok := GetFieldStringExtension(field, extension); ok {
return
}
if field.Options == nil {
field.Options = &descriptor.FieldOptions{}
}
if err := proto.SetExtension(field.Options, extension, &value); err != nil {
panic(err)
}
}
func SetEnumValueStringFieldOption(field *descriptor.EnumValueDescriptorProto, extension *proto.ExtensionDesc, value string) {
if _, ok := GetEnumValueStringExtension(field, extension); ok {
return
}
if field.Options == nil {
field.Options = &descriptor.EnumValueOptions{}
}
if err := proto.SetExtension(field.Options, extension, &value); err != nil {
panic(err)
}
}
func GetEnumValueStringExtension(enumValue *descriptor.EnumValueDescriptorProto, extension *proto.ExtensionDesc) (string, bool) {
if enumValue.Options == nil {
return "", false
}
value, err := proto.GetExtension(enumValue.Options, extension)
if err != nil {
return "", false
}
if value == nil {
return "", false
}
if v, ok := value.(*string); !ok || v == nil {
return "", false
} else {
return *v, true
}
}
func GetFieldStringExtension(field *descriptor.FieldDescriptorProto, extension *proto.ExtensionDesc) (string, bool) {
if field.Options == nil {
return "", false
}
value, err := proto.GetExtension(field.Options, extension)
if err != nil {
return "", false
}
if value == nil {
return "", false
}
if v, ok := value.(*string); !ok || v == nil {
return "", false
} else {
return *v, true
}
}
func GetFieldBooleanExtension(field *descriptor.FieldDescriptorProto, extension *proto.ExtensionDesc) (bool, bool) {
if field.Options == nil {
return false, false
}
value, err := proto.GetExtension(field.Options, extension)
if err != nil {
return false, false
}
if value == nil {
return false, false
}
if v, ok := value.(*bool); !ok || v == nil {
return false, false
} else {
return *v, true
}
}
func GetMessageBoolExtension(msg *descriptor.DescriptorProto, extension *proto.ExtensionDesc) (bool, bool) {
if msg.Options == nil {
return false, false
}
value, err := proto.GetExtension(msg.Options, extension)
if err != nil {
return false, false
}
if value == nil {
return false, false
}
val, ok := value.(*bool)
if !ok || val == nil {
return false, false
}
return *val, true
}
func HandleCustomExtensions(msg *descriptor.DescriptorProto) {
generateXmlTags := true
if generate, ok := GetMessageBoolExtension(msg, ext.E_XmlTags); ok {
generateXmlTags = generate
}
vanity.ForEachField([]*descriptor.DescriptorProto{msg}, func(field *descriptor.FieldDescriptorProto) {
if field.Options == nil {
field.Options = &descriptor.FieldOptions{}
}
deprecated := field.Options.Deprecated != nil && *field.Options.Deprecated == true
if field.Type != nil && *field.Type == descriptor.FieldDescriptorProto_TYPE_INT32 {
SetStringFieldOption(field, gogoproto.E_Casttype, "int")
}
if field.TypeName != nil && *field.TypeName == ".google.protobuf.Timestamp" {
vanity.SetBoolFieldOption(gogoproto.E_Stdtime, true)(field)
}
if goName, ok := GetFieldStringExtension(field, ext.E_Goname); ok {
SetStringFieldOption(field, gogoproto.E_Customname, goName)
} else if deprecated {
SetStringFieldOption(field, gogoproto.E_Customname, "Deprecated"+toCamelCase(*field.Name, true))
}
if val, ok := GetFieldBooleanExtension(field, ext.E_DeviceId); ok && val {
SetStringFieldOption(field, gogoproto.E_Customtype, "github.com/syncthing/syncthing/lib/protocol.DeviceID")
}
if jsonValue, ok := GetFieldStringExtension(field, ext.E_Json); ok {
SetStringFieldOption(field, gogoproto.E_Jsontag, jsonValue)
} else if deprecated {
SetStringFieldOption(field, gogoproto.E_Jsontag, "-")
} else {
SetStringFieldOption(field, gogoproto.E_Jsontag, toCamelCase(*field.Name, false))
}
current := ""
if v, ok := GetFieldStringExtension(field, gogoproto.E_Moretags); ok {
current = v
}
if generateXmlTags {
if len(current) > 0 {
current += " "
}
if xmlValue, ok := GetFieldStringExtension(field, ext.E_Xml); ok {
current += fmt.Sprintf(`xml:"%s"`, xmlValue)
} else {
xmlValue = toCamelCase(*field.Name, false)
// XML dictates element name within the collection, not collection name, so trim plural suffix.
if field.IsRepeated() {
if strings.HasSuffix(xmlValue, "ses") {
// addresses -> address
xmlValue = strings.TrimSuffix(xmlValue, "es")
} else {
// devices -> device
xmlValue = strings.TrimSuffix(xmlValue, "s")
}
}
if deprecated {
xmlValue += ",omitempty"
}
current += fmt.Sprintf(`xml:"%s"`, xmlValue)
}
}
if defaultValue, ok := GetFieldStringExtension(field, ext.E_Default); ok {
if len(current) > 0 {
current += " "
}
current += fmt.Sprintf(`default:"%s"`, defaultValue)
}
if restartValue, ok := GetFieldBooleanExtension(field, ext.E_Restart); ok {
if len(current) > 0 {
current += " "
}
current += fmt.Sprintf(`restart:"%t"`, restartValue)
}
SetStringFieldOption(field, gogoproto.E_Moretags, current)
})
}
+121
View File
@@ -0,0 +1,121 @@
// Copyright (C) 2016 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
// +build ignore
package main
import (
"bufio"
"flag"
"fmt"
"io"
"log"
"os"
"path/filepath"
"regexp"
"strings"
"text/tabwriter"
)
func main() {
flag.Parse()
for _, arg := range flag.Args() {
matches, err := filepath.Glob(arg)
if err != nil {
log.Fatal(err)
}
for _, file := range matches {
if stat, err := os.Stat(file); err != nil {
log.Fatal(err)
} else if stat.IsDir() {
err := filepath.Walk(file, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if filepath.Ext(path) == ".proto" {
return formatProtoFile(path)
}
return nil
})
if err != nil {
log.Fatal(err)
}
} else {
if err := formatProtoFile(file); err != nil {
log.Fatal(err)
}
}
}
}
}
func formatProtoFile(file string) error {
log.Println("Formatting", file)
in, err := os.Open(file)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(file + ".tmp")
if err != nil {
return err
}
defer out.Close()
if err := formatProto(in, out); err != nil {
return err
}
in.Close()
out.Close()
return os.Rename(file+".tmp", file)
}
func formatProto(in io.Reader, out io.Writer) error {
sc := bufio.NewScanner(in)
lineExp := regexp.MustCompile(`([^=]+)\s+([^=\s]+?)\s*=(.+)`)
var tw *tabwriter.Writer
for sc.Scan() {
line := sc.Text()
if strings.HasPrefix(line, "//") {
if _, err := fmt.Fprintln(out, line); err != nil {
return err
}
continue
}
ms := lineExp.FindStringSubmatch(line)
for i := range ms {
ms[i] = strings.TrimSpace(ms[i])
}
if len(ms) == 4 && ms[1] != "option" {
typ := strings.Join(strings.Fields(ms[1]), " ")
name := ms[2]
id := ms[3]
if tw == nil {
tw = tabwriter.NewWriter(out, 4, 4, 1, ' ', 0)
}
if typ == "" {
// We're in an enum
fmt.Fprintf(tw, "\t%s\t= %s\n", name, id)
} else {
// Message
fmt.Fprintf(tw, "\t%s\t%s\t= %s\n", typ, name, id)
}
} else {
if tw != nil {
if err := tw.Flush(); err != nil {
return err
}
tw = nil
}
if _, err := fmt.Fprintln(out, line); err != nil {
return err
}
}
}
return nil
}